Skip to content

Commit cc6dc0d

Browse files
committed
{EnumerableAnalyzer} - even more assertions
1 parent c5c91fe commit cc6dc0d

12 files changed

+141
-183
lines changed

FluentAssertions.BestPractices.sln

Lines changed: 0 additions & 41 deletions
This file was deleted.

build.cake

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,7 @@ Task("Default")
104104
.IsDependentOn("Update-Version")
105105
.IsDependentOn("Build")
106106
.IsDependentOn("Run-Unit-Tests")
107-
.IsDependentOn("Pack")
108-
.IsDependentOn("Publish-NuGet");
107+
.IsDependentOn("Pack");
109108

110109
//////////////////////////////////////////////////////////////////////
111110
// EXECUTION

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

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -259,14 +259,18 @@ public class CollectionTests
259259

260260
[AssertionDataTestMethod]
261261
[AssertionDiagnostic("actual.Should().NotBeNull().And.NotBeEmpty({0});")]
262-
[NotImplemented]
262+
[AssertionDiagnostic("actual.Should().NotBeEmpty().And.NotBeNull({0});")]
263+
[Implemented]
263264
public void CollectionShouldNotBeNullOrEmpty_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<CollectionShouldNotBeNullOrEmptyAnalyzer>(assertion);
264265

265266
[AssertionDataTestMethod]
266267
[AssertionCodeFix(
267-
oldAssertion: "actual.Should().NotBeNull({0}).And.NotBeEmpty({0});",
268-
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
269-
[NotImplemented]
268+
oldAssertion: "actual.Should().NotBeNull().And.NotBeEmpty({0});",
269+
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
270+
[AssertionCodeFix(
271+
oldAssertion: "actual.Should().NotBeEmpty().And.NotBeNull({0});",
272+
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
273+
[Implemented]
270274
public void CollectionShouldNotBeNullOrEmpty_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldNotBeNullOrEmptyCodeFix, CollectionShouldNotBeNullOrEmptyAnalyzer>(oldAssertion, newAssertion);
271275

272276
[AssertionDataTestMethod]
@@ -326,15 +330,15 @@ public class CollectionTests
326330
public void CollectionShouldBeInDescendingOrder_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldBeInDescendingOrderCodeFix, CollectionShouldBeInDescendingOrderAnalyzer>(oldAssertion, newAssertion);
327331

328332
[AssertionDataTestMethod]
329-
[AssertionDiagnostic("actual.Select(e1 => e1.SomeProperty).Should().Equal(expected.Select(e2 => e2.SomeProperty){0});")]
330-
[NotImplemented]
333+
[AssertionDiagnostic("actual.Select(e1 => e1.BooleanProperty).Should().Equal(expected.Select(e2 => e2.BooleanProperty){0});")]
334+
[Implemented]
331335
public void CollectionShouldEqualOtherCollectionByComparer_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<CollectionShouldEqualOtherCollectionByComparerAnalyzer>(assertion);
332336

333337
[AssertionDataTestMethod]
334338
[AssertionCodeFix(
335-
oldAssertion: "actual.Select(e1 => e1.SomeProperty).Should().Equal(expected.Select(e2 => e2.SomeProperty){0});",
336-
newAssertion: "actual.Should().Equal(expected, (e1, e2) => e1.SomeProperty == e2.SomeProperty{0});")]
337-
[NotImplemented]
339+
oldAssertion: "actual.Select(e1 => e1.BooleanProperty).Should().Equal(expected.Select(e2 => e2.BooleanProperty){0});",
340+
newAssertion: "actual.Should().Equal(expected, (e1, e2) => e1.BooleanProperty == e2.BooleanProperty{0});")]
341+
[Implemented]
338342
public void CollectionShouldEqualOtherCollectionByComparer_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldEqualOtherCollectionByComparerCodeFix, CollectionShouldEqualOtherCollectionByComparerAnalyzer>(oldAssertion, newAssertion);
339343

340344
[AssertionDataTestMethod]
@@ -344,8 +348,8 @@ public class CollectionTests
344348

345349
[AssertionDataTestMethod]
346350
[AssertionCodeFix(
347-
oldAssertion: "actual.Intersect(expected).Should().BeEmpty({0});",
348-
newAssertion: "actual.Should().NotIntersectWith(expected{0});")]
351+
oldAssertion: "actual.Intersect(expected).Should().BeEmpty({0});",
352+
newAssertion: "actual.Should().NotIntersectWith(expected{0});")]
349353
[Implemented]
350354
public void CollectionShouldNotIntersectWith_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldNotIntersectWithCodeFix, CollectionShouldNotIntersectWithAnalyzer>(oldAssertion, newAssertion);
351355

