Skip to content
Merged
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,172 @@
using Newtonsoft.Json.Linq;
using System.Text.Json.Serialization;
using APIView.Model.V2;
using Microsoft.CodeAnalysis;
using NuGet.ContentModel;


namespace CSharpAPIParserTests
{
public class CodeFileTests
{
private readonly CodeFile codeFile;
public Assembly assembly { get; set; }
static CodeFile templateCodeFile;
static Assembly templateAssembly { get; set; }
static CodeFile storageCodeFile;
static Assembly storageAssembly { get; set; }
static CodeFile coreCodeFile;
static Assembly coreAssembly { get; set; }

public CodeFileTests()
public CodeFileTests() { }
static CodeFileTests()
{
assembly = Assembly.Load("Azure.Template");
var dllStream = assembly.GetFile("Azure.Template.dll");
templateAssembly = Assembly.Load("Azure.Template");
var dllStream = templateAssembly.GetFile("Azure.Template.dll");
var assemblySymbol = CompilationFactory.GetCompilation(dllStream, null);
this.codeFile = new CSharpAPIParser.TreeToken.CodeFileBuilder().Build(assemblySymbol, true, null);
templateCodeFile = new CSharpAPIParser.TreeToken.CodeFileBuilder().Build(assemblySymbol, true, null);

storageAssembly = Assembly.Load("Azure.Storage.Blobs");
dllStream = storageAssembly.GetFile("Azure.Storage.Blobs.dll");
assemblySymbol = CompilationFactory.GetCompilation(dllStream, null);
storageCodeFile = new CSharpAPIParser.TreeToken.CodeFileBuilder().Build(assemblySymbol, true, null);

coreAssembly = Assembly.Load("Azure.Core");
dllStream = coreAssembly.GetFile("Azure.Core.dll");
assemblySymbol = CompilationFactory.GetCompilation(dllStream, null);
coreCodeFile = new CSharpAPIParser.TreeToken.CodeFileBuilder().Build(assemblySymbol, true, null);
}

[Fact]
public void TestPackageName()
public static IEnumerable<object[]> CodeFiles => new List<object[]>
{
Assert.Equal("Azure.Template", codeFile.PackageName);
new object[] { templateCodeFile, "Azure.Template" , "1.0.3.0"},
new object[] { storageCodeFile , "Azure.Storage.Blobs", "12.21.2.0"},
new object[] { coreCodeFile, "Azure.Core", "1.42.0.0"},
};

[Theory]
[MemberData(nameof(CodeFiles))]
public void TestPackageMetadata(CodeFile codeFile, string expectedPackageName, string expectedVersion)
{
Assert.Equal(expectedPackageName, codeFile.PackageName);
Assert.Equal(expectedVersion, codeFile.PackageVersion);
Assert.Equal("C#", codeFile.Language);
}

[Fact]
public void TestTopLevelReviewLineCount()
{
Assert.Equal(8, codeFile.ReviewLines.Count());
Assert.Equal(8, templateCodeFile.ReviewLines.Count());
Comment thread
praveenkuttappan marked this conversation as resolved.
Outdated
}

[Fact]
public void TestClassReviewLineWithoutBase()
{
var lines = storageCodeFile.ReviewLines;
var namespaceLine = lines.Where(lines => lines.LineId == "Azure.Storage.Blobs").FirstOrDefault();
Assert.NotNull(namespaceLine);
var classLine = namespaceLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.BlobServiceClient").FirstOrDefault();
Assert.NotNull(classLine);
Assert.Equal(4, classLine.Tokens.Count());
Assert.Equal("public class BlobServiceClient {", classLine.ToString().Trim());
}

[Fact]
public void TestClassReviewLineWithBase()
{
var lines = storageCodeFile.ReviewLines;
var namespaceLine = lines.Where(lines => lines.LineId == "Azure.Storage.Blobs.Models").FirstOrDefault();
Assert.NotNull(namespaceLine);
var classLine = namespaceLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.Models.BlobDownloadInfo").FirstOrDefault();
Assert.NotNull(classLine);
Assert.Equal(6, classLine.Tokens.Count());
Assert.Equal("public class BlobDownloadInfo : IDisposable {", classLine.ToString().Trim());
}

[Fact]
public void TestMultipleKeywords()
{
var lines = storageCodeFile.ReviewLines;
var namespaceLine = lines.Where(lines => lines.LineId == "Azure.Storage.Blobs.Models").FirstOrDefault();
Assert.NotNull(namespaceLine);
var classLine = namespaceLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.Models.AccessTier").FirstOrDefault();
Assert.NotNull(classLine);
Assert.Equal(10, classLine.Tokens.Count());
Assert.Equal("public readonly struct AccessTier : IEquatable<AccessTier> {", classLine.ToString().Trim());
}

[Fact]
public void TestApiReviewLine()
{
var lines = storageCodeFile.ReviewLines;
var namespaceLine = lines.Where(lines => lines.LineId == "Azure.Storage.Blobs").FirstOrDefault();
Assert.NotNull(namespaceLine);
var classLine = namespaceLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.BlobServiceClient").FirstOrDefault();
Assert.NotNull(classLine);
var methodLine = classLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.BlobServiceClient.BlobServiceClient(System.String)").FirstOrDefault();
Assert.Equal(7, methodLine.Tokens.Count());
Assert.Equal("public BlobServiceClient(string connectionString);", methodLine.ToString().Trim());
}

[Fact]
public void TestApiReviewLineMoreParams()
{
var lines = storageCodeFile.ReviewLines;
var namespaceLine = lines.Where(lines => lines.LineId == "Azure.Storage.Blobs").FirstOrDefault();
Assert.NotNull(namespaceLine);
var classLine = namespaceLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.BlobServiceClient").FirstOrDefault();
Assert.NotNull(classLine);
var methodLine = classLine.Children.Where(lines => lines.LineId.Contains("UndeleteBlobContainerAsync")).FirstOrDefault();
Assert.NotNull(methodLine);
Assert.Equal(23, methodLine.Tokens.Count);
Assert.Equal("public virtual Task<Response<BlobContainerClient>> UndeleteBlobContainerAsync(string deletedContainerName, string deletedContainerVersion, CancellationToken cancellationToken = default);", methodLine.ToString().Trim());
}

public static IEnumerable<object[]> PackageCodeFiles => new List<object[]>
{
new object[] { templateCodeFile },
new object[] { storageCodeFile },
new object[] { coreCodeFile }
};

[Theory]
[MemberData(nameof(PackageCodeFiles))]
public void TestAllClassesHaveEndOfContextLine(CodeFile codeFile)
{
// If current line is for class then next line at same level is expected to be a end of context line
var lines = codeFile.ReviewLines;
foreach(var namespaceLine in lines)
{
Assert.NotNull(namespaceLine);
bool expectEndOfContext = false;
var classLines = namespaceLine.Children;
for (int i = 0; i < classLines.Count; i++)
{
if (expectEndOfContext)
{
Assert.True(classLines[i].IsContextEndLine == true);
expectEndOfContext = false;
continue;
}

expectEndOfContext = classLines[i].Tokens.Any(t => (t.RenderClasses.Contains("class") ||
t.RenderClasses.Contains("struct") ||
t.RenderClasses.Contains("interface")) && !classLines[i].Tokens.Any(t => t.Value == "abstract"));
}
}
}

[Fact]
public void TestHiddenAPI()
{
var apiText = "protected static BlobServiceClient CreateClient(Uri serviceUri, BlobClientOptions options, HttpPipelinePolicy authentication, HttpPipeline pipeline);";
var lines = storageCodeFile.ReviewLines;
var namespaceLine = lines.Where(lines => lines.LineId == "Azure.Storage.Blobs").FirstOrDefault();
Assert.NotNull(namespaceLine);
var classLine = namespaceLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.BlobServiceClient").FirstOrDefault();
Assert.NotNull(classLine);
var hiddenApis = classLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.BlobServiceClient.CreateClient(System.Uri, Azure.Storage.Blobs.BlobClientOptions, Azure.Core.Pipeline.HttpPipelinePolicy, Azure.Core.Pipeline.HttpPipeline)").FirstOrDefault();
Assert.NotNull(hiddenApis);
Assert.Equal(18, hiddenApis.Tokens.Count());
Assert.Equal(apiText, hiddenApis.ToString().Trim());
}

[Fact]
Expand Down Expand Up @@ -77,29 +216,18 @@ public static class TemplateClientBuilderExtensions {
}
}
";
Assert.Equal(expected, codeFile.GetApiText());
Assert.Equal(expected, templateCodeFile.GetApiText());
}

