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
This commit is contained in:
parent
2d8cd179a1
commit
8ea3edadaf
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Globalization;
|
||||
|
|
|
|||
|
|
@ -63,8 +63,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
|
|||
"OpenApiReference" :
|
||||
"OpenApiProjectReference";
|
||||
|
||||
Log.LogError(
|
||||
Resources.FormatInvalidEmptyMetadataValue("CodeGenerator", "OpenApiReference", item.ItemSpec));
|
||||
Log.LogError(Resources.FormatInvalidEmptyMetadataValue("CodeGenerator", type, item.ItemSpec));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Microsoft.Extensions.ApiDescription.Client.Tests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||
|
|
@ -48,7 +48,9 @@
|
|||
</MSBuild>
|
||||
|
||||
<ItemGroup>
|
||||
<OpenApiReference Include="@(_Temporary)" Exclude="@(OpenApiReference)" RemoveMetadata="FullConfiguration" />
|
||||
<OpenApiReference Include="@(_Temporary)" Exclude="@(OpenApiReference)" RemoveMetadata="FullConfiguration">
|
||||
<SourceProject>%(_Temporary.OriginalItemSpec)</SourceProject>
|
||||
</OpenApiReference>
|
||||
<_Temporary Remove="@(_Temporary)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Extensions.ApiDescription.Client
|
||||
{
|
||||
public class CSharpIdentifierTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData('a')]
|
||||
[InlineData('Q')]
|
||||
[InlineData('\u2164')] // UnicodeCategory.LetterNumber (roman numeral five)
|
||||
[InlineData('_')]
|
||||
[InlineData('9')]
|
||||
[InlineData('\u0303')] // UnicodeCategory.NonSpacingMark (combining tilde)
|
||||
[InlineData('\u09CB')] // UnicodeCategory.SpacingCombiningMark (Bengali vowel sign O)
|
||||
[InlineData('\uFE4F')] // UnicodeCategory.ConnectorPunctuation (wavy low line)
|
||||
[InlineData('\u2062')] // UnicodeCategory.Format (invisible times)
|
||||
public void IsIdentifierPart_ReturnsTrue_WhenItShould(char character)
|
||||
{
|
||||
// Arrange and Act
|
||||
var result = CSharpIdentifier.IsIdentifierPart(character);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData('/')]
|
||||
[InlineData('-')]
|
||||
[InlineData('\u20DF')] // UnicodeCategory.EnclosingMark (combining enclosing diamond)
|
||||
[InlineData('\u2005')] // UnicodeCategory.SpaceSeparator (four-per-em space)
|
||||
[InlineData('\u0096')] // UnicodeCategory.Control (start of guarded area)
|
||||
[InlineData('\uFF1C')] // UnicodeCategory.MathSymbol (fullwidth less-than sign)
|
||||
public void IsIdentifierPart_ReturnsFalse_WhenItShould(char character)
|
||||
{
|
||||
// Arrange and Act
|
||||
var result = CSharpIdentifier.IsIdentifierPart(character);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
// Output length is one longer than input in these cases.
|
||||
[Theory]
|
||||
[InlineData("9", "_9")]
|
||||
[InlineData("\u0303", "_\u0303")] // UnicodeCategory.NonSpacingMark (combining tilde)
|
||||
[InlineData("\u09CB", "_\u09CB")] // UnicodeCategory.SpacingCombiningMark (Bengali vowel sign O)
|
||||
[InlineData("\uFE4F", "_\uFE4F")] // UnicodeCategory.ConnectorPunctuation (wavy low line)
|
||||
[InlineData("\u2062", "_\u2062")] // UnicodeCategory.Format (invisible times)
|
||||
public void SanitizeIdentifier_AddsUnderscore_WhenItShould(string input, string expectdOutput)
|
||||
{
|
||||
// Arrange and Act
|
||||
var output = CSharpIdentifier.SanitizeIdentifier(input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectdOutput, output);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("a", "a")]
|
||||
[InlineData("Q", "Q")]
|
||||
[InlineData("\u2164", "\u2164")]
|
||||
[InlineData("_", "_")]
|
||||
public void SanitizeIdentifier_DoesNotAddUnderscore_WhenValidStartCharacter(string input, string expectdOutput)
|
||||
{
|
||||
// Arrange and Act
|
||||
var output = CSharpIdentifier.SanitizeIdentifier(input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectdOutput, output);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/", "_")]
|
||||
[InlineData("-", "_")]
|
||||
[InlineData("\u20DF", "_")] // UnicodeCategory.EnclosingMark (combining enclosing diamond)
|
||||
[InlineData("\u2005", "_")] // UnicodeCategory.SpaceSeparator (four-per-em space)
|
||||
[InlineData("\u0096", "_")] // UnicodeCategory.Control (start of guarded area)
|
||||
[InlineData("\uFF1C", "_")] // UnicodeCategory.MathSymbol (fullwidth less-than sign)
|
||||
public void SanitizeIdentifier_DoesNotAddUnderscore_WhenInvalidCharacter(string input, string expectdOutput)
|
||||
{
|
||||
// Arrange and Act
|
||||
var output = CSharpIdentifier.SanitizeIdentifier(input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectdOutput, output);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("a/", "a_")]
|
||||
[InlineData("aa-bb", "aa_bb")]
|
||||
[InlineData("aa\u20DF\u20DF", "aa__")] // UnicodeCategory.EnclosingMark (combining enclosing diamond)
|
||||
[InlineData("aa\u2005bb\u2005cc", "aa_bb_cc")] // UnicodeCategory.SpaceSeparator (four-per-em space)
|
||||
[InlineData("aa\u0096\u0096bb", "aa__bb")] // UnicodeCategory.Control (start of guarded area)
|
||||
[InlineData("aa\uFF1C\uFF1C\uFF1Cbb", "aa___bb")] // UnicodeCategory.MathSymbol (fullwidth less-than sign)
|
||||
public void SanitizeIdentifier_ReplacesInvalidCharacters_WhenNotFirst(string input, string expectdOutput)
|
||||
{
|
||||
// Arrange and Act
|
||||
var output = CSharpIdentifier.SanitizeIdentifier(input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectdOutput, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Extensions.ApiDescription.Client
|
||||
{
|
||||
public class GetCurrentOpenApiReferenceTest
|
||||
{
|
||||
[Fact]
|
||||
public void Execute_ReturnsExpectedItem()
|
||||
{
|
||||
// Arrange
|
||||
string input = "Identity=../files/azureMonitor.json|ClassName=azureMonitorClient|" +
|
||||
"CodeGenerator=NSwagCSharp|Namespace=ConsoleClient|Options=|OutputPath=" +
|
||||
"C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs|" +
|
||||
"OriginalItemSpec=../files/azureMonitor.json|FirstForGenerator=true";
|
||||
var task = new GetCurrentOpenApiReference
|
||||
{
|
||||
Input = input,
|
||||
};
|
||||
|
||||
string expectedIdentity = "../files/azureMonitor.json";
|
||||
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", "azureMonitorClient" },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
{ "FirstForGenerator", "true" },
|
||||
{ "Namespace", "ConsoleClient" },
|
||||
{ "Options", "" },
|
||||
{ "OriginalItemSpec", expectedIdentity },
|
||||
{ "OutputPath", "C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs" },
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.False(task.Log.HasLoggedErrors);
|
||||
var output = Assert.Single(task.Outputs);
|
||||
Assert.Equal(expectedIdentity, output.ItemSpec);
|
||||
var metadata = Assert.IsAssignableFrom<IDictionary<string, string>>(output.CloneCustomMetadata());
|
||||
|
||||
// The dictionary CloneCustomMetadata returns doesn't provide a useful KeyValuePair enumerator.
|
||||
var orderedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
||||
foreach (var key in metadata.Keys)
|
||||
{
|
||||
orderedMetadata.Add(key, metadata[key]);
|
||||
}
|
||||
|
||||
Assert.Equal(expectedMetadata, orderedMetadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,576 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Extensions.ApiDescription.Client
|
||||
{
|
||||
public class GetOpenApiReferenceMetadataTest
|
||||
{
|
||||
[Fact]
|
||||
public void Execute_AddsExpectedMetadata()
|
||||
{
|
||||
// Arrange
|
||||
var identity = Path.Combine("TestProjects", "files", "NSwag.json");
|
||||
var @namespace = "Console.Client";
|
||||
var outputPath = Path.Combine("obj", "NSwagClient.cs");
|
||||
var inputMetadata = new Dictionary<string, string> { { "CodeGenerator", "NSwagCSharp" } };
|
||||
var task = new GetOpenApiReferenceMetadata
|
||||
{
|
||||
Extension = ".cs",
|
||||
Inputs = new[] { new TaskItem(identity, inputMetadata) },
|
||||
Namespace = @namespace,
|
||||
OutputDirectory = "obj",
|
||||
};
|
||||
|
||||
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", "NSwagClient" },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
{ "FirstForGenerator", "true" },
|
||||
{ "Namespace", @namespace },
|
||||
{ "OriginalItemSpec", identity },
|
||||
{ "OutputPath", outputPath },
|
||||
{
|
||||
"SerializedMetadata",
|
||||
$"Identity={identity}|CodeGenerator=NSwagCSharp|" +
|
||||
$"OriginalItemSpec={identity}|FirstForGenerator=true|" +
|
||||
$"OutputPath={outputPath}|ClassName=NSwagClient|Namespace={@namespace}"
|
||||
},
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.False(task.Log.HasLoggedErrors);
|
||||
var output = Assert.Single(task.Outputs);
|
||||
Assert.Equal(identity, output.ItemSpec);
|
||||
var metadata = Assert.IsAssignableFrom<IDictionary<string, string>>(output.CloneCustomMetadata());
|
||||
|
||||
// The dictionary CloneCustomMetadata returns doesn't provide a useful KeyValuePair enumerator.
|
||||
var orderedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
||||
foreach (var key in metadata.Keys)
|
||||
{
|
||||
orderedMetadata.Add(key, metadata[key]);
|
||||
}
|
||||
|
||||
Assert.Equal(expectedMetadata, orderedMetadata);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_DoesNotOverrideClassName()
|
||||
{
|
||||
// Arrange
|
||||
var identity = Path.Combine("TestProjects", "files", "NSwag.json");
|
||||
var className = "ThisIsClassy";
|
||||
var @namespace = "Console.Client";
|
||||
var outputPath = Path.Combine("obj", $"NSwagClient.cs");
|
||||
var inputMetadata = new Dictionary<string, string>
|
||||
{
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
{ "ClassName", className },
|
||||
};
|
||||
|
||||
var task = new GetOpenApiReferenceMetadata
|
||||
{
|
||||
Extension = ".cs",
|
||||
Inputs = new[] { new TaskItem(identity, inputMetadata) },
|
||||
Namespace = @namespace,
|
||||
OutputDirectory = "obj",
|
||||
};
|
||||
|
||||
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", className },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
{ "FirstForGenerator", "true" },
|
||||
{ "Namespace", @namespace },
|
||||
{ "OriginalItemSpec", identity },
|
||||
{ "OutputPath", outputPath },
|
||||
{
|
||||
"SerializedMetadata",
|
||||
$"Identity={identity}|CodeGenerator=NSwagCSharp|" +
|
||||
$"ClassName={className}|OriginalItemSpec={identity}|FirstForGenerator=true|" +
|
||||
$"OutputPath={outputPath}|Namespace={@namespace}"
|
||||
},
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.False(task.Log.HasLoggedErrors);
|
||||
var output = Assert.Single(task.Outputs);
|
||||
Assert.Equal(identity, output.ItemSpec);
|
||||
var metadata = Assert.IsAssignableFrom<IDictionary<string, string>>(output.CloneCustomMetadata());
|
||||
|
||||
// The dictionary CloneCustomMetadata returns doesn't provide a useful KeyValuePair enumerator.
|
||||
var orderedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
||||
foreach (var key in metadata.Keys)
|
||||
{
|
||||
orderedMetadata.Add(key, metadata[key]);
|
||||
}
|
||||
|
||||
Assert.Equal(expectedMetadata, orderedMetadata);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_DoesNotOverrideNamespace()
|
||||
{
|
||||
// Arrange
|
||||
var defaultNamespace = "Console.Client";
|
||||
var identity = Path.Combine("TestProjects", "files", "NSwag.json");
|
||||
var @namespace = "NotConsole.NotClient";
|
||||
var outputPath = Path.Combine("obj", "NSwagClient.cs");
|
||||
var inputMetadata = new Dictionary<string, string>
|
||||
{
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
{ "Namespace", @namespace },
|
||||
};
|
||||
|
||||
var task = new GetOpenApiReferenceMetadata
|
||||
{
|
||||
Extension = ".cs",
|
||||
Inputs = new[] { new TaskItem(identity, inputMetadata) },
|
||||
Namespace = defaultNamespace,
|
||||
OutputDirectory = "obj",
|
||||
};
|
||||
|
||||
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", "NSwagClient" },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
{ "FirstForGenerator", "true" },
|
||||
{ "Namespace", @namespace },
|
||||
{ "OriginalItemSpec", identity },
|
||||
{ "OutputPath", outputPath },
|
||||
{
|
||||
"SerializedMetadata",
|
||||
$"Identity={identity}|CodeGenerator=NSwagCSharp|" +
|
||||
$"Namespace={@namespace}|OriginalItemSpec={identity}|FirstForGenerator=true|" +
|
||||
$"OutputPath={outputPath}|ClassName=NSwagClient"
|
||||
},
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.False(task.Log.HasLoggedErrors);
|
||||
var output = Assert.Single(task.Outputs);
|
||||
Assert.Equal(identity, output.ItemSpec);
|
||||
var metadata = Assert.IsAssignableFrom<IDictionary<string, string>>(output.CloneCustomMetadata());
|
||||
|
||||
// The dictionary CloneCustomMetadata returns doesn't provide a useful KeyValuePair enumerator.
|
||||
var orderedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
||||
foreach (var key in metadata.Keys)
|
||||
{
|
||||
orderedMetadata.Add(key, metadata[key]);
|
||||
}
|
||||
|
||||
Assert.Equal(expectedMetadata, orderedMetadata);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_DoesNotOverrideOutputPath_IfRooted()
|
||||
{
|
||||
// Arrange
|
||||
var identity = Path.Combine("TestProjects", "files", "NSwag.json");
|
||||
var className = "ThisIsClassy";
|
||||
var @namespace = "Console.Client";
|
||||
var outputPath = Path.Combine(Path.GetTempPath(), $"{className}.cs");
|
||||
var inputMetadata = new Dictionary<string, string>
|
||||
{
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
{ "OutputPath", outputPath }
|
||||
};
|
||||
|
||||
var task = new GetOpenApiReferenceMetadata
|
||||
{
|
||||
Extension = ".cs",
|
||||
Inputs = new[] { new TaskItem(identity, inputMetadata) },
|
||||
Namespace = @namespace,
|
||||
OutputDirectory = "bin",
|
||||
};
|
||||
|
||||
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", className },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
{ "FirstForGenerator", "true" },
|
||||
{ "Namespace", @namespace },
|
||||
{ "OriginalItemSpec", identity },
|
||||
{ "OutputPath", outputPath },
|
||||
{
|
||||
"SerializedMetadata",
|
||||
$"Identity={identity}|CodeGenerator=NSwagCSharp|" +
|
||||
$"OutputPath={outputPath}|OriginalItemSpec={identity}|FirstForGenerator=true|" +
|
||||
$"ClassName={className}|Namespace={@namespace}"
|
||||
},
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.False(task.Log.HasLoggedErrors);
|
||||
var output = Assert.Single(task.Outputs);
|
||||
Assert.Equal(identity, output.ItemSpec);
|
||||
var metadata = Assert.IsAssignableFrom<IDictionary<string, string>>(output.CloneCustomMetadata());
|
||||
|
||||
// The dictionary CloneCustomMetadata returns doesn't provide a useful KeyValuePair enumerator.
|
||||
var orderedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
||||
foreach (var key in metadata.Keys)
|
||||
{
|
||||
orderedMetadata.Add(key, metadata[key]);
|
||||
}
|
||||
|
||||
Assert.Equal(expectedMetadata, orderedMetadata);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_LogsError_IfCodeGeneratorMissing()
|
||||
{
|
||||
// Arrange
|
||||
var identity1 = Path.Combine("TestProjects", "files", "NSwag.json");
|
||||
var identity2 = Path.Combine("TestProjects", "files", "swashbuckle.json");
|
||||
var error1 = Resources.FormatInvalidEmptyMetadataValue("CodeGenerator", "OpenApiReference", identity1);
|
||||
var error2 = Resources.FormatInvalidEmptyMetadataValue("CodeGenerator", "OpenApiProjectReference", identity2);
|
||||
var @namespace = "Console.Client";
|
||||
var inputMetadata1 = new Dictionary<string, string>
|
||||
{
|
||||
{ "ExtraMetadata", "this is extra" },
|
||||
};
|
||||
var inputMetadata2 = new Dictionary<string, string>
|
||||
{
|
||||
{ "Options", "-quiet" },
|
||||
{ "SourceProject", "ConsoleProject.csproj" },
|
||||
};
|
||||
|
||||
var buildEngine = new MockBuildEngine();
|
||||
var task = new GetOpenApiReferenceMetadata
|
||||
{
|
||||
BuildEngine = buildEngine,
|
||||
Extension = ".cs",
|
||||
Inputs = new[]
|
||||
{
|
||||
new TaskItem(identity1, inputMetadata1),
|
||||
new TaskItem(identity2, inputMetadata2),
|
||||
},
|
||||
Namespace = @namespace,
|
||||
OutputDirectory = "obj",
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
Assert.True(task.Log.HasLoggedErrors);
|
||||
Assert.Equal(2, buildEngine.Errors);
|
||||
Assert.Equal(0, buildEngine.Messages);
|
||||
Assert.Equal(0, buildEngine.Warnings);
|
||||
Assert.Contains(error1, buildEngine.Log, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains(error2, buildEngine.Log, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_LogsError_IfOutputPathDuplicated()
|
||||
{
|
||||
// Arrange
|
||||
var identity = Path.Combine("TestProjects", "files", "NSwag.json");
|
||||
var codeGenerator = "NSwagCSharp";
|
||||
var error = Resources.FormatDuplicateFileOutputPaths(Path.Combine("obj", "NSwagClient.cs"));
|
||||
var @namespace = "Console.Client";
|
||||
var inputMetadata1 = new Dictionary<string, string>
|
||||
{
|
||||
{ "CodeGenerator", codeGenerator },
|
||||
{ "ExtraMetadata", "this is extra" },
|
||||
};
|
||||
var inputMetadata2 = new Dictionary<string, string>
|
||||
{
|
||||
{ "CodeGenerator", codeGenerator },
|
||||
{ "Options", "-quiet" },
|
||||
};
|
||||
|
||||
var buildEngine = new MockBuildEngine();
|
||||
var task = new GetOpenApiReferenceMetadata
|
||||
{
|
||||
BuildEngine = buildEngine,
|
||||
Extension = ".cs",
|
||||
Inputs = new[]
|
||||
{
|
||||
new TaskItem(identity, inputMetadata1),
|
||||
new TaskItem(identity, inputMetadata2),
|
||||
},
|
||||
Namespace = @namespace,
|
||||
OutputDirectory = "obj",
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
Assert.True(task.Log.HasLoggedErrors);
|
||||
Assert.Equal(1, buildEngine.Errors);
|
||||
Assert.Equal(0, buildEngine.Messages);
|
||||
Assert.Equal(0, buildEngine.Warnings);
|
||||
Assert.Contains(error, buildEngine.Log, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_SetsClassName_BasedOnOutputPath()
|
||||
{
|
||||
// Arrange
|
||||
var identity = Path.Combine("TestProjects", "files", "NSwag.json");
|
||||
var className = "ThisIsClassy";
|
||||
var @namespace = "Console.Client";
|
||||
var outputPath = $"{className}.cs";
|
||||
var expectedOutputPath = Path.Combine("bin", outputPath);
|
||||
var inputMetadata = new Dictionary<string, string>
|
||||
{
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
{ "OutputPath", outputPath }
|
||||
};
|
||||
|
||||
var task = new GetOpenApiReferenceMetadata
|
||||
{
|
||||
Extension = ".cs",
|
||||
Inputs = new[] { new TaskItem(identity, inputMetadata) },
|
||||
Namespace = @namespace,
|
||||
OutputDirectory = "bin",
|
||||
};
|
||||
|
||||
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", className },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
{ "FirstForGenerator", "true" },
|
||||
{ "Namespace", @namespace },
|
||||
{ "OriginalItemSpec", identity },
|
||||
{ "OutputPath", expectedOutputPath },
|
||||
{
|
||||
"SerializedMetadata",
|
||||
$"Identity={identity}|CodeGenerator=NSwagCSharp|" +
|
||||
$"OutputPath={expectedOutputPath}|OriginalItemSpec={identity}|FirstForGenerator=true|" +
|
||||
$"ClassName={className}|Namespace={@namespace}"
|
||||
},
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.False(task.Log.HasLoggedErrors);
|
||||
var output = Assert.Single(task.Outputs);
|
||||
Assert.Equal(identity, output.ItemSpec);
|
||||
var metadata = Assert.IsAssignableFrom<IDictionary<string, string>>(output.CloneCustomMetadata());
|
||||
|
||||
// The dictionary CloneCustomMetadata returns doesn't provide a useful KeyValuePair enumerator.
|
||||
var orderedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
||||
foreach (var key in metadata.Keys)
|
||||
{
|
||||
orderedMetadata.Add(key, metadata[key]);
|
||||
}
|
||||
|
||||
Assert.Equal(expectedMetadata, orderedMetadata);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("aa-bb.cs", "aa_bb")]
|
||||
[InlineData("aa.bb.cc.ts", "aa_bb_cc")]
|
||||
[InlineData("aa\u20DF\u20DF.tsx", "aa__")] // UnicodeCategory.EnclosingMark (combining enclosing diamond)
|
||||
[InlineData("aa\u2005bb\u2005cc.cs", "aa_bb_cc")] // UnicodeCategory.SpaceSeparator (four-per-em space)
|
||||
[InlineData("aa\u0096\u0096bb.cs", "aa__bb")] // UnicodeCategory.Control (start of guarded area)
|
||||
[InlineData("aa\uFF1C\uFF1C\uFF1Cbb.cs", "aa___bb")] // UnicodeCategory.MathSymbol (fullwidth less-than sign)
|
||||
public void Execute_SetsClassName_BasedOnSanitizedOutputPath(string outputPath, string className)
|
||||
{
|
||||
// Arrange
|
||||
var identity = Path.Combine("TestProjects", "files", "NSwag.json");
|
||||
var @namespace = "Console.Client";
|
||||
var expectedOutputPath = Path.Combine("bin", outputPath);
|
||||
var inputMetadata = new Dictionary<string, string>
|
||||
{
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
{ "OutputPath", outputPath }
|
||||
};
|
||||
|
||||
var task = new GetOpenApiReferenceMetadata
|
||||
{
|
||||
Extension = ".cs",
|
||||
Inputs = new[] { new TaskItem(identity, inputMetadata) },
|
||||
Namespace = @namespace,
|
||||
OutputDirectory = "bin",
|
||||
};
|
||||
|
||||
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", className },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
{ "FirstForGenerator", "true" },
|
||||
{ "Namespace", @namespace },
|
||||
{ "OriginalItemSpec", identity },
|
||||
{ "OutputPath", expectedOutputPath },
|
||||
{
|
||||
"SerializedMetadata",
|
||||
$"Identity={identity}|CodeGenerator=NSwagCSharp|" +
|
||||
$"OutputPath={expectedOutputPath}|OriginalItemSpec={identity}|FirstForGenerator=true|" +
|
||||
$"ClassName={className}|Namespace={@namespace}"
|
||||
},
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.False(task.Log.HasLoggedErrors);
|
||||
var output = Assert.Single(task.Outputs);
|
||||
Assert.Equal(identity, output.ItemSpec);
|
||||
var metadata = Assert.IsAssignableFrom<IDictionary<string, string>>(output.CloneCustomMetadata());
|
||||
|
||||
// The dictionary CloneCustomMetadata returns doesn't provide a useful KeyValuePair enumerator.
|
||||
var orderedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
||||
foreach (var key in metadata.Keys)
|
||||
{
|
||||
orderedMetadata.Add(key, metadata[key]);
|
||||
}
|
||||
|
||||
Assert.Equal(expectedMetadata, orderedMetadata);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_SetsFirstForGenerator_UsesCorrectExtension()
|
||||
{
|
||||
// Arrange
|
||||
var identity12 = Path.Combine("TestProjects", "files", "NSwag.json");
|
||||
var identity3 = Path.Combine("TestProjects", "files", "swashbuckle.json");
|
||||
var className12 = "NSwagClient";
|
||||
var className3 = "swashbuckleClient";
|
||||
var codeGenerator13 = "NSwagCSharp";
|
||||
var codeGenerator2 = "NSwagTypeScript";
|
||||
var inputMetadata1 = new Dictionary<string, string> { { "CodeGenerator", codeGenerator13 } };
|
||||
var inputMetadata2 = new Dictionary<string, string> { { "CodeGenerator", codeGenerator2 } };
|
||||
var inputMetadata3 = new Dictionary<string, string> { { "CodeGenerator", codeGenerator13 } };
|
||||
var @namespace = "Console.Client";
|
||||
var outputPath1 = Path.Combine("obj", $"{className12}.cs");
|
||||
var outputPath2 = Path.Combine("obj", $"{className12}.ts");
|
||||
var outputPath3 = Path.Combine("obj", $"{className3}.cs");
|
||||
|
||||
var task = new GetOpenApiReferenceMetadata
|
||||
{
|
||||
Extension = ".cs",
|
||||
Inputs = new[]
|
||||
{
|
||||
new TaskItem(identity12, inputMetadata1),
|
||||
new TaskItem(identity12, inputMetadata2),
|
||||
new TaskItem(identity3, inputMetadata3),
|
||||
},
|
||||
Namespace = @namespace,
|
||||
OutputDirectory = "obj",
|
||||
};
|
||||
|
||||
IDictionary<string, string> expectedMetadata1 = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", className12 },
|
||||
{ "CodeGenerator", codeGenerator13 },
|
||||
{ "FirstForGenerator", "true" },
|
||||
{ "Namespace", @namespace },
|
||||
{ "OriginalItemSpec", identity12 },
|
||||
{ "OutputPath", outputPath1 },
|
||||
{
|
||||
"SerializedMetadata",
|
||||
$"Identity={identity12}|CodeGenerator={codeGenerator13}|" +
|
||||
$"OriginalItemSpec={identity12}|FirstForGenerator=true|" +
|
||||
$"OutputPath={outputPath1}|ClassName={className12}|Namespace={@namespace}"
|
||||
},
|
||||
};
|
||||
IDictionary<string, string> expectedMetadata2 = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", className12 },
|
||||
{ "CodeGenerator", codeGenerator2 },
|
||||
{ "FirstForGenerator", "true" },
|
||||
{ "Namespace", @namespace },
|
||||
{ "OriginalItemSpec", identity12 },
|
||||
{ "OutputPath", outputPath2 },
|
||||
{
|
||||
"SerializedMetadata",
|
||||
$"Identity={identity12}|CodeGenerator={codeGenerator2}|" +
|
||||
$"OriginalItemSpec={identity12}|FirstForGenerator=true|" +
|
||||
$"OutputPath={outputPath2}|ClassName={className12}|Namespace={@namespace}"
|
||||
},
|
||||
};
|
||||
IDictionary<string, string> expectedMetadata3 = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", className3 },
|
||||
{ "CodeGenerator", codeGenerator13 },
|
||||
{ "FirstForGenerator", "false" },
|
||||
{ "Namespace", @namespace },
|
||||
{ "OriginalItemSpec", identity3 },
|
||||
{ "OutputPath", outputPath3 },
|
||||
{
|
||||
"SerializedMetadata",
|
||||
$"Identity={identity3}|CodeGenerator={codeGenerator13}|" +
|
||||
$"OriginalItemSpec={identity3}|FirstForGenerator=false|" +
|
||||
$"OutputPath={outputPath3}|ClassName={className3}|Namespace={@namespace}"
|
||||
},
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = task.Execute();
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.False(task.Log.HasLoggedErrors);
|
||||
Assert.Collection(
|
||||
task.Outputs,
|
||||
output =>
|
||||
{
|
||||
Assert.Equal(identity12, output.ItemSpec);
|
||||
var metadata = Assert.IsAssignableFrom<IDictionary<string, string>>(output.CloneCustomMetadata());
|
||||
var orderedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
||||
foreach (var key in metadata.Keys)
|
||||
{
|
||||
orderedMetadata.Add(key, metadata[key]);
|
||||
}
|
||||
|
||||
Assert.Equal(expectedMetadata1, orderedMetadata);
|
||||
},
|
||||
output =>
|
||||
{
|
||||
Assert.Equal(identity12, output.ItemSpec);
|
||||
var metadata = Assert.IsAssignableFrom<IDictionary<string, string>>(output.CloneCustomMetadata());
|
||||
var orderedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
||||
foreach (var key in metadata.Keys)
|
||||
{
|
||||
orderedMetadata.Add(key, metadata[key]);
|
||||
}
|
||||
|
||||
Assert.Equal(expectedMetadata2, orderedMetadata);
|
||||
},
|
||||
output =>
|
||||
{
|
||||
Assert.Equal(identity3, output.ItemSpec);
|
||||
var metadata = Assert.IsAssignableFrom<IDictionary<string, string>>(output.CloneCustomMetadata());
|
||||
var orderedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
||||
foreach (var key in metadata.Keys)
|
||||
{
|
||||
orderedMetadata.Add(key, metadata[key]);
|
||||
}
|
||||
|
||||
Assert.Equal(expectedMetadata3, orderedMetadata);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);TestProjects\**\*</DefaultItemExcludes>
|
||||
<TestGroupName>ApiDescriptionClientTests</TestGroupName>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="$(MSBuildProjectDirectory)\..\src\build\**\*" CopyToOutputDirectory="PreserveNewest" LinkBase="build" />
|
||||
<Content Include="$(MSBuildProjectDirectory)\..\src\buildMultiTargeting\**\*" CopyToOutputDirectory="PreserveNewest" LinkBase="buildMultiTargeting" />
|
||||
<Content Include="TestProjects\**\*" CopyToOutputDirectory="PreserveNewest" />
|
||||
|
||||
<ProjectReference Include="..\src\Microsoft.Extensions.ApiDescription.Client.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CleanTestProjects" BeforeTargets="CoreCompile">
|
||||
<RemoveDir Directories="$(TargetDir)TestProjects" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.Build.Framework;
|
||||
|
||||
// Inspired by https://github.com/microsoft/msbuild/blob/master/src/Utilities.UnitTests/MockEngine.cs
|
||||
namespace Microsoft.Extensions.ApiDescription.Client
|
||||
{
|
||||
internal sealed class MockBuildEngine : IBuildEngine3
|
||||
{
|
||||
private readonly StringBuilder _log = new StringBuilder();
|
||||
|
||||
public bool IsRunningMultipleNodes => false;
|
||||
|
||||
public bool ContinueOnError => false;
|
||||
|
||||
public string ProjectFileOfTaskNode => string.Empty;
|
||||
|
||||
public int LineNumberOfTaskNode => 0;
|
||||
|
||||
public int ColumnNumberOfTaskNode => 0;
|
||||
|
||||
internal MessageImportance MinimumMessageImportance { get; set; } = MessageImportance.Low;
|
||||
|
||||
internal int Messages { set; get; }
|
||||
|
||||
internal int Warnings { set; get; }
|
||||
|
||||
internal int Errors { set; get; }
|
||||
|
||||
internal string Log => _log.ToString();
|
||||
|
||||
public bool BuildProjectFile(
|
||||
string projectFileName,
|
||||
string[] targetNames,
|
||||
IDictionary globalProperties,
|
||||
IDictionary targetOutputs) => false;
|
||||
|
||||
public bool BuildProjectFile(
|
||||
string projectFileName,
|
||||
string[] targetNames,
|
||||
IDictionary globalProperties,
|
||||
IDictionary targetOutputs,
|
||||
string toolsVersion) => false;
|
||||
|
||||
public bool BuildProjectFilesInParallel(
|
||||
string[] projectFileNames,
|
||||
string[] targetNames,
|
||||
IDictionary[] globalProperties,
|
||||
IDictionary[] targetOutputsPerProject,
|
||||
string[] toolsVersion,
|
||||
bool useResultsCache,
|
||||
bool unloadProjectsOnCompletion) => false;
|
||||
|
||||
public BuildEngineResult BuildProjectFilesInParallel(
|
||||
string[] projectFileNames,
|
||||
string[] targetNames,
|
||||
IDictionary[] globalProperties,
|
||||
IList<string>[] undefineProperties,
|
||||
string[] toolsVersion,
|
||||
bool includeTargetOutputs) => new BuildEngineResult(false, null);
|
||||
|
||||
public void LogErrorEvent(BuildErrorEventArgs eventArgs)
|
||||
{
|
||||
_log.AppendLine(eventArgs.Message);
|
||||
Errors++;
|
||||
}
|
||||
|
||||
public void LogWarningEvent(BuildWarningEventArgs eventArgs)
|
||||
{
|
||||
_log.AppendLine(eventArgs.Message);
|
||||
Warnings++;
|
||||
}
|
||||
|
||||
public void LogCustomEvent(CustomBuildEventArgs eventArgs)
|
||||
{
|
||||
_log.AppendLine(eventArgs.Message);
|
||||
}
|
||||
|
||||
public void LogMessageEvent(BuildMessageEventArgs eventArgs)
|
||||
{
|
||||
// Only record the message if it is above the minimum importance. MessageImportance enum has higher values
|
||||
// for lower importance.
|
||||
if (eventArgs.Importance <= MinimumMessageImportance)
|
||||
{
|
||||
_log.AppendLine(eventArgs.Message);
|
||||
Messages++;
|
||||
}
|
||||
}
|
||||
|
||||
public void Reacquire()
|
||||
{
|
||||
}
|
||||
|
||||
public void Yield()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="../../build/Microsoft.Extensions.ApiDescription.Client.props"
|
||||
Condition="Exists('../../build/Microsoft.Extensions.ApiDescription.Client.props')" />
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<IsTestAssetProject>true</IsTestAssetProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<OpenApiReference Include="../files/azureMonitor.json" />
|
||||
<OpenApiReference Include="../files/NSwag.json" />
|
||||
<OpenApiReference Include="../files/swashbuckle.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Position tasks assembly where Microsoft.Extensions.ApiDescription.Client.props expects it. -->
|
||||
<Target Name="CopyTargets" BeforeTargets="BeforeBuild">
|
||||
<ItemGroup>
|
||||
<_Files Include="../../Microsoft.Extensions.ApiDescription.Client.*"
|
||||
Exclude="../../Microsoft.Extensions.ApiDescription.Client.Tests.*" />
|
||||
</ItemGroup>
|
||||
|
||||
<Copy
|
||||
SourceFiles="@(_Files)"
|
||||
DestinationFolder="../../tasks/netstandard2.0/"
|
||||
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
|
||||
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
|
||||
Retries="$(CopyRetryCount)"
|
||||
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
|
||||
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)" />
|
||||
</Target>
|
||||
|
||||
<Import Project="../../build/Microsoft.Extensions.ApiDescription.Client.targets"
|
||||
Condition="Exists('../../build/Microsoft.Extensions.ApiDescription.Client.targets')" />
|
||||
<Import Project="../build/Fakes.targets" Condition="EXISTS('../build/Fakes.targets')" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace ConsoleClient
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello World!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project>
|
||||
<!-- NSwag's OpenApiReference support for C# (default target). -->
|
||||
|
||||
<Target Name="GenerateNSwagCSharp">
|
||||
<PropertyGroup>
|
||||
<_Metadata>'%(CurrentOpenApiReference.FullPath)'</_Metadata>
|
||||
<_Metadata>$(_Metadata) Class: '%(CurrentOpenApiReference.Namespace).%(CurrentOpenApiReference.ClassName)'</_Metadata>
|
||||
<_Metadata>$(_Metadata) FirstForGenerator: '%(CurrentOpenApiReference.FirstForGenerator)'</_Metadata>
|
||||
<_Metadata>$(_Metadata) Options: '%(CurrentOpenApiReference.Options)'</_Metadata>
|
||||
<_Metadata>$(_Metadata) OutputPath: '%(CurrentOpenApiReference.OutputPath)'</_Metadata>
|
||||
</PropertyGroup>
|
||||
|
||||
<Message Importance="high" Text="GenerateNSwagCSharp $(_Metadata)" />
|
||||
</Target>
|
||||
|
||||
<!-- NSwag's OpenApiReference support for TypeScript. -->
|
||||
|
||||
<Target Name="GenerateNSwagTypeScript">
|
||||
<PropertyGroup>
|
||||
<_Metadata>'%(FullPath)' Class: '%(Namespace).%(ClassName)'</_Metadata>
|
||||
<_Metadata>$(_Metadata) FirstForGenerator: '%(FirstForGenerator)' Options: '%(Options)'</_Metadata>
|
||||
<_Metadata>$(_Metadata) OutputPath: '%(OutputPath)'</_Metadata>
|
||||
</PropertyGroup>
|
||||
|
||||
<Message Importance="high" Text="GenerateNSwagTypeScript $(_Metadata)" />
|
||||
</Target>
|
||||
|
||||
<!-- Custom OpenApiReference support for C#. -->
|
||||
|
||||
<Target Name="GenerateCustomCSharp">
|
||||
<PropertyGroup>
|
||||
<_Metadata>'%(FullPath)' Class: '%(Namespace).%(ClassName)'</_Metadata>
|
||||
<_Metadata>$(_Metadata) FirstForGenerator: '%(FirstForGenerator)' Options: '%(Options)'</_Metadata>
|
||||
<_Metadata>$(_Metadata) OutputPath: '%(OutputPath)'</_Metadata>
|
||||
</PropertyGroup>
|
||||
|
||||
<Message Importance="high" Text="GenerateCustomCSharp $(_Metadata)" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
{
|
||||
"x-generator": "NSwag v11.18.6.0 (NJsonSchema v9.10.67.0 (Newtonsoft.Json v11.0.0.0))",
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"title": "My Title",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"host": "localhost:5000",
|
||||
"schemes": [
|
||||
"http"
|
||||
],
|
||||
"consumes": [
|
||||
"application/json-patch+json",
|
||||
"application/json",
|
||||
"text/json",
|
||||
"application/*+json",
|
||||
"application/xml",
|
||||
"text/xml",
|
||||
"application/*+xml"
|
||||
],
|
||||
"produces": [
|
||||
"text/plain",
|
||||
"application/json",
|
||||
"text/json",
|
||||
"application/xml",
|
||||
"text/xml"
|
||||
],
|
||||
"paths": {
|
||||
"/api/Values/matches": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Values"
|
||||
],
|
||||
"operationId": "Values_Matches",
|
||||
"consumes": [
|
||||
"application/json-patch+json",
|
||||
"application/json",
|
||||
"text/json",
|
||||
"application/*+json",
|
||||
"application/xml",
|
||||
"text/xml",
|
||||
"application/*+xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "possibilities",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"x-nullable": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "comparisonType",
|
||||
"in": "query",
|
||||
"x-schema": {
|
||||
"$ref": "#/definitions/StringComparison"
|
||||
},
|
||||
"x-nullable": false,
|
||||
"enum": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"x-nullable": true,
|
||||
"description": "",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/Values": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Values"
|
||||
],
|
||||
"operationId": "Values_Get",
|
||||
"responses": {
|
||||
"200": {
|
||||
"x-nullable": true,
|
||||
"description": "",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"Values"
|
||||
],
|
||||
"operationId": "Values_Post",
|
||||
"consumes": [
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-nullable": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/Values/too": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Values"
|
||||
],
|
||||
"operationId": "Values_GetToo",
|
||||
"responses": {
|
||||
"200": {
|
||||
"x-nullable": true,
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Model"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"StringComparison": {
|
||||
"type": "integer",
|
||||
"description": "",
|
||||
"x-enumNames": [
|
||||
"CurrentCulture",
|
||||
"CurrentCultureIgnoreCase",
|
||||
"InvariantCulture",
|
||||
"InvariantCultureIgnoreCase",
|
||||
"Ordinal",
|
||||
"OrdinalIgnoreCase"
|
||||
],
|
||||
"enum": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
"Model": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"userName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,155 @@
|
|||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"version": "and so is version",
|
||||
"title": "title is required"
|
||||
},
|
||||
"paths": {
|
||||
"/api/Values/matches": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Values"
|
||||
],
|
||||
"operationId": "ApiValuesMatchesPost",
|
||||
"consumes": [
|
||||
"application/json-patch+json",
|
||||
"application/json",
|
||||
"text/json",
|
||||
"application/*+json",
|
||||
"application/xml",
|
||||
"text/xml",
|
||||
"application/*+xml"
|
||||
],
|
||||
"produces": [
|
||||
"text/plain",
|
||||
"application/json",
|
||||
"text/json",
|
||||
"application/xml",
|
||||
"text/xml"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "possibilities",
|
||||
"in": "body",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"uniqueItems": false,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "comparisonType",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"enum": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"schema": {
|
||||
"uniqueItems": false,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/Values": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Values"
|
||||
],
|
||||
"operationId": "ApiValuesGet",
|
||||
"consumes": [],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"schema": {
|
||||
"uniqueItems": false,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"Values"
|
||||
],
|
||||
"operationId": "ApiValuesPost",
|
||||
"consumes": [
|
||||
"application/xml"
|
||||
],
|
||||
"produces": [],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"in": "body",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/Values/too": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Values"
|
||||
],
|
||||
"operationId": "ApiValuesTooGet",
|
||||
"consumes": [],
|
||||
"produces": [
|
||||
"application/xml"
|
||||
],
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Model"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"Model": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"userName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,22 +23,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.dotnet-openapi",
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-microsoft.openapi.Tests", "Microsoft.dotnet-openapi\test\dotnet-microsoft.openapi.Tests.csproj", "{26BBA8A7-0F69-4C5F-B1C2-16B3320FFE3F}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions.ApiDescription.Client", "Extensions.ApiDescription.Client", "{78610083-1FCE-47F5-AB4D-AF0E1313B351}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A0D46647-EF66-456E-9F79-134985E7445E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.ApiDescription.Client", "Extensions.ApiDescription.Client\src\Microsoft.Extensions.ApiDescription.Client.csproj", "{B29B2627-3604-4FDB-A976-EF1E077F5316}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions.ApiDescription.Server", "Extensions.ApiDescription.Server", "{003EA860-5DFC-40AE-87C0-9D21BB2C68D7}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4110117E-3C28-4064-A7A3-B112BD6F8CB9}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-getdocument", "dotnet-getdocument\src\dotnet-getdocument.csproj", "{160A445F-7E1F-430D-9403-41F7F6F4A16E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.ApiDescription.Server", "Extensions.ApiDescription.Server\src\Microsoft.Extensions.ApiDescription.Server.csproj", "{233119FC-E4C1-421C-89AE-1A445C5A947F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GetDocumentInsider", "GetDocumentInsider\src\GetDocumentInsider.csproj", "{EB63AECB-B898-475D-90F7-FE61F9C1CCC6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.ApiDescription.Client.Tests", "Extensions.ApiDescription.Client\test\Microsoft.Extensions.ApiDescription.Client.Tests.csproj", "{2C62584B-EC31-40C8-819B-E46334645AE5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -53,38 +49,6 @@ Global
|
|||
{63F7E822-D1E2-4C41-8ABF-60B9E3A9C54C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{63F7E822-D1E2-4C41-8ABF-60B9E3A9C54C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{63F7E822-D1E2-4C41-8ABF-60B9E3A9C54C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0D6D5693-7E0C-4FE8-B4AA-21207B2650AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0D6D5693-7E0C-4FE8-B4AA-21207B2650AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0D6D5693-7E0C-4FE8-B4AA-21207B2650AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0D6D5693-7E0C-4FE8-B4AA-21207B2650AA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7BBDBDA2-299F-4C36-8338-23C525901DE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7BBDBDA2-299F-4C36-8338-23C525901DE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7BBDBDA2-299F-4C36-8338-23C525901DE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7BBDBDA2-299F-4C36-8338-23C525901DE0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1EC6FA27-40A5-433F-8CA1-636E7ED8863E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1EC6FA27-40A5-433F-8CA1-636E7ED8863E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1EC6FA27-40A5-433F-8CA1-636E7ED8863E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1EC6FA27-40A5-433F-8CA1-636E7ED8863E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{15FB0E39-1A28-4325-AD3C-76352516C80D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{15FB0E39-1A28-4325-AD3C-76352516C80D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{15FB0E39-1A28-4325-AD3C-76352516C80D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{15FB0E39-1A28-4325-AD3C-76352516C80D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B29B2627-3604-4FDB-A976-EF1E077F5316}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B29B2627-3604-4FDB-A976-EF1E077F5316}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B29B2627-3604-4FDB-A976-EF1E077F5316}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B29B2627-3604-4FDB-A976-EF1E077F5316}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{160A445F-7E1F-430D-9403-41F7F6F4A16E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{160A445F-7E1F-430D-9403-41F7F6F4A16E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{160A445F-7E1F-430D-9403-41F7F6F4A16E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{160A445F-7E1F-430D-9403-41F7F6F4A16E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{233119FC-E4C1-421C-89AE-1A445C5A947F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{233119FC-E4C1-421C-89AE-1A445C5A947F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{233119FC-E4C1-421C-89AE-1A445C5A947F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{233119FC-E4C1-421C-89AE-1A445C5A947F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EB63AECB-B898-475D-90F7-FE61F9C1CCC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EB63AECB-B898-475D-90F7-FE61F9C1CCC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EB63AECB-B898-475D-90F7-FE61F9C1CCC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EB63AECB-B898-475D-90F7-FE61F9C1CCC6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{98550159-E04E-44EB-A969-E5BF12444B94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{98550159-E04E-44EB-A969-E5BF12444B94}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{98550159-E04E-44EB-A969-E5BF12444B94}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
|
@ -109,17 +73,31 @@ Global
|
|||
{26BBA8A7-0F69-4C5F-B1C2-16B3320FFE3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{26BBA8A7-0F69-4C5F-B1C2-16B3320FFE3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{26BBA8A7-0F69-4C5F-B1C2-16B3320FFE3F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B29B2627-3604-4FDB-A976-EF1E077F5316}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B29B2627-3604-4FDB-A976-EF1E077F5316}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B29B2627-3604-4FDB-A976-EF1E077F5316}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B29B2627-3604-4FDB-A976-EF1E077F5316}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{160A445F-7E1F-430D-9403-41F7F6F4A16E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{160A445F-7E1F-430D-9403-41F7F6F4A16E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{160A445F-7E1F-430D-9403-41F7F6F4A16E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{160A445F-7E1F-430D-9403-41F7F6F4A16E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{233119FC-E4C1-421C-89AE-1A445C5A947F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{233119FC-E4C1-421C-89AE-1A445C5A947F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{233119FC-E4C1-421C-89AE-1A445C5A947F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{233119FC-E4C1-421C-89AE-1A445C5A947F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EB63AECB-B898-475D-90F7-FE61F9C1CCC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EB63AECB-B898-475D-90F7-FE61F9C1CCC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EB63AECB-B898-475D-90F7-FE61F9C1CCC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EB63AECB-B898-475D-90F7-FE61F9C1CCC6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2C62584B-EC31-40C8-819B-E46334645AE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2C62584B-EC31-40C8-819B-E46334645AE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2C62584B-EC31-40C8-819B-E46334645AE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2C62584B-EC31-40C8-819B-E46334645AE5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{A0D46647-EF66-456E-9F79-134985E7445E} = {78610083-1FCE-47F5-AB4D-AF0E1313B351}
|
||||
{B29B2627-3604-4FDB-A976-EF1E077F5316} = {A0D46647-EF66-456E-9F79-134985E7445E}
|
||||
{4110117E-3C28-4064-A7A3-B112BD6F8CB9} = {003EA860-5DFC-40AE-87C0-9D21BB2C68D7}
|
||||
{160A445F-7E1F-430D-9403-41F7F6F4A16E} = {4110117E-3C28-4064-A7A3-B112BD6F8CB9}
|
||||
{233119FC-E4C1-421C-89AE-1A445C5A947F} = {4110117E-3C28-4064-A7A3-B112BD6F8CB9}
|
||||
{EB63AECB-B898-475D-90F7-FE61F9C1CCC6} = {4110117E-3C28-4064-A7A3-B112BD6F8CB9}
|
||||
{E16F10C8-5FC3-420B-AB33-D6E5CBE89B75} = {E01EE27B-6CF9-4707-9849-5BA2ABA825F2}
|
||||
{63F7E822-D1E2-4C41-8ABF-60B9E3A9C54C} = {2C485EAF-E4DE-4D14-8AE1-330641E17D44}
|
||||
{98550159-E04E-44EB-A969-E5BF12444B94} = {E01EE27B-6CF9-4707-9849-5BA2ABA825F2}
|
||||
|
|
@ -128,6 +106,12 @@ Global
|
|||
{25F8DCC4-4571-42F7-BA0F-5C2D5A802297} = {2C485EAF-E4DE-4D14-8AE1-330641E17D44}
|
||||
{C806041C-30F2-4B27-918A-5FF3576B833B} = {E01EE27B-6CF9-4707-9849-5BA2ABA825F2}
|
||||
{26BBA8A7-0F69-4C5F-B1C2-16B3320FFE3F} = {2C485EAF-E4DE-4D14-8AE1-330641E17D44}
|
||||
{B29B2627-3604-4FDB-A976-EF1E077F5316} = {E01EE27B-6CF9-4707-9849-5BA2ABA825F2}
|
||||
{003EA860-5DFC-40AE-87C0-9D21BB2C68D7} = {E01EE27B-6CF9-4707-9849-5BA2ABA825F2}
|
||||
{160A445F-7E1F-430D-9403-41F7F6F4A16E} = {003EA860-5DFC-40AE-87C0-9D21BB2C68D7}
|
||||
{233119FC-E4C1-421C-89AE-1A445C5A947F} = {003EA860-5DFC-40AE-87C0-9D21BB2C68D7}
|
||||
{EB63AECB-B898-475D-90F7-FE61F9C1CCC6} = {003EA860-5DFC-40AE-87C0-9D21BB2C68D7}
|
||||
{2C62584B-EC31-40C8-819B-E46334645AE5} = {2C485EAF-E4DE-4D14-8AE1-330641E17D44}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {EC668D8E-97B9-4758-9E5C-2E5DD6B9137B}
|
||||
|
|
|
|||
Loading…
Reference in New Issue