Skip to content

Commit 1de5127

Browse files
committed
{EnumerableAnalyzer} - more assertions
1 parent b50a3a4 commit 1de5127

12 files changed

+175
-96
lines changed

src/FluentAssertions.BestPractices.Tests/GenerateCode.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public static class GenerateCode
2828
.AppendLine("{")
2929
.AppendLine($" public class {ClassName}")
3030
.AppendLine(" {")
31-
.AppendLine($" public void {MethodName}({nameof(IEnumerable)}<{ComplexClassName}> {ActualVariableName}, {nameof(IEnumerable)}<{ComplexClassName}> {ExpectedVariableName}, {nameof(IEnumerable)}<{ComplexClassName}> {UnexpectedVariableName}, {ComplexClassName} {ExpectedItemVariableName}, {ComplexClassName} {UnexpectedItemVariableName}, int {CountVariable})")
31+
.AppendLine($" public void {MethodName}({nameof(IList)}<{ComplexClassName}> {ActualVariableName}, {nameof(IList)}<{ComplexClassName}> {ExpectedVariableName}, {nameof(IList)}<{ComplexClassName}> {UnexpectedVariableName}, {ComplexClassName} {ExpectedItemVariableName}, {ComplexClassName} {UnexpectedItemVariableName}, int {CountVariable})")
3232
.AppendLine(" {")
3333
.AppendLine($" {assertion}")
3434
.AppendLine(" }")

src/FluentAssertions.BestPractices.Tests/Tips/CollectionTests.cs

Lines changed: 31 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public class CollectionTests
5656
[AssertionDataTestMethod]
5757
[AssertionDiagnostic("actual.Any(x => x.BooleanProperty).Should().BeFalse({0});")]
5858
[AssertionDiagnostic("actual.Where(x => x.BooleanProperty).Should().BeEmpty({0});")]
59+
[AssertionDiagnostic("actual.Should().OnlyContain(x => !x.BooleanProperty{0});")]
5960
[Implemented]
6061
public void CollectionShouldNotContainProperty_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<CollectionShouldNotContainPropertyAnalyzer>(assertion);
6162

@@ -65,7 +66,10 @@ public class CollectionTests
6566
newAssertion: "actual.Should().NotContain(x => x.BooleanProperty{0});")]
6667
[AssertionCodeFix(
6768
oldAssertion: "actual.Where(x => x.BooleanProperty).Should().BeEmpty({0});",
68-
newAssertion: "actual.Should().NotContain(x => x.BooleanProperty{0});")]
69+
newAssertion: "actual.Should().NotContain(x => x.BooleanProperty{0});")]
70+
[AssertionCodeFix(
71+
oldAssertion: "actual.Should().OnlyContain(x => !x.BooleanProperty{0});",
72+
newAssertion: "actual.Should().NotContain(x => x.BooleanProperty{0});")]
6973
[Implemented]
7074
public void CollectionShouldNotContainProperty_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldNotContainPropertyCodeFix, CollectionShouldNotContainPropertyAnalyzer>(oldAssertion, newAssertion);
7175

