Skip to content

Commit 8c1b012

Browse files
authored
feat: improve TryGetFirstDescendent logic - p1 (#386)
* feat: improve TryGetFirstDescendent logic - p1
1 parent 4d7c385 commit 8c1b012

File tree

3 files changed

+56
-9
lines changed

3 files changed

+56
-9
lines changed

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

+38-3
Original file line numberDiff line numberDiff line change
@@ -318,9 +318,30 @@ public class CollectionTests
318318
public void CollectionShouldHaveCount_CountShouldBe1_TestAnalyzer(string assertion) => VerifyCSharpDiagnosticCodeBlock(assertion, DiagnosticMetadata.CollectionShouldContainSingle_CountShouldBe1);
319319

320320
[DataTestMethod]
321-
[AssertionDiagnostic("actual.ToArray().Length.Should().Be(1{0}).And.ToString();")]
322-
[Implemented]
323-
public void CollectionShouldHaveCount_LengthShouldBe_TestAnalyzer(string assertion) => VerifyCSharpDiagnosticCodeBlock(assertion, DiagnosticMetadata.CollectionShouldHaveCount_LengthShouldBe);
321+
[AssertionDiagnostic("(array.Count() + 1).Should().Be(0{0}).And.ToString();")]
322+
[AssertionDiagnostic("(array.Count() + 1).Should().Be(1{0}).And.ToString();")]
323+
[AssertionDiagnostic("(array.Count() + 1).Should().Be(expectedSize{0}).And.ToString();")]
324+
[AssertionDiagnostic("(list.Count + 1).Should().Be(0{0}).And.ToString();")]
325+
[AssertionDiagnostic("(list.Count + 1).Should().Be(1{0}).And.ToString();")]
326+
[AssertionDiagnostic("(list.Count + 1).Should().Be(expectedSize{0}).And.ToString();")]
327+
[Implemented]
328+
public void CollectionShouldHaveCount_CountShouldBe_TestNoAnalyzer(string assertion) => DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(new StringBuilder()
329+
.AppendLine("using System;")
330+
.AppendLine("using System.Collections.Generic;")
331+
.AppendLine("using System.Linq;")
332+
.AppendLine("using FluentAssertions;")
333+
.AppendLine("using FluentAssertions.Extensions;")
334+
.AppendLine("namespace TestNamespace")
335+
.AppendLine("{")
336+
.AppendLine(" public class TestClass")
337+
.AppendLine(" {")
338+
.AppendLine(" public void TestMethod(string[] array, List<string> list, int expectedSize)")
339+
.AppendLine(" {")
340+
.AppendLine(assertion)
341+
.AppendLine(" }")
342+
.AppendLine(" }")
343+
.AppendLine("}")
344+
.ToString());
324345

325346
[DataTestMethod]
326347
[AssertionDiagnostic(@"var array = new string[0, 0]; array.Length.Should().Be(0{0});")]
@@ -610,6 +631,12 @@ public void CollectionShouldHaveCount_LengthShouldBe_TestNoAnalyzer(string asser
610631
[Implemented]
611632
public void CollectionShouldNotHaveSameCount_TestAnalyzer(string assertion) => VerifyCSharpDiagnosticCodeBlock(assertion, DiagnosticMetadata.CollectionShouldNotHaveSameCount_CountShouldNotBeOtherCollectionCount);
612633

634+
[DataTestMethod]
635+
[AssertionDiagnostic("(actual.Count() + 1).Should().NotBe(unexpected.Count(){0});")]
636+
[AssertionDiagnostic("actual.Count().ToString().Length.Should().NotBe(unexpected.Count(){0});")]
637+
[Implemented]
638+
public void CollectionShouldNotHaveSameCount_TestNotAnalyzer(string assertion) => DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(GenerateCode.GenericIListCodeBlockAssertion(assertion));
639+
613640
[DataTestMethod]
614641
[AssertionCodeFix(
615642
oldAssertion: "actual.Count().Should().NotBe(unexpected.Count(){0});",
@@ -742,6 +769,14 @@ public void CollectionShouldContainSingle_TestAnalyzer_GenericIEnumerableShouldR
742769
[Implemented]
743770
public void CollectionShouldHaveElementAt_ElementAtIndexShouldBe_TestAnalyzer(string assertion) => VerifyCSharpDiagnosticCodeBlock(assertion, DiagnosticMetadata.CollectionShouldHaveElementAt_ElementAtIndexShouldBe);
744771

772+
[DataTestMethod]
773+
[AssertionDiagnostic("actual.ElementAt(k).BooleanProperty.Should().Be(expectedItem.BooleanProperty{0});")]
774+
[AssertionDiagnostic("actual.ElementAt(6).BooleanProperty.Should().Be(expectedItem.BooleanProperty{0});")]
775+
[AssertionDiagnostic("actual.AsEnumerable().ElementAt(k).BooleanProperty.Should().Be(expectedItem.BooleanProperty{0}).And.ToString();")]
776+
[AssertionDiagnostic("actual.AsEnumerable().ElementAt(6).BooleanProperty.Should().Be(expectedItem.BooleanProperty{0}).And.ToString();")]
777+
[Implemented]
778+
public void CollectionShouldHaveElementAt_ElementAtIndexShouldBe_TestNoAnalyzer(string assertion) => DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(GenerateCode.GenericIListCodeBlockAssertion(assertion));
779+
745780
[DataTestMethod]
746781
[AssertionDiagnostic("actual[k].Should().Be(expectedItem{0});")]
747782
[AssertionDiagnostic("actual[6].Should().Be(expectedItem{0});")]

src/FluentAssertions.Analyzers/Tips/FluentAssertionsAnalyzer.cs

+6-6
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ private static void AnalyzeInvocation(OperationAnalysisContext context, FluentAs
301301
return;
302302
case "OnlyHaveUniqueItems" when assertion.IsContainedInType(metadata.GenericCollectionAssertionsOfT3):
303303
{
304-
if (!invocation.TryGetFirstDescendent<IInvocationOperation>(out var invocationBeforeShould)) return;
304+
if (!invocation.TryGetSingleArgumentAs<IInvocationOperation>(out var invocationBeforeShould)) return;
305305
switch (invocationBeforeShould.TargetMethod.Name)
306306
{
307307
case nameof(Enumerable.Select) when IsEnumerableMethodWithPredicate(invocationBeforeShould, metadata):
@@ -312,7 +312,7 @@ private static void AnalyzeInvocation(OperationAnalysisContext context, FluentAs
312312
return;
313313
case "Be" when assertion.IsContainedInType(metadata.NumericAssertionsOfT2):
314314
{
315-
if (invocation.TryGetFirstDescendent<IInvocationOperation>(out var invocationBeforeShould))
315+
if (invocation.TryGetSingleArgumentAs<IInvocationOperation>(out var invocationBeforeShould))
316316
{
317317
switch (invocationBeforeShould.TargetMethod.Name)
318318
{
@@ -334,8 +334,8 @@ private static void AnalyzeInvocation(OperationAnalysisContext context, FluentAs
334334

335335
}
336336
}
337-
var argument = invocation.Arguments[0].Value.UnwrapConversion();
338-
if (argument is IPropertyReferenceOperation propertyBeforeShould)
337+
338+
if (invocation.TryGetSingleArgumentAs<IPropertyReferenceOperation>(out var propertyBeforeShould))
339339
{
340340
switch (propertyBeforeShould.Property.Name)
341341
{
@@ -370,7 +370,7 @@ private static void AnalyzeInvocation(OperationAnalysisContext context, FluentAs
370370
}
371371
case "Be" when assertion.IsContainedInType(metadata.ObjectAssertionsOfT2):
372372
{
373-
if (invocation.TryGetFirstDescendent<IInvocationOperation>(out var invocationBeforeShould))
373+
if (invocation.TryGetSingleArgumentAs<IInvocationOperation>(out var invocationBeforeShould))
374374
{
375375
switch (invocationBeforeShould.TargetMethod.Name)
376376
{
@@ -402,7 +402,7 @@ private static void AnalyzeInvocation(OperationAnalysisContext context, FluentAs
402402
return;
403403
case "NotBe" when assertion.IsContainedInType(metadata.NumericAssertionsOfT2):
404404
{
405-
if (invocation.TryGetFirstDescendent<IInvocationOperation>(out var invocationBeforeShould))
405+
if (invocation.TryGetSingleArgumentAs<IInvocationOperation>(out var invocationBeforeShould))
406406
{
407407
switch (invocationBeforeShould.TargetMethod.Name)
408408
{

src/FluentAssertions.Analyzers/Utilities/OperartionExtensions.cs

+12
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,18 @@ public static bool TryGetChainedInvocationAfterAndConstraint(this IInvocationOpe
192192
return false;
193193
}
194194

195+
public static bool TryGetSingleArgumentAs<TOperation>(this IInvocationOperation invocation, out TOperation operation)
196+
{
197+
if (invocation.Arguments.Length is 1 && invocation.Arguments[0].Value.UnwrapConversion() is TOperation op)
198+
{
199+
operation = op;
200+
return true;
201+
}
202+
203+
operation = default;
204+
return false;
205+
}
206+
195207
public static IOperation UnwrapConversion(this IOperation operation)
196208
{
197209
return operation switch

0 commit comments

Comments
 (0)