Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Rico Suter committed May 3, 2023
1 parent fb37aa2 commit 0ce206e
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,26 @@ public async Task When_response_is_wrapped_in_certain_generic_result_types_then_
var settings = new AspNetCoreOpenApiDocumentGeneratorSettings();

// Act
var document = await GenerateDocumentAsync(settings, typeof(WrappedResponseController));
var document = await GenerateDocumentAsync(settings, typeof(WrappedResponseController));

// Assert
OpenApiResponse GetOperationResponse(String ActionName)
=> document.Operations.Where(op => op.Operation.OperationId == $"{nameof(WrappedResponseController).Substring(0, nameof(WrappedResponseController).Length - "Controller".Length )}_{ActionName}").Single().Operation.ActualResponses.Single().Value;
JsonObjectType GetOperationResponseSchemaType( String ActionName )
=> GetOperationResponse( ActionName ).Schema.Type;
var IntType = JsonSchema.FromType<int>().Type;
OpenApiResponse GetOperationResponse(string actionName) => document.Operations
.Where(op => op.Operation.OperationId == $"{nameof(WrappedResponseController)
.Substring(0, nameof(WrappedResponseController).Length - "Controller".Length)}_{actionName}")
.Single().Operation.ActualResponses.Single().Value;

JsonObjectType GetOperationResponseSchemaType(string actionName) =>
GetOperationResponse(actionName).Schema.Type;

var intType = JsonSchema.FromType<int>().Type;

Assert.Null(GetOperationResponse(nameof(WrappedResponseController.Task)).Schema);
Assert.Equal(IntType, GetOperationResponseSchemaType(nameof( WrappedResponseController.Int)));
Assert.Equal(IntType, GetOperationResponseSchemaType(nameof( WrappedResponseController.TaskOfInt)));
Assert.Equal(IntType, GetOperationResponseSchemaType(nameof( WrappedResponseController.ValueTaskOfInt)));
Assert.Equal(IntType, GetOperationResponseSchemaType(nameof( WrappedResponseController.ActionResultOfInt)));
Assert.Equal(IntType, GetOperationResponseSchemaType(nameof( WrappedResponseController.TaskOfActionResultOfInt)));
Assert.Equal(IntType, GetOperationResponseSchemaType(nameof( WrappedResponseController.ValueTaskOfActionResultOfInt)));
Assert.Equal(intType, GetOperationResponseSchemaType(nameof( WrappedResponseController.Int)));
Assert.Equal(intType, GetOperationResponseSchemaType(nameof( WrappedResponseController.TaskOfInt)));
Assert.Equal(intType, GetOperationResponseSchemaType(nameof( WrappedResponseController.ValueTaskOfInt)));
Assert.Equal(intType, GetOperationResponseSchemaType(nameof( WrappedResponseController.ActionResultOfInt)));
Assert.Equal(intType, GetOperationResponseSchemaType(nameof( WrappedResponseController.TaskOfActionResultOfInt)));
Assert.Equal(intType, GetOperationResponseSchemaType(nameof( WrappedResponseController.ValueTaskOfActionResultOfInt)));
}
}
}
42 changes: 21 additions & 21 deletions src/NSwag.Generation.WebApi.Tests/WrappedResponseTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
Expand All @@ -10,75 +9,76 @@

using NJsonSchema;