@@ -241,7 +245,7 @@ public class CollectionTests
241245
[Implemented]
242246
[Ignore("Will be available in Fluent Assertions 5.0")]
243247
public void CollectionShouldNotHaveSameCount_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldNotHaveSameCountCodeFix, CollectionShouldNotHaveSameCountAnalyzer>(oldAssertion, newAssertion);
244-
248+
245249
[AssertionDataTestMethod]
246250
[AssertionDiagnostic("actual.Where(x => x.BooleanProperty).Should().HaveCount(1{0});")]
247251
[Implemented]
@@ -253,19 +257,7 @@ public class CollectionTests
253257
newAssertion: "actual.Should().ContainSingle(x => x.BooleanProperty{0});")]
254258
[Implemented]
255259
public void CollectionShouldContainSingleProperty_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldContainSinglePropertyCodeFix, CollectionShouldContainSinglePropertyAnalyzer>(oldAssertion, newAssertion);
256-
257-
[AssertionDataTestMethod]
258-
[AssertionDiagnostic("actual.Should().OnlyContain(e => !e.BooleanProperty{0});")]
259-
[NotImplemented]
260-
public void CollectionShouldNotContainProperty_TestAnalyzer03(string assertion) => VerifyCSharpDiagnostic<CollectionShouldNotContainPropertyAnalyzer>(assertion);
261-
262-
[AssertionDataTestMethod]
263-
[AssertionCodeFix(
264-
oldAssertion: "actual.Should().OnlyContain(e => !e.BooleanProperty{0});",
265-
newAssertion: "actual.Should().NotContain(x => x.BooleanProperty{0});")]
266-
[NotImplemented]
267-
public void CollectionShouldNotContainProperty_TestCodeFix03(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldNotContainPropertyCodeFix, CollectionShouldNotContainPropertyAnalyzer>(oldAssertion, newAssertion);
268-
260+
269261
[AssertionDataTestMethod]
270262
[AssertionDiagnostic("actual.Should().NotBeNull().And.NotBeEmpty({0});")]
271263
[NotImplemented]
@@ -280,40 +272,36 @@ public class CollectionTests
280272

281273
[AssertionDataTestMethod]
282274
[AssertionDiagnostic("actual.ElementAt(k).Should().Be(expectedItem{0});")]
283-
[NotImplemented]
275+
[AssertionDiagnostic("actual.ElementAt(6).Should().Be(expectedItem{0});")]
276+
[AssertionDiagnostic("actual[k].Should().Be(expectedItem{0});")]
277+
[AssertionDiagnostic("actual[6].Should().Be(expectedItem{0});")]
278+
[AssertionDiagnostic("actual.Skip(k).First().Should().Be(expectedItem{0});")]
279+
[AssertionDiagnostic("actual.Skip(6).First().Should().Be(expectedItem{0});")]
280+
[Implemented]
284281
public void CollectionShouldHaveElementAt_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<CollectionShouldHaveElementAtAnalyzer>(assertion);
285282

286283
[AssertionDataTestMethod]
287284
[AssertionCodeFix(
288-
oldAssertion: "actual.ElementAt(k).Should().Be(expectedItem{0});",
289-
newAssertion: "actual.Should().HaveElementAt(k, expectedItem{0});")]
290-
[NotImplemented]
291-
public void CollectionShouldHaveElementAt_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldHaveElementAtCodeFix, CollectionShouldHaveElementAtAnalyzer>(oldAssertion, newAssertion);
292-
293-
[AssertionDataTestMethod]
294-
[AssertionDiagnostic("actual[k].Should().Be(expectedItem{0});")]
295-
[NotImplemented]
296-
public void CollectionShouldHaveElementAt_TestAnalyzer02(string assertion) => VerifyCSharpDiagnostic<CollectionShouldHaveElementAtAnalyzer>(assertion);
297-
298-
[AssertionDataTestMethod]
285+
oldAssertion: "actual.ElementAt(k).Should().Be(expectedItem{0});",
286+
newAssertion: "actual.Should().HaveElementAt(k, expectedItem{0});")]
299287
[AssertionCodeFix(
300-
oldAssertion: "actual[k].Should().Be(expectedItem{0});",
301-
newAssertion: "actual.Should().HaveElementAt(k, expectedItem{0});")]
302-
[NotImplemented]
303-
public void CollectionShouldHaveElementAt_TestCodeFix02(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldHaveElementAtCodeFix, CollectionShouldHaveElementAtAnalyzer>(oldAssertion, newAssertion);
304-
305-
[AssertionDataTestMethod]
306-
[AssertionDiagnostic("actual.Skip(k).First().Should().Be(expectedItem{0});")]
307-
[NotImplemented]
308-
public void CollectionShouldHaveElementAt_TestAnalyzer03(string assertion) => VerifyCSharpDiagnostic<CollectionShouldHaveElementAtAnalyzer>(assertion);
309-
310-
[AssertionDataTestMethod]
288+
oldAssertion: "actual.ElementAt(6).Should().Be(expectedItem{0});",
289+
newAssertion: "actual.Should().HaveElementAt(6, expectedItem{0});")]
311290
[AssertionCodeFix(
312-
oldAssertion: "actual.Skip(k).First().Should().Be(expectedItem{0});",
313-
newAssertion: "actual.Should().HaveElementAt(k, expectedItem{0});")]
314-
[NotImplemented]
315-
public void CollectionShouldHaveElementAt_TestCodeFix03(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldHaveElementAtCodeFix, CollectionShouldHaveElementAtAnalyzer>(oldAssertion, newAssertion);
316-
291+
oldAssertion: "actual[k].Should().Be(expectedItem{0});",
292+
newAssertion: "actual.Should().HaveElementAt(k, expectedItem{0});")]
293+
[AssertionCodeFix(
294+
oldAssertion: "actual[6].Should().Be(expectedItem{0});",
295+
newAssertion: "actual.Should().HaveElementAt(6, expectedItem{0});")]
296+
[AssertionCodeFix(
297+
oldAssertion: "actual.Skip(k).First().Should().Be(expectedItem{0});",
298+
newAssertion: "actual.Should().HaveElementAt(k, expectedItem{0});")]
299+
[AssertionCodeFix(
300+
oldAssertion: "actual.Skip(6).First().Should().Be(expectedItem{0});",
301+
newAssertion: "actual.Should().HaveElementAt(6, expectedItem{0});")]
302+
[Implemented]
303+
public void CollectionShouldHaveElementAt_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldHaveElementAtCodeFix, CollectionShouldHaveElementAtAnalyzer>(oldAssertion, newAssertion);
304+
317305
[AssertionDataTestMethod]
318306
[AssertionDiagnostic("actual.OrderBy(x => x.BooleanProperty).Should().Equal(actual{0});")]
319307
[Implemented]

