diff --git a/src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs b/src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs index cff6dd1da..c7f5834e4 100644 --- a/src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs +++ b/src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs @@ -77,7 +77,7 @@ static JsonNode LoadJsonNodesFromYamlDocument(TextReader input) { var yamlStream = new YamlStream(); yamlStream.Load(input); - var yamlDocument = yamlStream.Documents.First(); + var yamlDocument = yamlStream.Documents[0]; return yamlDocument.ToJsonNode(); } diff --git a/src/Microsoft.OpenApi/Models/OpenApiTag.cs b/src/Microsoft.OpenApi/Models/OpenApiTag.cs index 6f79e0999..8e9321fe8 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiTag.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiTag.cs @@ -55,56 +55,31 @@ public OpenApiTag(OpenApiTag tag) { Name = tag?.Name ?? Name; Description = tag?.Description ?? Description; - ExternalDocs = tag?.ExternalDocs != null ? new(tag?.ExternalDocs) : null; + ExternalDocs = tag?.ExternalDocs != null ? new(tag.ExternalDocs) : null; Extensions = tag?.Extensions != null ? new Dictionary(tag.Extensions) : null; UnresolvedReference = tag?.UnresolvedReference ?? UnresolvedReference; - Reference = tag?.Reference != null ? new(tag?.Reference) : null; + Reference = tag?.Reference != null ? new(tag.Reference) : null; } /// /// Serialize to Open Api v3.1 /// - public virtual void SerializeAsV31(IOpenApiWriter writer) + public virtual void SerializeAsV31(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); - } - - /// - /// Serialize to Open Api v3.0 - /// - public virtual void SerializeAsV3(IOpenApiWriter writer) - { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); - } - - /// - /// Serialize to Open Api v3.0 - /// - private void SerializeInternal(IOpenApiWriter writer, Action callback) - { - Utils.CheckArgumentNull(writer); - writer.WriteValue(Name); - } - - /// - /// Serialize to OpenAPI V3 document without using reference. - /// - public virtual void SerializeAsV31WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_1, + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); } /// - /// Serialize to OpenAPI V3 document without using reference. + /// Serialize to Open Api v3.0 /// - public virtual void SerializeAsV3WithoutReference(IOpenApiWriter writer) + public virtual void SerializeAsV3(IOpenApiWriter writer) { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_0, + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } - internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpecVersion version, + internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { writer.WriteStartObject(); @@ -128,15 +103,6 @@ internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, O /// Serialize to Open Api v2.0 /// public virtual void SerializeAsV2(IOpenApiWriter writer) - { - Utils.CheckArgumentNull(writer); - writer.WriteValue(Name); - } - - /// - /// Serialize to OpenAPI V2 document without using reference. - /// - public void SerializeAsV2WithoutReference(IOpenApiWriter writer) { writer.WriteStartObject(); diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs index 884ffa68c..1e9caeecd 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs @@ -992,7 +992,7 @@ public OpenApiDocumentTests() { ["my-extension"] = new OpenApiAny(4) } - }, + }, Extensions = new Dictionary { ["my-extension"] = new OpenApiAny(4), @@ -2072,5 +2072,59 @@ public void SerializeDocWithDollarIdInDollarRefSucceeds() var actual = doc.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_1); actual.MakeLineBreaksEnvironmentNeutral().Should().BeEquivalentTo(expected.MakeLineBreaksEnvironmentNeutral()); } + + [Fact] + public void SerializeDocumentTagsWithMultipleExtensionsWorks() + { + var expected = @"{ + ""openapi"": ""3.0.4"", + ""info"": { + ""title"": ""Test"", + ""version"": ""1.0.0"" + }, + ""paths"": { }, + ""tags"": [ + { + ""name"": ""tag1"", + ""x-tag1"": ""tag1"" + }, + { + ""name"": ""tag2"", + ""x-tag2"": ""tag2"" + } + ] +}"; + var doc = new OpenApiDocument + { + Info = new OpenApiInfo + { + Title = "Test", + Version = "1.0.0" + }, + Paths = new OpenApiPaths(), + Tags = new List + { + new OpenApiTag + { + Name = "tag1", + Extensions = new Dictionary + { + ["x-tag1"] = new OpenApiAny("tag1") + } + }, + new OpenApiTag + { + Name = "tag2", + Extensions = new Dictionary + { + ["x-tag2"] = new OpenApiAny("tag2") + } + } + } + }; + + var actual = doc.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + actual.MakeLineBreaksEnvironmentNeutral().Should().BeEquivalentTo(expected.MakeLineBreaksEnvironmentNeutral()); + } } } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs index a65bf24c5..5f6b5f4e7 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs @@ -89,11 +89,6 @@ public class OpenApiOperationTests { Tags = new List { - new() - { - Name = "tagName1", - Description = "tagDescription1", - }, new OpenApiTagReference("tagId1", null) }, Summary = "summary1", @@ -360,7 +355,6 @@ public void SerializeAdvancedOperationWithTagAndSecurityAsV3JsonWorks() """ { "tags": [ - "tagName1", "tagId1" ], "summary": "summary1", @@ -669,7 +663,6 @@ public void SerializeAdvancedOperationWithTagAndSecurityAsV2JsonWorks() """ { "tags": [ - "tagName1", "tagId1" ], "summary": "summary1", diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt index d3d287dca..2afa516e0 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt @@ -1 +1,9 @@ -"pet" \ No newline at end of file +{ + "name": "pet", + "description": "Pets operations", + "externalDocs": { + "description": "Find more info here", + "url": "https://example.com" + }, + "x-tag-extension": null +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt index d3d287dca..f0a901938 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -"pet" \ No newline at end of file +{"name":"pet","description":"Pets operations","externalDocs":{"description":"Find more info here","url":"https://example.com"},"x-tag-extension":null} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt index d3d287dca..2afa516e0 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt @@ -1 +1,9 @@ -"pet" \ No newline at end of file +{ + "name": "pet", + "description": "Pets operations", + "externalDocs": { + "description": "Find more info here", + "url": "https://example.com" + }, + "x-tag-extension": null +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt index d3d287dca..f0a901938 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.SerializeAdvancedTagAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -"pet" \ No newline at end of file +{"name":"pet","description":"Pets operations","externalDocs":{"description":"Find more info here","url":"https://example.com"},"x-tag-extension":null} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.cs index c02f7598c..24c186b0b 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.cs @@ -8,6 +8,7 @@ using FluentAssertions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; using VerifyXunit; using Xunit; @@ -17,9 +18,9 @@ namespace Microsoft.OpenApi.Tests.Models [Collection("DefaultSettings")] public class OpenApiTagTests { - public static OpenApiTag BasicTag = new(); + public static readonly OpenApiTag BasicTag = new(); - public static OpenApiTag AdvancedTag = new() + public static readonly OpenApiTag AdvancedTag = new() { Name = "pet", Description = "Pets operations", @@ -30,21 +31,7 @@ public class OpenApiTagTests } }; - public static OpenApiTag ReferencedTag = new() - { - Name = "pet", - Description = "Pets operations", - ExternalDocs = OpenApiExternalDocsTests.AdvanceExDocs, - Extensions = new Dictionary - { - {"x-tag-extension", null} - }, - Reference = new() - { - Type = ReferenceType.Tag, - Id = "pet" - } - }; + public static OpenApiTag ReferencedTag = new OpenApiTagReference("pet", null); [Theory] [InlineData(true)] @@ -56,7 +43,7 @@ public async Task SerializeBasicTagAsV3JsonWithoutReferenceWorksAsync(bool produ var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput }); // Act - BasicTag.SerializeAsV3WithoutReference(writer); + BasicTag.SerializeAsV3(writer); writer.Flush(); // Assert @@ -73,7 +60,7 @@ public async Task SerializeBasicTagAsV2JsonWithoutReferenceWorksAsync(bool produ var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput }); // Act - BasicTag.SerializeAsV2WithoutReference(writer); + BasicTag.SerializeAsV2(writer); writer.Flush(); // Assert @@ -89,7 +76,7 @@ public void SerializeBasicTagAsV3YamlWithoutReferenceWorks() var expected = "{ }"; // Act - BasicTag.SerializeAsV3WithoutReference(writer); + BasicTag.SerializeAsV3(writer); var actual = outputStringWriter.GetStringBuilder().ToString(); // Assert @@ -107,7 +94,7 @@ public void SerializeBasicTagAsV2YamlWithoutReferenceWorks() var expected = "{ }"; // Act - BasicTag.SerializeAsV2WithoutReference(writer); + BasicTag.SerializeAsV2(writer); writer.Flush(); var actual = outputStringWriter.GetStringBuilder().ToString(); @@ -117,40 +104,6 @@ public void SerializeBasicTagAsV2YamlWithoutReferenceWorks() actual.Should().Be(expected); } - [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeAdvancedTagAsV3JsonWithoutReferenceWorksAsync(bool produceTerseOutput) - { - // Arrange - var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput }); - - // Act - AdvancedTag.SerializeAsV3WithoutReference(writer); - writer.Flush(); - - // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); - } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task SerializeAdvancedTagAsV2JsonWithoutReferenceWorksAsync(bool produceTerseOutput) - { - // Arrange - var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput }); - - // Act - AdvancedTag.SerializeAsV2WithoutReference(writer); - writer.Flush(); - - // Assert - await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); - } - [Fact] public void SerializeAdvancedTagAsV3YamlWithoutReferenceWorks() { @@ -168,7 +121,7 @@ public void SerializeAdvancedTagAsV3YamlWithoutReferenceWorks() """; // Act - AdvancedTag.SerializeAsV3WithoutReference(writer); + AdvancedTag.SerializeAsV3(writer); writer.Flush(); var actual = outputStringWriter.GetStringBuilder().ToString(); @@ -195,7 +148,7 @@ public void SerializeAdvancedTagAsV2YamlWithoutReferenceWorks() """; // Act - AdvancedTag.SerializeAsV2WithoutReference(writer); + AdvancedTag.SerializeAsV2(writer); writer.Flush(); var actual = outputStringWriter.GetStringBuilder().ToString(); @@ -246,7 +199,12 @@ public void SerializeAdvancedTagAsV3YamlWorks() var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); var writer = new OpenApiYamlWriter(outputStringWriter); - var expected = @" pet"; + var expected = @"name: pet +description: Pets operations +externalDocs: + description: Find more info here + url: https://example.com +x-tag-extension:"; // Act AdvancedTag.SerializeAsV3(writer); @@ -266,7 +224,12 @@ public void SerializeAdvancedTagAsV2YamlWorks() var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); var writer = new OpenApiYamlWriter(outputStringWriter); - var expected = @" pet"; + var expected = @"name: pet +description: Pets operations +externalDocs: + description: Find more info here + url: https://example.com +x-tag-extension:"; // Act AdvancedTag.SerializeAsV2(writer); diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 8f9f8ed41..cf69f3735 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -997,11 +997,8 @@ namespace Microsoft.OpenApi.Models public virtual Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } public virtual string Name { get; set; } public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiXml : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable {