Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactored analyzers visitors algorithm #16

Merged
merged 4 commits into from
Oct 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/FluentAssertions.Analyzers.Tests/TestAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class NotImplementedAttribute : TestCategoryBaseAttribute
[AttributeUsage(AttributeTargets.Method)]
public class ImplementedAttribute : TestCategoryBaseAttribute
{
public string Reason { get; set; }

public override IList<string> TestCategories => new[] { "Completed" };
}

Expand Down
26 changes: 20 additions & 6 deletions src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ public class CollectionTests
{
public TestContext TestContext { get; set; }

[AssertionDataTestMethod]
[AssertionDiagnostic("nestedList.Should().NotBeNull({0}).And.ContainSingle().Which.Should().NotBeEmpty();")]
[AssertionDiagnostic("nestedList.Should().NotBeNull().And.ContainSingle().Which.Should().NotBeEmpty({0});")]
[AssertionDiagnostic("nestedList.Should().NotBeNull().And.ContainSingle({0}).Which.Should().NotBeEmpty();")]
[NotImplemented]
public void NoDiagnostics(string assertion) => VerifyCSharpNoDiagnosticsCodeBlock(assertion);


[AssertionDataTestMethod]
[AssertionDiagnostic("actual.Any().Should().BeTrue({0});")]
[AssertionDiagnostic("actual.AsEnumerable().Any().Should().BeTrue({0}).And.ToString();")]
Expand Down Expand Up @@ -375,6 +383,8 @@ public class CollectionTests
[AssertionDiagnostic("actual.Should().NotBeEmpty().And.NotBeNull({0});")]
[AssertionDiagnostic("actual.AsEnumerable().Should().NotBeNull().And.NotBeEmpty({0}).And.ToString();")]
[AssertionDiagnostic("actual.AsEnumerable().Should().NotBeEmpty().And.NotBeNull({0}).And.ToString();")]
[AssertionDiagnostic("actual.AsEnumerable().Should().NotBeNull().And.HaveCount(2).And.NotBeEmpty({0}).And.ToString();")]
[AssertionDiagnostic("actual.AsEnumerable().Should().NotBeEmpty().And.HaveCount(2).And.NotBeNull({0}).And.ToString();")]
[Implemented]
public void CollectionShouldNotBeNullOrEmpty_TestAnalyzer(string assertion) => VerifyCSharpDiagnosticCodeBlock<CollectionShouldNotBeNullOrEmptyAnalyzer>(assertion);

Expand All @@ -390,7 +400,7 @@ public class CollectionTests
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
[AssertionCodeFix(
oldAssertion: "actual.Should().NotBeEmpty({0}).And.NotBeNull();",
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
[AssertionCodeFix(
oldAssertion: "actual.AsEnumerable().Should().NotBeNull().And.HaveCount(2).And.NotBeEmpty({0}).And.ToString();",
newAssertion: "actual.AsEnumerable().Should().NotBeNullOrEmpty({0}).And.HaveCount(2).And.ToString();")]
Expand All @@ -400,8 +410,6 @@ public class CollectionTests
[Implemented]
public void CollectionShouldNotBeNullOrEmpty_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFixCodeBlock<CollectionShouldNotBeNullOrEmptyCodeFix, CollectionShouldNotBeNullOrEmptyAnalyzer>(oldAssertion, newAssertion);

public void CollectionShouldNotBeNullOrEmptyMultipleReasons_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFixCodeBlock<CollectionShouldNotBeNullOrEmptyCodeFix, CollectionShouldNotBeNullOrEmptyAnalyzer>(oldAssertion, newAssertion);

[AssertionDataTestMethod]
[AssertionDiagnostic("actual.ElementAt(k).Should().Be(expectedItem{0});")]
[AssertionDiagnostic("actual.ElementAt(6).Should().Be(expectedItem{0});")]
Expand Down Expand Up @@ -604,7 +612,7 @@ public class CollectionTests
newAssertion: "actual.AsEnumerable().Should().HaveElementAt(0, null{0}).And.ToString();")]
[Ignore("What Should Happen?")]
public void CollectionShouldHaveElementAt0Null_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFixCodeBlock<CollectionShouldHaveElementAt0NullCodeFix, CollectionShouldHaveElementAt0NullAnalyzer>(oldAssertion, newAssertion);

private void VerifyCSharpDiagnosticCodeBlock<TDiagnosticAnalyzer>(string sourceAssertion) where TDiagnosticAnalyzer : Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer, new()
{
var source = GenerateCode.EnumerableCodeBlockAssertion(sourceAssertion);
Expand All @@ -616,7 +624,7 @@ public class CollectionTests
DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(source, new DiagnosticResult
{
Id = diagnosticId,
Message = string.Format(message, GenerateCode.ActualVariableName),
Message = message,
Locations = new DiagnosticResultLocation[]
{
new DiagnosticResultLocation("Test0.cs", 11,13)
Expand All @@ -636,7 +644,7 @@ public class CollectionTests
DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(source, new DiagnosticResult
{
Id = diagnosticId,
Message = string.Format(message, GenerateCode.ActualVariableName),
Message = message,
Locations = new DiagnosticResultLocation[]
{
new DiagnosticResultLocation("Test0.cs", 10,16)
Expand Down Expand Up @@ -664,5 +672,11 @@ private void VerifyCSharpFixExpressionBody<TCodeFixProvider, TDiagnosticAnalyzer

DiagnosticVerifier.VerifyCSharpFix<TCodeFixProvider, TDiagnosticAnalyzer>(oldSource, newSource);
}

private void VerifyCSharpNoDiagnosticsCodeBlock(string assertion)
{
var source = GenerateCode.EnumerableCodeBlockAssertion(assertion);
DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(source);
}
}
}
27 changes: 24 additions & 3 deletions src/FluentAssertions.Analyzers.Tests/Tips/SanityTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@ namespace FluentAssertions.Analyzers.Tests.Tips
public class SanityTests
{
[TestMethod]
[NotImplemented(Reason = "https://github.com/fluentassertions/fluentassertions.analyzers/issues/10")]
[Implemented(Reason = "https://github.com/fluentassertions/fluentassertions.analyzers/issues/11")]
public void CountWithPredicate()
{
const string assertion = "actual.Count(d => d.Message.Contains(\"a\")).Should().Be(2);";
var source = GenerateCode.EnumerableCodeBlockAssertion(assertion);

DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(source);
}

[TestMethod]
[Implemented(Reason = "https://github.com/fluentassertions/fluentassertions.analyzers/issues/10")]
public void AssertionCallMultipleMethodWithTheSameNameAndArguments()
{
const string assertion = "actual.Should().Contain(d => d.Message.Contains(\"a\")).And.Contain(d => d.Message.Contains(\"c\"));";
Expand All @@ -16,7 +26,7 @@ public void AssertionCallMultipleMethodWithTheSameNameAndArguments()
}

[TestMethod]
[NotImplemented(Reason = "https://github.com/fluentassertions/fluentassertions.analyzers/issues/13")]
[Implemented(Reason = "https://github.com/fluentassertions/fluentassertions.analyzers/issues/13")]
public void PropertyOfIndexerShouldBe_ShouldNotThrowException()
{
const string assertion = "actual[0].Message.Should().Be(\"test\");";
Expand All @@ -26,13 +36,24 @@ public void PropertyOfIndexerShouldBe_ShouldNotThrowException()
}

[TestMethod]
[NotImplemented(Reason = "https://github.com/fluentassertions/fluentassertions.analyzers/issues/13")]
[Implemented(Reason = "https://github.com/fluentassertions/fluentassertions.analyzers/issues/13")]
public void PropertyOfElementAtShouldBe_ShouldNotTriggerDiagnostic()
{
const string assertion = "actual.ElementAt(0).Message.Should().Be(\"test\");";
var source = GenerateCode.EnumerableCodeBlockAssertion(assertion);

DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(source);
}

[TestMethod]
[Implemented(Reason = "https://github.com/fluentassertions/fluentassertions.analyzers/issues/10")]
public void NestedAssertions_ShouldNotTrigger()
{
const string declaration = "var nestedList = new List<List<int>>();";
const string assertion = "nestedList.Should().NotBeNull().And.ContainSingle().Which.Should().NotBeEmpty();";
var source = GenerateCode.EnumerableCodeBlockAssertion(declaration + assertion);

DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(source);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class CollectionShouldBeEmptyAnalyzer : FluentAssertionsAnalyzer
public const string DiagnosticId = Constants.Tips.Collections.CollectionsShouldBeEmpty;
public const string Category = Constants.Tips.Category;

public const string Message = "Use {0} .Should() followed by .BeEmpty() instead.";
public const string Message = "Use .Should().BeEmpty() instead.";

protected override DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId, Title, Message, Category, DiagnosticSeverity.Info, true);
protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors
Expand All @@ -27,31 +27,24 @@ protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors
}
}

public class AnyShouldBeFalseSyntaxVisitor : FluentAssertionsWithoutLambdaArgumentCSharpSyntaxVisitor
public class AnyShouldBeFalseSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
{
protected override string MathodNotContainingLambda => "Any";

public AnyShouldBeFalseSyntaxVisitor() : base("Any", "Should", "BeFalse")
public AnyShouldBeFalseSyntaxVisitor() : base(MemberValidator.MathodNotContainingLambda("Any"), MemberValidator.Should, new MemberValidator("BeFalse"))
{
}
}

public class ShouldHaveCount0SyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
{
private bool _haveCountMethodHas0Argument;

public override bool IsValid => base.IsValid && _haveCountMethodHas0Argument;

public ShouldHaveCount0SyntaxVisitor() : base("Should", "HaveCount")
public ShouldHaveCount0SyntaxVisitor() : base(MemberValidator.Should, new MemberValidator("HaveCount", HaveCountArgumentsValidator))
{
}

public override void VisitArgumentList(ArgumentListSyntax node)
private static bool HaveCountArgumentsValidator(SeparatedSyntaxList<ArgumentSyntax> arguments)
{
if (!node.Arguments.Any()) return;
if (CurrentMethod != "HaveCount") return;
if (!arguments.Any()) return false;

_haveCountMethodHas0Argument =
node.Arguments[0].Expression is LiteralExpressionSyntax literal
return arguments[0].Expression is LiteralExpressionSyntax literal
&& literal.Token.Value is int argument
&& argument == 0;
}
Expand All @@ -62,7 +55,7 @@ node.Arguments[0].Expression is LiteralExpressionSyntax literal
public class CollectionShouldBeEmptyCodeFix : FluentAssertionsCodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(CollectionShouldBeEmptyAnalyzer.DiagnosticId);

protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties)
{
switch (properties.VisitorName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class CollectionShouldBeInAscendingOrderAnalyzer : FluentAssertionsAnalyz
public const string DiagnosticId = Constants.Tips.Collections.CollectionShouldBeInAscendingOrder;
public const string Category = Constants.Tips.Category;

public const string Message = "Use {0} .Should() followed by .BeInAscendingOrder() instead.";
public const string Message = "Use .Should().BeInAscendingOrder() instead.";

protected override DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId, Title, Message, Category, DiagnosticSeverity.Info, true);
protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors
Expand All @@ -24,28 +24,11 @@ protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors
yield return new OrderByShouldEqualSyntaxVisitor();
}
}
private class OrderByShouldEqualSyntaxVisitor : FluentAssertionsWithLambdaArgumentCSharpSyntaxVisitor
{
private bool _argumentIsSelf;
protected override string MethodContainingLambda => "OrderBy";

public override bool IsValid => base.IsValid && _argumentIsSelf;

public OrderByShouldEqualSyntaxVisitor() : base("OrderBy", "Should", "Equal")
{
}

public override void VisitArgumentList(ArgumentListSyntax node)
private class OrderByShouldEqualSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
{
public OrderByShouldEqualSyntaxVisitor() : base(MemberValidator.MathodContainingLambda("OrderBy"), MemberValidator.Should, MemberValidator.ArgumentIsVariable("Equal"))
{
if (!node.Arguments.Any()) return;
if (CurrentMethod != "Equal")
{
base.VisitArgumentList(node);
return;
}

_argumentIsSelf = node.Arguments[0].Expression is IdentifierNameSyntax identifier
&& identifier.Identifier.Text == VariableName;
}
}
}
Expand All @@ -54,7 +37,7 @@ public override void VisitArgumentList(ArgumentListSyntax node)
public class CollectionShouldBeInAscendingOrderCodeFix : FluentAssertionsCodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(CollectionShouldBeInAscendingOrderAnalyzer.DiagnosticId);

protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties)
{
var remove = NodeReplacement.RemoveAndExtractArguments("OrderBy");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class CollectionShouldBeInDescendingOrderAnalyzer : FluentAssertionsAnaly
public const string DiagnosticId = Constants.Tips.Collections.CollectionShouldBeInDescendingOrder;
public const string Category = Constants.Tips.Category;

public const string Message = "Use {0} .Should() followed by .BeInDescendingOrder() instead.";
public const string Message = "Use .Should().BeInDescendingOrder() instead.";

protected override DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId, Title, Message, Category, DiagnosticSeverity.Info, true);
protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors
Expand All @@ -24,28 +24,11 @@ protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors
yield return new OrderByDescendingShouldEqualSyntaxVisitor();
}
}
private class OrderByDescendingShouldEqualSyntaxVisitor : FluentAssertionsWithLambdaArgumentCSharpSyntaxVisitor
{
private bool _argumentIsSelf;
protected override string MethodContainingLambda => "OrderByDescending";

public override bool IsValid => base.IsValid && _argumentIsSelf;

public OrderByDescendingShouldEqualSyntaxVisitor() : base("OrderByDescending", "Should", "Equal")
{
}

public override void VisitArgumentList(ArgumentListSyntax node)
private class OrderByDescendingShouldEqualSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
{
public OrderByDescendingShouldEqualSyntaxVisitor() : base(MemberValidator.MathodContainingLambda("OrderByDescending"), MemberValidator.Should, MemberValidator.ArgumentIsVariable("Equal"))
{
if (!node.Arguments.Any()) return;
if (CurrentMethod != "Equal")
{
base.VisitArgumentList(node);
return;
}

_argumentIsSelf = node.Arguments[0].Expression is IdentifierNameSyntax identifier
&& identifier.Identifier.Text == VariableName;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class CollectionShouldContainItemAnalyzer : FluentAssertionsAnalyzer
public const string DiagnosticId = Constants.Tips.Collections.CollectionShouldContainItem;
public const string Category = Constants.Tips.Category;

public const string Message = "Use {0} .Should() followed by Contain() instead.";
public const string Message = "Use .Should()Contain() instead.";

protected override DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId, Title, Message, Category, DiagnosticSeverity.Info, true);

Expand All @@ -28,22 +28,8 @@ protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors

private class ContainsShouldBeTrueSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
{
public string ExpectedItemString { get; private set; }
public override bool IsValid => base.IsValid && ExpectedItemString != null;

public ContainsShouldBeTrueSyntaxVisitor() : base("Contains", "Should", "BeTrue")
{
}

public override ImmutableDictionary<string, string> ToDiagnosticProperties()
=> base.ToDiagnosticProperties().Add(Constants.DiagnosticProperties.ExpectedItemString, ExpectedItemString);

public override void VisitArgumentList(ArgumentListSyntax node)
public ContainsShouldBeTrueSyntaxVisitor() : base(new MemberValidator("Contains"), MemberValidator.Should, new MemberValidator("BeTrue"))
{
if (!node.Arguments.Any()) return;
if (CurrentMethod != "Contains") return;

ExpectedItemString = node.Arguments[0].ToFullString();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class CollectionShouldContainPropertyAnalyzer : FluentAssertionsAnalyzer
public const string DiagnosticId = Constants.Tips.Collections.CollectionShouldContainProperty;
public const string Category = Constants.Tips.Category;

public const string Message = "Use {0} .Should() followed by .Contain() instead.";
public const string Message = "Use .Should().Contain() instead.";

protected override DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId, Title, Message, Category, DiagnosticSeverity.Info, true);
protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors
Expand All @@ -26,17 +26,16 @@ protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors
}
}

public class AnyShouldBeTrueSyntaxVisitor : FluentAssertionsWithLambdaArgumentCSharpSyntaxVisitor
public class AnyShouldBeTrueSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
{
protected override string MethodContainingLambda => "Any";
public AnyShouldBeTrueSyntaxVisitor() : base("Any", "Should", "BeTrue")
public AnyShouldBeTrueSyntaxVisitor() : base(MemberValidator.MathodContainingLambda("Any"), MemberValidator.Should, new MemberValidator("BeTrue"))
{
}
}
public class WhereShouldNotBeEmptySyntaxVisitor : FluentAssertionsWithLambdaArgumentCSharpSyntaxVisitor

public class WhereShouldNotBeEmptySyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
{
protected override string MethodContainingLambda => "Where";
public WhereShouldNotBeEmptySyntaxVisitor() : base("Where", "Should", "NotBeEmpty")
public WhereShouldNotBeEmptySyntaxVisitor() : base(MemberValidator.MathodContainingLambda("Where"), MemberValidator.Should, new MemberValidator("NotBeEmpty"))
{
}
}
Expand Down
Loading