src/FluentAssertions.BestPractices/Tips/Collections/CollectionShouldBeInAscendingOrder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class CollectionShouldBeInAscendingOrderAnalyzer : FluentAssertionsAnalyz
2828
private class OrderByShouldEqualSyntaxVisitor : FluentAssertionsWithLambdaArgumentCSharpSyntaxVisitor
2929
{
3030
private bool _argumentIsSelf;
31-
protected override string MathodContainingLambda => "OrderBy";
31+
protected override string MethodContainingLambda => "OrderBy";
3232

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

src/FluentAssertions.BestPractices/Tips/Collections/CollectionShouldBeInDescendingOrder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class CollectionShouldBeInDescendingOrderAnalyzer : FluentAssertionsAnaly
2828
private class OrderByDescendingShouldEqualSyntaxVisitor : FluentAssertionsWithLambdaArgumentCSharpSyntaxVisitor
2929
{
3030
private bool _argumentIsSelf;
31-
protected override string MathodContainingLambda => "OrderByDescending";
31+
protected override string MethodContainingLambda => "OrderByDescending";
3232

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

src/FluentAssertions.BestPractices/Tips/Collections/CollectionShouldContainProperty.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ public class CollectionShouldContainPropertyAnalyzer : FluentAssertionsAnalyzer
2929

3030
private class AnyShouldBeTrueSyntaxVisitor : FluentAssertionsWithLambdaArgumentCSharpSyntaxVisitor
3131
{
32-
protected override string MathodContainingLambda => "Any";
32+
protected override string MethodContainingLambda => "Any";
3333
public AnyShouldBeTrueSyntaxVisitor() : base("Any", "Should", "BeTrue")
3434
{
3535
}
3636
}
3737
private class WhereShouldNotBeEmptySyntaxVisitor : FluentAssertionsWithLambdaArgumentCSharpSyntaxVisitor
3838
{
39-
protected override string MathodContainingLambda => "Where";
39+
protected override string MethodContainingLambda => "Where";
4040
public WhereShouldNotBeEmptySyntaxVisitor() : base("Where", "Should", "NotBeEmpty")
4141
{
4242
}

src/FluentAssertions.BestPractices/Tips/Collections/CollectionShouldContainSingleProperty.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ private class WhereShouldHaveCount1SyntaxVisitor : FluentAssertionsWithLambdaArg
3030
{
3131
private bool _haveCountMethodHas1Argument;
3232

33-
protected override string MathodContainingLambda => "Where";
33+
protected override string MethodContainingLambda => "Where";
3434
public override bool IsValid => base.IsValid && _haveCountMethodHas1Argument;
3535
public WhereShouldHaveCount1SyntaxVisitor() : base("Where", "Should", "HaveCount")
3636
{
Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.CodeAnalysis;
22
using Microsoft.CodeAnalysis.CodeFixes;
3+
using Microsoft.CodeAnalysis.CSharp;
34
using Microsoft.CodeAnalysis.CSharp.Syntax;
45
using Microsoft.CodeAnalysis.Diagnostics;
56
using System.Collections.Generic;
@@ -17,30 +18,63 @@ public class CollectionShouldHaveElementAtAnalyzer : FluentAssertionsAnalyzer
1718
public const string Message = "Use {0} .Should() followed by ### instead.";
1819

1920
protected override DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId, Title, Message, Category, DiagnosticSeverity.Info, true);
21+
protected override IEnumerable<(FluentAssertionsCSharpSyntaxVisitor, BecauseArgumentsSyntaxVisitor)> Visitors
22+
{
23+
get
24+
{
25+
yield return (new ElementAtIndexShouldBeSyntaxVisitor(), new BecauseArgumentsSyntaxVisitor("Be", 1));
26+
yield return (new IndexerShouldBeSyntaxVisitor(), new BecauseArgumentsSyntaxVisitor("Be", 1));
27+
yield return (new SkipFirstShouldBeSyntaxVisitor(), new BecauseArgumentsSyntaxVisitor("Be", 1));
28+
}
29+
}
2030

21-
protected override Diagnostic AnalyzeExpressionStatement(ExpressionStatementSyntax statement)
31+
private class ElementAtIndexShouldBeSyntaxVisitor : FluentAssertionsWithArgumentsCSharpSyntaxVisitor
2232
{
23-
return null;
24-
var visitor = new CollectionShouldHaveElementAtSyntaxVisitor();
25-
statement.Accept(visitor);
33+
protected override bool AreArgumentsValid =>
34+
Arguments.TryGetValue(("ElementAt", 0), out ExpressionSyntax index) && (index is LiteralExpressionSyntax || index is IdentifierNameSyntax)
35+
&& Arguments.TryGetValue(("Be", 0), out ExpressionSyntax expectedItem) && (expectedItem is LiteralExpressionSyntax || expectedItem is IdentifierNameSyntax);
2636

27-
if (visitor.IsValid)
37+
public ElementAtIndexShouldBeSyntaxVisitor() : base("ElementAt", "Should", "Be")
2838
{
29-
var properties = new Dictionary<string, string>
30-
{
31-
[Constants.DiagnosticProperties.VariableName] = visitor.VariableName,
32-
[Constants.DiagnosticProperties.Title] = Title
33-
}.ToImmutableDictionary();
34-
throw new System.NotImplementedException();
39+
}
40+
41+
public override ImmutableDictionary<string, string> ToDiagnosticProperties()
42+
=> base.ToDiagnosticProperties()
43+
.Add(Constants.DiagnosticProperties.ArgumentString, Arguments[("ElementAt", 0)].ToFullString())
44+
.Add(Constants.DiagnosticProperties.ExpectedItemString, Arguments[("Be", 0)].ToFullString());
45+
}
46+
private class IndexerShouldBeSyntaxVisitor : FluentAssertionsWithArgumentsCSharpSyntaxVisitor
47+
{
48+
protected override bool AreArgumentsValid =>
49+
Arguments.TryGetValue(("[]", 0), out ExpressionSyntax index) && (index is LiteralExpressionSyntax || index is IdentifierNameSyntax)
50+
&& Arguments.TryGetValue(("Be", 0), out ExpressionSyntax expectedItem) && (expectedItem is LiteralExpressionSyntax || expectedItem is IdentifierNameSyntax);
3551

36-
return Diagnostic.Create(
37-
descriptor: Rule,
38-
location: statement.Expression.GetLocation(),
39-
properties: properties,
40-
messageArgs: visitor.VariableName);
52+
public IndexerShouldBeSyntaxVisitor() : base("[]", "Should", "Be")
53+
{
4154
}
42-
return null;
55+
public override ImmutableDictionary<string, string> ToDiagnosticProperties()
56+
=> base.ToDiagnosticProperties()
57+
.Add(Constants.DiagnosticProperties.ArgumentString, Arguments[("[]", 0)].ToFullString())
58+
.Add(Constants.DiagnosticProperties.ExpectedItemString, Arguments[("Be", 0)].ToFullString());
4359
}
60+
61+
private class SkipFirstShouldBeSyntaxVisitor : FluentAssertionsWithArgumentsCSharpSyntaxVisitor
62+
{
63+
protected override bool AreArgumentsValid =>
64+
Arguments.TryGetValue(("Skip", 0), out ExpressionSyntax index) && (index is LiteralExpressionSyntax || index is IdentifierNameSyntax)
65+
&& Arguments.TryGetValue(("Be", 0), out ExpressionSyntax expectedItem) && (expectedItem is LiteralExpressionSyntax || expectedItem is IdentifierNameSyntax);
66+
67+
public SkipFirstShouldBeSyntaxVisitor() : base("Skip", "First", "Should", "Be")
68+
{
69+
}
70+
71+
public override ImmutableDictionary<string, string> ToDiagnosticProperties()
72+
=> base.ToDiagnosticProperties()
73+
.Add(Constants.DiagnosticProperties.ArgumentString, Arguments[("Skip", 0)].ToFullString())
74+
.Add(Constants.DiagnosticProperties.ExpectedItemString, Arguments[("Be", 0)].ToFullString());
75+
}
76+
77+
// actual.Skip(k).First().Should().Be(expectedItem{0});
4478
}
4579

4680
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CollectionShouldHaveElementAtCodeFix)), Shared]
@@ -49,16 +83,6 @@ public class CollectionShouldHaveElementAtCodeFix : FluentAssertionsCodeFixProvi
4983
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(CollectionShouldHaveElementAtAnalyzer.DiagnosticId);
5084

