Skip to content

Commit 8ea3eda

Browse files
authored
Add tests of client code generation components (#13444)
- #4914 - test service ref MSBuild tasks - add `MockBuildEngine` class to support tests where a task logs - correct an incredibly minor product issue about logging errors for `@(OpenApiProjectReference)` items - set `%(SourceProject)` metadata and use it when logging - add test project that builds and can be tested in the future
1 parent 2d8cd17 commit 8ea3eda

16 files changed

+1331
-48
lines changed

src/Tools/Extensions.ApiDescription.Client/src/CSharpIdentifier.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System.Globalization;

src/Tools/Extensions.ApiDescription.Client/src/GetOpenApiReferenceMetadata.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,7 @@ public override bool Execute()
6363
"OpenApiReference" :
6464
"OpenApiProjectReference";
6565

66-
Log.LogError(
67-
Resources.FormatInvalidEmptyMetadataValue("CodeGenerator", "OpenApiReference", item.ItemSpec));
66+
Log.LogError(Resources.FormatInvalidEmptyMetadataValue("CodeGenerator", type, item.ItemSpec));
6867
continue;
6968
}
7069

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Runtime.CompilerServices;
5+
6+
[assembly: InternalsVisibleTo("Microsoft.Extensions.ApiDescription.Client.Tests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

src/Tools/Extensions.ApiDescription.Client/src/build/Microsoft.Extensions.ApiDescription.Client.targets

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@
4848
</MSBuild>
4949

5050
<ItemGroup>
51-
<OpenApiReference Include="@(_Temporary)" Exclude="@(OpenApiReference)" RemoveMetadata="FullConfiguration" />
51+
<OpenApiReference Include="@(_Temporary)" Exclude="@(OpenApiReference)" RemoveMetadata="FullConfiguration">
52+
<SourceProject>%(_Temporary.OriginalItemSpec)</SourceProject>
53+
</OpenApiReference>
5254
<_Temporary Remove="@(_Temporary)" />
5355
</ItemGroup>
5456
</Target>
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Xunit;
5+
6+
namespace Microsoft.Extensions.ApiDescription.Client
7+
{
8+
public class CSharpIdentifierTest
9+
{
10+
[Theory]
11+
[InlineData('a')]
12+
[InlineData('Q')]
13+
[InlineData('\u2164')] // UnicodeCategory.LetterNumber (roman numeral five)
14+
[InlineData('_')]
15+
[InlineData('9')]
16+
[InlineData('\u0303')] // UnicodeCategory.NonSpacingMark (combining tilde)
17+
[InlineData('\u09CB')] // UnicodeCategory.SpacingCombiningMark (Bengali vowel sign O)
18+
[InlineData('\uFE4F')] // UnicodeCategory.ConnectorPunctuation (wavy low line)
19+
[InlineData('\u2062')] // UnicodeCategory.Format (invisible times)
20+
public void IsIdentifierPart_ReturnsTrue_WhenItShould(char character)
21+
{
22+
// Arrange and Act
23+
var result = CSharpIdentifier.IsIdentifierPart(character);
24+
25+
// Assert
26+
Assert.True(result);
27+
}
28+
29+
[Theory]
30+
[InlineData('/')]
31+
[InlineData('-')]
32+
[InlineData('\u20DF')] // UnicodeCategory.EnclosingMark (combining enclosing diamond)
33+
[InlineData('\u2005')] // UnicodeCategory.SpaceSeparator (four-per-em space)
34+
[InlineData('\u0096')] // UnicodeCategory.Control (start of guarded area)
35+
[InlineData('\uFF1C')] // UnicodeCategory.MathSymbol (fullwidth less-than sign)
36+
public void IsIdentifierPart_ReturnsFalse_WhenItShould(char character)
37+
{
38+
// Arrange and Act
39+
var result = CSharpIdentifier.IsIdentifierPart(character);
40+
41+
// Assert
42+
Assert.False(result);
43+
}
44+
45+
// Output length is one longer than input in these cases.
46+
[Theory]
47+
[InlineData("9", "_9")]
48+
[InlineData("\u0303", "_\u0303")] // UnicodeCategory.NonSpacingMark (combining tilde)
49+
[InlineData("\u09CB", "_\u09CB")] // UnicodeCategory.SpacingCombiningMark (Bengali vowel sign O)
50+
[InlineData("\uFE4F", "_\uFE4F")] // UnicodeCategory.ConnectorPunctuation (wavy low line)
51+
[InlineData("\u2062", "_\u2062")] // UnicodeCategory.Format (invisible times)
52+
public void SanitizeIdentifier_AddsUnderscore_WhenItShould(string input, string expectdOutput)
53+
{
54+
// Arrange and Act
55+
var output = CSharpIdentifier.SanitizeIdentifier(input);
56+
57+
// Assert
58+
Assert.Equal(expectdOutput, output);
59+
}
60+
61+
[Theory]
62+
[InlineData("a", "a")]
63+
[InlineData("Q", "Q")]
64+
[InlineData("\u2164", "\u2164")]
65+
[InlineData("_", "_")]
66+
public void SanitizeIdentifier_DoesNotAddUnderscore_WhenValidStartCharacter(string input, string expectdOutput)
67+
{
68+
// Arrange and Act
69+
var output = CSharpIdentifier.SanitizeIdentifier(input);
70+
71+
// Assert
72+
Assert.Equal(expectdOutput, output);
73+
}
74+
75+
[Theory]
76+
[InlineData("/", "_")]
77+
[InlineData("-", "_")]
78+
[InlineData("\u20DF", "_")] // UnicodeCategory.EnclosingMark (combining enclosing diamond)
79+
[InlineData("\u2005", "_")] // UnicodeCategory.SpaceSeparator (four-per-em space)
80+
[InlineData("\u0096", "_")] // UnicodeCategory.Control (start of guarded area)
81+
[InlineData("\uFF1C", "_")] // UnicodeCategory.MathSymbol (fullwidth less-than sign)
82+
public void SanitizeIdentifier_DoesNotAddUnderscore_WhenInvalidCharacter(string input, string expectdOutput)
83+
{
84+
// Arrange and Act
85+
var output = CSharpIdentifier.SanitizeIdentifier(input);
86+
87+
// Assert
88+
Assert.Equal(expectdOutput, output);
89+
}
90+
91+
[Theory]
92+
[InlineData("a/", "a_")]
93+
[InlineData("aa-bb", "aa_bb")]
94+
[InlineData("aa\u20DF\u20DF", "aa__")] // UnicodeCategory.EnclosingMark (combining enclosing diamond)
95+
[InlineData("aa\u2005bb\u2005cc", "aa_bb_cc")] // UnicodeCategory.SpaceSeparator (four-per-em space)
96+
[InlineData("aa\u0096\u0096bb", "aa__bb")] // UnicodeCategory.Control (start of guarded area)
97+
[InlineData("aa\uFF1C\uFF1C\uFF1Cbb", "aa___bb")] // UnicodeCategory.MathSymbol (fullwidth less-than sign)
98+
public void SanitizeIdentifier_ReplacesInvalidCharacters_WhenNotFirst(string input, string expectdOutput)
99+
{
100+
// Arrange and Act
101+
var output = CSharpIdentifier.SanitizeIdentifier(input);
102+
103+
// Assert
104+
Assert.Equal(expectdOutput, output);
105+
}
106+
}
107+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using Xunit;
7+
8+
namespace Microsoft.Extensions.ApiDescription.Client
9+
{
10+
public class GetCurrentOpenApiReferenceTest
11+
{
12+
[Fact]
13+
public void Execute_ReturnsExpectedItem()
14+
{
15+
// Arrange
16+
string input = "Identity=../files/azureMonitor.json|ClassName=azureMonitorClient|" +
17+
"CodeGenerator=NSwagCSharp|Namespace=ConsoleClient|Options=|OutputPath=" +
18+
"C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs|" +
19+
"OriginalItemSpec=../files/azureMonitor.json|FirstForGenerator=true";
20+
var task = new GetCurrentOpenApiReference
21+
{
22+
Input = input,
23+
};
24+
25+
string expectedIdentity = "../files/azureMonitor.json";
26+
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
27+
{
28+
{ "ClassName", "azureMonitorClient" },
29+
{ "CodeGenerator", "NSwagCSharp" },
30+
{ "FirstForGenerator", "true" },
31+
{ "Namespace", "ConsoleClient" },
32+
{ "Options", "" },
33+
{ "OriginalItemSpec", expectedIdentity },
34+
{ "OutputPath", "C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs" },
35+
};
36+
37+
// Act
38+
var result = task.Execute();
39+
40+
// Assert
41+
Assert.True(result);
42+
Assert.False(task.Log.HasLoggedErrors);
43+
var output = Assert.Single(task.Outputs);
44+
Assert.Equal(expectedIdentity, output.ItemSpec);
45+
var metadata = Assert.IsAssignableFrom<IDictionary<string, string>>(output.CloneCustomMetadata());
46+
47+
// The dictionary CloneCustomMetadata returns doesn't provide a useful KeyValuePair enumerator.
48+
var orderedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal);
49+
foreach (var key in metadata.Keys)
50+
{
51+
orderedMetadata.Add(key, metadata[key]);
52+
}
53+
54+
Assert.Equal(expectedMetadata, orderedMetadata);
55+
}
56+
}
57+
}

0 commit comments

Comments
 (0)