Skip to content

Commit fea1230

Browse files
committed
Progress
1 parent f01b19c commit fea1230

5 files changed

Lines changed: 76 additions & 45 deletions

File tree

src/Microsoft.OpenApi/Models/OpenApiSchema.cs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,8 @@ private void WriteV3CompatibilityKeywords(IOpenApiWriter writer, Action<IOpenApi
762762
internal void WriteAsItemsProperties(IOpenApiWriter writer)
763763
{
764764
// type
765-
writer.WriteProperty(OpenApiConstants.Type, (Type & ~JsonSchemaType.Null)?.ToFirstIdentifier());
765+
var typeToUse = Type ?? GetKnownTypeAndFormatPreOpenApi31()?.Type;
766+
writer.WriteProperty(OpenApiConstants.Type, (typeToUse & ~JsonSchemaType.Null)?.ToFirstIdentifier());
766767

767768
// format
768769
WriteFormatProperty(writer);
@@ -819,7 +820,8 @@ private void WriteFormatProperty(IOpenApiWriter writer)
819820
var formatToWrite = Format;
820821
if (string.IsNullOrEmpty(formatToWrite))
821822
{
822-
formatToWrite = AllOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format ??
823+
formatToWrite = GetKnownTypeAndFormatPreOpenApi31()?.Format ??
824+
AllOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format ??
823825
AnyOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format ??
824826
OneOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format;
825827
}
@@ -850,14 +852,7 @@ private void SerializeAsV2(
850852
writer.WriteProperty(OpenApiConstants.Description, Description);
851853

852854
// format
853-
if (Format is null && GetKnownTypeAndFormatPreOpenApi31() is { } typeAndFormat)
854-
{
855-
writer.WriteProperty(OpenApiConstants.Format, typeAndFormat.Format);
856-
}
857-
else
858-
{
859-
WriteFormatProperty(writer);
860-
}
855+
WriteFormatProperty(writer);
861856

862857
// title
863858
writer.WriteProperty(OpenApiConstants.Title, Title);
@@ -1183,9 +1178,9 @@ private void SerializeNullable(IOpenApiWriter writer, OpenApiSpecVersion version
11831178
private (JsonSchemaType Type, string Format)? GetKnownTypeAndFormatPreOpenApi31()
11841179
{
11851180
// https://spec.openapis.org/oas/v3.2.0.html#migrating-binary-descriptions-from-oas-3-0
1186-
if (Type == JsonSchemaType.String && ContentEncoding == "base64")
1181+
if (Type is JsonSchemaType.String or (JsonSchemaType.String | JsonSchemaType.Null) && ContentEncoding == "base64")
11871182
{
1188-
return (JsonSchemaType.String, "byte");
1183+
return (Type.Value, "byte");
11891184
}
11901185

11911186
if (Type is null && ContentEncoding is null && !string.IsNullOrEmpty(ContentMediaType))

src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ public static IOpenApiSchema LoadSchema(JsonNode node, OpenApiDocument hostDocum
326326
// transform it in the object model to the latest thing.
327327
if (schema.Type.HasValue && schema.Type.Value.HasFlag(JsonSchemaType.String) &&
328328
schema.Format == "byte" &&
329-
schema.ContentEncoding is null)
329+
schema.ContentEncoding is null or "base64")
330330
{
331331
schema.ContentEncoding = "base64";
332332
schema.Format = null;

test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ public void ParseSchemaWithByteFormatNormalizesToContentEncoding()
219219
[Fact]
220220
public void ParseSchemaWithBinaryFormatNormalizesToContentMediaType()
221221
{
222-
var schema = LoadV2Schema($$"""{ "type": "string", "format": "byte" }""");
222+
var schema = LoadV2Schema("""{ "type": "string", "format": "binary" }""");
223223

224224
Assert.Null(schema.Type);
225225
Assert.Equal("application/octet-stream", schema.ContentMediaType);

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

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Collections.Generic;
66
using System.Globalization;
77
using System.IO;
8+
using System.Text.Json.Nodes;
89
using System.Threading.Tasks;
910
using VerifyXunit;
1011
using Xunit;
@@ -289,6 +290,72 @@ public async Task SerializeAdvancedParameterAsV2JsonWorks()
289290
Assert.Equal(expected, actual);
290291
}
291292

293+
// A v2 non-body parameter serializes its schema inline rather than as a nested "schema"
294+
// object, so the pre-3.1 binary description has to be reconstructed there as well.
295+
// https://spec.openapis.org/oas/v3.2.0.html#migrating-binary-descriptions-from-oas-3-0
296+
[Fact]
297+
public async Task SerializeParameterWithContentEncodingAsV2JsonReconstructsByteFormat()
298+
{
299+
// Arrange
300+
var parameter = new OpenApiParameter
301+
{
302+
Name = "token",
303+
In = ParameterLocation.Query,
304+
Schema = new OpenApiSchema
305+
{
306+
Type = JsonSchemaType.String,
307+
ContentEncoding = "base64"
308+
}
309+
};
310+
311+
var expected =
312+
"""
313+
{
314+
"in": "query",
315+
"name": "token",
316+
"type": "string",
317+
"format": "byte"
318+
}
319+
""";
320+
321+
// Act
322+
var actual = await parameter.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0);
323+
324+
// Assert
325+
Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual)));
326+
}
327+
328+
[Fact]
329+
public async Task SerializeParameterWithContentMediaTypeAsV2JsonReconstructsBinaryFormat()
330+
{
331+
// Arrange
332+
var parameter = new OpenApiParameter
333+
{
334+
Name = "upload",
335+
In = ParameterLocation.Query,
336+
Schema = new OpenApiSchema
337+
{
338+
ContentMediaType = "image/png"
339+
}
340+
};
341+
342+
var expected =
343+
"""
344+
{
345+
"in": "query",
346+
"name": "upload",
347+
"type": "string",
348+
"format": "binary"
349+
}
350+
""";
351+
352+
// Act
353+
var actual = await parameter.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0);
354+
355+
// Assert
356+
Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual)));
357+
}
358+
292359
[Theory]
293360
[InlineData(true)]
294361
[InlineData(false)]

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

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -764,37 +764,6 @@ public async Task WriteAsItemsPropertiesDoesNotWriteNull()
764764
Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual)));
765765
}
766766

