public void HasAttribute_ReturnsTrueForAttributesOnOverridenProperties()
    {
        // Arrange
        var source = @"
using System;
namespace TestApp
{
    public class TestAttribute : Attribute { }

    public class TestControllerBase
    {
        [TestAttribute]
        public virtual string SomeProperty { get; set; }
    }

    public class TestController : TestControllerBase
    {
        public override string SomeProperty { get; set; }
    }
}";

        var compilation = TestCompilation.Create(source);
        var attribute   = compilation.GetTypeByMetadataName("TestApp.TestAttribute");
        var testClass   = compilation.GetTypeByMetadataName("TestApp.TestController");
        var property    = (IPropertySymbol)testClass.GetMembers("SomeProperty").First();

        // Act
        var hasAttributeWithoutInherit = CodeAnalysisExtensions.HasAttribute(property, attribute, inherit: false);
        var hasAttributeWithInherit    = CodeAnalysisExtensions.HasAttribute(property, attribute, inherit: true);

        // Assert
        Assert.False(hasAttributeWithoutInherit);
        Assert.True(hasAttributeWithInherit);
    }
    public void IsAssignable_ReturnsTrueIfAncestorTypeImplementsInterface()
    {
        // Arrange
        var source      = @"
namespace TestApp
{
public interface ITestInterface
{
}

public class ITestInterfaceA : ITestInterface
{
}

public class ITestInterfaceB : ITestInterfaceA
{
}

public class TestClass : ITestInterfaceB
{
}";
        var compilation = TestCompilation.Create(source);
        var sourceType  = compilation.GetTypeByMetadataName("TestApp.ITestInterface");
        var target      = compilation.GetTypeByMetadataName("TestApp.TestClass");

        // Act
        var isAssignableFrom        = CodeAnalysisExtensions.IsAssignableFrom(sourceType, target);
        var isAssignableFromDerived = CodeAnalysisExtensions.IsAssignableFrom(target, sourceType);

        // Assert
        Assert.True(isAssignableFrom);
        Assert.False(isAssignableFromDerived); // Inverse shouldn't be true
    }
    public void HasAttribute_ReturnsTrueForAttributesOnMethods()
    {
        // Arrange
        var source = @"
using System;
namespace TestApp
{
    public class TestAttribute : Attribute { }

    public class TestController
    {
        [TestAttribute]
        public void SomeMethod() { }
    }
}";

        var compilation = TestCompilation.Create(source);
        var attribute   = compilation.GetTypeByMetadataName("TestApp.TestAttribute");
        var testClass   = compilation.GetTypeByMetadataName("TestApp.TestController");
        var method      = (IMethodSymbol)testClass.GetMembers("SomeMethod").First();

        // Act
        var hasAttribute = CodeAnalysisExtensions.HasAttribute(method, attribute, inherit: false);

        // Assert
        Assert.True(hasAttribute);
    }
    public void GetAttributes_WithInheritFalse_ReturnsAllAttributesOnCurrentAction()
    {
        // Arrange
        var source = @"
using Microsoft.AspNetCore.Mvc;
namespace TestApp
{
    public class BaseClass
    {
        [ProducesResponseType(200)]
        [ProducesResponseType(404)]
        public virtual void Method() { }
    }

    public class TestClass : BaseClass
    {
        [ProducesResponseType(400)]
        public override void Method() { }
    }
}
";

        var compilation = TestCompilation.Create(source);
        var attribute   = compilation.GetTypeByMetadataName(typeof(ProducesResponseTypeAttribute).FullName);
        var testClass   = compilation.GetTypeByMetadataName("TestApp.TestClass");
        var method      = (IMethodSymbol)testClass.GetMembers("Method").First();

        // Act
        var attributes = CodeAnalysisExtensions.GetAttributes(method, attribute, inherit: false);

        // Assert
        Assert.Collection(
            attributes,
            attributeData => Assert.Equal(400, attributeData.ConstructorArguments[0].Value));
    }
    public void HasAttribute_ReturnsTrueIfBaseTypeHasAttribute()
    {
        // Arrange
        var source = @"
using Microsoft.AspNetCore.Mvc;
namespace TestApp
{
    [Controller]
    public class TestControllerBase { }

    public class TestController : TestControllerBase { }
}";

        var compilation = TestCompilation.Create(source);

        var attribute = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Mvc.ControllerAttribute");
        var testClass = compilation.GetTypeByMetadataName($"TestApp.TestController");

        // Act
        var hasAttributeWithoutInherit = CodeAnalysisExtensions.HasAttribute(testClass, attribute, inherit: false);
        var hasAttributeWithInherit    = CodeAnalysisExtensions.HasAttribute(testClass, attribute, inherit: true);

        // Assert
        Assert.False(hasAttributeWithoutInherit);
        Assert.True(hasAttributeWithInherit);
    }
    public void HasAttribute_ReturnsTrueForInterfaceContractOnAttribute()
    {
        // Arrange
        var source = @"
using System;
namespace TestApp
{
    public interface ITestInterface { }

    public class TestAttribute : Attribute, ITestInterface  { }

    [TestAttribute]
    public class TestController
    {
    }
}";

        var compilation = TestCompilation.Create(source);
        var @interface  = compilation.GetTypeByMetadataName("TestApp.ITestInterface");
        var testClass   = compilation.GetTypeByMetadataName("TestApp.TestController");

        // Act
        var hasAttribute          = CodeAnalysisExtensions.HasAttribute(testClass, @interface, inherit: true);
        var hasAttributeOnDerived = CodeAnalysisExtensions.HasAttribute(testClass, @interface, inherit: true);

        // Assert
        Assert.True(hasAttribute);
        Assert.True(hasAttributeOnDerived);
    }
    public void GetAttributes_BaseTypeWithAttributes()
    {
        // Arrange
        var source = @"
using Microsoft.AspNetCore.Mvc;
namespace TestApp
{
    [ApiConventionType(typeof(object))]
    [ApiController]
    [ApiConventionType(typeof(string))]
    public class BaseType
    {
    }

    [ApiConventionType(typeof(int))]
    public class TestClass : BaseType
    {
    }
}";

        var compilation = TestCompilation.Create(source);
        var attribute   = compilation.GetTypeByMetadataName(typeof(ApiConventionTypeAttribute).FullName);
        var testClass   = compilation.GetTypeByMetadataName("TestApp.TestClass");

        // Act
        var attributes = CodeAnalysisExtensions.GetAttributes(testClass, attribute, inherit: true);

        // Assert
        Assert.Collection(
            attributes,
            attributeData =>
        {
            Assert.Same(attribute, attributeData.AttributeClass);
            Assert.Equal(attributeData.ConstructorArguments[0].Value, compilation.GetSpecialType(SpecialType.System_Int32));
        },
            attributeData =>
        {
            Assert.Same(attribute, attributeData.AttributeClass);
            Assert.Equal(attributeData.ConstructorArguments[0].Value, compilation.GetSpecialType(SpecialType.System_Object));
        },
            attributeData =>
        {
            Assert.Same(attribute, attributeData.AttributeClass);
            Assert.Equal(attributeData.ConstructorArguments[0].Value, compilation.GetSpecialType(SpecialType.System_String));
        });
    }
    public void IsAssignable_ReturnsTrue_IfSourceAndDestinationAreTheSameInterface()
    {
        // Arrange
        var source = @"
namespace TestApp
{
    public interface ITestInterface { }
}";

        var compilation = TestCompilation.Create(source);
        var sourceType  = compilation.GetTypeByMetadataName("TestApp.ITestInterface");
        var target      = compilation.GetTypeByMetadataName("TestApp.ITestInterface");

        // Act
        var isAssignableFrom = CodeAnalysisExtensions.IsAssignableFrom(sourceType, target);

        // Assert
        Assert.True(isAssignableFrom);
    }
    public void IsAssignable_ReturnsTrueIfTypesAreExact()
    {
        // Arrange
        var source = @"
namespace TestApp
{
    public class TestType  {  }
}";

        var compilation = TestCompilation.Create(source);
        var sourceType  = compilation.GetTypeByMetadataName("TestApp.TestType");
        var target      = compilation.GetTypeByMetadataName("TestApp.TestType");

        // Act
        var isAssignableFrom = CodeAnalysisExtensions.IsAssignableFrom(sourceType, target);

        // Assert
        Assert.True(isAssignableFrom);
    }
    public void IsAssignable_ReturnsFalseIfTypeDoesNotImplementInterface()
    {
        // Arrange
        var source = @"
namespace TestApp
{
    public class TypeA { }
}";

        var compilation = TestCompilation.Create(source);
        var sourceType  = compilation.GetTypeByMetadataName("TestApp.TypeA");
        var target      = compilation.GetTypeByMetadataName("System.IDisposable");

        // Act
        var isAssignableFrom = CodeAnalysisExtensions.IsAssignableFrom(sourceType, target);

        // Assert
        Assert.False(isAssignableFrom);
    }
    public void GetAttributes_OnNewMethodOfNonVirtualBaseMethod()
    {
        // Arrange
        var source = @"
using Microsoft.AspNetCore.Mvc;
namespace TestApp
{
    public class BaseClass
    {
        [ProducesResponseType(200)]
        [ProducesResponseType(404)]
        public virtual void VirtualMethod() { }

        [ProducesResponseType(200)]
        [ProducesResponseType(404)]
        public virtual void NotVirtualMethod() { }
    }

    public class TestClass : BaseClass
    {
        [ProducesResponseType(400)]
        public new void VirtualMethod() { }

        [ProducesResponseType(401)]
        public new void NotVirtualMethod() { }
    }
}";

        var compilation = TestCompilation.Create(source);
        var attribute   = compilation.GetTypeByMetadataName(typeof(ProducesResponseTypeAttribute).FullName);
        var testClass   = compilation.GetTypeByMetadataName("TestApp.TestClass");
        var method      = (IMethodSymbol)testClass.GetMembers("NotVirtualMethod").First();

        // Act
        var attributes = CodeAnalysisExtensions.GetAttributes(method, attribute, inherit: true);

        // Assert
        Assert.Collection(
            attributes,
            attributeData => Assert.Equal(401, attributeData.ConstructorArguments[0].Value));
    }
    public void IsAssignable_ReturnsFalseForDifferentTypes()
    {
        // Arrange
        var source = @"
namespace TestApp
{
    public class TypeA { }

    public class TypeB { }
}";

        var compilation = TestCompilation.Create(source);
        var sourceType  = compilation.GetTypeByMetadataName("TestApp.TypeA");
        var target      = compilation.GetTypeByMetadataName("TestApp.TypeB");

        // Act
        var isAssignableFrom = CodeAnalysisExtensions.IsAssignableFrom(sourceType, target);

        // Assert
        Assert.False(isAssignableFrom);
    }
    public void GetAttributes_OnTypeWithoutAttributes()
    {
        // Arrange
        var source = @"
using Microsoft.AspNetCore.Mvc;
namespace TestApp
{
    public class TestClass
    {
    }
}";

        var compilation = TestCompilation.Create(source);
        var attribute   = compilation.GetTypeByMetadataName(typeof(ApiConventionTypeAttribute).FullName);
        var testClass   = compilation.GetTypeByMetadataName("TestApp.TestClass");

        // Act
        var attributes = CodeAnalysisExtensions.GetAttributes(testClass, attribute, inherit: true);

        // Assert
        Assert.Empty(attributes);
    }
    public void GetAttributes_OnMethodWithoutAttributes()
    {
        // Arrange
        var source = @"
namespace TestApp
{
    public class TestController
    {
        public void Method() { }
    }
}";

        var compilation = TestCompilation.Create(source);
        var attribute   = compilation.GetTypeByMetadataName(typeof(ProducesResponseTypeAttribute).FullName);
        var testClass   = compilation.GetTypeByMetadataName("TestApp.TestController");
        var method      = (IMethodSymbol)testClass.GetMembers("Method").First();

        // Act
        var attributes = CodeAnalysisExtensions.GetAttributes(method, attribute, inherit: true);

        // Assert
        Assert.Empty(attributes);
    }
Example #15
0
    /// <summary>
    /// Replace invocation expression with awaited invocation.
    /// </summary>
    /// <param name="document"></param>
    /// <param name="invocation"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public static async Task <Document> InvokeAsync(Document document,
                                                    InvocationExpressionSyntax invocation, CancellationToken cancellationToken)
    {
        var parentMethodDeclaration = CodeAnalysisExtensions.GetContainingMethodDeclaration(invocation);
        var annotation    = new SyntaxAnnotation(Guid.NewGuid().ToString("D"));
        var newInvocation = AwaitExpression(invocation)
                            .WithAdditionalAnnotations(annotation);
        var root = await document.GetSyntaxRootAsync(cancellationToken);

        root          = root.ReplaceNode(invocation, newInvocation);
        newInvocation = (AwaitExpressionSyntax)root.GetAnnotatedNodes(annotation).Single();
        // if newInvocation.Parent is equals and parent.parent is declaration, look for all uses of that symbol
        var oldParentMethodDeclaration = newInvocation
                                         .Ancestors()
                                         .OfType <MethodDeclarationSyntax>()
                                         .FirstOrDefault();
        var model = await document.GetSemanticModelAsync(cancellationToken);

        if (oldParentMethodDeclaration != null)
        {
            root = root.ReplaceNode(oldParentMethodDeclaration,
                                    parentMethodDeclaration
                                    .WithAsync(oldParentMethodDeclaration, model)
                                    .WithAdditionalAnnotations(Formatter.Annotation));
        }

        var compilationUnitSyntax = (CompilationUnitSyntax)root;

        var usings = compilationUnitSyntax.Usings;

        if (!usings.Any(e => e.Name.ToString().Equals(typeof(Task).Namespace)))
        {
            var usingDirective = UsingDirective(ParseName(typeof(Task).Namespace));
            root = compilationUnitSyntax.AddUsings(usingDirective);
        }
        return(document.WithSyntaxRoot(root));
    }
    public void HasAttribute_ReturnsFalseIfSymbolDoesNotHaveAttribute()
    {
        // Arrange
        var source = @"
using Microsoft.AspNetCore.Mvc;
namespace TestApp
{
    public class HasAttribute_ReturnsFalseIfTypeDoesNotHaveAttribute : Attribute { }

    [Controller]
    public class HasAttribute_ReturnsFalseIfTypeDoesNotHaveAttributeTest
    {
        [NonAction]
        public void SomeMethod() { }

        [BindProperty]
        public string SomeProperty { get; set; }
    }
}";

        var compilation  = TestCompilation.Create(source);
        var attribute    = compilation.GetTypeByMetadataName("TestApp.HasAttribute_ReturnsFalseIfTypeDoesNotHaveAttribute");
        var testClass    = compilation.GetTypeByMetadataName("TestApp.HasAttribute_ReturnsFalseIfTypeDoesNotHaveAttributeTest");
        var testMethod   = (IMethodSymbol)testClass.GetMembers("SomeMethod").First();
        var testProperty = (IPropertySymbol)testClass.GetMembers("SomeProperty").First();

        // Act
        var classHasAttribute    = CodeAnalysisExtensions.HasAttribute(testClass, attribute, inherit: false);
        var methodHasAttribute   = CodeAnalysisExtensions.HasAttribute(testMethod, attribute, inherit: false);
        var propertyHasAttribute = CodeAnalysisExtensions.HasAttribute(testProperty, attribute, inherit: false);

        // AssertControllerAttribute
        Assert.False(classHasAttribute);
        Assert.False(methodHasAttribute);
        Assert.False(propertyHasAttribute);
    }