From fe4a25f1f25c853404540d30f11812f1208f93c9 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 8 Jul 2026 08:25:00 -0400 Subject: [PATCH 1/4] fix: default mapping is not being serialized with the correct shape --- .../Models/OpenApiDiscriminator.cs | 18 ++++++--- .../Models/OpenApiDiscriminatorTests.cs | 38 +++++++++++++++++++ 2 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 test/Microsoft.OpenApi.Tests/Models/OpenApiDiscriminatorTests.cs diff --git a/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs b/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs index 69e15f9a4..094499afb 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs @@ -58,7 +58,7 @@ public void SerializeAsV32(IOpenApiWriter writer) if (DefaultMapping != null) { writer.WritePropertyName("defaultMapping"); - DefaultMapping.SerializeAsV32(writer); + WriteMappingReference(writer, DefaultMapping); } // extensions @@ -79,7 +79,7 @@ public void SerializeAsV31(IOpenApiWriter writer) if (DefaultMapping != null) { writer.WritePropertyName("x-oas-default-mapping"); - DefaultMapping.SerializeAsV31(writer); + WriteMappingReference(writer, DefaultMapping); } // extensions @@ -110,13 +110,19 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version // mapping writer.WriteOptionalMap(OpenApiConstants.Mapping, Mapping, (w, s) => { - if (!string.IsNullOrEmpty(s.Reference.ReferenceV3) && s.Reference.ReferenceV3 is not null) - { - w.WriteValue(s.Reference.ReferenceV3); - } + WriteMappingReference(w, s); }); } + private static void WriteMappingReference(IOpenApiWriter writer, OpenApiSchemaReference schemaReference) + { + var reference = schemaReference.Reference.ReferenceV3; + if (!string.IsNullOrEmpty(reference)) + { + writer.WriteValue(reference); + } + } + /// /// Serialize to Open Api v2.0 /// diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDiscriminatorTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDiscriminatorTests.cs new file mode 100644 index 000000000..1cbcf32a1 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDiscriminatorTests.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System.Text.Json.Nodes; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.OpenApi.Tests.Models +{ + [Collection("DefaultSettings")] + public class OpenApiDiscriminatorTests + { + [Theory] + [InlineData(OpenApiSpecVersion.OpenApi3_2, "defaultMapping", "Pet", true)] + [InlineData(OpenApiSpecVersion.OpenApi3_2, "defaultMapping", "#/components/schemas/Pet", true)] + [InlineData(OpenApiSpecVersion.OpenApi3_2, "defaultMapping", "Pet", false)] + [InlineData(OpenApiSpecVersion.OpenApi3_1, "x-oas-default-mapping", "Pet", true)] + [InlineData(OpenApiSpecVersion.OpenApi3_1, "x-oas-default-mapping", "#/components/schemas/Pet", true)] + [InlineData(OpenApiSpecVersion.OpenApi3_1, "x-oas-default-mapping", "Pet", false)] + public async Task SerializeDefaultMappingAsReferenceString(OpenApiSpecVersion specVersion, string propertyName, string referenceId, bool useDocument) + { + // Arrange + var document = useDocument ? new OpenApiDocument() : null; + var discriminator = new OpenApiDiscriminator + { + PropertyName = "pet_type", + DefaultMapping = new OpenApiSchemaReference(referenceId, document) + }; + + // Act + var actual = JsonNode.Parse(await discriminator.SerializeAsJsonAsync(specVersion)); + + // Assert + Assert.NotNull(actual); + Assert.Equal("#/components/schemas/Pet", actual[propertyName]?.GetValue()); + } + } +} From 6347c7ab2fb8b5002b0630029e06dcad620e0e56 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 8 Jul 2026 08:29:28 -0400 Subject: [PATCH 2/4] tests: adds tests for discriminator mappings formatting --- .../Models/OpenApiDiscriminatorTests.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDiscriminatorTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDiscriminatorTests.cs index 1cbcf32a1..495a0729e 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDiscriminatorTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDiscriminatorTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System.Collections.Generic; using System.Text.Json.Nodes; using System.Threading.Tasks; using Xunit; @@ -34,5 +35,41 @@ public async Task SerializeDefaultMappingAsReferenceString(OpenApiSpecVersion sp Assert.NotNull(actual); Assert.Equal("#/components/schemas/Pet", actual[propertyName]?.GetValue()); } + + [Theory] + [InlineData(OpenApiSpecVersion.OpenApi3_0)] + [InlineData(OpenApiSpecVersion.OpenApi3_1)] + [InlineData(OpenApiSpecVersion.OpenApi3_2)] + public async Task SerializeMappingValuesAsReferenceStrings(OpenApiSpecVersion specVersion) + { + // Arrange + var document = new OpenApiDocument(); + var discriminator = new OpenApiDiscriminator + { + PropertyName = "pet_type", + Mapping = new Dictionary + { + ["simple"] = new OpenApiSchemaReference("Pet", document), + ["explicit"] = new OpenApiSchemaReference("#/components/schemas/Pet", document), + ["noDocument"] = new OpenApiSchemaReference("Pet") + } + }; + + // Act + var actual = JsonNode.Parse(await discriminator.SerializeAsJsonAsync(specVersion)); + + // Assert + Assert.NotNull(actual); + var mapping = Assert.IsAssignableFrom(actual["mapping"]); + AssertMappingValue(mapping, "simple"); + AssertMappingValue(mapping, "explicit"); + AssertMappingValue(mapping, "noDocument"); + } + + private static void AssertMappingValue(JsonObject mapping, string key) + { + var value = Assert.IsAssignableFrom(mapping[key]); + Assert.Equal("#/components/schemas/Pet", value.GetValue()); + } } } From 7fcd1fbda29f79e8886d6e69ec1e35cc5fb710af Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 8 Jul 2026 08:33:43 -0400 Subject: [PATCH 3/4] chore: null forgiving because of lack of annotations for netstandard2.0 Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs b/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs index 094499afb..7764c633f 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs @@ -119,7 +119,7 @@ private static void WriteMappingReference(IOpenApiWriter writer, OpenApiSchemaRe var reference = schemaReference.Reference.ReferenceV3; if (!string.IsNullOrEmpty(reference)) { - writer.WriteValue(reference); + writer.WriteValue(reference!); } } From 2a6ebec9caa7dc525348e0ff1081905f5ee84d80 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 8 Jul 2026 08:37:24 -0400 Subject: [PATCH 4/4] chore: linting Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs b/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs index 7764c633f..ed7a5f4d3 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs @@ -108,10 +108,7 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version writer.WriteProperty(OpenApiConstants.PropertyName, PropertyName); // mapping - writer.WriteOptionalMap(OpenApiConstants.Mapping, Mapping, (w, s) => - { - WriteMappingReference(w, s); - }); + writer.WriteOptionalMap(OpenApiConstants.Mapping, Mapping, WriteMappingReference); } private static void WriteMappingReference(IOpenApiWriter writer, OpenApiSchemaReference schemaReference)