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);
        }