From 7cb5a7edae9037257302ec8ae93b8f402d2965b1 Mon Sep 17 00:00:00 2001 From: Meir Blachman Date: Mon, 7 Oct 2024 23:04:23 +0300 Subject: [PATCH 1/6] feat: improve TryGetFirstDescendent logic --- .../Tips/CollectionTests.cs | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs b/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs index f98b395..cb9f402 100644 --- a/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs +++ b/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs @@ -316,11 +316,32 @@ public class CollectionTests [AssertionDiagnostic("actual.ToArray().Count().Should().Be(1{0}).And.ToString();")] [Implemented] public void CollectionShouldHaveCount_CountShouldBe1_TestAnalyzer(string assertion) => VerifyCSharpDiagnosticCodeBlock(assertion, DiagnosticMetadata.CollectionShouldContainSingle_CountShouldBe1); - + [DataTestMethod] - [AssertionDiagnostic("actual.ToArray().Length.Should().Be(1{0}).And.ToString();")] + [AssertionDiagnostic("(array.Count() + 1).Should().Be(0{0}).And.ToString();")] + [AssertionDiagnostic("(array.Count() + 1).Should().Be(1{0}).And.ToString();")] + [AssertionDiagnostic("(array.Count() + 1).Should().Be(expectedSize{0}).And.ToString();")] + [AssertionDiagnostic("(list.Count + 1).Should().Be(0{0}).And.ToString();")] + [AssertionDiagnostic("(list.Count + 1).Should().Be(1{0}).And.ToString();")] + [AssertionDiagnostic("(list.Count + 1).Should().Be(expectedSize{0}).And.ToString();")] [Implemented] - public void CollectionShouldHaveCount_LengthShouldBe_TestAnalyzer(string assertion) => VerifyCSharpDiagnosticCodeBlock(assertion, DiagnosticMetadata.CollectionShouldHaveCount_LengthShouldBe); + public void CollectionShouldHaveCount_CountShouldBe_TestNoAnalyzer(string assertion) => DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(new StringBuilder() + .AppendLine("using System;") + .AppendLine("using System.Collections.Generic;") + .AppendLine("using System.Linq;") + .AppendLine("using FluentAssertions;") + .AppendLine("using FluentAssertions.Extensions;") + .AppendLine("namespace TestNamespace") + .AppendLine("{") + .AppendLine(" public class TestClass") + .AppendLine(" {") + .AppendLine(" public void TestMethod(string[] array, List list, int expectedSize)") + .AppendLine(" {") + .AppendLine(assertion) + .AppendLine(" }") + .AppendLine(" }") + .AppendLine("}") + .ToString()); [DataTestMethod] [AssertionDiagnostic(@"var array = new string[0, 0]; array.Length.Should().Be(0{0});")] @@ -330,6 +351,7 @@ public class CollectionTests [AssertionDiagnostic(@"var array = new string[2, 2]; array.Length.Should().Be(0{0});")] [AssertionDiagnostic(@"var array = new string[3, 3, 3]; array.Length.Should().Be(0{0});")] [AssertionDiagnostic(@"int[] array1 = [1, 2, 3]; int[] array2 = [4, 5, 6]; int[] both = [..array1, ..array2]; (array1.Length + array2.Length).Should().Be(both.Length{0});")] + [AssertionDiagnostic("(actual.Count() + 1).Should().Be(1{0}).And.ToString();")] [Implemented(Reason = "https://github.com/fluentassertions/fluentassertions.analyzers/issues/309")] public void CollectionShouldHaveCount_LengthShouldBe_TestNoAnalyzer(string assertion) => DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(new StringBuilder() .AppendLine("using System;") From 0c08231edf74f833a4d8b7f500fe54572f48f519 Mon Sep 17 00:00:00 2001 From: Meir Blachman Date: Mon, 7 Oct 2024 23:08:02 +0300 Subject: [PATCH 2/6] feat: improve TryGetFirstDescendent logic --- src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs b/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs index cb9f402..cd52e1d 100644 --- a/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs +++ b/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs @@ -351,7 +351,6 @@ public void CollectionShouldHaveCount_CountShouldBe_TestNoAnalyzer(string assert [AssertionDiagnostic(@"var array = new string[2, 2]; array.Length.Should().Be(0{0});")] [AssertionDiagnostic(@"var array = new string[3, 3, 3]; array.Length.Should().Be(0{0});")] [AssertionDiagnostic(@"int[] array1 = [1, 2, 3]; int[] array2 = [4, 5, 6]; int[] both = [..array1, ..array2]; (array1.Length + array2.Length).Should().Be(both.Length{0});")] - [AssertionDiagnostic("(actual.Count() + 1).Should().Be(1{0}).And.ToString();")] [Implemented(Reason = "https://github.com/fluentassertions/fluentassertions.analyzers/issues/309")] public void CollectionShouldHaveCount_LengthShouldBe_TestNoAnalyzer(string assertion) => DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(new StringBuilder() .AppendLine("using System;") From ef0096bf90fe0b9b57ce34470f424c3e3302aa22 Mon Sep 17 00:00:00 2001 From: Meir Blachman Date: Mon, 7 Oct 2024 23:11:42 +0300 Subject: [PATCH 3/6] feat: improve TryGetFirstDescendent logic --- .../Tips/FluentAssertionsAnalyzer.cs | 6 +++--- .../Utilities/OperartionExtensions.cs | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/FluentAssertions.Analyzers/Tips/FluentAssertionsAnalyzer.cs b/src/FluentAssertions.Analyzers/Tips/FluentAssertionsAnalyzer.cs index b63b97c..39f7b86 100644 --- a/src/FluentAssertions.Analyzers/Tips/FluentAssertionsAnalyzer.cs +++ b/src/FluentAssertions.Analyzers/Tips/FluentAssertionsAnalyzer.cs @@ -312,7 +312,7 @@ private static void AnalyzeInvocation(OperationAnalysisContext context, FluentAs return; case "Be" when assertion.IsContainedInType(metadata.NumericAssertionsOfT2): { - if (invocation.TryGetFirstDescendent(out var invocationBeforeShould)) + if (invocation.TryGetSingleArgumentAs(out var invocationBeforeShould)) { switch (invocationBeforeShould.TargetMethod.Name) { @@ -334,8 +334,8 @@ private static void AnalyzeInvocation(OperationAnalysisContext context, FluentAs } } - var argument = invocation.Arguments[0].Value.UnwrapConversion(); - if (argument is IPropertyReferenceOperation propertyBeforeShould) + + if (invocation.TryGetSingleArgumentAs(out var propertyBeforeShould)) { switch (propertyBeforeShould.Property.Name) { diff --git a/src/FluentAssertions.Analyzers/Utilities/OperartionExtensions.cs b/src/FluentAssertions.Analyzers/Utilities/OperartionExtensions.cs index 9c048f6..22a9c12 100644 --- a/src/FluentAssertions.Analyzers/Utilities/OperartionExtensions.cs +++ b/src/FluentAssertions.Analyzers/Utilities/OperartionExtensions.cs @@ -192,6 +192,18 @@ public static bool TryGetChainedInvocationAfterAndConstraint(this IInvocationOpe return false; } + public static bool TryGetSingleArgumentAs(this IInvocationOperation invocation, out TOperation operation) + { + if (invocation.Arguments.Length is 1 && invocation.Arguments[0].Value.UnwrapConversion() is TOperation op) + { + operation = op; + return true; + } + + operation = default; + return false; + } + public static IOperation UnwrapConversion(this IOperation operation) { return operation switch From 2d2b6e6174d5a288d9f615f404717b411f76de34 Mon Sep 17 00:00:00 2001 From: Meir Blachman Date: Tue, 8 Oct 2024 08:15:40 +0300 Subject: [PATCH 4/6] feat: improve TryGetFirstDescendent logic --- src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs b/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs index cd52e1d..033ea32 100644 --- a/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs +++ b/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs @@ -316,7 +316,7 @@ public class CollectionTests [AssertionDiagnostic("actual.ToArray().Count().Should().Be(1{0}).And.ToString();")] [Implemented] public void CollectionShouldHaveCount_CountShouldBe1_TestAnalyzer(string assertion) => VerifyCSharpDiagnosticCodeBlock(assertion, DiagnosticMetadata.CollectionShouldContainSingle_CountShouldBe1); - + [DataTestMethod] [AssertionDiagnostic("(array.Count() + 1).Should().Be(0{0}).And.ToString();")] [AssertionDiagnostic("(array.Count() + 1).Should().Be(1{0}).And.ToString();")] From a88c08867b50df3f5e9043f7132082870c7d8bc0 Mon Sep 17 00:00:00 2001 From: Meir Blachman Date: Tue, 8 Oct 2024 08:21:38 +0300 Subject: [PATCH 5/6] feat: improve TryGetFirstDescendent logic --- .../Tips/CollectionTests.cs | 8 ++++++++ .../Tips/FluentAssertionsAnalyzer.cs | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs b/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs index 033ea32..49a07e1 100644 --- a/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs +++ b/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs @@ -763,6 +763,14 @@ public void CollectionShouldContainSingle_TestAnalyzer_GenericIEnumerableShouldR [Implemented] public void CollectionShouldHaveElementAt_ElementAtIndexShouldBe_TestAnalyzer(string assertion) => VerifyCSharpDiagnosticCodeBlock(assertion, DiagnosticMetadata.CollectionShouldHaveElementAt_ElementAtIndexShouldBe); + [DataTestMethod] + [AssertionDiagnostic("actual.ElementAt(k).BooleanProperty.Should().Be(expectedItem.BooleanProperty{0});")] + [AssertionDiagnostic("actual.ElementAt(6).BooleanProperty.Should().Be(expectedItem.BooleanProperty{0});")] + [AssertionDiagnostic("actual.AsEnumerable().ElementAt(k).BooleanProperty.Should().Be(expectedItem.BooleanProperty{0}).And.ToString();")] + [AssertionDiagnostic("actual.AsEnumerable().ElementAt(6).BooleanProperty.Should().Be(expectedItem.BooleanProperty{0}).And.ToString();")] + [Implemented] + public void CollectionShouldHaveElementAt_ElementAtIndexShouldBe_TestNoAnalyzer(string assertion) => DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(GenerateCode.GenericIListCodeBlockAssertion(assertion)); + [DataTestMethod] [AssertionDiagnostic("actual[k].Should().Be(expectedItem{0});")] [AssertionDiagnostic("actual[6].Should().Be(expectedItem{0});")] diff --git a/src/FluentAssertions.Analyzers/Tips/FluentAssertionsAnalyzer.cs b/src/FluentAssertions.Analyzers/Tips/FluentAssertionsAnalyzer.cs index 39f7b86..8f97848 100644 --- a/src/FluentAssertions.Analyzers/Tips/FluentAssertionsAnalyzer.cs +++ b/src/FluentAssertions.Analyzers/Tips/FluentAssertionsAnalyzer.cs @@ -301,7 +301,7 @@ private static void AnalyzeInvocation(OperationAnalysisContext context, FluentAs return; case "OnlyHaveUniqueItems" when assertion.IsContainedInType(metadata.GenericCollectionAssertionsOfT3): { - if (!invocation.TryGetFirstDescendent(out var invocationBeforeShould)) return; + if (!invocation.TryGetSingleArgumentAs(out var invocationBeforeShould)) return; switch (invocationBeforeShould.TargetMethod.Name) { case nameof(Enumerable.Select) when IsEnumerableMethodWithPredicate(invocationBeforeShould, metadata): @@ -370,7 +370,7 @@ private static void AnalyzeInvocation(OperationAnalysisContext context, FluentAs } case "Be" when assertion.IsContainedInType(metadata.ObjectAssertionsOfT2): { - if (invocation.TryGetFirstDescendent(out var invocationBeforeShould)) + if (invocation.TryGetSingleArgumentAs(out var invocationBeforeShould)) { switch (invocationBeforeShould.TargetMethod.Name) { From 98c80f9796833c69e63fa1c14aba185d0bd9cd6d Mon Sep 17 00:00:00 2001 From: Meir Blachman Date: Tue, 8 Oct 2024 09:05:00 +0300 Subject: [PATCH 6/6] feat: improve TryGetFirstDescendent logic --- .../Tips/CollectionTests.cs | 6 ++++++ .../Tips/FluentAssertionsAnalyzer.cs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs b/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs index 49a07e1..99d0748 100644 --- a/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs +++ b/src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs @@ -631,6 +631,12 @@ public void CollectionShouldHaveCount_LengthShouldBe_TestNoAnalyzer(string asser [Implemented] public void CollectionShouldNotHaveSameCount_TestAnalyzer(string assertion) => VerifyCSharpDiagnosticCodeBlock(assertion, DiagnosticMetadata.CollectionShouldNotHaveSameCount_CountShouldNotBeOtherCollectionCount); + [DataTestMethod] + [AssertionDiagnostic("(actual.Count() + 1).Should().NotBe(unexpected.Count(){0});")] + [AssertionDiagnostic("actual.Count().ToString().Length.Should().NotBe(unexpected.Count(){0});")] + [Implemented] + public void CollectionShouldNotHaveSameCount_TestNotAnalyzer(string assertion) => DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(GenerateCode.GenericIListCodeBlockAssertion(assertion)); + [DataTestMethod] [AssertionCodeFix( oldAssertion: "actual.Count().Should().NotBe(unexpected.Count(){0});", diff --git a/src/FluentAssertions.Analyzers/Tips/FluentAssertionsAnalyzer.cs b/src/FluentAssertions.Analyzers/Tips/FluentAssertionsAnalyzer.cs index 8f97848..4f2e644 100644 --- a/src/FluentAssertions.Analyzers/Tips/FluentAssertionsAnalyzer.cs +++ b/src/FluentAssertions.Analyzers/Tips/FluentAssertionsAnalyzer.cs @@ -402,7 +402,7 @@ private static void AnalyzeInvocation(OperationAnalysisContext context, FluentAs return; case "NotBe" when assertion.IsContainedInType(metadata.NumericAssertionsOfT2): { - if (invocation.TryGetFirstDescendent(out var invocationBeforeShould)) + if (invocation.TryGetSingleArgumentAs(out var invocationBeforeShould)) { switch (invocationBeforeShould.TargetMethod.Name) {