@@ -376,37 +380,41 @@ public class CollectionTests
376380

377381
[AssertionDataTestMethod]
378382
[AssertionDiagnostic("actual.Should().HaveSameCount(actual.Distinct(){0});")]
379-
[NotImplemented]
383+
[Implemented]
380384
public void CollectionShouldOnlyHaveUniqueItems_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<CollectionShouldOnlyHaveUniqueItemsAnalyzer>(assertion);
381385

382386
[AssertionDataTestMethod]
383387
[AssertionCodeFix(
384388
oldAssertion: "actual.Should().HaveSameCount(actual.Distinct(){0});",
385389
newAssertion: "actual.Should().OnlyHaveUniqueItems({0});")]
386-
[NotImplemented]
390+
[Implemented]
387391
public void CollectionShouldOnlyHaveUniqueItems_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldOnlyHaveUniqueItemsCodeFix, CollectionShouldOnlyHaveUniqueItemsAnalyzer>(oldAssertion, newAssertion);
388392

389393
[AssertionDataTestMethod]
390394
[AssertionDiagnostic("actual.Select(x => x.BooleanProperty).Should().OnlyHaveUniqueItems({0});")]
391-
[NotImplemented]
395+
[Implemented]
392396
public void CollectionShouldOnlyHaveUniqueItemsByComparer_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<CollectionShouldOnlyHaveUniqueItemsByComparerAnalyzer>(assertion);
393397

394398
[AssertionDataTestMethod]
395399
[AssertionCodeFix(
396400
oldAssertion: "actual.Select(x => x.BooleanProperty).Should().OnlyHaveUniqueItems({0});",
397401
newAssertion: "actual.Should().OnlyHaveUniqueItems(x => x.BooleanProperty{0});")]
398-
[NotImplemented]
402+
[Implemented]
403+
[Ignore("Will be available in Fluent Assertions 5.0")]
399404
public void CollectionShouldOnlyHaveUniqueItemsByComparer_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldOnlyHaveUniqueItemsByComparerCodeFix, CollectionShouldOnlyHaveUniqueItemsByComparerAnalyzer>(oldAssertion, newAssertion);
405+
400406
[AssertionDataTestMethod]
401407
[AssertionDiagnostic("actual.FirstOrDefault().Should().BeNull({0});")]
402408
[NotImplemented]
409+
[Ignore("What Should Happen?")]
403410
public void CollectionShouldHaveElementAt0Null_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<CollectionShouldHaveElementAt0NullAnalyzer>(assertion);
404411

405412
[AssertionDataTestMethod]
406413
[AssertionCodeFix(
407414
oldAssertion: "actual.FirstOrDefault().Should().BeNull({0});",
408415
newAssertion: "actual.Should().HaveElementAt(0, null{0});")]
409416
[NotImplemented]
417+
[Ignore("What Should Happen?")]
410418
public void CollectionShouldHaveElementAt0Null_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<CollectionShouldHaveElementAt0NullCodeFix, CollectionShouldHaveElementAt0NullAnalyzer>(oldAssertion, newAssertion);
411419

412420
private void VerifyCSharpDiagnostic<TDiagnosticAnalyzer>(string sourceAssersion) where TDiagnosticAnalyzer : Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer, new()

src/FluentAssertions.BestPractices/FluentAssertions.BestPractices.nuspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<metadata>
44
<id>FluentAssertions.BestPractices</id>
55
<title>Fluent Assertions Best Practice</title>
6-
<version>0.2.1</version>
6+
<version>0.3.0</version>
77
<owners>Meir Blachman</owners>
88
<authors>Meir Blachman</authors>
99
<summary>
Lines changed: 49 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;
@@ -14,32 +15,62 @@ public class CollectionShouldEqualOtherCollectionByComparerAnalyzer : FluentAsse
1415
public const string DiagnosticId = Constants.Tips.Collections.CollectionShouldEqualOtherCollectionByComparer;
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 .Equal() instead.";
1819

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

