Skip to content

Commit 7556ba5

Browse files
Merge pull request #1939 from microsoft/mk/fix-tags-serialization
Fix tags serialization bug
2 parents 7db6469 + d7064c4 commit 7556ba5

10 files changed

+106
-117
lines changed

src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static JsonNode LoadJsonNodesFromYamlDocument(TextReader input)
7777
{
7878
var yamlStream = new YamlStream();
7979
yamlStream.Load(input);
80-
var yamlDocument = yamlStream.Documents.First();
80+
var yamlDocument = yamlStream.Documents[0];
8181
return yamlDocument.ToJsonNode();
8282
}
8383

src/Microsoft.OpenApi/Models/OpenApiTag.cs

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -55,56 +55,31 @@ public OpenApiTag(OpenApiTag tag)
5555
{
5656
Name = tag?.Name ?? Name;
5757
Description = tag?.Description ?? Description;
58-
ExternalDocs = tag?.ExternalDocs != null ? new(tag?.ExternalDocs) : null;
58+
ExternalDocs = tag?.ExternalDocs != null ? new(tag.ExternalDocs) : null;
5959
Extensions = tag?.Extensions != null ? new Dictionary<string, IOpenApiExtension>(tag.Extensions) : null;
6060
UnresolvedReference = tag?.UnresolvedReference ?? UnresolvedReference;
61-
Reference = tag?.Reference != null ? new(tag?.Reference) : null;
61+
Reference = tag?.Reference != null ? new(tag.Reference) : null;
6262
}
6363

6464
/// <summary>
6565
/// Serialize <see cref="OpenApiTag"/> to Open Api v3.1
6666
/// </summary>
67-
public virtual void SerializeAsV31(IOpenApiWriter writer)
67+
public virtual void SerializeAsV31(IOpenApiWriter writer)
6868
{
69-
SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer));
70-
}
71-
72-
/// <summary>
73-
/// Serialize <see cref="OpenApiTag"/> to Open Api v3.0
74-
/// </summary>
75-
public virtual void SerializeAsV3(IOpenApiWriter writer)
76-
{
77-
SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer));
78-
}
79-
80-
/// <summary>
81-
/// Serialize <see cref="OpenApiTag"/> to Open Api v3.0
82-
/// </summary>
83-
private void SerializeInternal(IOpenApiWriter writer, Action<IOpenApiWriter, IOpenApiSerializable> callback)
84-
{
85-
Utils.CheckArgumentNull(writer);
86-
writer.WriteValue(Name);
87-
}
88-
89-
/// <summary>
90-
/// Serialize to OpenAPI V3 document without using reference.
91-
/// </summary>
92-
public virtual void SerializeAsV31WithoutReference(IOpenApiWriter writer)
93-
{
94-
SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_1,
69+
SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1,
9570
(writer, element) => element.SerializeAsV31(writer));
9671
}
9772

9873
/// <summary>
99-
/// Serialize to OpenAPI V3 document without using reference.
74+
/// Serialize <see cref="OpenApiTag"/> to Open Api v3.0
10075
/// </summary>
101-
public virtual void SerializeAsV3WithoutReference(IOpenApiWriter writer)
76+
public virtual void SerializeAsV3(IOpenApiWriter writer)
10277
{
103-
SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_0,
78+
SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0,
10479
(writer, element) => element.SerializeAsV3(writer));
10580
}
10681

