diff --git a/src/OasReader.Tests/EmbeddedResources.cs b/src/OasReader.Tests/EmbeddedResources.cs new file mode 100644 index 0000000..a69a5e7 --- /dev/null +++ b/src/OasReader.Tests/EmbeddedResources.cs @@ -0,0 +1,17 @@ +using System.Reflection; + +namespace OasReader.Tests; + +internal class EmbeddedResources +{ + public static string GetStream(string name) + { + var assembly = Assembly.GetExecutingAssembly(); + var resourceName = $"OasReader.Tests.Resources.{name}"; + + using var stream = assembly.GetManifestResourceStream(resourceName); + using var reader = new StreamReader(stream ?? throw new InvalidOperationException($"Could not find the embedded resource {name}")); + + return reader.ReadToEnd(); + } +} \ No newline at end of file diff --git a/src/OasReader.Tests/OpenApiDocumentExtensionsTests.cs b/src/OasReader.Tests/OpenApiDocumentExtensionsTests.cs new file mode 100644 index 0000000..10cc7d3 --- /dev/null +++ b/src/OasReader.Tests/OpenApiDocumentExtensionsTests.cs @@ -0,0 +1,35 @@ +using FluentAssertions; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Readers; +using Xunit; + +namespace OasReader.Tests; + +public class OpenApiDocumentExtensionsTests +{ + [Theory] + [InlineData("bot.yaml", "bot.components.yaml")] + [InlineData("petstore.yaml", "petstore.components.yaml")] + public async Task Returns_NotNull(string apiFile, string componentsFile) + { + var folder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(folder); + + var componentsFilename = Path.Combine(folder, componentsFile); + var openapiFilename = Path.Combine(folder, apiFile); + + var componentContents = EmbeddedResources.GetStream(componentsFile); + var apiContents = EmbeddedResources.GetStream(apiFile); + + await File.WriteAllTextAsync(componentsFilename, componentContents); + await File.WriteAllTextAsync(openapiFilename, apiContents); + + var file = File.OpenRead(openapiFilename); + var textReader = new StreamReader(file); + var reader = new OpenApiTextReaderReader(); + var result = await reader.ReadAsync(textReader, CancellationToken.None); + OpenApiDocument sut = result.OpenApiDocument; + + sut.ContainsExternalReferences().Should().BeTrue(); + } +} diff --git a/src/OasReader.Tests/OpenApiReaderTests.cs b/src/OasReader.Tests/OpenApiReaderTests.cs index a6fac7d..c18754e 100644 --- a/src/OasReader.Tests/OpenApiReaderTests.cs +++ b/src/OasReader.Tests/OpenApiReaderTests.cs @@ -1,5 +1,4 @@ -using System.Reflection; -using FluentAssertions; +using FluentAssertions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Readers; using Xunit; @@ -8,66 +7,67 @@ namespace OasReader.Tests; public class OpenApiReaderTests { - [Fact] - public async Task Returns_NotNull() + [Theory] + [InlineData("bot.yaml", "bot.components.yaml")] + [InlineData("petstore.yaml", "petstore.components.yaml")] + public async Task Returns_NotNull(string apiFile, string componentsFile) { - OpenApiDocument result = await Arrange(); + OpenApiDocument result = await Arrange(apiFile, componentsFile); result.Should().NotBeNull(); } [Theory] - [InlineData("BaseGuildID")] - [InlineData("BaseChannelID")] - [InlineData("BaseChannelCategoryID")] - [InlineData("BaseUserID")] - [InlineData("BaseRoleID")] - [InlineData("BaseMessageID")] - [InlineData("BaseSequenceInChannel")] - [InlineData("BaseScheduleID")] - [InlineData("Guild")] - [InlineData("User")] - [InlineData("Channel")] - [InlineData("Member")] - [InlineData("Role")] - [InlineData("ChannelPermissions")] - [InlineData("Message")] - public async Task Returns_Document_With_External_Schemas(string schemaName) + [InlineData("bot.yaml", "bot.components.yaml")] + [InlineData("petstore.yaml", "petstore.components.yaml")] + public async Task Returns_Components_Schemas_NotNull(string apiFile, string componentsFile) { - OpenApiDocument result = await Arrange(); + OpenApiDocument result = await Arrange(apiFile, componentsFile); + result.Components.Should().NotBeNull(); + result.Components.Schemas.Should().NotBeNull(); + } + + [Theory] + [InlineData("bot.yaml", "bot.components.yaml", "BaseGuildID")] + [InlineData("bot.yaml", "bot.components.yaml", "BaseChannelID")] + [InlineData("bot.yaml", "bot.components.yaml", "BaseChannelCategoryID")] + [InlineData("bot.yaml", "bot.components.yaml", "BaseUserID")] + [InlineData("bot.yaml", "bot.components.yaml", "BaseRoleID")] + [InlineData("bot.yaml", "bot.components.yaml", "BaseMessageID")] + [InlineData("bot.yaml", "bot.components.yaml", "BaseSequenceInChannel")] + [InlineData("bot.yaml", "bot.components.yaml", "BaseScheduleID")] + [InlineData("bot.yaml", "bot.components.yaml", "Guild")] + [InlineData("bot.yaml", "bot.components.yaml", "User")] + [InlineData("bot.yaml", "bot.components.yaml", "Channel")] + [InlineData("bot.yaml", "bot.components.yaml", "Member")] + [InlineData("bot.yaml", "bot.components.yaml", "Role")] + [InlineData("bot.yaml", "bot.components.yaml", "ChannelPermissions")] + [InlineData("bot.yaml", "bot.components.yaml", "Message")] + [InlineData("petstore.yaml", "petstore.components.yaml", "Order")] + [InlineData("petstore.yaml", "petstore.components.yaml", "Pet")] + [InlineData("petstore.yaml", "petstore.components.yaml", "Tag")] + [InlineData("petstore.yaml", "petstore.components.yaml", "Category")] + [InlineData("petstore.yaml", "petstore.components.yaml", "ApiResponse")] + public async Task Returns_Document_With_External_Schemas(string apiFile, string componentsFile, string schemaName) + { + OpenApiDocument result = await Arrange(apiFile, componentsFile); result.Components.Schemas.Should().ContainKey(schemaName); } - private static async Task Arrange() + private static async Task Arrange(string apiFile, string componentsFile) { var folder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); Directory.CreateDirectory(folder); - var componentsFilename = Path.Combine(folder, "components.yaml"); - var openapiFilename = Path.Combine(folder, "openapi.yaml"); - - await File.WriteAllTextAsync(componentsFilename, EmbeddedResources.Components); - await File.WriteAllTextAsync(openapiFilename, EmbeddedResources.OpenApi); - - var result = await OpenApiMultiFileReader.Read(openapiFilename); - return result; - } -} + var componentsFilename = Path.Combine(folder, componentsFile); + var openapiFilename = Path.Combine(folder, apiFile); -internal class EmbeddedResources -{ - public static string GetStream(string name) - { - var assembly = Assembly.GetExecutingAssembly(); - var resourceName = $"OasReader.Tests.Resources.{name}"; + var componentContents = EmbeddedResources.GetStream(componentsFile); + var apiContents = EmbeddedResources.GetStream(apiFile); - using var stream = assembly.GetManifestResourceStream(resourceName); - using var reader = new StreamReader(stream ?? throw new InvalidOperationException($"Could not find the embedded resource {name}")); + await File.WriteAllTextAsync(componentsFilename, componentContents); + await File.WriteAllTextAsync(openapiFilename, apiContents); - return reader.ReadToEnd(); + return await OpenApiMultiFileReader.Read(openapiFilename); } - - public static string OpenApi => GetStream("openapi.yaml"); - - public static string Components => GetStream("components.yaml"); -} \ No newline at end of file +} diff --git a/src/OasReader/OpenApiDocumentExtensions.cs b/src/OasReader/OpenApiDocumentExtensions.cs index c91d7d2..191abab 100644 --- a/src/OasReader/OpenApiDocumentExtensions.cs +++ b/src/OasReader/OpenApiDocumentExtensions.cs @@ -43,6 +43,20 @@ public static OpenApiDocument MergeExternalReferences(this OpenApiDocument docum } public static bool ContainsExternalReferences(this OpenApiDocument document) => - document.Paths.Any(kvp => kvp.Value.Parameters.Any(p => p.Reference?.IsExternal == true)); + document.Paths + .Any(kvp => + kvp.Value.Parameters.Any( + p => p.Reference?.IsExternal == true || + p.Schema.Reference?.IsExternal == true || + p.Content.Any(c => c.Value.Schema?.Reference?.IsExternal == true)) || + kvp.Value.Operations.Any( + o => o.Value.Parameters.Any(p => + p.Reference?.IsExternal == true || + p.Schema.Reference?.IsExternal == true || + p.Content.Any(c => c.Value.Schema?.Reference?.IsExternal == true)) || + o.Value.RequestBody?.Content?.Any(c => c.Value.Schema?.Reference?.IsExternal == true) == true || + o.Value.Responses.Any(r => + r.Value.Content.Any(c => c.Value.Schema?.Reference?.IsExternal == true) || + r.Value.Headers.Any(h => h.Value.Schema?.Reference?.IsExternal == true)))); } } \ No newline at end of file