Skip to content
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
},
"cSpell.words": [
"csdl",
"Hidi"
"Hidi",
"Xunit"
]
}
2 changes: 1 addition & 1 deletion performance/resultsComparer/resultsComparer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.10" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.10" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="10.0.10" />
<PackageReference Include="System.CommandLine" Version="2.0.5" />
<PackageReference Include="System.CommandLine" Version="2.0.10" />
<PackageReference Include="system.text.json" Version="10.0.10" />
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="System.CommandLine" Version="2.0.5" />
<PackageReference Include="System.CommandLine" Version="2.0.10" />
<PackageReference Include="Microsoft.OData.Edm" Version="8.4.4" />
<PackageReference Include="Microsoft.OpenApi.OData" Version="3.2.1" />
<PackageReference Include="Microsoft.OpenApi.ApiManifest" Version="3.0.0-preview.1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@

<!-- Windows-specific dependencies -->
<ItemGroup Condition="'$(OS)' == 'Windows_NT'">
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.14.15">
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="18.7.23">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Windows.Compatibility" Version="10.0.5" />
<PackageReference Include="System.Security.Cryptography.Xml" Version="10.0.6" />
<PackageReference Include="Microsoft.Windows.Compatibility" Version="10.0.10" />
<PackageReference Include="System.Security.Cryptography.Xml" Version="10.0.10" />
</ItemGroup>

<!-- Windows-specific resources -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<PackageReference Include="coverlet.msbuild" Version="10.0.1" PrivateAssets="all" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.8.1" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" PrivateAssets="all" />
<PackageReference Include="coverlet.collector" Version="10.0.1" PrivateAssets="all" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public void ReturnFilteredOpenApiDocumentBasedOnOperationIdsAndTags(string? oper
public void ReturnFilteredOpenApiDocumentBasedOnPostmanCollection()
{
// Arrange
var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UtilityFiles", "postmanCollection_ver2.json");
var filePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "UtilityFiles", "postmanCollection_ver2.json");
var fileInput = new FileInfo(filePath);
var stream = fileInput.OpenRead();

Expand Down Expand Up @@ -158,7 +158,7 @@ public void CreateFilteredDocumentUsingPredicateFromRequestUrl()
public void ShouldParseNestedPostmanCollection()
{
// Arrange
var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UtilityFiles", "postmanCollection_ver3.json");
var filePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "UtilityFiles", "postmanCollection_ver3.json");
var fileInput = new FileInfo(filePath);
var stream = fileInput.OpenRead();

Expand All @@ -175,7 +175,7 @@ public void ShouldParseNestedPostmanCollection()
public void ThrowsExceptionWhenUrlsInCollectionAreMissingFromSourceDocument()
{
// Arrange
var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UtilityFiles", "postmanCollection_ver1.json");
var filePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "UtilityFiles", "postmanCollection_ver1.json");
var fileInput = new FileInfo(filePath);
var stream = fileInput.OpenRead();

Expand All @@ -192,7 +192,7 @@ public void ThrowsExceptionWhenUrlsInCollectionAreMissingFromSourceDocument()
public void ContinueProcessingWhenUrlsInCollectionAreMissingFromSourceDocument()
{
// Arrange
var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UtilityFiles", "postmanCollection_ver4.json");
var filePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "UtilityFiles", "postmanCollection_ver4.json");
var fileInput = new FileInfo(filePath);
var stream = fileInput.OpenRead();

Expand Down Expand Up @@ -291,14 +291,14 @@ public void CreatePredicateMatchesAbsoluteUrlsWhenSourceHasNoServers()
public async Task CopiesOverAllReferencedComponentsToTheSubsetDocumentCorrectly()
{
// Arrange
var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UtilityFiles", "docWithReusableHeadersAndExamples.yaml");
var filePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "UtilityFiles", "docWithReusableHeadersAndExamples.yaml");
var operationIds = "getItems";

// Act
using var stream = File.OpenRead(filePath);
var settings = new OpenApiReaderSettings();
settings.AddYamlReader();
var doc = (await OpenApiDocument.LoadAsync(stream, "yaml", settings)).Document;
var doc = (await OpenApiDocument.LoadAsync(stream, "yaml", settings, TestContext.Current.CancellationToken)).Document;

// validated the tags are read as references
var openApiOperationTags = doc?.Paths["/items"].Operations?[HttpMethod.Get].Tags?.ToArray();
Expand Down Expand Up @@ -344,7 +344,7 @@ public async Task CopiesOverAllReferencedComponentsToTheSubsetDocumentCorrectly(
}
};
subsetOpenApiDocument.SerializeAsV3(writer);
await writer.FlushAsync();
await writer.FlushAsync(TestContext.Current.CancellationToken);
var result = outputStringWriter.ToString();
Assert.NotEmpty(result);
}
Expand Down
86 changes: 46 additions & 40 deletions test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,13 @@ public async Task ShowCommandGeneratesMermaidMarkdownFileWithMermaidDiagramAsync
// create a dummy ILogger instance for testing
var options = new HidiOptions
{
OpenApi = Path.Combine("UtilityFiles", "SampleOpenApi.yml"),
Output = new("sample.md")
OpenApi = Path.Join("UtilityFiles", "SampleOpenApi.yml"),
Output = new($"{nameof(ShowCommandGeneratesMermaidMarkdownFileWithMermaidDiagramAsync)}.md")
};

