Skip to content

Commit

Permalink
Merge pull request #16 from fluentassertions/feature/GH-13
Browse files Browse the repository at this point in the history
refactored analyzers visitors algorithm
fixed #11 
fixed #10 
fixed #13
  • Loading branch information
Meir017 authored Oct 24, 2017
2 parents 0a0c026 + 55c5ee8 commit 9f69a5a
Show file tree
Hide file tree
Showing 45 changed files with 413 additions and 633 deletions.
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

0 comments on commit 9f69a5a

Please sign in to comment.