21-
protected override Diagnostic AnalyzeExpressionStatement(ExpressionStatementSyntax statement)
22+
protected override IEnumerable<(FluentAssertionsCSharpSyntaxVisitor, BecauseArgumentsSyntaxVisitor)> Visitors
2223
{
23-
return null;
24-
var visitor = new CollectionShouldEqualOtherCollectionByComparerSyntaxVisitor();
25-
statement.Accept(visitor);
24+
get
25+
{
26+
yield return (new SelectShouldEqualOtherCollectionSelectSyntaxVisitor(), new BecauseArgumentsSyntaxVisitor("Equal", 1));
27+
}
28+
}
29+
30+
private class SelectShouldEqualOtherCollectionSelectSyntaxVisitor : FluentAssertionsWithArgumentsCSharpSyntaxVisitor
31+
{
32+
private ExpressionSyntax _lambdaArgument;
33+
private string _otherVariable;
2634

27-
if (visitor.IsValid)
35+
protected override bool AreArgumentsValid()
2836
{
29-
var properties = new Dictionary<string, string>
37+
if (Arguments.TryGetValue(("Select", 0), out var selectArgument) && selectArgument is SimpleLambdaExpressionSyntax select
38+
&& Arguments.TryGetValue(("Equal", 0), out var expectedArgument) && expectedArgument is InvocationExpressionSyntax expected)
3039
{
31-
[Constants.DiagnosticProperties.VariableName] = visitor.VariableName,
32-
[Constants.DiagnosticProperties.Title] = Title
33-
}.ToImmutableDictionary();
34-
throw new System.NotImplementedException();
40+
var visitor = new SelectSyntaxVisitor();
41+
expected.Accept(visitor);
42+
43+
if (visitor.IsValid)
44+
{
45+
_otherVariable = visitor.VariableName;
46+
_lambdaArgument = SyntaxFactory.ParenthesizedLambdaExpression(
47+
parameterList: SyntaxFactory.ParameterList().AddParameters(select.Parameter, visitor.Lambda.Parameter),
48+
body: SyntaxFactory.BinaryExpression(SyntaxKind.EqualsExpression,
49+
left: (ExpressionSyntax)select.Body,
50+
right: (ExpressionSyntax)visitor.Lambda.Body)
51+
).NormalizeWhitespace();
52+
return true;
53+
}
54+
}
55+
return false;
56+
}
57+
58+
public SelectShouldEqualOtherCollectionSelectSyntaxVisitor() : base("Select", "Should", "Equal")
59+
{
60+
}
3561

36-
return Diagnostic.Create(
37-
descriptor: Rule,
38-
location: statement.Expression.GetLocation(),
39-
properties: properties,
40-
messageArgs: visitor.VariableName);
62+
public override ImmutableDictionary<string, string> ToDiagnosticProperties() => base.ToDiagnosticProperties()
63+
.Add(Constants.DiagnosticProperties.LambdaString, _lambdaArgument.ToFullString())
64+
.Add(Constants.DiagnosticProperties.ArgumentString, _otherVariable);
65+
66+
67+
private class SelectSyntaxVisitor : FluentAssertionsWithLambdaArgumentCSharpSyntaxVisitor
68+
{
69+
protected override string MethodContainingLambda => "Select";
70+
public SelectSyntaxVisitor() : base("Select")
71+
{
72+
}
4173
}
42-
return null;
4374
}
4475
}
4576

@@ -49,16 +80,6 @@ public class CollectionShouldEqualOtherCollectionByComparerCodeFix : FluentAsser
4980
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(CollectionShouldEqualOtherCollectionByComparerAnalyzer.DiagnosticId);
5081

5182
protected override StatementSyntax GetNewStatement(FluentAssertionsDiagnosticProperties properties)
52-
{
53-
throw new System.NotImplementedException();
54-
}
55-
}
56-
57-
public class CollectionShouldEqualOtherCollectionByComparerSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
58-
{
59-
public CollectionShouldEqualOtherCollectionByComparerSyntaxVisitor() : base("###")
60-
{
61-
throw new System.NotImplementedException();
62-
}
83+
=> SyntaxFactory.ParseStatement($"{properties.VariableName}.Should().Equal({properties.ArgumentString}, {properties.CombineWithBecauseArgumentsString(properties.LambdaString)});");
6384
}
6485
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class CollectionShouldHaveElementAtAnalyzer : FluentAssertionsAnalyzer
3030

