Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix that XML comment examples do not show up if the type is string and the example contains quotation marks #2727

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Text.Json;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;

namespace Swashbuckle.AspNetCore.SwaggerGen
{
internal static class XmlCommentsExampleHelper
{
public static IOpenApiAny Create(
SchemaRepository schemaRepository,
OpenApiSchema schema,
string exampleString)
{
var isStringType =
martincostello marked this conversation as resolved.
Show resolved Hide resolved
(schema?.ResolveType(schemaRepository) == "string") &&
!string.Equals(exampleString, "null");

var exampleAsJson = isStringType
? JsonSerializer.Serialize(exampleString)
: exampleString;

var example = OpenApiAnyFactory.CreateFromJson(exampleAsJson);

return example;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}

Expand Down Expand Up @@ -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);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,7 @@ private static void TrySetExample(OpenApiSchema schema, SchemaFilterContext cont
if (example == null)
return;

var exampleAsJson = (schema.ResolveType(context.SchemaRepository) == "string") && !example.Equals("null")
? $"\"{example}\""
: example;

schema.Example = OpenApiAnyFactory.CreateFromJson(exampleAsJson);
schema.Example = XmlCommentsExampleHelper.Create(context.SchemaRepository, schema, example);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public class GenericControllerWithXmlComments<T>
public void ActionWithSummaryAndResponseTags(T param)
{ }

/// <param name="param1" example="Example for param1">Description for param1</param>
/// <param name="param2" example="Example for param2">Description for param2</param>
/// <param name="param1" example="Example for &quot;param1&quot;">Description for param1</param>
/// <param name="param2" example="Example for &quot;param2&quot;">Description for param2</param>
public void ActionWithParamTags(T param1, T param2)
{ }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class FakeControllerWithXmlComments
public void ActionWithSummaryAndRemarksTags()
{ }

/// <param name="param1" example="Example for param1">Description for param1</param>
/// <param name="param1" example="Example for &quot;param1&quot;">Description for param1</param>
/// <param name="param2" example="http://test.com/?param1=1&amp;param2=2">Description for param2</param>
public void ActionWithParamTags(string param1, string param2)
{ }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
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()
{
var schema = new OpenApiSchema();

IOpenApiAny example = XmlCommentsExampleHelper.Create(
schemaRepository,
schema,
"[\"one\",\"two\",\"three\"]");

Assert.NotNull(example);
var actual = Assert.IsType<OpenApiArray>(example);
Assert.Equal(3, actual.Count);

var item1 = Assert.IsType<OpenApiString>(actual[0]);
var item2 = Assert.IsType<OpenApiString>(actual[1]);
var item3 = Assert.IsType<OpenApiString>(actual[2]);
Assert.Equal("one", item1.Value);
Assert.Equal("two", item2.Value);
Assert.Equal("three", item3.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.NotNull(example);
var actual = Assert.IsType<OpenApiString>(example);
Assert.Equal(actual.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.NotNull(example);
var actual = Assert.IsType<OpenApiNull>(example);
Assert.Equal(AnyType.Null, actual.AnyType);
}

[Fact]
public void Create_AllowsSchemaToBeNull()
{
OpenApiSchema schema = null;

IOpenApiAny example = XmlCommentsExampleHelper.Create(schemaRepository, schema, "[]");

Assert.NotNull(example);
var actual = Assert.IsType<OpenApiArray>(example);
Assert.Empty(actual);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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]
Expand Down