Skip to content

Commit aaee6f9

Browse files
committed
fix(serialization): additional recursive paths
1 parent 9fa157e commit aaee6f9

5 files changed

Lines changed: 142 additions & 11 deletions

File tree

‎src/Microsoft.OpenApi/Models/OpenApiHeader.cs‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public virtual void SerializeAsV3(IOpenApiWriter writer)
9898
SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer));
9999
}
100100

101-
internal void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version,
101+
internal void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version,
102102
Action<IOpenApiWriter, IOpenApiSerializable> callback)
103103
{
104104
Utils.CheckArgumentNull(writer);
@@ -175,7 +175,12 @@ public virtual void SerializeAsV2(IOpenApiWriter writer)
175175
writer.WriteProperty(OpenApiConstants.AllowReserved, AllowReserved, false);
176176

177177
// schema
178-
var targetSchema = Schema switch {
178+
if (Schema is OpenApiSchemaReference)
179+
{
180+
writer.CountInlineReference();
181+
}
182+
var targetSchema = Schema switch
183+
{
179184
OpenApiSchemaReference schemaReference => schemaReference.RecursiveTarget,
180185
OpenApiSchema schema => schema,
181186
_ => null,

‎src/Microsoft.OpenApi/Models/OpenApiParameter.cs‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,11 @@ public virtual void SerializeAsV3(IOpenApiWriter writer)
113113
SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer));
114114
}
115115