5185
protected override StatementSyntax GetNewStatement(FluentAssertionsDiagnosticProperties properties)
52-
{
53-
throw new System.NotImplementedException();
54-
}
55-
}
56-
57-
public class CollectionShouldHaveElementAtSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
58-
{
59-
public CollectionShouldHaveElementAtSyntaxVisitor() : base("###")
60-
{
61-
throw new System.NotImplementedException();
62-
}
86+
=> SyntaxFactory.ParseStatement($"{properties.VariableName}.Should().HaveElementAt({properties.ArgumentString}, {properties.CombineWithBecauseArgumentsString(properties.ExpectedItemString)});");
6387
}
6488
}

src/FluentAssertions.BestPractices/Tips/Collections/CollectionShouldNotContainProperty.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,44 @@ public class CollectionShouldNotContainPropertyAnalyzer : FluentAssertionsAnalyz
2424
{
2525
yield return (new AnyShouldBeFalseSyntaxVisitor(), new BecauseArgumentsSyntaxVisitor("BeFalse", 0));
2626
yield return (new WhereShouldBeEmptySyntaxVisitor(), new BecauseArgumentsSyntaxVisitor("BeEmpty", 0));
27+
yield return (new ShouldOnlyContainNotSyntaxVisitor(), new BecauseArgumentsSyntaxVisitor("OnlyContain", 1));
2728
}
2829
}
2930

