Пример #1
0
    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();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));

        // Act
        var result = SymbolApiResponseMetadataProvider.GetDeclaredResponseMetadata(symbolCache, method);

        // Assert
        Assert.Collection(
            result,
            metadata =>
        {
            Assert.Equal(200, metadata.StatusCode);
            Assert.NotNull(metadata.Attribute);
        },
            metadata =>
        {
            Assert.Equal(404, metadata.StatusCode);
            Assert.NotNull(metadata.Attribute);
        },
            metadata =>
        {
            Assert.True(metadata.IsDefault);
        });
    }
Пример #2
0
    public async Task IsApiControllerAction_ReturnsFalse_IfMethodReturnTypeIsInvalid()
    {
        // Arrange
        var source      = @"
using Microsoft.AspNetCore.Mvc;

namespace TestNamespace
{
    [ApiController]
    public class TestController : ControllerBase
    {
        public DoesNotExist Get(int id)
        {
            if (id == 0)
            {
                return NotFound();
            }

            return new DoesNotExist(id);
        }
    }
}";
        var project     = MvcDiagnosticAnalyzerRunner.CreateProjectWithReferencesInBinDir(GetType().Assembly, new[] { source });
        var compilation = await project.GetCompilationAsync();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));
        var method = (IMethodSymbol)compilation.GetTypeByMetadataName("TestNamespace.TestController").GetMembers("Get").First();

        // Act
        var result = ApiControllerFacts.IsApiControllerAction(symbolCache, method);

        // Assert
        Assert.False(result);
    }
Пример #3
0
    public async Task IsApiControllerAction_ReturnsTrue_IfAttributeIsDeclaredOnAssembly()
    {
        // Arrange
        var compilation = await GetCompilation(nameof(IsApiControllerAction_ReturnsTrue_IfAttributeIsDeclaredOnAssembly));

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));
        var type   = compilation.GetTypeByMetadataName(typeof(IsApiControllerAction_ReturnsTrue_IfAttributeIsDeclaredOnAssemblyController).FullName);
        var method = (IMethodSymbol)type.GetMembers(nameof(IsApiControllerAction_ReturnsTrue_IfAttributeIsDeclaredOnAssemblyController.Action)).First();

        // Act
        var result = ApiControllerFacts.IsApiControllerAction(symbolCache, method);

        // Assert
        Assert.True(result);
    }
Пример #4
0
    public async Task IsApiControllerAction_ReturnsTrue_ForValidActionMethods()
    {
        // Arrange
        var compilation = await GetCompilation();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));
        var type   = compilation.GetTypeByMetadataName(typeof(ApiConventionAnalyzerTest_Valid).FullName);
        var method = (IMethodSymbol)type.GetMembers(nameof(ApiConventionAnalyzerTest_Valid.Index)).First();

        // Act
        var result = ApiControllerFacts.IsApiControllerAction(symbolCache, method);

        // Assert
        Assert.True(result);
    }