116-
internal void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version,
116+
internal void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version,
117117
Action<IOpenApiWriter, IOpenApiSerializable> callback)
118118
{
119119
Utils.CheckArgumentNull(writer);
120-
120+
121121
// Validate that Cookie style is only used in OpenAPI 3.2 and later
122122
if (Style == ParameterStyle.Cookie && version < OpenApiSpecVersion.OpenApi3_2)
123123
{
@@ -228,7 +228,12 @@ internal virtual void WriteRequestBodySchemaForV2(IOpenApiWriter writer, Diction
228228
// uniqueItems
229229
// enum
230230
// multipleOf
231-
var targetSchema = Schema switch {
231+
if (Schema is OpenApiSchemaReference)
232+
{
233+
writer.CountInlineReference();
234+
}
235+
var targetSchema = Schema switch
236+
{
232237
OpenApiSchemaReference schemaReference => schemaReference.RecursiveTarget,
233238
OpenApiSchema schema => schema,
234239
_ => null,
@@ -273,7 +278,7 @@ internal virtual void WriteRequestBodySchemaForV2(IOpenApiWriter writer, Diction
273278
public virtual void SerializeAsV2(IOpenApiWriter writer)
274279
{
275280
Utils.CheckArgumentNull(writer);
276-
281+
277282
// Validate that Cookie style is only used in OpenAPI 3.2 and later
278283
if (Style == ParameterStyle.Cookie)
279284
{

‎src/Microsoft.OpenApi/Models/References/OpenApiMediaTypeReference.cs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,13 @@ protected override BaseOpenApiReference CopyReference(BaseOpenApiReference sourc
7777
/// <inheritdoc/>
7878
public override void SerializeAsV31(IOpenApiWriter writer)
7979
{
80+
writer.CountInlineReference();
8081
CopyReferenceAsTargetElementWithOverrides(new OpenApiMediaType()).SerializeAsV31(writer);
8182
}
8283
/// <inheritdoc/>
8384
public override void SerializeAsV3(IOpenApiWriter writer)
8485
{
86+
writer.CountInlineReference();
8587
CopyReferenceAsTargetElementWithOverrides(new OpenApiMediaType()).SerializeAsV3(writer);
8688
}
8789
}

‎src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public override void SerializeAsV2(IOpenApiWriter writer)
6464
{
6565
if (writer.GetSettings().ShouldInlineReference(Reference))
6666
{
67+
writer.CountInlineReference();
6768
return GetFromTarget(target => target.ConvertToBodyParameter(writer));
6869
}
6970

@@ -74,6 +75,7 @@ public override void SerializeAsV2(IOpenApiWriter writer)
7475
{
7576
if (writer.GetSettings().ShouldInlineReference(Reference))
7677
{
78+
writer.CountInlineReference();
7779
return GetFromTarget(target => target.ConvertToFormDataParameters(writer));
7880
}
7981

‎test/Microsoft.OpenApi.Tests/Writers/OpenApiWriterInlineReferenceTests.cs‎

Lines changed: 122 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT license.
33

44
using System;
5+
using System.Collections.Generic;
56
using System.Globalization;
67
using System.IO;
78
using System.Text;
@@ -87,6 +88,122 @@ public void ReusingSettingsWithNewWriterStartsANewInlineReferenceCount()
8788
Assert.DoesNotContain("$ref", secondOutput.ToString());
8889
}
8990

91+
[Theory]
92+
[InlineData(OpenApiSpecVersion.OpenApi3_0)]
93+
[InlineData(OpenApiSpecVersion.OpenApi3_1)]
94+
public void SerializeMediaTypeReferenceUsesInlineReferenceCount(OpenApiSpecVersion specVersion)
95+
{
96+
var document = new OpenApiDocument
97+
{
98+
Components = new OpenApiComponents
99+
{
100+
MediaTypes = new Dictionary<string, IOpenApiMediaType>
101+
{
102+
["shared"] = new OpenApiMediaType
103+
{
104+
Schema = new OpenApiSchema { Type = JsonSchemaType.String }
105+
}
106+
}
107+
}
108+
};
109+
document.Workspace.RegisterComponents(document);
110+
var reference = new OpenApiMediaTypeReference("shared", document);
111+
using var output = new StringWriter(CultureInfo.InvariantCulture);
112+
var writer = new OpenApiJsonWriter(output, CreateWriterSettings(0));
113+
114+
Assert.Throws<OpenApiWriterException>(() => Serialize(reference, writer, specVersion));
115+
}
116+
117+
[Fact]
118+
public void ConvertRequestBodyReferenceToV2ParameterUsesInlineReferenceCount()
119+
{
120+
var document = CreateDocumentWithRequestBodyComponent();
121+
var reference = new OpenApiRequestBodyReference("shared", document);
122+
using var output = new StringWriter(CultureInfo.InvariantCulture);
123+
var writer = new OpenApiJsonWriter(output, CreateWriterSettings(0));
124+
125+
Assert.Throws<OpenApiWriterException>(() => reference.ConvertToBodyParameter(writer));
126+
Assert.Throws<OpenApiWriterException>(() => reference.ConvertToFormDataParameters(writer));
127+
}
128+
129+
[Fact]
130+
public void SerializeV2HeaderSchemaReferenceUsesInlineReferenceCount()
131+
{
132+
var document = CreateDocumentWithSchemaComponent();
133+
var header = new OpenApiHeader
134+
{
135+
Schema = new OpenApiSchemaReference("shared", document)
136+
};
137+
using var output = new StringWriter(CultureInfo.InvariantCulture);
138+
var writer = new OpenApiJsonWriter(output, CreateWriterSettings(0));
139+
140+
Assert.Throws<OpenApiWriterException>(() => header.SerializeAsV2(writer));
141+
}
142+
143+
[Fact]
144+
public void SerializeV2ParameterSchemaReferenceUsesInlineReferenceCount()
145+
{
146+
var document = CreateDocumentWithSchemaComponent();
147+
var parameter = new OpenApiParameter
148+
{
149+
Name = "value",
150+
In = ParameterLocation.Query,
151+
Schema = new OpenApiSchemaReference("shared", document)
152+
};
153+
using var output = new StringWriter(CultureInfo.InvariantCulture);
154+
var writer = new OpenApiJsonWriter(output, CreateWriterSettings(0));
155+
156+
Assert.Throws<OpenApiWriterException>(() => parameter.SerializeAsV2(writer));
157+
}
158+
159+
private static OpenApiDocument CreateDocumentWithRequestBodyComponent()
160+
{
161+
var document = new OpenApiDocument
162+
{
163+
Components = new OpenApiComponents
164+
{
165+
RequestBodies = new Dictionary<string, IOpenApiRequestBody>
166+
{
167+
["shared"] = new OpenApiRequestBody
168+
{
169+
Content = new Dictionary<string, IOpenApiMediaType>
170+
{
171+
["application/x-www-form-urlencoded"] = new OpenApiMediaType
172+
{
173+
Schema = new OpenApiSchema
174+
{
175+
Type = JsonSchemaType.Object,
176+
Properties = new Dictionary<string, IOpenApiSchema>
177+
{
178+
["value"] = new OpenApiSchema { Type = JsonSchemaType.String }
179+
}
180+
}
181+
}
182+
}
183+
}
184+
}
185+
}
186+
};
187+
document.Workspace.RegisterComponents(document);
188+
return document;
189+
}
190+
191+
private static OpenApiDocument CreateDocumentWithSchemaComponent()
192+
{
193+
var document = new OpenApiDocument
194+
{
195+
Components = new OpenApiComponents
196+
{
197+
Schemas = new Dictionary<string, IOpenApiSchema>
198+
{
199+
["shared"] = new OpenApiSchema { Type = JsonSchemaType.String }
200+
}
201+
}
202+
};
203+
document.Workspace.RegisterComponents(document);
204+
return document;
205+
}
206+
90207
private static string CreateDocumentWithRepeatedReferences(int levels)
91208
{
92209
var schemas = new StringBuilder();
@@ -147,23 +264,23 @@ private static string CreateDocumentWithRepeatedReferences(int levels)
147264
}
148265

149266
private static void Serialize(
150-
OpenApiDocument document,
267+
IOpenApiSerializable serializable,
151268
IOpenApiWriter writer,
152269
OpenApiSpecVersion specVersion)
153270
{
154271
switch (specVersion)
155272
{
156273
case OpenApiSpecVersion.OpenApi2_0:
157-
document.SerializeAsV2(writer);
274+
serializable.SerializeAsV2(writer);
158275
break;
159276
case OpenApiSpecVersion.OpenApi3_0:
160-
document.SerializeAsV3(writer);
277+
serializable.SerializeAsV3(writer);
161278
break;
162279
case OpenApiSpecVersion.OpenApi3_1:
163-
document.SerializeAsV31(writer);
280+
serializable.SerializeAsV31(writer);
164281
break;
165282
case OpenApiSpecVersion.OpenApi3_2:
166-
document.SerializeAsV32(writer);
283+
serializable.SerializeAsV32(writer);
167284
break;
168285
default:
169286
throw new ArgumentOutOfRangeException(nameof(specVersion), specVersion, null);

0 commit comments

Comments
 (0)