107-
internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpecVersion version,
82+
internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version,
10883
Action<IOpenApiWriter, IOpenApiSerializable> callback)
10984
{
11085
writer.WriteStartObject();
@@ -128,15 +103,6 @@ internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, O
128103
/// Serialize <see cref="OpenApiTag"/> to Open Api v2.0
129104
/// </summary>
130105
public virtual void SerializeAsV2(IOpenApiWriter writer)
131-
{
132-
Utils.CheckArgumentNull(writer);
133-
writer.WriteValue(Name);
134-
}
135-
136-
/// <summary>
137-
/// Serialize to OpenAPI V2 document without using reference.
138-
/// </summary>
139-
public void SerializeAsV2WithoutReference(IOpenApiWriter writer)
140106
{
141107
writer.WriteStartObject();
142108

test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -992,7 +992,7 @@ public OpenApiDocumentTests()
992992
{
993993
["my-extension"] = new OpenApiAny(4)
994994
}
995-
},
995+
},
996996
Extensions = new Dictionary<string, IOpenApiExtension>
997997
{
998998
["my-extension"] = new OpenApiAny(4),
@@ -2072,5 +2072,59 @@ public void SerializeDocWithDollarIdInDollarRefSucceeds()
20722072
var actual = doc.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_1);
20732073
actual.MakeLineBreaksEnvironmentNeutral().Should().BeEquivalentTo(expected.MakeLineBreaksEnvironmentNeutral());
20742074
}
2075+
2076+
[Fact]
2077+
public void SerializeDocumentTagsWithMultipleExtensionsWorks()
2078+
{
2079+
var expected = @"{
2080+
""openapi"": ""3.0.4"",
2081+
""info"": {
2082+
""title"": ""Test"",
2083+
""version"": ""1.0.0""
2084+
},
2085+
""paths"": { },
2086+
""tags"": [
2087+
{
2088+
""name"": ""tag1"",
2089+
""x-tag1"": ""tag1""
2090+
},
2091+
{
2092+
""name"": ""tag2"",
2093+
""x-tag2"": ""tag2""
2094+
}
2095+
]
2096+
}";
2097+
var doc = new OpenApiDocument
2098+
{
2099+
Info = new OpenApiInfo
2100+
{
2101+
Title = "Test",
2102+
Version = "1.0.0"
2103+
},
2104+
Paths = new OpenApiPaths(),
2105+
Tags = new List<OpenApiTag>
2106+
{
2107+
new OpenApiTag
2108+
{
2109+
Name = "tag1",
2110+
Extensions = new Dictionary<string, IOpenApiExtension>
2111+
{
2112+
["x-tag1"] = new OpenApiAny("tag1")
2113+
}
2114+
},
2115+
new OpenApiTag
2116+
{
2117+
Name = "tag2",
2118+
Extensions = new Dictionary<string, IOpenApiExtension>
2119+
{
2120+
["x-tag2"] = new OpenApiAny("tag2")
2121+
}
2122+
}
2123+
}
2124+
};
2125+
2126+
var actual = doc.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);
2127+
actual.MakeLineBreaksEnvironmentNeutral().Should().BeEquivalentTo(expected.MakeLineBreaksEnvironmentNeutral());
2128+
}
20752129
}
20762130
}

test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,6 @@ public class OpenApiOperationTests
8989
{
9090
Tags = new List<OpenApiTag>
9191
{
92-
new()
93-
{
94-
Name = "tagName1",
95-
Description = "tagDescription1",
96-
},
9792
new OpenApiTagReference("tagId1", null)
9893
},
9994
Summary = "summary1",
@@ -360,7 +355,6 @@ public void SerializeAdvancedOperationWithTagAndSecurityAsV3JsonWorks()
360355
"""
361356
{
362357
"tags": [
363-
"tagName1",
364358
"tagId1"
365359
],
366360
"summary": "summary1",
@@ -669,7 +663,6 @@ public void SerializeAdvancedOperationWithTagAndSecurityAsV2JsonWorks()
669663
"""
670664
{
671665
"tags": [
672-
"tagName1",
673666
"tagId1"
674667
],
675668
"summary": "summary1",
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
1-
"pet"
1+
{
2+
"name": "pet",
3+
"description": "Pets operations",
4+
"externalDocs": {
5+
"description": "Find more info here",
6+
"url": "https://example.com"
7+
},
8+
"x-tag-extension": null
9+
}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"pet"
1+
{"name":"pet","description":"Pets operations","externalDocs":{"description":"Find more info here","url":"https://example.com"},"x-tag-extension":null}
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
1-
"pet"
1+
{
2+
"name": "pet",
3+
"description": "Pets operations",
4+
"externalDocs": {
5+
"description": "Find more info here",
6+
"url": "https://example.com"
7+
},
8+
"x-tag-extension": null
9+
}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"pet"
1+
{"name":"pet","description":"Pets operations","externalDocs":{"description":"Find more info here","url":"https://example.com"},"x-tag-extension":null}

test/Microsoft.OpenApi.Tests/Models/OpenApiTagTests.cs

Lines changed: 22 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using FluentAssertions;
99
using Microsoft.OpenApi.Interfaces;
1010
using Microsoft.OpenApi.Models;
11+
using Microsoft.OpenApi.Models.References;
1112
using Microsoft.OpenApi.Writers;
1213
using VerifyXunit;
1314
using Xunit;
@@ -17,9 +18,9 @@ namespace Microsoft.OpenApi.Tests.Models
1718
[Collection("DefaultSettings")]
1819
public class OpenApiTagTests
1920
{
20-
public static OpenApiTag BasicTag = new();
21+
public static readonly OpenApiTag BasicTag = new();
2122

22-
public static OpenApiTag AdvancedTag = new()
23+
public static readonly OpenApiTag AdvancedTag = new()
2324
{
2425
Name = "pet",
2526
Description = "Pets operations",
@@ -30,21 +31,7 @@ public class OpenApiTagTests
3031
}
3132
};
3233

33-
public static OpenApiTag ReferencedTag = new()
34-
{
35-
Name = "pet",
36-
Description = "Pets operations",
37-
ExternalDocs = OpenApiExternalDocsTests.AdvanceExDocs,
38-
Extensions = new Dictionary<string, IOpenApiExtension>
39-
{
40-
{"x-tag-extension", null}
41-
},
42-
Reference = new()
43-
{
44-
Type = ReferenceType.Tag,
45-
Id = "pet"
46-
}
47-
};
34+
public static OpenApiTag ReferencedTag = new OpenApiTagReference("pet", null);
4835

4936
[Theory]
5037
[InlineData(true)]
@@ -56,7 +43,7 @@ public async Task SerializeBasicTagAsV3JsonWithoutReferenceWorksAsync(bool produ
5643
var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput });
5744

5845
// Act
59-
BasicTag.SerializeAsV3WithoutReference(writer);
46+
BasicTag.SerializeAsV3(writer);
6047
writer.Flush();
6148

6249
// Assert
@@ -73,7 +60,7 @@ public async Task SerializeBasicTagAsV2JsonWithoutReferenceWorksAsync(bool produ
7360
var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput });
7461

