Skip to content

Commit 14bab81

Browse files
authored
feat: support List<>.Count.Should().Be scenario (#314)
* feat: support List<?>.Count.Should.Be() scenario
1 parent 598caee commit 14bab81

File tree

7 files changed

+56
-3
lines changed

7 files changed

+56
-3
lines changed

docs/FluentAssertionsAnalyzer.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ var collection = new List<int>();
4545
// old assertion:
4646
collection.Any().Should().BeFalse();
4747
collection.Count().Should().Be(0);
48+
collection.Count.Should().Be(0);
4849
collection.Should().HaveCount(0);
4950

5051
// new assertion:
@@ -126,6 +127,7 @@ var collection = new List<int> { 1, 2, 3 };
126127

127128
// old assertion:
128129
collection.Count().Should().Be(3);
130+
collection.Count.Should().Be(3);
129131

130132
// new assertion:
131133
collection.Should().HaveCount(3);
@@ -165,6 +167,7 @@ var collection = new List<int> { 1 };
165167

166168
// old assertion:
167169
collection.Count().Should().Be(1);
170+
collection.Count.Should().Be(1);
168171
collection.Should().HaveCount(1);
169172

170173
// new assertion:

src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs/FluentAssertionsAnalyzerTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public void CollectionShouldBeEmpty()
3030
// old assertion:
3131
collection.Any().Should().BeFalse();
3232
collection.Count().Should().Be(0);
33+
collection.Count.Should().Be(0);
3334
collection.Should().HaveCount(0);
3435

3536
// new assertion:
@@ -111,6 +112,7 @@ public void CollectionShouldHaveCount_Count()
111112

112113
// old assertion:
113114
collection.Count().Should().Be(3);
115+
collection.Count.Should().Be(3);
114116

115117
// new assertion:
116118
collection.Should().HaveCount(3);
@@ -150,6 +152,7 @@ public void CollectionShouldContainSingle()
150152

151153
// old assertion:
152154
collection.Count().Should().Be(1);
155+
collection.Count.Should().Be(1);
153156
collection.Should().HaveCount(1);
154157

155158
// new assertion:

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,10 @@ public class CollectionTests
293293
[AssertionDiagnostic("actual.Count().Should().Be(6{0});")]
294294
[AssertionDiagnostic("actual.AsEnumerable().Count().Should().Be(k{0}).And.ToString();")]
295295
[AssertionDiagnostic("actual.AsEnumerable().Count().Should().Be(6{0}).And.ToString();")]
296-
[AssertionDiagnostic("actual.ToList().Count().Should().Be(k{0}).And.ToString();;")]
297-
[AssertionDiagnostic("actual.ToList().Count().Should().Be(6{0}).And.ToString();;")]
296+
[AssertionDiagnostic("actual.ToList().Count().Should().Be(k{0}).And.ToString();")]
297+
[AssertionDiagnostic("actual.ToList().Count().Should().Be(6{0}).And.ToString();")]
298+
[AssertionDiagnostic("actual.ToList().Count.Should().Be(k{0}).And.ToString();")]
299+
[AssertionDiagnostic("actual.ToList().Count.Should().Be(6{0}).And.ToString();")]
298300
[AssertionDiagnostic("actual.ToArray().Count().Should().Be(k{0}).And.ToString();")]
299301
[AssertionDiagnostic("actual.ToArray().Count().Should().Be(6{0}).And.ToString();")]
300302
[Implemented]
@@ -365,6 +367,18 @@ public void CollectionShouldHaveCount_LengthShouldBe_TestNoAnalyzer(string asser
365367
[AssertionCodeFix(
366368
oldAssertion: "actual.Count().Should().Be(6{0});",
367369
newAssertion: "actual.Should().HaveCount(6{0});")]
370+
[AssertionCodeFix(
371+
oldAssertion: "actual.ToList().Count.Should().Be(k{0});",
372+
newAssertion: "actual.ToList().Should().HaveCount(k{0});")]
373+
[AssertionCodeFix(
374+
oldAssertion: "actual.ToList().Count.Should().Be(0{0});",
375+
newAssertion: "actual.ToList().Should().BeEmpty({0});")]
376+
[AssertionCodeFix(
377+
oldAssertion: "actual.ToList().Count.Should().Be(1{0});",
378+
newAssertion: "actual.ToList().Should().ContainSingle({0});")]
379+
[AssertionCodeFix(
380+
oldAssertion: "actual.ToList().Count.Should().Be(6{0});",
381+
newAssertion: "actual.ToList().Should().HaveCount(6{0});")]
368382
[AssertionCodeFix(
369383
oldAssertion: "actual.ToArray().Length.Should().Be(6{0});",
370384
newAssertion: "actual.ToArray().Should().HaveCount(6{0});")]

src/FluentAssertions.Analyzers/Tips/DiagnosticMetadata.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ private DiagnosticMetadata(string message, string helpLink, [CallerMemberName] s
3232
public static DiagnosticMetadata CollectionShouldNotHaveCount_CountShouldNotBe { get; } = new("Use .Should().NotHaveCount()", GetHelpLink("Collections-14"));
3333
public static DiagnosticMetadata CollectionShouldContainSingle_ShouldHaveCount1 { get; } = new("Use .Should().ContainSingle()", GetHelpLink("Collections-15"));
3434
public static DiagnosticMetadata CollectionShouldContainSingle_CountShouldBe1 { get; } = new("Use .Should().ContainSingle()", GetHelpLink("Collections-15"));
35+
public static DiagnosticMetadata CollectionShouldContainSingle_CountPropertyShouldBe1 { get; } = new("Use .Should().ContainSingle()", GetHelpLink("Collections-15"));
3536
public static DiagnosticMetadata CollectionShouldBeEmpty_ShouldHaveCount0 { get; } = new("Use .Should().BeEmpty()", GetHelpLink("Collections-16"));
3637
public static DiagnosticMetadata CollectionShouldBeEmpty_CountShouldBe0 { get; } = new("Use .Should().BeEmpty()", GetHelpLink("Collections-16"));
38+
public static DiagnosticMetadata CollectionShouldBeEmpty_CountPropertyShouldBe0 { get; } = new("Use .Should().BeEmpty()", GetHelpLink("Collections-16"));
3739
public static DiagnosticMetadata CollectionShouldHaveSameCount_ShouldHaveCountOtherCollectionCount { get; } = new("Use .Should().HaveSameCount()", GetHelpLink("Collections-17"));
3840
public static DiagnosticMetadata CollectionShouldNotHaveSameCount_CountShouldNotBeOtherCollectionCount { get; } = new("Use .Should().NotHaveSameCount()", GetHelpLink("Collections-18"));
3941
public static DiagnosticMetadata CollectionShouldContainProperty_WhereShouldNotBeEmpty { get; } = new("Use .Should().Contain()", GetHelpLink("Collections-19"));

src/FluentAssertions.Analyzers/Tips/FluentAssertionsAnalyzer.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System.Linq;
55
using FluentAssertions.Analyzers.Utilities;
66
using Microsoft.CodeAnalysis;
7-
using Microsoft.CodeAnalysis.CSharp.Syntax;
87
using Microsoft.CodeAnalysis.Diagnostics;
98
using Microsoft.CodeAnalysis.Operations;
109

@@ -342,6 +341,20 @@ private static void AnalyzeInvocation(OperationAnalysisContext context, FluentAs
342341
case nameof(string.Length) when propertyBeforeShould.IsContainedInType(SpecialType.System_String):
343342
context.ReportDiagnostic(CreateDiagnostic(assertion, DiagnosticMetadata.StringShouldHaveLength_LengthShouldBe));
344343
return;
344+
case nameof(List<object>.Count) when propertyBeforeShould.ImplementsOrIsInterface(SpecialType.System_Collections_Generic_ICollection_T):
345+
if (assertion.Arguments[0].IsLiteralValue(1))
346+
{
347+
context.ReportDiagnostic(CreateDiagnostic(assertion, DiagnosticMetadata.CollectionShouldContainSingle_CountPropertyShouldBe1));
348+
}
349+
else if (assertion.Arguments[0].IsLiteralValue(0))
350+
{
351+
context.ReportDiagnostic(CreateDiagnostic(assertion, DiagnosticMetadata.CollectionShouldBeEmpty_CountPropertyShouldBe0));
352+
}
353+
else
354+
{
355+
context.ReportDiagnostic(CreateDiagnostic(assertion, DiagnosticMetadata.CollectionShouldHaveCount_CountShouldBe));
356+
}
357+
return;
345358
}
346359
}
347360
if (subject is IPropertyReferenceOperation propertyReference && propertyReference.Property.Name is WellKnownMemberNames.Indexer

src/FluentAssertions.Analyzers/Tips/FluentAssertionsCodeFixProvider.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,18 @@ CreateChangedDocument RemoveMethodBeforeShouldAndRenameAssertionWithoutFirstArgu
7474
]);
7575
}
7676