767-
// Non-body parameters and headers in v2 serialize the schema inline, so the pre-3.1
768-
// binary description has to be reconstructed there too.
769-
// https://spec.openapis.org/oas/v3.2.0.html#migrating-binary-descriptions-from-oas-3-0
770-
[Theory]
771-
[InlineData("base64", null, """{ "type": "string", "format": "byte" }""")]
772-
[InlineData(null, "image/png", """{ "type": "string", "format": "binary" }""")]
773-
public async Task WriteAsItemsPropertiesReconstructsBinaryDescription(
774-
string contentEncoding, string contentMediaType, string expected)
775-
{
776-
// Arrange
777-
var schema = new OpenApiSchema
778-
{
779-
Type = contentEncoding is null ? null : JsonSchemaType.String,
780-
ContentEncoding = contentEncoding,
781-
ContentMediaType = contentMediaType
782-
};
783-
784-
var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture);
785-
var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = false });
786-
writer.WriteStartObject();
787-
788-
// Act
789-
schema.WriteAsItemsProperties(writer);
790-
writer.WriteEndObject();
791-
await writer.FlushAsync();
792-
793-
// Assert
794-
var actual = outputStringWriter.GetStringBuilder().ToString();
795-
Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual)));
796-
}
797-
798767
[Fact]
799768
public async Task SerializeConstAsEnumV30()
800769
{

0 commit comments

Comments
 (0)