7562
// Act
76-
BasicTag.SerializeAsV2WithoutReference(writer);
63+
BasicTag.SerializeAsV2(writer);
7764
writer.Flush();
7865

7966
// Assert
@@ -89,7 +76,7 @@ public void SerializeBasicTagAsV3YamlWithoutReferenceWorks()
8976
var expected = "{ }";
9077

9178
// Act
92-
BasicTag.SerializeAsV3WithoutReference(writer);
79+
BasicTag.SerializeAsV3(writer);
9380
var actual = outputStringWriter.GetStringBuilder().ToString();
9481

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

10996
// Act
110-
BasicTag.SerializeAsV2WithoutReference(writer);
97+
BasicTag.SerializeAsV2(writer);
11198
writer.Flush();
11299
var actual = outputStringWriter.GetStringBuilder().ToString();
113100

@@ -117,40 +104,6 @@ public void SerializeBasicTagAsV2YamlWithoutReferenceWorks()
117104
actual.Should().Be(expected);
118105
}
119106

120-
[Theory]
121-
[InlineData(true)]
122-
[InlineData(false)]
123-
public async Task SerializeAdvancedTagAsV3JsonWithoutReferenceWorksAsync(bool produceTerseOutput)
124-
{
125-
// Arrange
126-
var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture);
127-
var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput });
128-
129-
// Act
130-
AdvancedTag.SerializeAsV3WithoutReference(writer);
131-
writer.Flush();
132-
133-
// Assert
134-
await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput);
135-
}
136-
137-
[Theory]
138-
[InlineData(true)]
139-
[InlineData(false)]
140-
public async Task SerializeAdvancedTagAsV2JsonWithoutReferenceWorksAsync(bool produceTerseOutput)
141-
{
142-
// Arrange
143-
var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture);
144-
var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput });
145-
146-
// Act
147-
AdvancedTag.SerializeAsV2WithoutReference(writer);
148-
writer.Flush();
149-
150-
// Assert
151-
await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput);
152-
}
153-
154107
[Fact]
155108
public void SerializeAdvancedTagAsV3YamlWithoutReferenceWorks()
156109
{
@@ -168,7 +121,7 @@ public void SerializeAdvancedTagAsV3YamlWithoutReferenceWorks()
168121
""";
169122

170123
// Act
171-
AdvancedTag.SerializeAsV3WithoutReference(writer);
124+
AdvancedTag.SerializeAsV3(writer);
172125
writer.Flush();
173126
var actual = outputStringWriter.GetStringBuilder().ToString();
174127

@@ -195,7 +148,7 @@ public void SerializeAdvancedTagAsV2YamlWithoutReferenceWorks()
195148
""";
196149

197150
// Act
198-
AdvancedTag.SerializeAsV2WithoutReference(writer);
151+
AdvancedTag.SerializeAsV2(writer);
199152
writer.Flush();
200153
var actual = outputStringWriter.GetStringBuilder().ToString();
201154

@@ -246,7 +199,12 @@ public void SerializeAdvancedTagAsV3YamlWorks()
246199
var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture);
247200
var writer = new OpenApiYamlWriter(outputStringWriter);
248201

249-
var expected = @" pet";
202+
var expected = @"name: pet
203+
description: Pets operations
204+
externalDocs:
205+
description: Find more info here
206+
url: https://example.com
207+
x-tag-extension:";
250208

251209
// Act
252210
AdvancedTag.SerializeAsV3(writer);
@@ -266,7 +224,12 @@ public void SerializeAdvancedTagAsV2YamlWorks()
266224
var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture);
267225
var writer = new OpenApiYamlWriter(outputStringWriter);
268226

269-
var expected = @" pet";
227+
var expected = @"name: pet
228+
description: Pets operations
229+
externalDocs:
230+
description: Find more info here
231+
url: https://example.com
232+
x-tag-extension:";
270233

271234
// Act
272235
AdvancedTag.SerializeAsV2(writer);

0 commit comments

Comments
 (0)