Skip to content

Commit f62d097

Browse files
committed
{EnumerableAnalyzer} - added more assertions
1 parent e5691f7 commit f62d097

File tree

7 files changed

+77
-82
lines changed

7 files changed

+77
-82
lines changed

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

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,17 @@ public class CollectionTests
5555

5656
[AssertionDataTestMethod]
5757
[AssertionDiagnostic("actual.Any(x => x.BooleanProperty).Should().BeFalse({0});")]
58+
[AssertionDiagnostic("actual.Where(x => x.BooleanProperty).Should().BeEmpty({0});")]
5859
[Implemented]
5960
public void CollectionShouldNotContainProperty_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<CollectionShouldNotContainPropertyAnalyzer>(assertion);
6061

6162
[AssertionDataTestMethod]
6263
[AssertionCodeFix(
6364
oldAssertion: "actual.Any(x => x.BooleanProperty).Should().BeFalse({0});",
6465
newAssertion: "actual.Should().NotContain(x => x.BooleanProperty{0});")]
66+
[AssertionCodeFix(
67+
oldAssertion: "actual.Where(x => x.BooleanProperty).Should().BeEmpty({0});",
68+
newAssertion: "actual.Should().NotContain(x => x.BooleanProperty{0});")]
6569
[Implemented]
6670
public void CollectionShouldNotContainProperty_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldNotContainPropertyCodeFix, CollectionShouldNotContainPropertyAnalyzer>(oldAssertion, newAssertion);
6771

@@ -227,38 +231,27 @@ public class CollectionTests
227231

228232
[AssertionDataTestMethod]
229233
[AssertionDiagnostic("actual.Count().Should().NotBe(unexpected.Count(){0});")]
230-
[NotImplemented]
234+
[Implemented]
231235
public void CollectionShouldNotHaveSameCount_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<CollectionShouldNotHaveSameCountAnalyzer>(assertion);
232236

233237
[AssertionDataTestMethod]
234238
[AssertionCodeFix(
235239
oldAssertion: "actual.Count().Should().NotBe(unexpected.Count(){0});",
236240
newAssertion: "actual.Should().NotHaveSameCount(unexpected{0});")]
237-
[NotImplemented]
241+
[Implemented]
242+
[Ignore("Will be available in Fluent Assertions 5.0")]
238243
public void CollectionShouldNotHaveSameCount_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldNotHaveSameCountCodeFix, CollectionShouldNotHaveSameCountAnalyzer>(oldAssertion, newAssertion);
239-
240-
[AssertionDataTestMethod]
241-
[AssertionDiagnostic("actual.Where(x => x.BooleanProperty).Should().BeEmpty({0});")]
242-
[NotImplemented]
243-
public void CollectionShouldNotContainProperty_TestAnalyzer02(string assertion) => VerifyCSharpDiagnostic<CollectionShouldNotContainPropertyAnalyzer>(assertion);
244-
245-
[AssertionDataTestMethod]
246-
[AssertionCodeFix(
247-
oldAssertion: "actual.Where(x => x.BooleanProperty).Should().BeEmpty({0});",
248-
newAssertion: "actual.Should().NotContain(x => x.BooleanProperty{0});")]
249-
[NotImplemented]
250-
public void CollectionShouldNotContainProperty_TestCodeFix02(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldNotContainPropertyCodeFix, CollectionShouldNotContainPropertyAnalyzer>(oldAssertion, newAssertion);
251-
244+
252245
[AssertionDataTestMethod]
253246
[AssertionDiagnostic("actual.Where(x => x.BooleanProperty).Should().HaveCount(1{0});")]
254-
[NotImplemented]
247+
[Implemented]
255248
public void CollectionShouldContainSingleProperty_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<CollectionShouldContainSinglePropertyAnalyzer>(assertion);
256249

257250
[AssertionDataTestMethod]
258251
[AssertionCodeFix(
259-
oldAssertion: "actual.Where(x => x.BooleanProperty).Should().HaveCount(1{0});",
260-
newAssertion: "actual.Should().ContainSingle(x => x.BooleanProperty{0});")]
261-
[NotImplemented]
252+
oldAssertion: "actual.Where(x => x.BooleanProperty).Should().HaveCount(1{0});",
253+
newAssertion: "actual.Should().ContainSingle(x => x.BooleanProperty{0});")]
254+
[Implemented]
262255
public void CollectionShouldContainSingleProperty_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldContainSinglePropertyCodeFix, CollectionShouldContainSinglePropertyAnalyzer>(oldAssertion, newAssertion);
263256

