public async Task GetResponseMetadata_ReturnsValuesFromApiConventionMethodAttribute() { // Arrange var compilation = await GetResponseMetadataCompilation(); var controller = compilation.GetTypeByMetadataName($"{Namespace}.{nameof(GetResponseMetadata_ControllerActionWithAttributes)}"); var method = (IMethodSymbol)controller.GetMembers(nameof(GetResponseMetadata_ControllerActionWithAttributes.GetResponseMetadata_ReturnsValuesFromApiConventionMethodAttribute)).First(); var symbolCache = new ApiControllerSymbolCache(compilation); // Act var result = SymbolApiResponseMetadataProvider.GetDeclaredResponseMetadata(symbolCache, method, Array.Empty <AttributeData>()); // Assert Assert.Collection( result, metadata => { Assert.Equal(200, metadata.StatusCode); Assert.NotNull(metadata.Attribute); }, metadata => { Assert.Equal(404, metadata.StatusCode); Assert.NotNull(metadata.Attribute); }); }
public async Task GetResponseMetadata_IgnoresProducesAttribute() { // Arrange var compilation = await GetResponseMetadataCompilation(); var controller = compilation.GetTypeByMetadataName($"{Namespace}.{nameof(GetResponseMetadata_ControllerActionWithAttributes)}"); var method = (IMethodSymbol)controller.GetMembers(nameof(GetResponseMetadata_ControllerActionWithAttributes.ActionWithProducesAttribute)).First(); var symbolCache = new ApiControllerSymbolCache(compilation); // Act var result = SymbolApiResponseMetadataProvider.GetDeclaredResponseMetadata(symbolCache, method, Array.Empty <AttributeData>()); // Assert Assert.Empty(result); }
public async Task GetResponseMetadata_ReturnsEmptySequence_IfNoAttributesArePresent_ForPostAction() { // Arrange var compilation = await GetResponseMetadataCompilation(); var controller = compilation.GetTypeByMetadataName($"{Namespace}.{nameof(GetResponseMetadata_ControllerWithoutConvention)}"); var method = (IMethodSymbol)controller.GetMembers(nameof(GetResponseMetadata_ControllerWithoutConvention.PostPerson)).First(); var symbolCache = new ApiControllerSymbolCache(compilation); // Act var result = SymbolApiResponseMetadataProvider.GetDeclaredResponseMetadata(symbolCache, method, Array.Empty <AttributeData>()); // Assert Assert.Empty(result); }
public async Task GetResponseMetadata_ReturnsValueFromProducesResponseType_WhenStatusCodeIsSpecifiedInConstructorWithResponseType() { // Arrange var compilation = await GetResponseMetadataCompilation(); var controller = compilation.GetTypeByMetadataName($"{Namespace}.{nameof(GetResponseMetadata_ControllerActionWithAttributes)}"); var method = (IMethodSymbol)controller.GetMembers(nameof(GetResponseMetadata_ControllerActionWithAttributes.ActionWithProducesResponseType_StatusCodeAndTypeInConstructor)).First(); var symbolCache = new ApiControllerSymbolCache(compilation); // Act var result = SymbolApiResponseMetadataProvider.GetDeclaredResponseMetadata(symbolCache, method, Array.Empty <AttributeData>()); // Assert Assert.Collection( result, metadata => { Assert.Equal(202, metadata.StatusCode); Assert.NotNull(metadata.Attribute); Assert.Null(metadata.Convention); }); }
private async Task GetResponseMetadata_IgnoresInvalidOrUnsupportedAttribues(string typeName, string methodName) { // Arrange var compilation = await GetResponseMetadataCompilation(); var controller = compilation.GetTypeByMetadataName($"{Namespace}.{typeName}"); var method = (IMethodSymbol)controller.GetMembers(methodName).First(); var symbolCache = new ApiControllerSymbolCache(compilation); // Act var result = SymbolApiResponseMetadataProvider.GetDeclaredResponseMetadata(symbolCache, method, Array.Empty <AttributeData>()); // Assert Assert.Collection( result, metadata => { Assert.Equal(200, metadata.StatusCode); Assert.NotNull(metadata.Attribute); Assert.Null(metadata.Convention); }); }
private void InitializeWorker(CompilationStartAnalysisContext compilationStartAnalysisContext, ApiControllerSymbolCache symbolCache) { compilationStartAnalysisContext.RegisterSyntaxNodeAction(syntaxNodeContext => { var cancellationToken = syntaxNodeContext.CancellationToken; var methodSyntax = (MethodDeclarationSyntax)syntaxNodeContext.Node; var semanticModel = syntaxNodeContext.SemanticModel; var method = semanticModel.GetDeclaredSymbol(methodSyntax, syntaxNodeContext.CancellationToken); if (!ApiControllerFacts.IsApiControllerAction(symbolCache, method)) { return; } var conventionAttributes = GetConventionTypeAttributes(symbolCache, method); var declaredResponseMetadata = SymbolApiResponseMetadataProvider.GetDeclaredResponseMetadata(symbolCache, method, conventionAttributes); var hasUnreadableStatusCodes = SymbolApiResponseMetadataProvider.TryGetActualResponseMetadata(symbolCache, semanticModel, methodSyntax, cancellationToken, out var actualResponseMetadata); var hasUndocumentedStatusCodes = false; foreach (var item in actualResponseMetadata) { var location = item.ReturnStatement.GetLocation(); if (item.IsDefaultResponse) { if (!(HasStatusCode(declaredResponseMetadata, 200) || HasStatusCode(declaredResponseMetadata, 201))) { hasUndocumentedStatusCodes = true; syntaxNodeContext.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.MVC1005_ActionReturnsUndocumentedSuccessResult, location)); } } else if (!HasStatusCode(declaredResponseMetadata, item.StatusCode)) { hasUndocumentedStatusCodes = true; syntaxNodeContext.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.MVC1004_ActionReturnsUndocumentedStatusCode, location, item.StatusCode)); } } if (hasUndocumentedStatusCodes || hasUnreadableStatusCodes) { // If we produced analyzer warnings about undocumented status codes, don't attempt to determine // if there are documented status codes that are missing from the method body. return; } for (var i = 0; i < declaredResponseMetadata.Count; i++) { var expectedStatusCode = declaredResponseMetadata[i].StatusCode; if (!HasStatusCode(actualResponseMetadata, expectedStatusCode)) { syntaxNodeContext.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.MVC1006_ActionDoesNotReturnDocumentedStatusCode, methodSyntax.Identifier.GetLocation(), expectedStatusCode)); } } }, SyntaxKind.MethodDeclaration); }