3131
private class ElementAtIndexShouldBeSyntaxVisitor : FluentAssertionsWithArgumentsCSharpSyntaxVisitor
3232
{
33-
protected override bool AreArgumentsValid =>
33+
protected override bool AreArgumentsValid() =>
3434
Arguments.TryGetValue(("ElementAt", 0), out ExpressionSyntax index) && (index is LiteralExpressionSyntax || index is IdentifierNameSyntax)
3535
&& Arguments.TryGetValue(("Be", 0), out ExpressionSyntax expectedItem) && (expectedItem is LiteralExpressionSyntax || expectedItem is IdentifierNameSyntax);
3636

@@ -45,7 +45,7 @@ public override ImmutableDictionary<string, string> ToDiagnosticProperties()
4545
}
4646
private class IndexerShouldBeSyntaxVisitor : FluentAssertionsWithArgumentsCSharpSyntaxVisitor
4747
{
48-
protected override bool AreArgumentsValid =>
48+
protected override bool AreArgumentsValid() =>
4949
Arguments.TryGetValue(("[]", 0), out ExpressionSyntax index) && (index is LiteralExpressionSyntax || index is IdentifierNameSyntax)
5050
&& Arguments.TryGetValue(("Be", 0), out ExpressionSyntax expectedItem) && (expectedItem is LiteralExpressionSyntax || expectedItem is IdentifierNameSyntax);
5151

@@ -60,7 +60,7 @@ public override ImmutableDictionary<string, string> ToDiagnosticProperties()
6060

6161
private class SkipFirstShouldBeSyntaxVisitor : FluentAssertionsWithArgumentsCSharpSyntaxVisitor
6262
{
63-
protected override bool AreArgumentsValid =>
63+
protected override bool AreArgumentsValid() =>
6464
Arguments.TryGetValue(("Skip", 0), out ExpressionSyntax index) && (index is LiteralExpressionSyntax || index is IdentifierNameSyntax)
6565
&& Arguments.TryGetValue(("Be", 0), out ExpressionSyntax expectedItem) && (expectedItem is LiteralExpressionSyntax || expectedItem is IdentifierNameSyntax);
6666

Lines changed: 18 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;
@@ -18,28 +19,26 @@ public class CollectionShouldNotBeNullOrEmptyAnalyzer : FluentAssertionsAnalyzer
1819

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

21-
protected override Diagnostic AnalyzeExpressionStatement(ExpressionStatementSyntax statement)
22+
protected override IEnumerable<(FluentAssertionsCSharpSyntaxVisitor, BecauseArgumentsSyntaxVisitor)> Visitors
2223
{
23-
return null;
24-
var visitor = new CollectionShouldNotBeNullOrEmptySyntaxVisitor();
25-
statement.Accept(visitor);
26-
27-
if (visitor.IsValid)
24+
get
2825
{
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();
26+
yield return (new ShouldNotBeNullAndNotBeEmptySyntaxVisitor(), new BecauseArgumentsSyntaxVisitor("NotBeEmpty", 0));
27+
yield return (new ShouldNotBeEmptyAndNotBeNullSyntaxVisitor(), new BecauseArgumentsSyntaxVisitor("NotBeNull", 0));
28+
}
29+
}
3530

36-
return Diagnostic.Create(
37-
descriptor: Rule,
38-
location: statement.Expression.GetLocation(),
39-
properties: properties,
40-
messageArgs: visitor.VariableName);
31+
private class ShouldNotBeNullAndNotBeEmptySyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
32+
{
33+
public ShouldNotBeNullAndNotBeEmptySyntaxVisitor() : base("Should", "NotBeNull", "And", "NotBeEmpty")
34+
{
35+
}
36+
}
37+
private class ShouldNotBeEmptyAndNotBeNullSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
38+
{
39+
public ShouldNotBeEmptyAndNotBeNullSyntaxVisitor() : base("Should", "NotBeEmpty", "And", "NotBeNull")
40+
{
4141
}
42-
return null;
4342
}
4443
}
4544

@@ -49,16 +48,6 @@ public class CollectionShouldNotBeNullOrEmptyCodeFix : FluentAssertionsCodeFixPr
4948
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(CollectionShouldNotBeNullOrEmptyAnalyzer.DiagnosticId);
5049

5150
protected override StatementSyntax GetNewStatement(FluentAssertionsDiagnosticProperties properties)
52-
{
53-
throw new System.NotImplementedException();
54-
}
55-
}
56-
57-
public class CollectionShouldNotBeNullOrEmptySyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
58-
{
59-
public CollectionShouldNotBeNullOrEmptySyntaxVisitor() : base("###")
60-
{
61-
throw new System.NotImplementedException();
62-
}
51+
=> SyntaxFactory.ParseStatement($"{properties.VariableName}.Should().NotBeNullOrEmpty({properties.BecauseArgumentsString});");
6352
}
6453
}

0 commit comments

Comments
 (0)