Skip to content

Commit

Permalink
Merge pull request #1939 from microsoft/mk/fix-tags-serialization
Browse files Browse the repository at this point in the history
Fix tags serialization bug
  • Loading branch information
MaggieKimani1 authored Dec 17, 2024
2 parents 7db6469 + d7064c4 commit 7556ba5
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 117 deletions.
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
50 changes: 8 additions & 42 deletions src/Microsoft.OpenApi/Models/OpenApiTag.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Check warning

Code scanning / CodeQL

Virtual call in constructor or destructor Warning

Avoid virtual calls in a constructor or destructor.
Extensions = tag?.Extensions != null ? new Dictionary<string, IOpenApiExtension>(tag.Extensions) : null;
UnresolvedReference = tag?.UnresolvedReference ?? UnresolvedReference;
Reference = tag?.Reference != null ? new(tag?.Reference) : null;
Reference = tag?.Reference != null ? new(tag.Reference) : null;
}

/// <summary>
/// Serialize <see cref="OpenApiTag"/> to Open Api v3.1
/// </summary>
public virtual void SerializeAsV31(IOpenApiWriter writer)
public virtual void SerializeAsV31(IOpenApiWriter writer)
{
SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer));
}

/// <summary>
/// Serialize <see cref="OpenApiTag"/> to Open Api v3.0
/// </summary>
public virtual void SerializeAsV3(IOpenApiWriter writer)
{
SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer));
}

/// <summary>
/// Serialize <see cref="OpenApiTag"/> to Open Api v3.0
/// </summary>
private void SerializeInternal(IOpenApiWriter writer, Action<IOpenApiWriter, IOpenApiSerializable> callback)
{
Utils.CheckArgumentNull(writer);
writer.WriteValue(Name);
}

/// <summary>
/// Serialize to OpenAPI V3 document without using reference.
/// </summary>
public virtual void SerializeAsV31WithoutReference(IOpenApiWriter writer)
{
SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_1,
SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1,
(writer, element) => element.SerializeAsV31(writer));
}

/// <summary>
/// Serialize to OpenAPI V3 document without using reference.
/// Serialize <see cref="OpenApiTag"/> to Open Api v3.0
/// </summary>
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<IOpenApiWriter, IOpenApiSerializable> callback)
{
writer.WriteStartObject();
Expand All @@ -128,15 +103,6 @@ internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, O
/// Serialize <see cref="OpenApiTag"/> to Open Api v2.0
/// </summary>
public virtual void SerializeAsV2(IOpenApiWriter writer)
{
Utils.CheckArgumentNull(writer);
writer.WriteValue(Name);
}

/// <summary>
/// Serialize to OpenAPI V2 document without using reference.
/// </summary>
public void SerializeAsV2WithoutReference(IOpenApiWriter writer)
{
writer.WriteStartObject();

Expand Down
56 changes: 55 additions & 1 deletion test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -992,7 +992,7 @@ public OpenApiDocumentTests()
{
["my-extension"] = new OpenApiAny(4)
}
},
},
Extensions = new Dictionary<string, IOpenApiExtension>
{
["my-extension"] = new OpenApiAny(4),
Expand Down Expand Up @@ -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<OpenApiTag>
{
new OpenApiTag
{
Name = "tag1",
Extensions = new Dictionary<string, IOpenApiExtension>
{
["x-tag1"] = new OpenApiAny("tag1")
}
},
new OpenApiTag
{
Name = "tag2",
Extensions = new Dictionary<string, IOpenApiExtension>
{
["x-tag2"] = new OpenApiAny("tag2")
}
}
}
};

var actual = doc.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);
actual.MakeLineBreaksEnvironmentNeutral().Should().BeEquivalentTo(expected.MakeLineBreaksEnvironmentNeutral());
}
}
}
7 changes: 0 additions & 7 deletions test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,6 @@ public class OpenApiOperationTests
{
Tags = new List<OpenApiTag>
{
new()
{
Name = "tagName1",
Description = "tagDescription1",
},
new OpenApiTagReference("tagId1", null)
},
Summary = "summary1",
Expand Down Expand Up @@ -360,7 +355,6 @@ public void SerializeAdvancedOperationWithTagAndSecurityAsV3JsonWorks()
"""
{
"tags": [
"tagName1",
"tagId1"
],
"summary": "summary1",
Expand Down Expand Up @@ -669,7 +663,6 @@ public void SerializeAdvancedOperationWithTagAndSecurityAsV2JsonWorks()
"""
{
"tags": [
"tagName1",
"tagId1"
],
"summary": "summary1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
"pet"
{
"name": "pet",
"description": "Pets operations",
"externalDocs": {
"description": "Find more info here",
"url": "https://example.com"
},
"x-tag-extension": null
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"pet"
{"name":"pet","description":"Pets operations","externalDocs":{"description":"Find more info here","url":"https://example.com"},"x-tag-extension":null}
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
"pet"
{
"name": "pet",
"description": "Pets operations",
"externalDocs": {
"description": "Find more info here",
"url": "https://example.com"
},
"x-tag-extension": null
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"pet"
{"name":"pet","description":"Pets operations","externalDocs":{"description":"Find more info here","url":"https://example.com"},"x-tag-extension":null}
81 changes: 22 additions & 59 deletions test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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",
Expand All @@ -30,21 +31,7 @@ public class OpenApiTagTests
}
};

public static OpenApiTag ReferencedTag = new()
{
Name = "pet",
Description = "Pets operations",
ExternalDocs = OpenApiExternalDocsTests.AdvanceExDocs,
Extensions = new Dictionary<string, IOpenApiExtension>
{
{"x-tag-extension", null}
},
Reference = new()
{
Type = ReferenceType.Tag,
Id = "pet"
}
};
public static OpenApiTag ReferencedTag = new OpenApiTagReference("pet", null);

[Theory]
[InlineData(true)]
Expand All @@ -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
Expand All @@ -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
Expand All @@ -89,7 +76,7 @@ public void SerializeBasicTagAsV3YamlWithoutReferenceWorks()
var expected = "{ }";

// Act
BasicTag.SerializeAsV3WithoutReference(writer);
BasicTag.SerializeAsV3(writer);
var actual = outputStringWriter.GetStringBuilder().ToString();

// Assert
Expand All @@ -107,7 +94,7 @@ public void SerializeBasicTagAsV2YamlWithoutReferenceWorks()
var expected = "{ }";

// Act
BasicTag.SerializeAsV2WithoutReference(writer);
BasicTag.SerializeAsV2(writer);
writer.Flush();
var actual = outputStringWriter.GetStringBuilder().ToString();

Expand All @@ -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()
{
Expand All @@ -168,7 +121,7 @@ public void SerializeAdvancedTagAsV3YamlWithoutReferenceWorks()
""";

// Act
AdvancedTag.SerializeAsV3WithoutReference(writer);
AdvancedTag.SerializeAsV3(writer);
writer.Flush();
var actual = outputStringWriter.GetStringBuilder().ToString();

Expand All @@ -195,7 +148,7 @@ public void SerializeAdvancedTagAsV2YamlWithoutReferenceWorks()
""";

// Act
AdvancedTag.SerializeAsV2WithoutReference(writer);
AdvancedTag.SerializeAsV2(writer);
writer.Flush();
var actual = outputStringWriter.GetStringBuilder().ToString();

Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
Loading

0 comments on commit 7556ba5

Please sign in to comment.