await OpenApiService.ShowOpenApiDocumentAsync(options, _logger);
await OpenApiService.ShowOpenApiDocumentAsync(options, _logger, TestContext.Current.CancellationToken);

var output = await File.ReadAllTextAsync(options.Output.FullName);
var output = await File.ReadAllTextAsync(options.Output.FullName, TestContext.Current.CancellationToken);
Assert.Contains("graph LR", output, StringComparison.Ordinal);
}

Expand All @@ -149,54 +149,54 @@ public async Task ShowCommandGeneratesMermaidHtmlFileWithMermaidDiagramAsync()
{
var options = new HidiOptions
{
OpenApi = Path.Combine("UtilityFiles", "SampleOpenApi.yml")
OpenApi = Path.Join("UtilityFiles", "SampleOpenApi.yml")
};
var filePath = await OpenApiService.ShowOpenApiDocumentAsync(options, _logger);
var filePath = await OpenApiService.ShowOpenApiDocumentAsync(options, _logger, TestContext.Current.CancellationToken);
Assert.True(File.Exists(filePath));
}

[Fact]
public Task ThrowIfOpenApiUrlIsNotProvidedWhenValidatingAsync()
{
return Assert.ThrowsAsync<ArgumentNullException>(() =>
OpenApiService.ValidateOpenApiDocumentAsync("", _logger));
OpenApiService.ValidateOpenApiDocumentAsync("", _logger, TestContext.Current.CancellationToken));
}

[Fact]
public Task ThrowIfURLIsNotResolvableWhenValidatingAsync()
{
return Assert.ThrowsAsync<InvalidOperationException>(() =>
OpenApiService.ValidateOpenApiDocumentAsync("https://example.org926F4F21-88E7-4DC5-BF88-6C529BB77844/itdoesnmatter", _logger));
OpenApiService.ValidateOpenApiDocumentAsync("https://example.org926F4F21-88E7-4DC5-BF88-6C529BB77844/itdoesnmatter", _logger, TestContext.Current.CancellationToken));
}

[Fact]
public Task ThrowIfFileDoesNotExistWhenValidatingAsync()
{
return Assert.ThrowsAsync<InvalidOperationException>(() =>
OpenApiService.ValidateOpenApiDocumentAsync("aFileThatBetterNotExist.fake", _logger));
OpenApiService.ValidateOpenApiDocumentAsync("aFileThatBetterNotExist.fake", _logger, TestContext.Current.CancellationToken));
}

[Fact]
public async Task ValidateCommandProcessesOpenApiAsync()
{
// create a dummy ILogger instance for testing
await OpenApiService.ValidateOpenApiDocumentAsync(Path.Combine("UtilityFiles", "SampleOpenApi.yml"), _logger);
await OpenApiService.ValidateOpenApiDocumentAsync(Path.Join("UtilityFiles", "SampleOpenApi.yml"), _logger, TestContext.Current.CancellationToken);

Assert.True(true);
}

[Fact]
public async Task ValidFileReturnsTrueAsync()
{
var isValid = await OpenApiService.ValidateOpenApiDocumentAsync(Path.Combine("UtilityFiles", "SampleOpenApi.yml"), _logger);
var isValid = await OpenApiService.ValidateOpenApiDocumentAsync(Path.Join("UtilityFiles", "SampleOpenApi.yml"), _logger, TestContext.Current.CancellationToken);

Assert.True(isValid);
}

[Fact]
public async Task InvalidFileReturnsFalseAsync()
{
var isValid = await OpenApiService.ValidateOpenApiDocumentAsync(Path.Combine("UtilityFiles", "InvalidSampleOpenApi.yml"), _logger);
var isValid = await OpenApiService.ValidateOpenApiDocumentAsync(Path.Join("UtilityFiles", "InvalidSampleOpenApi.yml"), _logger, TestContext.Current.CancellationToken);

Assert.False(isValid);
}
Expand All @@ -206,7 +206,7 @@ public async Task CancellingValidationReturnsNullAsync()
{
using var cts = new CancellationTokenSource();
await cts.CancelAsync();
var isValid = await OpenApiService.ValidateOpenApiDocumentAsync(Path.Combine("UtilityFiles", "SampleOpenApi.yml"), _logger, cts.Token);
var isValid = await OpenApiService.ValidateOpenApiDocumentAsync(Path.Join("UtilityFiles", "SampleOpenApi.yml"), _logger, cts.Token);

Assert.Null(isValid);
}
Expand All @@ -216,17 +216,17 @@ public async Task TransformCommandConvertsOpenApiAsync()
{
var options = new HidiOptions
{
OpenApi = Path.Combine("UtilityFiles", "SampleOpenApi.yml"),
Output = new("sample.json"),
OpenApi = Path.Join("UtilityFiles", "SampleOpenApi.yml"),
Output = new($"{nameof(TransformCommandConvertsOpenApiAsync)}.json"),
CleanOutput = true,
TerseOutput = false,
InlineLocal = false,
InlineExternal = false,
};
// create a dummy ILogger instance for testing
await OpenApiService.TransformOpenApiDocumentAsync(options, _logger);
await OpenApiService.TransformOpenApiDocumentAsync(options, _logger, TestContext.Current.CancellationToken);

var output = await File.ReadAllTextAsync("sample.json");
var output = await File.ReadAllTextAsync(options.Output.FullName, TestContext.Current.CancellationToken);
Assert.NotEmpty(output);
}

Expand All @@ -236,16 +236,17 @@ public async Task TransformCommandConvertsOpenApiWithDefaultOutputNameAsync()
{
var options = new HidiOptions
{
OpenApi = Path.Combine("UtilityFiles", "SampleOpenApi.yml"),
OpenApi = Path.Join("UtilityFiles", "SampleOpenApi.yml"),
CleanOutput = true,
TerseOutput = false,
InlineLocal = false,
InlineExternal = false,
Output = new FileInfo($"{nameof(TransformCommandConvertsOpenApiWithDefaultOutputNameAsync)}.yml")
};
// create a dummy ILogger instance for testing
await OpenApiService.TransformOpenApiDocumentAsync(options, _logger);
await OpenApiService.TransformOpenApiDocumentAsync(options, _logger, TestContext.Current.CancellationToken);

var output = await File.ReadAllTextAsync("output.yml");
var output = await File.ReadAllTextAsync(options.Output.FullName, TestContext.Current.CancellationToken);
Assert.NotEmpty(output);
}

Expand All @@ -254,7 +255,8 @@ public async Task TransformCommandConvertsOpenApiWithDefaultOutputNameAndSwitchF
{
var options = new HidiOptions
{
OpenApi = Path.Combine("UtilityFiles", "SampleOpenApi.yml"),
OpenApi = Path.Join("UtilityFiles", "SampleOpenApi.yml"),
Output = new($"{nameof(TransformCommandConvertsOpenApiWithDefaultOutputNameAndSwitchFormatAsync)}.yml"),
CleanOutput = true,
Version = "3.0",
OpenApiFormat = OpenApiConstants.Yaml,
Expand All @@ -263,9 +265,9 @@ public async Task TransformCommandConvertsOpenApiWithDefaultOutputNameAndSwitchF
InlineExternal = false,
};
// create a dummy ILogger instance for testing
await OpenApiService.TransformOpenApiDocumentAsync(options, _logger);
await OpenApiService.TransformOpenApiDocumentAsync(options, _logger, TestContext.Current.CancellationToken);

var output = await File.ReadAllTextAsync("output.yml");
var output = await File.ReadAllTextAsync(options.Output.FullName, TestContext.Current.CancellationToken);
Assert.NotEmpty(output);
}

Expand All @@ -280,16 +282,17 @@ public Task ThrowTransformCommandIfOpenApiAndCsdlAreEmptyAsync()
InlineExternal = false,
};
return Assert.ThrowsAsync<ArgumentException>(() =>
OpenApiService.TransformOpenApiDocumentAsync(options, _logger));
OpenApiService.TransformOpenApiDocumentAsync(options, _logger, TestContext.Current.CancellationToken));
}