Пример #5
0
    public async Task IsApiControllerAction_ReturnsFalse_IfContainingTypeIsNotController()
    {
        // Arrange
        var compilation = await GetCompilation();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));
        var type   = compilation.GetTypeByMetadataName(typeof(ApiConventionAnalyzerTest_IndexModel).FullName);
        var method = (IMethodSymbol)type.GetMembers(nameof(ApiConventionAnalyzerTest_IndexModel.OnGet)).First();

        // Act
        var result = ApiControllerFacts.IsApiControllerAction(symbolCache, method);

        // Assert
        Assert.False(result);
    }
    public override void Initialize(AnalysisContext context)
    {
        context.EnableConcurrentExecution();
        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

        context.RegisterCompilationStartAction(compilationStartAnalysisContext =>
        {
            if (!ApiControllerSymbolCache.TryCreate(compilationStartAnalysisContext.Compilation, out var symbolCache))
            {
                // No-op if we can't find types we care about.
                return;
            }

            InitializeWorker(compilationStartAnalysisContext, symbolCache);
        });
    }
    private async Task RunMatchTest(string methodName, string conventionMethodName, bool expected)
    {
        var compilation = await GetCompilationAsync();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));

        var testController   = compilation.GetTypeByMetadataName(TestControllerName);
        var testConvention   = compilation.GetTypeByMetadataName(TestConventionName);
        var method           = (IMethodSymbol)testController.GetMembers(methodName).First();
        var conventionMethod = (IMethodSymbol)testConvention.GetMembers(conventionMethodName).First();

        // Act
        var result = IsMatch(symbolCache, method, conventionMethod);

        // Assert
        Assert.Equal(expected, result);
    }
    public async Task GetNameMatchBehavior_ReturnsValueFromAttributes()
    {
        // Arrange
        var expected    = SymbolApiConventionNameMatchBehavior.Prefix;
        var compilation = await GetCompilationAsync();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));

        var testConvention = compilation.GetTypeByMetadataName(TestConventionName);
        var method         = testConvention.GetMembers(nameof(TestConvention.Get)).First();

        // Act
        var result = GetNameMatchBehavior(symbolCache, method);

        // Assert
        Assert.Equal(expected, result);
    }
Пример #9
0
    public async Task GetErrorResponseType_ReturnsProblemDetails_IfNoAttributeIsDiscovered()
    {
        // Arrange
        var compilation = await GetCompilation(nameof(GetErrorResponseType_ReturnsProblemDetails_IfNoAttributeIsDiscovered));

        var expected = compilation.GetTypeByMetadataName(typeof(ProblemDetails).FullName);

        var type   = compilation.GetTypeByMetadataName(typeof(GetErrorResponseType_ReturnsProblemDetails_IfNoAttributeIsDiscoveredController).FullName);
        var method = (IMethodSymbol)type.GetMembers("Action").First();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));

        // Act
        var result = SymbolApiResponseMetadataProvider.GetErrorResponseType(symbolCache, method);

        // Assert
        Assert.Same(expected, result);
    }
Пример #10
0
    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();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));

        // Act
        var result = SymbolApiResponseMetadataProvider.GetDeclaredResponseMetadata(symbolCache, method);

        // Assert
        Assert.Collection(
            result,
            metadata => Assert.True(metadata.IsImplicit));
    }
Пример #11
0
    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();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));

        // Act
        var result = SymbolApiResponseMetadataProvider.GetDeclaredResponseMetadata(symbolCache, method);

        // Assert
        Assert.Collection(
            result,
            metadata => Assert.True(metadata.IsImplicit));
    }
Пример #12
0
    public async Task GetErrorResponseType_ReturnsTypeDefinedAtAction()
    {
        // Arrange
        var compilation = await GetCompilation(nameof(GetErrorResponseType_ReturnsTypeDefinedAtAction));

        var expected = compilation.GetTypeByMetadataName(typeof(GetErrorResponseType_ReturnsTypeDefinedAtActionModel).FullName);

        var type   = compilation.GetTypeByMetadataName(typeof(GetErrorResponseType_ReturnsTypeDefinedAtActionController).FullName);
        var method = (IMethodSymbol)type.GetMembers("Action").First();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));

        // Act
        var result = SymbolApiResponseMetadataProvider.GetErrorResponseType(symbolCache, method);

        // Assert
        Assert.Same(expected, result);
    }
    public async Task GetTypeMatchBehavior_ReturnsValueFromAttributes()
    {
        // Arrange
        var expected    = SymbolApiConventionTypeMatchBehavior.Any;
        var compilation = await GetCompilationAsync();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));

        var testConvention = compilation.GetTypeByMetadataName(TestConventionName);
        var method         = (IMethodSymbol)testConvention.GetMembers(nameof(TestConvention.MethodWithAnyTypeMatchBehaviorParameter)).First();
        var parameter      = method.Parameters[0];

        // Act
        var result = GetTypeMatchBehavior(symbolCache, parameter);

        // Assert
        Assert.Equal(expected, result);
    }