[Fact]
public void TestCodeFileJsonSchema()
[Theory]
[MemberData(nameof(PackageCodeFiles))]
public void TestCodeFileJsonSchema(CodeFile codeFile)
{
//Verify JSON file generated for Azure.Template
var isValid = validateSchema(codeFile);
Assert.True(isValid);
}

[Fact]
public void TestCodeFileJsonSchema2()
{
//Verify JSON file generated for Azure.Storage.Blobs
var storageAssembly = Assembly.Load("Azure.Storage.Blobs");
var dllStream = storageAssembly.GetFile("Azure.Storage.Blobs.dll");
var assemblySymbol = CompilationFactory.GetCompilation(dllStream, null);
var storageCodeFile = new CSharpAPIParser.TreeToken.CodeFileBuilder().Build(assemblySymbol, true, null);
var isValid = validateSchema(storageCodeFile);
Assert.True(isValid);
}

private bool validateSchema(CodeFile codeFile)
{
var json = JsonSerializer.Serialize(codeFile, new JsonSerializerOptions
Expand Down Expand Up @@ -129,9 +257,9 @@ private bool validateSchema(CodeFile codeFile)
}

[Fact]
public void TestNavigatonNodeHasRenderingClass()
public void TestNavigationNodeHasRenderingClass()
{
var jsonString = JsonSerializer.Serialize(codeFile);
var jsonString = JsonSerializer.Serialize(templateCodeFile);
var parsedCodeFile = JsonSerializer.Deserialize<CodeFile>(jsonString);
Assert.Equal(8, CountNavigationNodes(parsedCodeFile.ReviewLines));
}
Expand Down