diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsExampleHelper.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsExampleHelper.cs new file mode 100644 index 0000000000..fc7b17b2c8 --- /dev/null +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsExampleHelper.cs @@ -0,0 +1,27 @@ +using System.Text.Json; +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; + +namespace Swashbuckle.AspNetCore.SwaggerGen +{ + public static class XmlCommentsExampleHelper + { + public static IOpenApiAny Create( + SchemaRepository schemaRepository, + OpenApiSchema schema, + string exampleString) + { + var isStringType = + (schema.ResolveType(schemaRepository) == "string") && + !exampleString.Equals("null"); + + var exampleAsJson = isStringType + ? JsonSerializer.Serialize(exampleString) + : exampleString; + + var example = OpenApiAnyFactory.CreateFromJson(exampleAsJson); + + return example; + } + } +} diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsParameterFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsParameterFilter.cs index 58e00c31c8..1e3c7dee15 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsParameterFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsParameterFilter.cs @@ -42,11 +42,7 @@ private void ApplyPropertyTags(OpenApiParameter parameter, ParameterFilterContex var exampleNode = propertyNode.SelectSingleNode("example"); if (exampleNode == null) return; - var exampleAsJson = (parameter.Schema?.ResolveType(context.SchemaRepository) == "string") - ? $"\"{exampleNode.ToString()}\"" - : exampleNode.ToString(); - - parameter.Example = OpenApiAnyFactory.CreateFromJson(exampleAsJson); + parameter.Example = XmlCommentsExampleHelper.Create(context.SchemaRepository, parameter.Schema, exampleNode.ToString()); } private void ApplyParamTags(OpenApiParameter parameter, ParameterFilterContext context) @@ -71,11 +67,7 @@ private void ApplyParamTags(OpenApiParameter parameter, ParameterFilterContext c var example = paramNode.GetAttribute("example", ""); if (string.IsNullOrEmpty(example)) return; - var exampleAsJson = (parameter.Schema?.ResolveType(context.SchemaRepository) == "string") - ? $"\"{example}\"" - : example; - - parameter.Example = OpenApiAnyFactory.CreateFromJson(exampleAsJson); + parameter.Example = XmlCommentsExampleHelper.Create(context.SchemaRepository, parameter.Schema, example.ToString()); } } } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsRequestBodyFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsRequestBodyFilter.cs index 5640cbda42..dcd4f96267 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsRequestBodyFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsRequestBodyFilter.cs @@ -50,11 +50,7 @@ private void ApplyPropertyTags(OpenApiRequestBody requestBody, RequestBodyFilter foreach (var mediaType in requestBody.Content.Values) { - var exampleAsJson = (mediaType.Schema?.ResolveType(context.SchemaRepository) == "string") - ? $"\"{exampleNode.ToString()}\"" - : exampleNode.ToString(); - - mediaType.Example = OpenApiAnyFactory.CreateFromJson(exampleAsJson); + mediaType.Example = XmlCommentsExampleHelper.Create(context.SchemaRepository, mediaType.Schema, exampleNode.ToString()); } } @@ -82,11 +78,7 @@ private void ApplyParamTags(OpenApiRequestBody requestBody, RequestBodyFilterCon foreach (var mediaType in requestBody.Content.Values) { - var exampleAsJson = (mediaType.Schema?.ResolveType(context.SchemaRepository) == "string") - ? $"\"{example}\"" - : example; - - mediaType.Example = OpenApiAnyFactory.CreateFromJson(exampleAsJson); + mediaType.Example = XmlCommentsExampleHelper.Create(context.SchemaRepository, mediaType.Schema, example); } } } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsSchemaFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsSchemaFilter.cs index 44fae0245e..0aaecf0608 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsSchemaFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsSchemaFilter.cs @@ -48,11 +48,7 @@ private void ApplyMemberTags(OpenApiSchema schema, SchemaFilterContext context) var exampleNode = fieldOrPropertyNode.SelectSingleNode("example"); if (exampleNode != null) { - var exampleAsJson = (schema.ResolveType(context.SchemaRepository) == "string") && !exampleNode.Value.Equals("null") - ? $"\"{exampleNode.ToString()}\"" - : exampleNode.ToString(); - - schema.Example = OpenApiAnyFactory.CreateFromJson(exampleAsJson); + schema.Example = XmlCommentsExampleHelper.Create(context.SchemaRepository, schema, exampleNode.ToString()); } } } diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeConstructedControllerWithXmlComments.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeConstructedControllerWithXmlComments.cs index 9c331aa73f..f759e38c2a 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeConstructedControllerWithXmlComments.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeConstructedControllerWithXmlComments.cs @@ -17,8 +17,8 @@ public class GenericControllerWithXmlComments public void ActionWithSummaryAndResponseTags(T param) { } - /// Description for param1 - /// Description for param2 + /// Description for param1 + /// Description for param2 public void ActionWithParamTags(T param1, T param2) { } } diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeControllerWithXmlComments.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeControllerWithXmlComments.cs index 6d9cd92377..431b33333c 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeControllerWithXmlComments.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeControllerWithXmlComments.cs @@ -18,7 +18,7 @@ public class FakeControllerWithXmlComments public void ActionWithSummaryAndRemarksTags() { } - /// Description for param1 + /// Description for param1 /// Description for param2 public void ActionWithParamTags(string param1, string param2) { } diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.xml b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.xml index 7b4ea815f7..e505a7a9f0 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.xml +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.xml @@ -18,8 +18,8 @@ - Description for param1 - Description for param2 + Description for param1 + Description for param2 @@ -36,7 +36,7 @@ - Description for param1 + Description for param1 Description for param2 diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsExampleHelperTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsExampleHelperTests.cs new file mode 100644 index 0000000000..50d9b59bad --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsExampleHelperTests.cs @@ -0,0 +1,54 @@ +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; +using Xunit; + +namespace Swashbuckle.AspNetCore.SwaggerGen.Test +{ + public class XmlCommentsExampleHelperTests + { + private readonly SchemaRepository schemaRepository = new SchemaRepository(); + + [Fact] + public void Create_BuildsOpenApiArrayJson__When_NotStringTypeAndDataIsArray() + { + OpenApiSchema schema = new OpenApiSchema(); + + IOpenApiAny example = XmlCommentsExampleHelper.Create( + schemaRepository, + schema, + "[\"one\",\"two\",\"three\"]"); + + + var output = (OpenApiArray)example; + Assert.Equal(3, output.Count); + Assert.Equal("one", ((OpenApiString)output[0]).Value); + Assert.Equal("two", ((OpenApiString)output[1]).Value); + Assert.Equal("three", ((OpenApiString)output[2]).Value); + } + + [Fact] + public void Create_BuildsOpenApiString_When_TypeString() + { + string exampleString = "example string with special characters\"<>\r\n\""; + OpenApiSchema schema = new OpenApiSchema { Type = "string" }; + schemaRepository.AddDefinition("test", schema); + + IOpenApiAny example = XmlCommentsExampleHelper.Create( + schemaRepository, schema, exampleString); + + Assert.Equal(((OpenApiString)example).Value, exampleString); + } + + [Fact] + public void Create_ReturnsNull_When_TypeString_and_ValueNull() + { + OpenApiSchema schema = new OpenApiSchema { Type = "string" }; + schemaRepository.AddDefinition("test", schema); + + IOpenApiAny example = XmlCommentsExampleHelper.Create( + schemaRepository, schema, "null"); + + Assert.Equal(AnyType.Null, ((OpenApiNull)example).AnyType); + } + } +} diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsParameterFilterTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsParameterFilterTests.cs index f27613e293..77502b15ab 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsParameterFilterTests.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsParameterFilterTests.cs @@ -23,7 +23,7 @@ public void Apply_SetsDescriptionAndExample_FromActionParamTag() Assert.Equal("Description for param1", parameter.Description); Assert.NotNull(parameter.Example); - Assert.Equal("\"Example for param1\"", parameter.Example.ToJson()); + Assert.Equal("\"Example for \\\"param1\\\"\"", parameter.Example.ToJson()); } [Fact] @@ -57,7 +57,7 @@ public void Apply_SetsDescriptionAndExample_FromUnderlyingGenericTypeActionParam Assert.Equal("Description for param1", parameter.Description); Assert.NotNull(parameter.Example); - Assert.Equal("\"Example for param1\"", parameter.Example.ToJson()); + Assert.Equal("\"Example for \\\"param1\\\"\"", parameter.Example.ToJson()); } [Fact] diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsRequestBodyFilterTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsRequestBodyFilterTests.cs index 73995e32da..9d4bd7dabf 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsRequestBodyFilterTests.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsRequestBodyFilterTests.cs @@ -34,7 +34,7 @@ public void Apply_SetsDescriptionAndExample_FromActionParamTag() Assert.Equal("Description for param1", requestBody.Description); Assert.NotNull(requestBody.Content["application/json"].Example); - Assert.Equal("\"Example for param1\"", requestBody.Content["application/json"].Example.ToJson()); + Assert.Equal("\"Example for \\\"param1\\\"\"", requestBody.Content["application/json"].Example.ToJson()); } [Fact] @@ -60,7 +60,7 @@ public void Apply_SetsDescriptionAndExample_FromUnderlyingGenericTypeActionParam Assert.Equal("Description for param1", requestBody.Description); Assert.NotNull(requestBody.Content["application/json"].Example); - Assert.Equal("\"Example for param1\"", requestBody.Content["application/json"].Example.ToJson()); + Assert.Equal("\"Example for \\\"param1\\\"\"", requestBody.Content["application/json"].Example.ToJson()); } [Fact]