Skip to content

Commit

Permalink
Convert Inline Table Rows to Individual CodeLines (#5898)
Browse files Browse the repository at this point in the history
* Update CodeFileRenderer

* Make inline table on per row basis

* Improve inline table

* Fix line numbers for inline tables

* Update test pipeline

* Disable single integration test.
  • Loading branch information
chidozieononiwu authored Apr 26, 2023
1 parent b3301af commit 27fdb90
Show file tree
Hide file tree
Showing 14 changed files with 318 additions and 89 deletions.
15 changes: 2 additions & 13 deletions eng/pipelines/templates/steps/apiview-ui-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ steps:
AZURE_TENANT_ID: "$(apiview-appconfig-tenant-id)"
AZURE_CLIENT_SECRET: "$(apiview-appconfig-client-secret)"
APIVIEW_APPROVERS: "azure-sdk"
APIVIEW_SWAGGERMETADATABACKGROUNDTASKDISABLED: "true"

- task: Powershell@2
inputs:
Expand All @@ -65,19 +66,7 @@ steps:
displayName: 'Copy from Test Files From Blob'
env:
AZCOPY_SPA_CLIENT_SECRET: $(apiviewstorageaccess-service-principal-key)

- task: Powershell@2
inputs:
filePath: $(Build.SourcesDirectory)/eng/common/scripts/copy-from-blobstorage.ps1
arguments: >
-SourceBlobPath '${{ parameters.TestingDataContainer }}'
-ApplicationId $(apiviewstorageaccess-application-id)
-DestinationDirectory $(Build.BinariesDirectory)
pwsh: true
displayName: 'Copy from Test Files From Blob'
env:
AZCOPY_SPA_CLIENT_SECRET: $(apiviewstorageaccess-service-principal-key)


- task: DotNetCoreCLI@2
displayName: 'Build & Test (UI)'
env:
Expand Down
121 changes: 63 additions & 58 deletions src/dotnet/APIView/APIView/CodeFileRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ private void Render(List<CodeLine> list, IEnumerable<CodeFileToken> node, bool s
{
var stringBuilder = new StringBuilder();
string currentId = null;
string currentTableId = null;
bool isDocumentationRange = false;
bool isHiddenApiToken = false;
bool isDeprecatedToken = false;
Expand All @@ -56,43 +57,7 @@ private void Render(List<CodeLine> list, IEnumerable<CodeFileToken> node, bool s
switch (token.Kind)
{
case CodeFileTokenKind.Newline:
int ? sectionKey = (nodesInProcess.Count > 0 && section == null) ? sections.Count: null;
CodeLine codeLine = new CodeLine(stringBuilder.ToString(), currentId, String.Empty, ++lineNumber, sectionKey, isDocumentation: isDocumentationRange, isHiddenApi: isHiddenApiToken);
if (leafSectionPlaceHolderNumber != 0)
{
lineNumber += leafSectionPlaceHolderNumber - 1;
leafSectionPlaceHolderNumber = 0;
}
if (nodesInProcess.Count > 0)
{
if (nodesInProcess.Peek().Equals(SectionType.Heading))
{
if (section == null)
{
section = new TreeNode<CodeLine>(codeLine);
list.Add(codeLine);
}
else
{
section = section.AddChild(codeLine);
}
}
else
{
section.AddChild(codeLine);
}
}
else
{
if (section != null)
{
sections.Add(sections.Count, section);
section = null;
}
list.Add(codeLine);
}
currentId = null;
stringBuilder.Clear();
CaptureCodeLine(list, sections, nodesInProcess, ref section, stringBuilder, ref lineNumber, ref leafSectionPlaceHolderNumber, ref currentId, isDocumentationRange, isHiddenApiToken);
break;

case CodeFileTokenKind.DocumentRangeStart:
Expand Down Expand Up @@ -154,8 +119,7 @@ private void Render(List<CodeLine> list, IEnumerable<CodeFileToken> node, bool s
break;

case CodeFileTokenKind.TableBegin:
stringBuilder.Append("<table class=\"table table-sm\">");
currentId = (token.DefinitionId != null) ? token.DefinitionId : currentId;
currentTableId = (token.DefinitionId != null) ? token.DefinitionId : currentId;
break;

case CodeFileTokenKind.TableColumnCount:
Expand All @@ -171,61 +135,62 @@ private void Render(List<CodeLine> list, IEnumerable<CodeFileToken> node, bool s
case CodeFileTokenKind.TableColumnName:
if (tableColumnCount.Curr == 0)
{
stringBuilder.Append($"<thead><tr>");
stringBuilder.Append($"<th height=\"30\" scope=\"col\">");
stringBuilder.Append($"<ul class=\"list-group list-group-horizontal\">");
stringBuilder.Append($"<li class=\"list-group-item border-top\"><strong>");
RenderToken(token, stringBuilder, isDeprecatedToken, isHiddenApiToken);
stringBuilder.Append("</th>");
stringBuilder.Append("</strong></li>");
tableColumnCount.Curr++;
}
else if (tableColumnCount.Curr == tableColumnCount.Count - 1)
{
stringBuilder.Append($"<th height=\"30\" scope=\"col\">");
currentId = $"{currentTableId}-th";
stringBuilder.Append($"<li class=\"list-group-item border-top\"><strong>");
RenderToken(token, stringBuilder, isDeprecatedToken, isHiddenApiToken);
stringBuilder.Append("</th>");
stringBuilder.Append("</tr></thead><tbody>");
stringBuilder.Append("</strong></li>");
stringBuilder.Append("</ul>");
tableColumnCount.Curr = 0;
CaptureCodeLine(list, sections, nodesInProcess, ref section, stringBuilder, ref lineNumber, ref leafSectionPlaceHolderNumber, ref currentId, isDocumentationRange, isHiddenApiToken);
}
else
{
stringBuilder.Append($"<th height=\"30\" scope=\"col\">");
stringBuilder.Append($"<li class=\"list-group-item border-top\"><strong>");
RenderToken(token, stringBuilder, isDeprecatedToken, isHiddenApiToken);
stringBuilder.Append("</th>");
stringBuilder.Append("</strong></li>");
tableColumnCount.Curr++;
}
break;

case CodeFileTokenKind.TableCellBegin:
if (tableColumnCount.Curr == 0)
{
var rowId = $"{currentId}-tr-{tableRowCount.Curr + 1}";
stringBuilder.Append($"<tr data-inline-id=\"{rowId}\"><td height=\"30\"><a class=\"line-comment-button\">+</a>");
stringBuilder.Append($"<ul class=\"list-group list-group-horizontal\">");
stringBuilder.Append($"<li class=\"list-group-item\">");
tableColumnCount.Curr++;
}
else if (tableColumnCount.Curr == tableColumnCount.Count - 1)
{
stringBuilder.Append($"<td height=\"30\">");
currentId = $"{currentTableId}-tr-{tableRowCount.Curr + 1}";
stringBuilder.Append($"<li class=\"list-group-item\">");
tableColumnCount.Curr = 0;
tableRowCount.Curr++;
}
else
{
stringBuilder.Append($"<td height=\"30\">");
stringBuilder.Append($"<li class=\"list-group-item\">");
tableColumnCount.Curr++;
}
break;

case CodeFileTokenKind.TableCellEnd:
stringBuilder.Append($"</td height=\"30\">");
stringBuilder.Append("</li>");
if (tableColumnCount.Curr == 0)
{
stringBuilder.Append($"</tr>");
stringBuilder.Append("</ul>");
CaptureCodeLine(list, sections, nodesInProcess, ref section, stringBuilder, ref lineNumber, ref leafSectionPlaceHolderNumber, ref currentId, isDocumentationRange, isHiddenApiToken);
}
break;

case CodeFileTokenKind.TableEnd:
stringBuilder.Append($"</tbody>");
stringBuilder.Append("</table>");

break;

case CodeFileTokenKind.LeafSectionPlaceholder:
Expand Down Expand Up @@ -262,12 +227,52 @@ protected virtual void RenderToken(CodeFileToken token, StringBuilder stringBuil
protected virtual void StartDocumentationRange(StringBuilder stringBuilder) { }
protected virtual void CloseDocumentationRange(StringBuilder stringBuilder) { }

private void UpdateDefinitionId(CodeFileToken token, string currentId)
private void CaptureCodeLine(List<CodeLine> list, Dictionary<int, TreeNode<CodeLine>> sections, Stack<SectionType> nodesInProcess,
ref TreeNode<CodeLine> section, StringBuilder stringBuilder, ref int lineNumber, ref int leafSectionPlaceHolderNumber, ref string currentId,
bool isDocumentationRange = false, bool isHiddenApiToken = false)
{
currentId = (token.DefinitionId != null) ? token.DefinitionId : currentId;
int? sectionKey = (nodesInProcess.Count > 0 && section == null) ? sections.Count : null;
CodeLine codeLine = new CodeLine(stringBuilder.ToString(), currentId, String.Empty, ++lineNumber, sectionKey, isDocumentation: isDocumentationRange, isHiddenApi: isHiddenApiToken);
if (leafSectionPlaceHolderNumber != 0)
{
lineNumber += leafSectionPlaceHolderNumber - 1;
leafSectionPlaceHolderNumber = 0;
}
if (nodesInProcess.Count > 0)
{
if (nodesInProcess.Peek().Equals(SectionType.Heading))
{
if (section == null)
{
section = new TreeNode<CodeLine>(codeLine);
list.Add(codeLine);
}
else
{
section = section.AddChild(codeLine);
}
}
else
{
section.AddChild(codeLine);
}
}
else
{
if (section != null)
{
sections.Add(sections.Count, section);
section = null;
}
list.Add(codeLine);
}
currentId = null;
stringBuilder.Clear();
}
}



public struct RenderResult
{
public RenderResult(CodeLine[] codeLines, Dictionary<int,TreeNode<CodeLine>> sections)
Expand Down
6 changes: 6 additions & 0 deletions src/dotnet/APIView/APIView/Model/CodeFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ public static async Task<CodeFile> DeserializeAsync(Stream stream, bool hasSecti
{
numberOfLinesinLeafSection++;
}

if (isLeaf && token.Kind == CodeFileTokenKind.TableRowCount)
{
numberOfLinesinLeafSection += (Convert.ToInt16(token.Value)) + 1;
}

section.Add(token);
}
index++;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.10.0" />
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.26.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="3.1.13" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Moq" Version="4.18.2" />
Expand Down
55 changes: 55 additions & 0 deletions src/dotnet/APIView/APIViewIntegrationTests/ReviewManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
using System;
using APIViewWeb;
using APIViewWeb.Repositories;
using Newtonsoft.Json;
using APIViewWeb.Models;
using System.Collections.Generic;
using ApiView;
using FluentAssertions;

namespace APIViewIntegrationTests
{
Expand Down Expand Up @@ -90,5 +95,55 @@ public async Task Delete_PullRequest_Review_Throws_Exception()

await Assert.ThrowsAsync<UnDeletableReviewException>(async () => await reviewManager.DeleteRevisionAsync(user, review.ReviewId, review.Revisions[0].RevisionId));
}

[Fact(Skip = "Need Resource to run so won't run on PR piplines plus Only needed once.")]
public async Task UpdateSwaggerReviewsMetaData_Test()
{
string reviewJson = File.ReadAllText(Path.Join(testsBaseFixture.TestDataPath, "account.swagger-cosmos-data.json"));
ReviewModel testReview = JsonConvert.DeserializeObject<ReviewModel>(reviewJson);
await testsBaseFixture.ReviewRepository.UpsertReviewAsync(testReview);

DirectoryInfo directoryInfo = new DirectoryInfo(Path.Join(testsBaseFixture.TestDataPath, "testComments"));

foreach(var file in directoryInfo.GetFiles())
{
string commentJson = File.ReadAllText(file.FullName);
CommentModel comment = JsonConvert.DeserializeObject<CommentModel>(commentJson);
await testsBaseFixture.CommentRepository.UpsertCommentAsync(comment);
}

foreach (var revision in testReview.Revisions)
{
string codeFileJson = File.ReadAllText(Path.Join(testsBaseFixture.TestDataPath, "codeFiles", revision.Files[0].ReviewFileId));
CodeFile testCodeFile = JsonConvert.DeserializeObject<CodeFile>(codeFileJson);
await testsBaseFixture.BlobCodeFileRepository.UpsertCodeFileAsync(revision.RevisionId, revision.Files[0].ReviewFileId, testCodeFile);
}

await testsBaseFixture.ReviewManager.UpdateSwaggerReviewsMetaData();

ReviewModel updatedReview = await testsBaseFixture.ReviewRepository.GetReviewAsync(testReview.ReviewId);
IEnumerable<CommentModel> updatedComments = await testsBaseFixture.CommentRepository.GetCommentsAsync(testReview.ReviewId);

List<string> expectedCommentIds = new List<string>() {
"-account.swagger-General-consumes",
"-account.swagger-Paths-/",
"-account.swagger-Paths-/collections-0-operationId-Collections_ListCollections-QueryParameters-table-tr-2",
"-account.swagger-Paths-/collections-0-operationId-Collections_ListCollections-Responses-200-table-tr-3"
};

foreach (var comment in updatedComments)
{
expectedCommentIds.Should().Contain(comment.ElementId);
}

int[] expectedLineNumbers = { 1, 2, 3, 7, 8, 9, 10, 11, 20, 26, 860, 1184, 1193};
var renderedCodeFile = await testsBaseFixture.BlobCodeFileRepository.GetCodeFileAsync(updatedReview.Revisions[1]);
renderedCodeFile.Render(false);

for (int i = 0; i < renderedCodeFile.RenderResult.CodeLines.Length; i++)
{
Assert.Equal(renderedCodeFile.RenderResult.CodeLines[i].LineNumber, expectedLineNumbers[i]);
}
}
}
}
13 changes: 9 additions & 4 deletions src/dotnet/APIView/APIViewIntegrationTests/TestsBaseFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@ public class TestsBaseFixture : IDisposable
private readonly CosmosClient _cosmosClient;
private readonly BlobContainerClient _blobCodeFileContainerClient;
private readonly BlobContainerClient _blobOriginalContainerClient;

public PackageNameManager PackageNameManager { get; private set; }
public ReviewManager ReviewManager { get; private set; }
public BlobCodeFileRepository BlobCodeFileRepository { get; private set; }
public CosmosReviewRepository ReviewRepository { get; private set; }
public CosmosCommentsRepository CommentRepository { get; private set; }
public ClaimsPrincipal User { get; private set; }
public string TestDataPath { get; private set; }

public TestsBaseFixture()
{
Expand Down Expand Up @@ -65,15 +68,15 @@ public TestsBaseFixture()
_ = dataBaseResponse.Database.CreateContainerIfNotExistsAsync("Comments", "/ReviewId");
_ = dataBaseResponse.Database.CreateContainerIfNotExistsAsync("Profiles", "/id");
ReviewRepository = new CosmosReviewRepository(config);
var cosmosCommentsRepository = new CosmosCommentsRepository(config);
CommentRepository = new CosmosCommentsRepository(config);
var cosmosUserProfileRepository = new CosmosUserProfileRepository(config);

_blobCodeFileContainerClient = new BlobContainerClient(config["Blob:ConnectionString"], "codefiles");
_blobOriginalContainerClient = new BlobContainerClient(config["Blob:ConnectionString"], "originals");
_ = _blobCodeFileContainerClient.CreateIfNotExistsAsync(PublicAccessType.BlobContainer);
_ = _blobOriginalContainerClient.CreateIfNotExistsAsync(PublicAccessType.BlobContainer);

var blobCodeFileRepository = new BlobCodeFileRepository(config, memoryCache);
BlobCodeFileRepository = new BlobCodeFileRepository(config, memoryCache);
var blobOriginalsRepository = new BlobOriginalsRepository(config);

var authorizationServiceMoq = new Mock<IAuthorizationService>();
Expand All @@ -90,8 +93,10 @@ public TestsBaseFixture()
.Returns(Task.CompletedTask);

ReviewManager = new ReviewManager(
authorizationServiceMoq.Object, ReviewRepository, blobCodeFileRepository, blobOriginalsRepository, cosmosCommentsRepository,
authorizationServiceMoq.Object, ReviewRepository, BlobCodeFileRepository, blobOriginalsRepository, CommentRepository,
languageService, notificationManager, devopsArtifactRepositoryMoq.Object, PackageNameManager);

TestDataPath = config["TestPkgPath"];
}

public void Dispose()
Expand Down
6 changes: 3 additions & 3 deletions src/dotnet/APIView/APIViewUnitTests/CodeFileRendererTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public void RenderedResult_Sections_Correct_CodeLines()
Assert.Equal(2, codeLines[1].LineNumber);
Assert.Equal(15, codeLines[2].LineNumber);
Assert.Equal(16, codeLines[3].LineNumber);
Assert.Equal(58, codeLines[4].LineNumber);
Assert.Equal(60, codeLines[4].LineNumber);
}

[Fact]
Expand All @@ -51,8 +51,8 @@ public void RenderedResult_Sections_Has_Detached_Leafs()

[Theory]
[InlineData(0, 3, 14)]
[InlineData(1, 17, 57)]
[InlineData(2, 59, 83)]
[InlineData(1, 17, 59)]
[InlineData(2, 61, 87)]
public void RenderedResult_Sections_Has_Correct_Lines_In_Sections(int sectionPosition, int firstLineNumber, int lastLineNumber)
{
var sectionKey = renderedCodeFile.RenderResult.Sections[sectionPosition].Data.SectionKey;
Expand Down
8 changes: 8 additions & 0 deletions src/dotnet/APIView/APIViewUnitTests/ReviewManagerTests.cs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Moq;

namespace APIViewUnitTests
{
public class ReviewManagerTests
{
}
}
Loading

0 comments on commit 27fdb90

Please sign in to comment.