264257
[AssertionDataTestMethod]
Lines changed: 25 additions & 29 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,29 +18,34 @@ public class CollectionShouldContainSinglePropertyAnalyzer : FluentAssertionsAna
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);
20-
21-
protected override Diagnostic AnalyzeExpressionStatement(ExpressionStatementSyntax statement)
21+
protected override IEnumerable<(FluentAssertionsCSharpSyntaxVisitor, BecauseArgumentsSyntaxVisitor)> Visitors
2222
{
23-
return null;
24-
var visitor = new CollectionShouldContainSinglePropertySyntaxVisitor();
25-
statement.Accept(visitor);
23+
get
24+
{
25+
yield return (new WhereShouldHaveCount1SyntaxVisitor(), new BecauseArgumentsSyntaxVisitor("HaveCount", 1));
26+
}
27+
}
28+
// actual.Where(x => x.BooleanProperty).Should().HaveCount(1{0});
29+
private class WhereShouldHaveCount1SyntaxVisitor : FluentAssertionsWithLambdaArgumentCSharpSyntaxVisitor
30+
{
31+
private bool _haveCountMethodHas1Argument;
32+
33+
protected override string MathodContainingLambda => "Where";
34+
public override bool IsValid => base.IsValid && _haveCountMethodHas1Argument;
35+
public WhereShouldHaveCount1SyntaxVisitor() : base("Where", "Should", "HaveCount")
36+
{
37+
}
2638

27-
if (visitor.IsValid)
39+
public override void VisitArgumentList(ArgumentListSyntax node)
2840
{
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();
41+
if (!node.Arguments.Any()) return;
42+
if (CurrentMethod != "HaveCount") base.VisitArgumentList(node); ;
3543

36-
return Diagnostic.Create(
37-
descriptor: Rule,
38-
location: statement.Expression.GetLocation(),
39-
properties: properties,
40-
messageArgs: visitor.VariableName);
44+
_haveCountMethodHas1Argument =
45+
node.Arguments[0].Expression is LiteralExpressionSyntax literal
46+
&& literal.Token.Value is int argument
47+
&& argument == 1;
4148
}
42-
return null;
4349
}
4450
}
4551

@@ -49,16 +55,6 @@ public class CollectionShouldContainSinglePropertyCodeFix : FluentAssertionsCode
4955
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(CollectionShouldContainSinglePropertyAnalyzer.DiagnosticId);
5056

5157
protected override StatementSyntax GetNewStatement(FluentAssertionsDiagnosticProperties properties)
52-
{
53-
throw new System.NotImplementedException();
54-
}
55-
}
56-
57-
public class CollectionShouldContainSinglePropertySyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
58-
{
59-
public CollectionShouldContainSinglePropertySyntaxVisitor() : base("###")
60-
{
61-
throw new System.NotImplementedException();
62-
}
58+
=> SyntaxFactory.ParseStatement($"{properties.VariableName}.Should().ContainSingle({properties.CombineWithBecauseArgumentsString(properties.PredicateString)});");
6359
}
6460
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Microsoft.CodeAnalysis.CSharp;
44
using Microsoft.CodeAnalysis.CSharp.Syntax;
55
using Microsoft.CodeAnalysis.Diagnostics;
6+
using System.Collections.Generic;
67
using System.Collections.Immutable;
78
using System.Composition;
89

@@ -17,7 +18,7 @@ public class CollectionShouldHaveSameCountAnalyzer : FluentAssertionsAnalyzer
1718
public const string Message = "Use {0} .Should() followed by HaveSameCount() instead.";
1819

1920
protected override DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId, Title, Message, Category, DiagnosticSeverity.Info, true);
20-
protected override System.Collections.Generic.IEnumerable<(FluentAssertionsCSharpSyntaxVisitor, BecauseArgumentsSyntaxVisitor)> Visitors
21+
protected override IEnumerable<(FluentAssertionsCSharpSyntaxVisitor, BecauseArgumentsSyntaxVisitor)> Visitors
2122
{
2223
get
2324
{
@@ -42,7 +43,7 @@ protected override ExpressionSyntax ModifyArgument(ExpressionSyntax expression)
4243
}
4344
}
4445
}
45-
46+
4647
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CollectionShouldHaveSameCountCodeFix)), Shared]
4748
public class CollectionShouldHaveSameCountCodeFix : FluentAssertionsCodeFixProvider
4849
{

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class CollectionShouldNotContainPropertyAnalyzer : FluentAssertionsAnalyz
2323
get
2424
{
2525
yield return (new AnyShouldBeFalseSyntaxVisitor(), new BecauseArgumentsSyntaxVisitor("BeFalse", 0));
26+
yield return (new WhereShouldBeEmptySyntaxVisitor(), new BecauseArgumentsSyntaxVisitor("BeEmpty", 0));
2627
}
2728
}
2829

@@ -33,6 +34,13 @@ public AnyShouldBeFalseSyntaxVisitor() : base("Any", "Should", "BeFalse")
3334
{
3435
}
3536
}
37+
private class WhereShouldBeEmptySyntaxVisitor : FluentAssertionsWithLambdaArgumentCSharpSyntaxVisitor
38+
{
39+
protected override string MathodContainingLambda => "Where";
40+
public WhereShouldBeEmptySyntaxVisitor() : base("Where", "Should", "BeEmpty")
41+
{
42+
}
43+
}
3644
}
3745

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

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public class CollectionShouldNotHaveCountAnalyzer : FluentAssertionsAnalyzer
1515
public const string DiagnosticId = Constants.Tips.Collections.CollectionShouldNotHaveCount;
1616
public const string Category = Constants.Tips.Category;
1717

