From c14dd2434fbb1ec83882431fc67a9f05455710df Mon Sep 17 00:00:00 2001 From: "Brodski, David" Date: Thu, 18 Sep 2025 16:34:52 -0400 Subject: [PATCH] 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 77d601a22..5e509949c 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiEncoding.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiEncoding.cs @@ -13,6 +13,10 @@ namespace Microsoft.OpenApi.Models /// 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), @@ -37,7 +41,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, @@ -65,7 +73,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; } @@ -89,7 +97,10 @@ public void SerializeAsV3(IOpenApiWriter writer) 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 fe699f7aa..30d06dae7 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiEncodingTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiEncodingTests.cs @@ -78,5 +78,55 @@ public void SerializeAdvanceEncodingAsV3YamlWorks() expected = expected.MakeLineBreaksEnvironmentNeutral(); actual.Should().Be(expected); } + + [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); + } } }