From 0755685a682db92193992910466e82c41c9eb207 Mon Sep 17 00:00:00 2001 From: "Brodski, David" Date: Thu, 18 Sep 2025 16:34:52 -0400 Subject: [PATCH 1/2] Fix OpenApiEncoding explode property serialization --- .../Models/OpenApiEncoding.cs | 17 +++++-- .../Models/OpenApiEncodingTests.cs | 50 +++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiEncoding.cs b/src/Microsoft.OpenApi/Models/OpenApiEncoding.cs index b478b8074..d12a24b5f 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiEncoding.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiEncoding.cs @@ -11,6 +11,10 @@ namespace Microsoft.OpenApi /// public class OpenApiEncoding : IOpenApiSerializable, IOpenApiExtensible { + /// + /// Explode backing variable + /// + private bool? _explode; /// /// The Content-Type for encoding a specific property. /// The value can be a specific media type (e.g. application/json), @@ -35,7 +39,11 @@ public class OpenApiEncoding : IOpenApiSerializable, IOpenApiExtensible /// For all other styles, the default value is false. /// This property SHALL be ignored if the request body media type is not application/x-www-form-urlencoded. /// - public bool? Explode { get; set; } + public bool? Explode + { + get => _explode ?? Style == ParameterStyle.Form; + set => _explode = value; + } /// /// Determines whether the parameter value SHOULD allow reserved characters, @@ -63,7 +71,7 @@ public OpenApiEncoding(OpenApiEncoding encoding) ContentType = encoding?.ContentType ?? ContentType; Headers = encoding?.Headers != null ? new Dictionary(encoding.Headers) : null; Style = encoding?.Style ?? Style; - Explode = encoding?.Explode ?? Explode; + Explode = encoding?._explode; AllowReserved = encoding?.AllowReserved ?? AllowReserved; Extensions = encoding?.Extensions != null ? new Dictionary(encoding.Extensions) : null; } @@ -106,7 +114,10 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version writer.WriteProperty(OpenApiConstants.Style, Style?.GetDisplayName()); // explode - writer.WriteProperty(OpenApiConstants.Explode, Explode, false); + if (_explode.HasValue) + { + writer.WriteProperty(OpenApiConstants.Explode, Explode); + } // allowReserved writer.WriteProperty(OpenApiConstants.AllowReserved, AllowReserved, false); diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiEncodingTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiEncodingTests.cs index 0d57b6ee7..f3f13d057 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiEncodingTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiEncodingTests.cs @@ -76,5 +76,55 @@ public async Task SerializeAdvanceEncodingAsV3YamlWorks() expected = expected.MakeLineBreaksEnvironmentNeutral(); Assert.Equal(expected, actual); } + + [Theory] + [InlineData(ParameterStyle.Form, true)] + [InlineData(ParameterStyle.SpaceDelimited, false)] + [InlineData(null, false)] + public void WhenStyleIsFormTheDefaultValueOfExplodeShouldBeTrueOtherwiseFalse(ParameterStyle? style, bool expectedExplode) + { + // Arrange + var parameter = new OpenApiEncoding + { + Style = style + }; + + // Act & Assert + parameter.Explode.Should().Be(expectedExplode); + } + + [Theory] + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(null, false)] + public void WhenExplodeIsSetOutputShouldHaveExplode(bool? expectedExplode, bool hasExplode) + { + // Arrange + OpenApiEncoding parameter = new() + { + ContentType = "multipart/form-data", + Style = ParameterStyle.Form, + Explode = expectedExplode, + }; + + var expected = + $""" + contentType: multipart/form-data + style: form + """; + + if (hasExplode) + { + expected = expected + $"\nexplode: {expectedExplode.ToString().ToLower()}"; + } + + // Act + var actual = parameter.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0); + + // Assert + actual = actual.MakeLineBreaksEnvironmentNeutral(); + expected = expected.MakeLineBreaksEnvironmentNeutral(); + actual.Should().Be(expected); + } } } From d2fe743158883e3ecfe546a3abb95253fb33156b Mon Sep 17 00:00:00 2001 From: "Brodski, David" Date: Fri, 19 Sep 2025 16:40:35 -0400 Subject: [PATCH 2/2] Fix test to work with Assert and new API --- .../Models/OpenApiEncodingTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiEncodingTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiEncodingTests.cs index f3f13d057..81d6426ad 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiEncodingTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiEncodingTests.cs @@ -90,14 +90,14 @@ public void WhenStyleIsFormTheDefaultValueOfExplodeShouldBeTrueOtherwiseFalse(Pa }; // Act & Assert - parameter.Explode.Should().Be(expectedExplode); + Assert.Equal(parameter.Explode, expectedExplode); } [Theory] [InlineData(true, true)] [InlineData(false, true)] [InlineData(null, false)] - public void WhenExplodeIsSetOutputShouldHaveExplode(bool? expectedExplode, bool hasExplode) + public async Task WhenExplodeIsSetOutputShouldHaveExplode(bool? expectedExplode, bool hasExplode) { // Arrange OpenApiEncoding parameter = new() @@ -119,12 +119,12 @@ public void WhenExplodeIsSetOutputShouldHaveExplode(bool? expectedExplode, bool } // Act - var actual = parameter.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0); + var actual = await parameter.SerializeAsYamlAsync(OpenApiSpecVersion.OpenApi3_0); // Assert actual = actual.MakeLineBreaksEnvironmentNeutral(); expected = expected.MakeLineBreaksEnvironmentNeutral(); - actual.Should().Be(expected); + Assert.Equal(actual, expected); } } }