18-
public const string Message = "Use {0} .Should() followed by NotHaveCount instead.";
18+
public const string Message = "Use {0} .Should() followed by .NotHaveCount() instead.";
1919

2020
protected override DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId, Title, Message, Category, DiagnosticSeverity.Info, true);
2121
protected override IEnumerable<(FluentAssertionsCSharpSyntaxVisitor, BecauseArgumentsSyntaxVisitor)> Visitors
@@ -32,6 +32,13 @@ private class CountShouldNotBeSyntaxVisitor : FluentAssertionsWithArgumentCSharp
3232
public CountShouldNotBeSyntaxVisitor() : base("Count", "Should", "NotBe")
3333
{
3434
}
35+
36+
protected override ExpressionSyntax ModifyArgument(ExpressionSyntax expression)
37+
{
38+
if (expression is IdentifierNameSyntax identifier) return identifier;
39+
if (expression is LiteralExpressionSyntax literal) return literal;
40+
return null;
41+
}
3542
}
3643
}
3744

Lines changed: 20 additions & 30 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;
@@ -14,32 +15,31 @@ public class CollectionShouldNotHaveSameCountAnalyzer : FluentAssertionsAnalyzer
1415
public const string DiagnosticId = Constants.Tips.Collections.CollectionShouldNotHaveSameCount;
1516
public const string Category = Constants.Tips.Category;
1617

17-
public const string Message = "Use {0} .Should() followed by ### instead.";
18+
public const string Message = "Use {0} .Should() followed by .NotHaveSameCount() instead.";
1819

1920
protected override DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId, Title, Message, Category, DiagnosticSeverity.Info, true);
20-
21-
protected override Diagnostic AnalyzeExpressionStatement(ExpressionStatementSyntax statement)
21+
protected override IEnumerable<(FluentAssertionsCSharpSyntaxVisitor, BecauseArgumentsSyntaxVisitor)> Visitors
2222
{
23-
return null;
24-
var visitor = new CollectionShouldNotHaveSameCountSyntaxVisitor();
25-
statement.Accept(visitor);
23+
get
24+
{
25+
yield return (new CountShouldNotBeOtherCollectionCountSyntaxVisitor(), new BecauseArgumentsSyntaxVisitor("NotBe", 1));
26+
}
27+
}
28+
private class CountShouldNotBeOtherCollectionCountSyntaxVisitor : FluentAssertionsWithArgumentCSharpSyntaxVisitor
29+
{
30+
protected override string MethodContainingArgument => "NotBe";
31+
public CountShouldNotBeOtherCollectionCountSyntaxVisitor() : base("Count", "Should", "NotBe")
32+
{
33+
}
2634

27-
if (visitor.IsValid)
35+
protected override ExpressionSyntax ModifyArgument(ExpressionSyntax expression)
2836
{
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();
37+
var invocation = expression as InvocationExpressionSyntax;
38+
var memberAccess = invocation?.Expression as MemberAccessExpressionSyntax;
39+
var identifier = memberAccess?.Expression as IdentifierNameSyntax;
3540

36-
return Diagnostic.Create(
37-
descriptor: Rule,
38-
location: statement.Expression.GetLocation(),
39-
properties: properties,
40-
messageArgs: visitor.VariableName);
41+
return identifier;
4142
}
42-
return null;
4343
}
4444
}
4545

@@ -49,16 +49,6 @@ public class CollectionShouldNotHaveSameCountCodeFix : FluentAssertionsCodeFixPr
4949
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(CollectionShouldNotHaveSameCountAnalyzer.DiagnosticId);
5050

5151
protected override StatementSyntax GetNewStatement(FluentAssertionsDiagnosticProperties properties)
52-
{
53-
throw new System.NotImplementedException();
54-
}
55-
}
56-
57-
public class CollectionShouldNotHaveSameCountSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
58-
{
59-
public CollectionShouldNotHaveSameCountSyntaxVisitor() : base("###")
60-
{
61-
throw new System.NotImplementedException();
62-
}
52+
=> SyntaxFactory.ParseStatement($"{properties.VariableName}.Should().NotHaveSameCount({properties.CombineWithBecauseArgumentsString(properties.ArgumentString)});");
6353
}
6454
}

src/FluentAssertions.BestPractices/Utilities/FluentAssertionsCSharpSyntaxVisitor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public sealed override void VisitMemberAccessExpression(MemberAccessExpressionSy
5959
{
6060
Visit(node.Expression);
6161
}
62-
else if (methodName.Equals(RequiredMethods.Pop()))
62+
else if (RequiredMethods.Count > 0 && methodName.Equals(RequiredMethods.Pop()))
6363
{
6464
EncounteredFirstMethod = true;
6565
Visit(node.Expression);

0 commit comments

Comments
 (0)