namespace NSwag.Generation.WebApi.Tests
{
[TestClass]
public class WrappedResponseTests
{
public class WrappedResponseController : ApiController
{
[HttpGet, Route( "task" )]
[HttpGet, Route("task")]
public Task Task()
{
throw new NotImplementedException();
}

[HttpGet, Route( "int" )]
[HttpGet, Route("int")]
public int Int()
{
throw new NotImplementedException();
}

[HttpGet, Route( "taskofint" )]
[HttpGet, Route("taskofint")]
public Task<int> TaskOfInt()
{
throw new NotImplementedException();
}

[HttpGet, Route( "valuetaskofint" )]
[HttpGet, Route("valuetaskofint")]
public ValueTask<int> ValueTaskOfInt()
{
throw new NotImplementedException();
}

[HttpGet, Route( "jsonresultofint" )]
[HttpGet, Route("jsonresultofint")]
public JsonResult<int> JsonResultOfInt()
{
throw new NotImplementedException();
}

[HttpGet, Route( "actionresultofint" )]
[HttpGet, Route("actionresultofint")]
public CoreMvc.ActionResult<int> ActionResultOfInt()
{
throw new NotImplementedException();
}

}

[TestMethod]
public async Task When_response_is_wrapped_in_certain_generic_result_types_then_discard_the_wrapper_type()
{
// Arrange
var generator = new WebApiOpenApiDocumentGenerator( new WebApiOpenApiDocumentGeneratorSettings() );
var generator = new WebApiOpenApiDocumentGenerator(new WebApiOpenApiDocumentGeneratorSettings());

// Act
var document = await generator.GenerateForControllerAsync<WrappedResponseController>();

// Assert
OpenApiResponse GetOperationResponse( String ActionName )
=> document.Operations.Where( op => op.Operation.OperationId == $"{nameof(WrappedResponseController).Substring(0,nameof(WrappedResponseController).Length - "Controller".Length )}_{ActionName}" ).Single().Operation.ActualResponses.Single().Value;
JsonObjectType GetOperationResponseSchemaType( String ActionName )
=> GetOperationResponse( ActionName ).Schema.Type;
var IntType = JsonSchema.FromType<int>().Type;
OpenApiResponse GetOperationResponse(string actionName) => document.Operations
.Where(op => op.Operation.OperationId == $"{nameof(WrappedResponseController)
.Substring(0, nameof(WrappedResponseController).Length - "Controller".Length)}_{actionName}")
.Single().Operation.ActualResponses.Single().Value;

JsonObjectType GetOperationResponseSchemaType(string actionName) =>
GetOperationResponse(actionName).Schema.Type;

Assert.IsNull( GetOperationResponse( nameof( WrappedResponseController.Task ) ).Schema );
Assert.AreEqual( IntType, GetOperationResponseSchemaType( nameof( WrappedResponseController.Int ) ) );
Assert.AreEqual( IntType, GetOperationResponseSchemaType( nameof( WrappedResponseController.TaskOfInt ) ) );
Assert.AreEqual( IntType, GetOperationResponseSchemaType( nameof( WrappedResponseController.ValueTaskOfInt ) ) );
Assert.AreEqual( IntType, GetOperationResponseSchemaType( nameof( WrappedResponseController.JsonResultOfInt ) ) );
Assert.AreEqual( IntType, GetOperationResponseSchemaType( nameof( WrappedResponseController.ActionResultOfInt ) ) );
var intType = JsonSchema.FromType<int>().Type;

Assert.IsNull(GetOperationResponse(nameof(WrappedResponseController.Task)).Schema);
Assert.AreEqual(intType, GetOperationResponseSchemaType(nameof(WrappedResponseController.Int)));
Assert.AreEqual(intType, GetOperationResponseSchemaType(nameof(WrappedResponseController.TaskOfInt)));
Assert.AreEqual(intType, GetOperationResponseSchemaType(nameof(WrappedResponseController.ValueTaskOfInt)));
Assert.AreEqual(intType, GetOperationResponseSchemaType(nameof(WrappedResponseController.JsonResultOfInt)));
Assert.AreEqual(intType, GetOperationResponseSchemaType(nameof(WrappedResponseController.ActionResultOfInt)));
}
}
}
22 changes: 10 additions & 12 deletions src/NSwag.Generation/GenericResultWrapperTypes.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
using System;
using System.Linq;