Пример #14
0
    private async Task <ActualApiResponseMetadata?> RunInspectReturnStatementSyntax(string source, string test)
    {
        var project     = MvcDiagnosticAnalyzerRunner.CreateProjectWithReferencesInBinDir(GetType().Assembly, new[] { source });
        var compilation = await project.GetCompilationAsync();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));

        var returnType = compilation.GetTypeByMetadataName($"{Namespace}.{test}");
        var syntaxTree = returnType.DeclaringSyntaxReferences[0].SyntaxTree;

        var method          = (IMethodSymbol)returnType.GetMembers().First();
        var methodSyntax    = syntaxTree.GetRoot().FindNode(method.Locations[0].SourceSpan);
        var returnStatement = methodSyntax.DescendantNodes().OfType <ReturnStatementSyntax>().First();
        var returnOperation = (IReturnOperation)compilation.GetSemanticModel(syntaxTree).GetOperation(returnStatement);

        return(ActualApiResponseMetadataFactory.InspectReturnOperation(
                   symbolCache,
                   returnOperation));
    }
Пример #15
0
    private async Task <ActualApiResponseMetadata?> RunInspectReturnStatementSyntax([CallerMemberName] string test = null)
    {
        // Arrange
        var compilation = await GetCompilation("InspectReturnExpressionTests");

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));

        var controllerType = compilation.GetTypeByMetadataName(typeof(TestFiles.InspectReturnExpressionTests.TestController).FullName);
        var syntaxTree     = controllerType.DeclaringSyntaxReferences[0].SyntaxTree;

        var method          = (IMethodSymbol)Assert.Single(controllerType.GetMembers(test));
        var methodSyntax    = syntaxTree.GetRoot().FindNode(method.Locations[0].SourceSpan);
        var returnStatement = methodSyntax.DescendantNodes().OfType <ReturnStatementSyntax>().First();
        var returnOperation = (IReturnOperation)compilation.GetSemanticModel(syntaxTree).GetOperation(returnStatement);

        return(ActualApiResponseMetadataFactory.InspectReturnOperation(
                   symbolCache,
                   returnOperation));
    }
Пример #16
0
    private async Task <(bool result, IList <ActualApiResponseMetadata> responseMetadatas, TestSource testSource)> TryGetActualResponseMetadata(string typeName, string methodName)
    {
        var testSource = MvcTestSource.Read(GetType().Name, "TryGetActualResponseMetadataTests");
        var project    = MvcDiagnosticAnalyzerRunner.CreateProjectWithReferencesInBinDir(GetType().Assembly, new[] { testSource.Source });

        var compilation = await GetCompilation("TryGetActualResponseMetadataTests");

        var type   = compilation.GetTypeByMetadataName(typeName);
        var method = (IMethodSymbol)type.GetMembers(methodName).First();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));

        var syntaxTree      = method.DeclaringSyntaxReferences[0].SyntaxTree;
        var methodSyntax    = (MethodDeclarationSyntax)syntaxTree.GetRoot().FindNode(method.Locations[0].SourceSpan);
        var methodOperation = (IMethodBodyBaseOperation)compilation.GetSemanticModel(syntaxTree).GetOperation(methodSyntax);

        var result = ActualApiResponseMetadataFactory.TryGetActualResponseMetadata(symbolCache, methodOperation, CancellationToken.None, out var responseMetadatas);

        return(result, responseMetadatas, testSource);
    }
Пример #17
0
    private async Task <CodeActionContext?> CreateCodeActionContext(CancellationToken cancellationToken)
    {
        var root = await _document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

        var semanticModel = await _document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

        var diagnosticNode = root.FindNode(_diagnostic.Location.SourceSpan);
        var methodSyntax   = diagnosticNode.FirstAncestorOrSelf <MethodDeclarationSyntax>();
        var method         = semanticModel.GetDeclaredSymbol(methodSyntax, cancellationToken);

        var statusCodesType     = semanticModel.Compilation.GetTypeByMetadataName(ApiSymbolNames.HttpStatusCodes);
        var statusCodeConstants = GetStatusCodeConstants(statusCodesType);

        if (!ApiControllerSymbolCache.TryCreate(semanticModel.Compilation, out var symbolCache))
        {
            return(null);
        }

        var codeActionContext = new CodeActionContext(semanticModel, symbolCache, method, methodSyntax, statusCodeConstants, cancellationToken);

        return(codeActionContext);
    }