77+
// oldAssertion: subject.<method>(<argument1>).Should().<assertion>([arg1, arg2, arg3...]);
78+
// oldAssertion: subject.<property>.Should().<assertion>([arg1, arg2, arg3...]);
79+
// newAssertion: subject.Should().<newName>([argument1, arg1, arg2, arg3...]);
80+
CreateChangedDocument RemoveExpressionBeforeShouldAndRenameAssertionWithoutFirstArgumentWithArgumentsFromRemoved(string newName)
81+
{
82+
return RewriteFluentAssertion(assertion, context, [
83+
FluentAssertionsEditAction.RenameAssertion(newName),
84+
FluentAssertionsEditAction.SkipExpressionBeforeShould(),
85+
FluentAssertionsEditAction.RemoveAssertionArgument(index: 0)
86+
]);
87+
}
88+
7789
switch (visitorName)
7890
{
7991
case nameof(DiagnosticMetadata.CollectionShouldBeEmpty_AnyShouldBeFalse):
@@ -121,10 +133,14 @@ CreateChangedDocument RemoveMethodBeforeShouldAndRenameAssertionWithoutFirstArgu
121133
editor.ReplaceNode(context.AssertionExpression.ArgumentList, arguments);
122134
}
123135
]);
136+
case nameof(DiagnosticMetadata.CollectionShouldBeEmpty_CountPropertyShouldBe0):
137+
return RemoveExpressionBeforeShouldAndRenameAssertionWithoutFirstArgumentWithArgumentsFromRemoved("BeEmpty");
124138
case nameof(DiagnosticMetadata.CollectionShouldBeEmpty_CountShouldBe0):
125139
return RemoveMethodBeforeShouldAndRenameAssertionWithoutFirstArgumentWithArgumentsFromRemoved("BeEmpty");
126140
case nameof(DiagnosticMetadata.CollectionShouldContainSingle_CountShouldBe1):
127141
return RemoveMethodBeforeShouldAndRenameAssertionWithoutFirstArgumentWithArgumentsFromRemoved("ContainSingle");
142+
case nameof(DiagnosticMetadata.CollectionShouldContainSingle_CountPropertyShouldBe1):
143+
return RemoveExpressionBeforeShouldAndRenameAssertionWithoutFirstArgumentWithArgumentsFromRemoved("ContainSingle");
128144
case nameof(DiagnosticMetadata.CollectionShouldHaveCount_CountShouldBe):
129145
return RemoveExpressionBeforeShouldAndRenameAssertion("HaveCount");
130146
case nameof(DiagnosticMetadata.CollectionShouldHaveCount_LengthShouldBe):

src/FluentAssertions.Analyzers/Utilities/OperartionExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ public static bool IsContainedInType(this IInvocationOperation invocation, Speci
7373
=> invocation.TargetMethod.ContainingType.ConstructedFromType(type);
7474
public static bool IsContainedInType(this IInvocationOperation invocation, INamedTypeSymbol type)
7575
=> invocation.TargetMethod.ContainingType.ConstructedFromType(type);
76+
public static bool ImplementsOrIsInterface(this IPropertyReferenceOperation property, SpecialType type)
77+
=> property.Property.ContainingType.ImplementsOrIsInterface(type);
7678
public static bool ImplementsOrIsInterface(this IInvocationOperation invocation, SpecialType type)
7779
=> invocation.TargetMethod.ContainingType.ImplementsOrIsInterface(type);
7880
public static bool ImplementsOrIsInterface(this IInvocationOperation invocation, INamedTypeSymbol type)

0 commit comments

Comments
 (0)