|
7 | 7 | using Newtonsoft.Json.Linq; |
8 | 8 | using System.Text.Json.Serialization; |
9 | 9 | using APIView.Model.V2; |
| 10 | +using Microsoft.CodeAnalysis; |
| 11 | +using NuGet.ContentModel; |
10 | 12 |
|
11 | 13 |
|
12 | 14 | namespace CSharpAPIParserTests |
13 | 15 | { |
14 | 16 | public class CodeFileTests |
15 | 17 | { |
16 | | - private readonly CodeFile codeFile; |
17 | | - public Assembly assembly { get; set; } |
| 18 | + static CodeFile templateCodeFile; |
| 19 | + static Assembly templateAssembly { get; set; } |
| 20 | + static CodeFile storageCodeFile; |
| 21 | + static Assembly storageAssembly { get; set; } |
| 22 | + static CodeFile coreCodeFile; |
| 23 | + static Assembly coreAssembly { get; set; } |
18 | 24 |
|
19 | | - public CodeFileTests() |
| 25 | + public CodeFileTests() { } |
| 26 | + static CodeFileTests() |
20 | 27 | { |
21 | | - assembly = Assembly.Load("Azure.Template"); |
22 | | - var dllStream = assembly.GetFile("Azure.Template.dll"); |
| 28 | + templateAssembly = Assembly.Load("Azure.Template"); |
| 29 | + var dllStream = templateAssembly.GetFile("Azure.Template.dll"); |
23 | 30 | var assemblySymbol = CompilationFactory.GetCompilation(dllStream, null); |
24 | | - this.codeFile = new CSharpAPIParser.TreeToken.CodeFileBuilder().Build(assemblySymbol, true, null); |
| 31 | + templateCodeFile = new CSharpAPIParser.TreeToken.CodeFileBuilder().Build(assemblySymbol, true, null); |
| 32 | + |
| 33 | + storageAssembly = Assembly.Load("Azure.Storage.Blobs"); |
| 34 | + dllStream = storageAssembly.GetFile("Azure.Storage.Blobs.dll"); |
| 35 | + assemblySymbol = CompilationFactory.GetCompilation(dllStream, null); |
| 36 | + storageCodeFile = new CSharpAPIParser.TreeToken.CodeFileBuilder().Build(assemblySymbol, true, null); |
| 37 | + |
| 38 | + coreAssembly = Assembly.Load("Azure.Core"); |
| 39 | + dllStream = coreAssembly.GetFile("Azure.Core.dll"); |
| 40 | + assemblySymbol = CompilationFactory.GetCompilation(dllStream, null); |
| 41 | + coreCodeFile = new CSharpAPIParser.TreeToken.CodeFileBuilder().Build(assemblySymbol, true, null); |
| 42 | + } |
| 43 | + |
| 44 | + public static IEnumerable<object[]> CodeFiles => new List<object[]> |
| 45 | + { |
| 46 | + new object[] { templateCodeFile, "Azure.Template" , "1.0.3.0", 8}, |
| 47 | + new object[] { storageCodeFile , "Azure.Storage.Blobs", "12.21.2.0", 14}, |
| 48 | + new object[] { coreCodeFile, "Azure.Core", "1.42.0.0", 26}, |
| 49 | + }; |
| 50 | + |
| 51 | + [Theory] |
| 52 | + [MemberData(nameof(CodeFiles))] |
| 53 | + public void TestPackageMetadata(CodeFile codeFile, string expectedPackageName, string expectedVersion, int expectedNumberOfTopLines) |
| 54 | + { |
| 55 | + Assert.Equal(expectedPackageName, codeFile.PackageName); |
| 56 | + Assert.Equal(expectedVersion, codeFile.PackageVersion); |
| 57 | + Assert.Equal("C#", codeFile.Language); |
| 58 | + Assert.Equal(expectedNumberOfTopLines, codeFile.ReviewLines.Count); |
| 59 | + } |
| 60 | + |
| 61 | + [Fact] |
| 62 | + public void TestClassReviewLineWithoutBase() |
| 63 | + { |
| 64 | + var lines = storageCodeFile.ReviewLines; |
| 65 | + var namespaceLine = lines.Where(lines => lines.LineId == "Azure.Storage.Blobs").FirstOrDefault(); |
| 66 | + Assert.NotNull(namespaceLine); |
| 67 | + var classLine = namespaceLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.BlobServiceClient").FirstOrDefault(); |
| 68 | + Assert.NotNull(classLine); |
| 69 | + Assert.Equal(4, classLine.Tokens.Count()); |
| 70 | + Assert.Equal("public class BlobServiceClient {", classLine.ToString().Trim()); |
| 71 | + } |
| 72 | + |
| 73 | + [Fact] |
| 74 | + public void TestClassReviewLineWithBase() |
| 75 | + { |
| 76 | + var lines = storageCodeFile.ReviewLines; |
| 77 | + var namespaceLine = lines.Where(lines => lines.LineId == "Azure.Storage.Blobs.Models").FirstOrDefault(); |
| 78 | + Assert.NotNull(namespaceLine); |
| 79 | + var classLine = namespaceLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.Models.BlobDownloadInfo").FirstOrDefault(); |
| 80 | + Assert.NotNull(classLine); |
| 81 | + Assert.Equal(6, classLine.Tokens.Count()); |
| 82 | + Assert.Equal("public class BlobDownloadInfo : IDisposable {", classLine.ToString().Trim()); |
25 | 83 | } |
26 | 84 |
|
27 | 85 | [Fact] |
28 | | - public void TestPackageName() |
| 86 | + public void TestMultipleKeywords() |
29 | 87 | { |
30 | | - Assert.Equal("Azure.Template", codeFile.PackageName); |
| 88 | + var lines = storageCodeFile.ReviewLines; |
| 89 | + var namespaceLine = lines.Where(lines => lines.LineId == "Azure.Storage.Blobs.Models").FirstOrDefault(); |
| 90 | + Assert.NotNull(namespaceLine); |
| 91 | + var classLine = namespaceLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.Models.AccessTier").FirstOrDefault(); |
| 92 | + Assert.NotNull(classLine); |
| 93 | + Assert.Equal(10, classLine.Tokens.Count()); |
| 94 | + Assert.Equal("public readonly struct AccessTier : IEquatable<AccessTier> {", classLine.ToString().Trim()); |
31 | 95 | } |
32 | 96 |
|
33 | 97 | [Fact] |
34 | | - public void TestTopLevelReviewLineCount() |
| 98 | + public void TestApiReviewLine() |
35 | 99 | { |
36 | | - Assert.Equal(8, codeFile.ReviewLines.Count()); |
| 100 | + var lines = storageCodeFile.ReviewLines; |
| 101 | + var namespaceLine = lines.Where(lines => lines.LineId == "Azure.Storage.Blobs").FirstOrDefault(); |
| 102 | + Assert.NotNull(namespaceLine); |
| 103 | + var classLine = namespaceLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.BlobServiceClient").FirstOrDefault(); |
| 104 | + Assert.NotNull(classLine); |
| 105 | + var methodLine = classLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.BlobServiceClient.BlobServiceClient(System.String)").FirstOrDefault(); |
| 106 | + Assert.Equal(7, methodLine.Tokens.Count()); |
| 107 | + Assert.Equal("public BlobServiceClient(string connectionString);", methodLine.ToString().Trim()); |
| 108 | + } |
| 109 | + |
| 110 | + [Fact] |
| 111 | + public void TestApiReviewLineMoreParams() |
| 112 | + { |
| 113 | + var lines = storageCodeFile.ReviewLines; |
| 114 | + var namespaceLine = lines.Where(lines => lines.LineId == "Azure.Storage.Blobs").FirstOrDefault(); |
| 115 | + Assert.NotNull(namespaceLine); |
| 116 | + var classLine = namespaceLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.BlobServiceClient").FirstOrDefault(); |
| 117 | + Assert.NotNull(classLine); |
| 118 | + var methodLine = classLine.Children.Where(lines => lines.LineId.Contains("UndeleteBlobContainerAsync")).FirstOrDefault(); |
| 119 | + Assert.NotNull(methodLine); |
| 120 | + Assert.Equal(23, methodLine.Tokens.Count); |
| 121 | + Assert.Equal("public virtual Task<Response<BlobContainerClient>> UndeleteBlobContainerAsync(string deletedContainerName, string deletedContainerVersion, CancellationToken cancellationToken = default);", methodLine.ToString().Trim()); |
| 122 | + } |
| 123 | + |
| 124 | + public static IEnumerable<object[]> PackageCodeFiles => new List<object[]> |
| 125 | + { |
| 126 | + new object[] { templateCodeFile }, |
| 127 | + new object[] { storageCodeFile }, |
| 128 | + new object[] { coreCodeFile } |
| 129 | + }; |
| 130 | + |
| 131 | + [Theory] |
| 132 | + [MemberData(nameof(PackageCodeFiles))] |
| 133 | + public void TestAllClassesHaveEndOfContextLine(CodeFile codeFile) |
| 134 | + { |
| 135 | + // If current line is for class then next line at same level is expected to be a end of context line |
| 136 | + var lines = codeFile.ReviewLines; |
| 137 | + foreach(var namespaceLine in lines) |
| 138 | + { |
| 139 | + Assert.NotNull(namespaceLine); |
| 140 | + bool expectEndOfContext = false; |
| 141 | + var classLines = namespaceLine.Children; |
| 142 | + for (int i = 0; i < classLines.Count; i++) |
| 143 | + { |
| 144 | + if (expectEndOfContext) |
| 145 | + { |
| 146 | + Assert.True(classLines[i].IsContextEndLine == true); |
| 147 | + expectEndOfContext = false; |
| 148 | + continue; |
| 149 | + } |
| 150 | + |
| 151 | + expectEndOfContext = classLines[i].Tokens.Any(t => (t.RenderClasses.Contains("class") || |
| 152 | + t.RenderClasses.Contains("struct") || |
| 153 | + t.RenderClasses.Contains("interface")) && !classLines[i].Tokens.Any(t => t.Value == "abstract")); |
| 154 | + } |
| 155 | + } |
| 156 | + } |
| 157 | + |
| 158 | + [Fact] |
| 159 | + public void TestHiddenAPI() |
| 160 | + { |
| 161 | + var apiText = "protected static BlobServiceClient CreateClient(Uri serviceUri, BlobClientOptions options, HttpPipelinePolicy authentication, HttpPipeline pipeline);"; |
| 162 | + var lines = storageCodeFile.ReviewLines; |
| 163 | + var namespaceLine = lines.Where(lines => lines.LineId == "Azure.Storage.Blobs").FirstOrDefault(); |
| 164 | + Assert.NotNull(namespaceLine); |
| 165 | + var classLine = namespaceLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.BlobServiceClient").FirstOrDefault(); |
| 166 | + Assert.NotNull(classLine); |
| 167 | + 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(); |
| 168 | + Assert.NotNull(hiddenApis); |
| 169 | + Assert.Equal(18, hiddenApis.Tokens.Count()); |
| 170 | + Assert.Equal(apiText, hiddenApis.ToString().Trim()); |
37 | 171 | } |
38 | 172 |
|
39 | 173 | [Fact] |
@@ -77,29 +211,18 @@ public static class TemplateClientBuilderExtensions { |
77 | 211 | } |
78 | 212 | } |
79 | 213 | "; |
80 | | - Assert.Equal(expected, codeFile.GetApiText()); |
| 214 | + Assert.Equal(expected, templateCodeFile.GetApiText()); |
81 | 215 | } |
82 | 216 |
|
83 | | - [Fact] |
84 | | - public void TestCodeFileJsonSchema() |
| 217 | + [Theory] |
| 218 | + [MemberData(nameof(PackageCodeFiles))] |
| 219 | + public void TestCodeFileJsonSchema(CodeFile codeFile) |
85 | 220 | { |
86 | 221 | //Verify JSON file generated for Azure.Template |
87 | 222 | var isValid = validateSchema(codeFile); |
88 | 223 | Assert.True(isValid); |
89 | 224 | } |
90 | 225 |
|
91 | | - [Fact] |
92 | | - public void TestCodeFileJsonSchema2() |
93 | | - { |
94 | | - //Verify JSON file generated for Azure.Storage.Blobs |
95 | | - var storageAssembly = Assembly.Load("Azure.Storage.Blobs"); |
96 | | - var dllStream = storageAssembly.GetFile("Azure.Storage.Blobs.dll"); |
97 | | - var assemblySymbol = CompilationFactory.GetCompilation(dllStream, null); |
98 | | - var storageCodeFile = new CSharpAPIParser.TreeToken.CodeFileBuilder().Build(assemblySymbol, true, null); |
99 | | - var isValid = validateSchema(storageCodeFile); |
100 | | - Assert.True(isValid); |
101 | | - } |
102 | | - |
103 | 226 | private bool validateSchema(CodeFile codeFile) |
104 | 227 | { |
105 | 228 | var json = JsonSerializer.Serialize(codeFile, new JsonSerializerOptions |
@@ -129,9 +252,9 @@ private bool validateSchema(CodeFile codeFile) |
129 | 252 | } |
130 | 253 |
|
131 | 254 | [Fact] |
132 | | - public void TestNavigatonNodeHasRenderingClass() |
| 255 | + public void TestNavigationNodeHasRenderingClass() |
133 | 256 | { |
134 | | - var jsonString = JsonSerializer.Serialize(codeFile); |
| 257 | + var jsonString = JsonSerializer.Serialize(templateCodeFile); |
135 | 258 | var parsedCodeFile = JsonSerializer.Deserialize<CodeFile>(jsonString); |
136 | 259 | Assert.Equal(8, CountNavigationNodes(parsedCodeFile.ReviewLines)); |
137 | 260 | } |
|
0 commit comments