Пример #18
0
    private async Task GetResponseMetadata_WorksForInvalidOrUnsupportedAttributes(string typeName, string methodName)
    {
        // Arrange
        var compilation = await GetResponseMetadataCompilation();

        var controller = compilation.GetTypeByMetadataName($"{Namespace}.{typeName}");
        var method     = (IMethodSymbol)controller.GetMembers(methodName).First();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));

        // Act
        var result = SymbolApiResponseMetadataProvider.GetDeclaredResponseMetadata(symbolCache, method);

        // Assert
        Assert.Collection(
            result,
            metadata =>
        {
            Assert.Equal(200, metadata.StatusCode);
            Assert.Same(method, metadata.AttributeSource);
        });
    }
Пример #19
0
    public async Task GetDeclaredResponseMetadata_ApiConventionTypeAttributeOnBaseType_Works()
    {
        // Arrange
        var type        = typeof(GetDeclaredResponseMetadata_ApiConventionTypeAttributeOnBaseType);
        var compilation = await GetResponseMetadataCompilation();

        var controller = compilation.GetTypeByMetadataName(type.FullName);
        var method     = (IMethodSymbol)controller.GetMembers().First();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));

        // Act
        var result = SymbolApiResponseMetadataProvider.GetDeclaredResponseMetadata(symbolCache, method);

        // Assert
        // We should expect 3 entries specified by DefaultApiConventions.Post
        Assert.Collection(
            result.OrderBy(r => r.StatusCode),
            metadata => Assert.True(metadata.IsDefault),
            metadata => Assert.Equal(201, metadata.StatusCode),
            metadata => Assert.Equal(400, metadata.StatusCode));
    }
Пример #20
0
    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();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));

        // Act
        var result = SymbolApiResponseMetadataProvider.GetDeclaredResponseMetadata(symbolCache, method);

        // Assert
        Assert.Collection(
            result,
            metadata =>
        {
            Assert.Equal(202, metadata.StatusCode);
            Assert.NotNull(metadata.Attribute);
            Assert.Equal(method, metadata.AttributeSource);
        });
    }
Пример #21
0
    public async Task InspectReturnExpression_ReturnsNull_IfReturnExpressionCannotBeFound()
    {
        // Arrange & Act
        var source      = @"
            using Microsoft.AspNetCore.Mvc;

namespace Microsoft.AspNetCore.Mvc.Api.Analyzers
{
    [ApiController]
    public class TestController : ControllerBase
    {
        public IActionResult Get(int id)
        {
            return new DoesNotExist(id);
        }
    }
}";
        var project     = MvcDiagnosticAnalyzerRunner.CreateProjectWithReferencesInBinDir(GetType().Assembly, new[] { source });
        var compilation = await project.GetCompilationAsync();

        Assert.True(ApiControllerSymbolCache.TryCreate(compilation, out var symbolCache));

        var returnType = compilation.GetTypeByMetadataName($"{Namespace}.TestController");
        var syntaxTree = returnType.DeclaringSyntaxReferences[0].SyntaxTree;

        var method          = (IMethodSymbol)returnType.GetMembers().First();
        var methodSyntax    = syntaxTree.GetRoot().FindNode(method.Locations[0].SourceSpan);
        var returnStatement = methodSyntax.DescendantNodes().OfType <ReturnStatementSyntax>().First();
        var returnOperation = (IReturnOperation)compilation.GetSemanticModel(syntaxTree).GetOperation(returnStatement);

        var actualResponseMetadata = ActualApiResponseMetadataFactory.InspectReturnOperation(
            symbolCache,
            returnOperation);

        // Assert
        Assert.Null(actualResponseMetadata);
    }