Skip to content

Commit 366f8b8

Browse files
committed
Add test that checks that the type check is unidirectional
1 parent 77e48fe commit 366f8b8

File tree

1 file changed

+18
-11
lines changed

1 file changed

+18
-11
lines changed

src/Mvc/Mvc.ApiExplorer/test/EndpointMetadataApiDescriptionProviderTest.cs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -464,23 +464,30 @@ public void AddsResponseDescription_WorksWithCollectionsWhereInnerTypeIsInEndpoi
464464
Assert.Equal("application/json", createdOkFormat.MediaType);
465465
}
466466

467+
/// <summary>
468+
/// EndpointMetadataApiDescriptionProvider performs a one way type check for discovering response types to match the description that's set in [ProducesResponseType]
469+
/// The reason we do a one-way check instead of a bidirectional check is to prevent too many positive matches.
470+
/// </summary>
471+
/// <remarks>
472+
/// Example: If we did a bidirectional check, we would match something scenarios like this, which can cause confusion:
473+
/// [ProducesResponseType<string>(StatusCodes.Status200OK, Description = "Returned with a string")] -> TypedResults.Ok(new object())
474+
/// This would match because object is assignable to string,
475+
/// but it doesn't make sense to add the Description to the object type because the attribute says we should return a string.
476+
///
477+
/// This test documents this desired behavior and will fail if the behavior changes, so the developer can double check if their change is intentional.
478+
/// </summary>
467479
[Fact]
468-
public void AddsResponseDescription_WorksWithCollectionsAndTypedResultsWhereInnerTypeIsInEndpointAndIsBaseClass()
480+
public void AddsResponseDescription_ShouldFailWhenInferredTypeIsNotDirectlyAssignableToAttributeType()
469481
{
470-
const string expectedOkDescription = "The weather forecast for the next 5 days.";
471-
472-
var apiDescription = GetApiDescription([ProducesResponseType<List<GenericClass<string>>>(StatusCodes.Status200OK, Description = expectedOkDescription)]
473-
() => TypedResults.Ok(new List<BaseClass> { new() }.AsEnumerable()));
482+
var apiDescription = GetApiDescription([ProducesResponseType<string>(StatusCodes.Status200OK, Description = "Only returned with a string")]
483+
() => TypedResults.Ok(new object()));
474484

475485
var okResponseType = Assert.Single(apiDescription.SupportedResponseTypes);
476486

477487
Assert.Equal(200, okResponseType.StatusCode);
478-
Assert.Equal(typeof(IEnumerable<BaseClass>), okResponseType.Type); // We use IEnumerable<BaseClass> as the inferred type has higher priority than those set by metadata (attributes)
479-
Assert.Equal(typeof(IEnumerable<BaseClass>), okResponseType.ModelMetadata?.ModelType);
480-
Assert.Equal(expectedOkDescription, okResponseType.Description);
481-
482-
var createdOkFormat = Assert.Single(okResponseType.ApiResponseFormats);
483-
Assert.Equal("application/json", createdOkFormat.MediaType);
488+
Assert.Equal(typeof(object), okResponseType.Type);
489+
Assert.Equal(typeof(object), okResponseType.ModelMetadata?.ModelType);
490+
Assert.Null(okResponseType.Description);
484491
}
485492

486493
[Fact]

0 commit comments

Comments
 (0)