3031
private class AnyShouldBeFalseSyntaxVisitor : FluentAssertionsWithLambdaArgumentCSharpSyntaxVisitor
3132
{
32-
protected override string MathodContainingLambda => "Any";
33+
protected override string MethodContainingLambda => "Any";
3334
public AnyShouldBeFalseSyntaxVisitor() : base("Any", "Should", "BeFalse")
3435
{
3536
}
3637
}
3738
private class WhereShouldBeEmptySyntaxVisitor : FluentAssertionsWithLambdaArgumentCSharpSyntaxVisitor
3839
{
39-
protected override string MathodContainingLambda => "Where";
40+
protected override string MethodContainingLambda => "Where";
4041
public WhereShouldBeEmptySyntaxVisitor() : base("Where", "Should", "BeEmpty")
4142
{
4243
}
4344
}
45+
// actual.Should().OnlyContain(e => !e.BooleanProperty{0});
46+
private class ShouldOnlyContainNotSyntaxVisitor : FluentAssertionsWithLambdaArgumentCSharpSyntaxVisitor
47+
{
48+
protected override string MethodContainingLambda => "OnlyContain";
49+
protected override SimpleLambdaExpressionSyntax Lambda => ReverseLambda(base.Lambda);
50+
51+
public ShouldOnlyContainNotSyntaxVisitor() : base("Should", "OnlyContain")
52+
{
53+
}
54+
55+
private SimpleLambdaExpressionSyntax ReverseLambda(SimpleLambdaExpressionSyntax lambda)
56+
{
57+
if (lambda.Body is PrefixUnaryExpressionSyntax prefixUnary && prefixUnary.OperatorToken.IsKind(SyntaxKind.ExclamationToken))
58+
{
59+
return lambda.WithBody(prefixUnary.Operand);
60+
}
61+
62+
return lambda;
63+
}
64+
}
4465
}
4566

4667
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CollectionShouldNotContainPropertyCodeFix)), Shared]

src/FluentAssertions.BestPractices/Tips/Collections/CollectionShouldOnlyContainProperty.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public class CollectionShouldOnlyContainPropertyAnalyzer : FluentAssertionsAnaly
2929

3030
private class AllShouldBeTrueSyntaxVisitor : FluentAssertionsWithLambdaArgumentCSharpSyntaxVisitor
3131
{
32-
protected override string MathodContainingLambda => "All";
32+
protected override string MethodContainingLambda => "All";
3333
public AllShouldBeTrueSyntaxVisitor() : base("All", "Should", "BeTrue")
3434
{
3535
}

0 commit comments

Comments
 (0)