[Fact]
public async Task TransformToPowerShellCompliantOpenApiAsync()
{
var settingsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UtilityFiles", "examplepowershellsettings.json");
var settingsPath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "UtilityFiles", "examplepowershellsettings.json");
var options = new HidiOptions
{
OpenApi = Path.Combine("UtilityFiles", "SampleOpenApi.yml"),
OpenApi = Path.Join("UtilityFiles", "SampleOpenApi.yml"),
Output = new($"{nameof(TransformToPowerShellCompliantOpenApiAsync)}.yaml"),
CleanOutput = true,
Version = "3.0",
OpenApiFormat = OpenApiConstants.Yaml,
Expand All @@ -299,24 +302,25 @@ public async Task TransformToPowerShellCompliantOpenApiAsync()
SettingsConfig = SettingsUtilities.GetConfiguration(settingsPath)
};
// create a dummy ILogger instance for testing
await OpenApiService.TransformOpenApiDocumentAsync(options, _logger);
await OpenApiService.TransformOpenApiDocumentAsync(options, _logger, TestContext.Current.CancellationToken);

var output = await File.ReadAllTextAsync("output.yaml");
var output = await File.ReadAllTextAsync(options.Output.FullName, TestContext.Current.CancellationToken);
Assert.NotEmpty(output);
}

[Fact]
public async Task InvokeTransformCommandAsync()
{
var rootCommand = Program.CreateRootCommand();
var openapi = Path.Combine(".", "UtilityFiles", "SampleOpenApi.yml");
var args = new[] { "transform", "-d", openapi, "-o", "sample.json", "--co" };
var openapi = Path.Join(".", "UtilityFiles", "SampleOpenApi.yml");
var outputPath = $"{nameof(InvokeTransformCommandAsync)}.json";
var args = new[] { "transform", "-d", openapi, "-o", outputPath, "--co" };
var parseResult = rootCommand.Parse(args);
var handler = Assert.IsType<AsynchronousCommandLineAction>(rootCommand.Subcommands.First(c => c.Name == "transform").Action, exactMatch: false);

await handler.InvokeAsync(parseResult);
await handler.InvokeAsync(parseResult, TestContext.Current.CancellationToken);

var output = await File.ReadAllTextAsync("sample.json");
var output = await File.ReadAllTextAsync(outputPath, TestContext.Current.CancellationToken);
Assert.NotEmpty(output);
}

Expand All @@ -325,29 +329,31 @@ public async Task InvokeTransformCommandAsync()
public async Task InvokeShowCommandAsync()
{
var rootCommand = Program.CreateRootCommand();
var openApi = Path.Combine(".", "UtilityFiles", "SampleOpenApi.yml");
var args = new[] { "show", "-d", openApi, "-o", "sample.md" };
var openApi = Path.Join(".", "UtilityFiles", "SampleOpenApi.yml");
var outputPath = $"{nameof(InvokeShowCommandAsync)}.md";
var args = new[] { "show", "-d", openApi, "-o", outputPath };
var parseResult = rootCommand.Parse(args);
var handler = Assert.IsType<AsynchronousCommandLineAction>(rootCommand.Subcommands.First(c => c.Name == "show").Action, exactMatch: false);

await handler.InvokeAsync(parseResult);
await handler.InvokeAsync(parseResult, TestContext.Current.CancellationToken);

var output = await File.ReadAllTextAsync("sample.md");
var output = await File.ReadAllTextAsync(outputPath, TestContext.Current.CancellationToken);
Assert.Contains("graph LR", output, StringComparison.Ordinal);
}

[Fact]
public async Task InvokePluginCommandAsync()
{
var rootCommand = Program.CreateRootCommand();
var manifest = Path.Combine(".", "UtilityFiles", "exampleapimanifest.json");
var args = new[] { "plugin", "-m", manifest, "--of", AppDomain.CurrentDomain.BaseDirectory };
var manifest = Path.Join(".", "UtilityFiles", "exampleapimanifest.json");
var outputPath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, nameof(InvokePluginCommandAsync));
var args = new[] { "plugin", "-m", manifest, "--of", outputPath };
var parseResult = rootCommand.Parse(args);
var handler = Assert.IsType<AsynchronousCommandLineAction>(rootCommand.Subcommands.First(c => c.Name == "plugin").Action, exactMatch: false);

await handler.InvokeAsync(parseResult);
await handler.InvokeAsync(parseResult, TestContext.Current.CancellationToken);

using var jsDoc = JsonDocument.Parse(await File.ReadAllTextAsync("ai-plugin.json"));
using var jsDoc = JsonDocument.Parse(await File.ReadAllTextAsync(Path.Join(outputPath, "ai-plugin.json"), TestContext.Current.CancellationToken));
var openAiManifest = OpenAIPluginManifest.Load(jsDoc.RootElement);

Assert.NotNull(openAiManifest);
Expand Down
Loading
Loading