namespace NSwag.Generation
{
internal static class GenericResultWrapperTypes
{
internal static bool IsGenericWrapperType( string typeName )
=>
typeName == "Task`1" ||
typeName == "ValueTask`1" ||
typeName == "JsonResult`1" ||
typeName == "ActionResult`1"
;
internal static bool IsGenericWrapperType(string typeName) =>
typeName == "Task`1" ||
typeName == "ValueTask`1" ||
typeName == "JsonResult`1" ||
typeName == "ActionResult`1";

internal static void RemoveGenericWrapperTypes<T>(ref T o, Func<T,string> getName, Func<T,T> unwrap)
internal static T RemoveGenericWrapperTypes<T>(T type, Func<T, string> getName, Func<T, T> unwrap)
{
// We iterate because a common signature is public async Task<ActionResult<T>> Action()
while (IsGenericWrapperType(getName(o)))
while (IsGenericWrapperType(getName(type)))
{
o = unwrap(o);
type = unwrap(type);
}

return type;
}
}
}
19 changes: 10 additions & 9 deletions src/NSwag.Generation/OpenApiSchemaGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,19 @@ protected override void GenerateObject(JsonSchema schema, JsonTypeDescription ty
}
}

/// <summary>Generetes a schema directly or referenced for the requested schema type; also adds nullability if required.</summary>
/// <typeparam name="TSchemaType">The resulted schema type which may reference the actual schema.</typeparam>
/// <param name="contextualType">The type of the schema to generate.</param>
/// <param name="isNullable">Specifies whether the property, parameter or requested schema type is nullable.</param>
/// <param name="schemaResolver">The schema resolver.</param>
/// <param name="transformation">An action to transform the resulting schema (e.g. property or parameter) before the type of reference is determined (with $ref or allOf/oneOf).</param>
/// <returns>The requested schema object.</returns>
public override TSchemaType GenerateWithReferenceAndNullability<TSchemaType>(
/// <summary>Generetes a schema directly or referenced for the requested schema type; also adds nullability if required.</summary>
/// <typeparam name="TSchemaType">The resulted schema type which may reference the actual schema.</typeparam>
/// <param name="contextualType">The type of the schema to generate.</param>
/// <param name="isNullable">Specifies whether the property, parameter or requested schema type is nullable.</param>
/// <param name="schemaResolver">The schema resolver.</param>
/// <param name="transformation">An action to transform the resulting schema (e.g. property or parameter) before the type of reference is determined (with $ref or allOf/oneOf).</param>
/// <returns>The requested schema object.</returns>
public override TSchemaType GenerateWithReferenceAndNullability<TSchemaType>(
ContextualType contextualType, bool isNullable,
JsonSchemaResolver schemaResolver, Action<TSchemaType, JsonSchema> transformation = null)
{
GenericResultWrapperTypes.RemoveGenericWrapperTypes (ref contextualType,t=>t.TypeName,t=>t.OriginalGenericArguments[0]);
contextualType = GenericResultWrapperTypes.RemoveGenericWrapperTypes(
contextualType, t => t.TypeName, t => t.OriginalGenericArguments[0]);

if (IsFileResponse(contextualType))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ protected void UpdateResponseDescription(OperationProcessorContext operationProc
protected XElement GetResponseXmlDocsElement(MethodInfo methodInfo, string responseCode)
{
var operationXmlDocsNodes = GetResponseXmlDocsNodes(methodInfo);
try
try
{
return operationXmlDocsNodes?.SingleOrDefault(n => n.Name == "response" && n.Attributes().Any(a => a.Name == "code" && a.Value == responseCode));
}
Expand Down Expand Up @@ -268,7 +268,8 @@ private void LoadDefaultSuccessResponse(ParameterInfo returnParameter, string su
returnType = typeof(void);
}

GenericResultWrapperTypes.RemoveGenericWrapperTypes (ref returnType,t=>t.Name,t=>t.GenericTypeArguments[0]);
returnType = GenericResultWrapperTypes.RemoveGenericWrapperTypes(
returnType, t => t.Name, t => t.GenericTypeArguments[0]);

if (IsVoidResponse(returnType))
{
Expand Down

0 comments on commit 0ce206e

Please sign in to comment.