From db3aeac8059d6527aef5a94b60a5f4b2a19721b9 Mon Sep 17 00:00:00 2001 From: Meir Blachman Date: Mon, 20 May 2024 21:42:25 +0300 Subject: [PATCH] feat: add nunit collection assert AllItemsAreInstancesOfType (#349) --- docs/Nunit3Analyzer.md | 60 +++++++++++++ docs/Nunit4Analyzer.md | 62 ++++++++++++++ .../Nunit4AnalyzerTests.cs | 69 +++++++++++++++ .../Nunit3AnalyzerTests.cs | 69 +++++++++++++++ .../Tips/NunitTests.cs | 84 +++++++++++++++++-- .../Tips/NunitCodeFixProvider.cs | 55 ++++++++++-- .../Utilities/OperartionExtensions.cs | 6 ++ 7 files changed, 392 insertions(+), 13 deletions(-) diff --git a/docs/Nunit3Analyzer.md b/docs/Nunit3Analyzer.md index a84b3612..6ffdfd1c 100644 --- a/docs/Nunit3Analyzer.md +++ b/docs/Nunit3Analyzer.md @@ -18,6 +18,8 @@ This is a generated file, please edit src\FluentAssertions.Analyzers.FluentAsser - [CollectionAssertContains_WithCasting](#scenario-collectionassertcontains_withcasting) - `collection.Should().Contain((int)item);` - [CollectionAssertDoesNotContain](#scenario-collectionassertdoesnotcontain) - `collection.Should().NotContain(4);` - [CollectionAssertDoesNotContain_WithCasting](#scenario-collectionassertdoesnotcontain_withcasting) - `collection.Should().NotContain((int)item);` +- [CollectionAssertAllItemsAreInstancesOfType](#scenario-collectionassertallitemsareinstancesoftype) - `collection.Should().AllBeOfType();` +- [CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument](#scenario-collectionassertallitemsareinstancesoftype_withtypeargument) - `collection.Should().AllBeOfType(type);` ## Scenarios @@ -478,4 +480,62 @@ CollectionAssert.DoesNotContain(collection, item); /* fail message: Expected: collection.Should().NotContain((int)item); /* fail message: Expected collection {1, 2, 3} to not contain 2. */ ``` +### scenario: CollectionAssertAllItemsAreInstancesOfType + +```cs +// arrange +var collection = new object[] { 1, 2, 3 }; + +// old assertion: +CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); + +// new assertion: +collection.Should().AllBeOfType(); +``` + +#### Failure messages + +```cs +var collection = new object[] { 1, 2, "3" }; + +// old assertion: +CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); /* fail message: Expected: all items instance of + But was: < 1, 2, "3" > + First non-matching item at index [2]: "3" + */ + +// new assertion: +collection.Should().AllBeOfType(); /* fail message: Expected type to be "System.Int32", but found "[System.Int32, System.Int32, System.String]". */ +``` + +### scenario: CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument + +```cs +// arrange +var collection = new object[] { 1, 2, 3 }; +var type = typeof(int); + +// old assertion: +CollectionAssert.AllItemsAreInstancesOfType(collection, type); + +// new assertion: +collection.Should().AllBeOfType(type); +``` + +#### Failure messages + +```cs +var collection = new object[] { 1, 2, "3" }; +var type = typeof(int); + +// old assertion: +CollectionAssert.AllItemsAreInstancesOfType(collection, type); /* fail message: Expected: all items instance of + But was: < 1, 2, "3" > + First non-matching item at index [2]: "3" + */ + +// new assertion: +collection.Should().AllBeOfType(type); /* fail message: Expected type to be "System.Int32", but found "[System.Int32, System.Int32, System.String]". */ +``` + diff --git a/docs/Nunit4Analyzer.md b/docs/Nunit4Analyzer.md index acac8d74..1742854a 100644 --- a/docs/Nunit4Analyzer.md +++ b/docs/Nunit4Analyzer.md @@ -18,6 +18,8 @@ This is a generated file, please edit src\FluentAssertions.Analyzers.FluentAsser - [CollectionAssertContains_WithCasting](#scenario-collectionassertcontains_withcasting) - `collection.Should().Contain((int)item);` - [CollectionAssertDoesNotContain](#scenario-collectionassertdoesnotcontain) - `collection.Should().NotContain(4);` - [CollectionAssertDoesNotContain_WithCasting](#scenario-collectionassertdoesnotcontain_withcasting) - `collection.Should().NotContain((int)item);` +- [CollectionAssertAllItemsAreInstancesOfType](#scenario-collectionassertallitemsareinstancesoftype) - `collection.Should().AllBeOfType();` +- [CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument](#scenario-collectionassertallitemsareinstancesoftype_withtypeargument) - `collection.Should().AllBeOfType(type);` ## Scenarios @@ -509,4 +511,64 @@ CollectionAssert.DoesNotContain(collection, item); /* fail message: Assert.Tha collection.Should().NotContain((int)item); /* fail message: Expected collection {1, 2, 3} to not contain 2. */ ``` +### scenario: CollectionAssertAllItemsAreInstancesOfType + +```cs +// arrange +var collection = new object[] { 1, 2, 3 }; + +// old assertion: +CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); + +// new assertion: +collection.Should().AllBeOfType(); +``` + +#### Failure messages + +```cs +var collection = new object[] { 1, 2, "3" }; + +// old assertion: +CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); /* fail message: Assert.That(collection, Is.All.InstanceOf(expectedType)) + Expected: all items instance of + But was: < 1, 2, "3" > + First non-matching item at index [2]: "3" + */ + +// new assertion: +collection.Should().AllBeOfType(); /* fail message: Expected type to be "System.Int32", but found "[System.Int32, System.Int32, System.String]". */ +``` + +### scenario: CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument + +```cs +// arrange +var collection = new object[] { 1, 2, 3 }; +var type = typeof(int); + +// old assertion: +CollectionAssert.AllItemsAreInstancesOfType(collection, type); + +// new assertion: +collection.Should().AllBeOfType(type); +``` + +#### Failure messages + +```cs +var collection = new object[] { 1, 2, "3" }; +var type = typeof(int); + +// old assertion: +CollectionAssert.AllItemsAreInstancesOfType(collection, type); /* fail message: Assert.That(collection, Is.All.InstanceOf(expectedType)) + Expected: all items instance of + But was: < 1, 2, "3" > + First non-matching item at index [2]: "3" + */ + +// new assertion: +collection.Should().AllBeOfType(type); /* fail message: Expected type to be "System.Int32", but found "[System.Int32, System.Int32, System.String]". */ +``` + diff --git a/src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs.Nunit4/Nunit4AnalyzerTests.cs b/src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs.Nunit4/Nunit4AnalyzerTests.cs index bb90f8f4..dbb87c79 100644 --- a/src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs.Nunit4/Nunit4AnalyzerTests.cs +++ b/src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs.Nunit4/Nunit4AnalyzerTests.cs @@ -667,4 +667,73 @@ public void CollectionAssertDoesNotContain_WithCasting_Failure_NewAssertion() // new assertion: collection.Should().NotContain((int)item); } + + [Test] + public void CollectionAssertAllItemsAreInstancesOfType() + { + // arrange + var collection = new object[] { 1, 2, 3 }; + + // old assertion: + CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); + + // new assertion: + collection.Should().AllBeOfType(); + } + + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + + // old assertion: + CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); + } + + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_Failure_NewAssertion() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + + // new assertion: + collection.Should().AllBeOfType(); + } + + [Test] + public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument() + { + // arrange + var collection = new object[] { 1, 2, 3 }; + var type = typeof(int); + + // old assertion: + CollectionAssert.AllItemsAreInstancesOfType(collection, type); + + // new assertion: + collection.Should().AllBeOfType(type); + } + + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_OldAssertion() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + var type = typeof(int); + + // old assertion: + CollectionAssert.AllItemsAreInstancesOfType(collection, type); + } + + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_NewAssertion() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + var type = typeof(int); + + // new assertion: + collection.Should().AllBeOfType(type); + } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs/Nunit3AnalyzerTests.cs b/src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs/Nunit3AnalyzerTests.cs index 5b94240e..52161c2b 100644 --- a/src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs/Nunit3AnalyzerTests.cs +++ b/src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs/Nunit3AnalyzerTests.cs @@ -670,4 +670,73 @@ public void CollectionAssertDoesNotContain_WithCasting_Failure_NewAssertion() // new assertion: collection.Should().NotContain((int)item); } + + [TestMethod] + public void CollectionAssertAllItemsAreInstancesOfType() + { + // arrange + var collection = new object[] { 1, 2, 3 }; + + // old assertion: + CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); + + // new assertion: + collection.Should().AllBeOfType(); + } + + [TestMethod, ExpectedTestFrameworkException] + public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + + // old assertion: + CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); + } + + [TestMethod, ExpectedTestFrameworkException] + public void CollectionAssertAllItemsAreInstancesOfType_Failure_NewAssertion() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + + // new assertion: + collection.Should().AllBeOfType(); + } + + [TestMethod] + public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument() + { + // arrange + var collection = new object[] { 1, 2, 3 }; + var type = typeof(int); + + // old assertion: + CollectionAssert.AllItemsAreInstancesOfType(collection, type); + + // new assertion: + collection.Should().AllBeOfType(type); + } + + [TestMethod, ExpectedTestFrameworkException] + public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_OldAssertion() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + var type = typeof(int); + + // old assertion: + CollectionAssert.AllItemsAreInstancesOfType(collection, type); + } + + [TestMethod, ExpectedTestFrameworkException] + public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_NewAssertion() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + var type = typeof(int); + + // new assertion: + collection.Should().AllBeOfType(type); + } } diff --git a/src/FluentAssertions.Analyzers.Tests/Tips/NunitTests.cs b/src/FluentAssertions.Analyzers.Tests/Tips/NunitTests.cs index 35f06d53..28b9307c 100644 --- a/src/FluentAssertions.Analyzers.Tests/Tips/NunitTests.cs +++ b/src/FluentAssertions.Analyzers.Tests/Tips/NunitTests.cs @@ -1,4 +1,6 @@ using System; +using System.Collections; +using System.Collections.Generic; using FluentAssertions.Analyzers.TestUtils; using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -1201,24 +1203,26 @@ public void Nunit4_AssertContains_WithCasting_TestCodeFix(string methodArguments [DataTestMethod] [AssertionDiagnostic("CollectionAssert.AreEqual(expected, actual{0});")] + [AssertionDiagnostic("CollectionAssert.AreEqual(expected, actual, comparer{0});")] [AssertionDiagnostic("Assert.That(actual, Is.EqualTo(expected){0});", ignore: true)] [Implemented] public void Nunit3_CollectionAssertAreEqual_TestAnalyzer(string assertion) { - Nunit3VerifyDiagnostic("IEnumerable expected, IEnumerable actual", assertion); - Nunit3VerifyDiagnostic("ICollection expected, ICollection actual", assertion); - Nunit3VerifyDiagnostic("ICollection expected, ICollection actual", assertion); + Nunit3VerifyDiagnostic("IEnumerable expected, IEnumerable actual, IComparer comparer", assertion); + Nunit3VerifyDiagnostic("ICollection expected, ICollection actual, Comparer comparer", assertion); + Nunit3VerifyDiagnostic("ICollection expected, ICollection actual, Comparer comparer", assertion); } [DataTestMethod] [AssertionDiagnostic("CollectionAssert.AreEqual(expected, actual{0});")] + [AssertionDiagnostic("CollectionAssert.AreEqual(expected, actual, comparer{0});")] [AssertionDiagnostic("Assert.That(actual, Is.EqualTo(expected));", ignore: true)] [Implemented] public void Nunit4_CollectionAssertAreEqual_TestAnalyzer(string assertion) { - Nunit4VerifyDiagnostic("IEnumerable expected, IEnumerable actual", assertion); - Nunit4VerifyDiagnostic("ICollection expected, ICollection actual", assertion); - Nunit4VerifyDiagnostic("ICollection expected, ICollection actual", assertion); + Nunit4VerifyDiagnostic("IEnumerable expected, IEnumerable actual, IComparer comparer", assertion); + Nunit4VerifyDiagnostic("ICollection expected, ICollection actual, Comparer comparer", assertion); + Nunit4VerifyDiagnostic("ICollection expected, ICollection actual, Comparer comparer", assertion); } [DataTestMethod] @@ -1232,11 +1236,27 @@ public void Nunit4_CollectionAssertAreEqual_TestAnalyzer(string assertion) [Implemented] public void Nunit3_CollectionAssertAreEqual_TestCodeFix(string oldAssertion, string newAssertion) { - Nunit3VerifyNoFix("IEnumerable expected, IEnumerable actual", oldAssertion); Nunit3VerifyFix("ICollection expected, ICollection actual", oldAssertion, newAssertion); Nunit3VerifyFix("ICollection expected, ICollection actual", oldAssertion, newAssertion); } + [DataTestMethod] + [AssertionDiagnostic("CollectionAssert.AreEqual(expected, actual{0});")] + [Implemented] + public void Nunit3_CollectionAssertAreEqual_NoFix_NonGenericIEnumerable_TestCodeFix(string assertion) + { + Nunit3VerifyNoFix("IEnumerable expected, IEnumerable actual", assertion); + } + + [DataTestMethod] + [AssertionDiagnostic("CollectionAssert.AreEqual(expected, actual, comparer{0});")] + [Implemented] + public void Nunit3_CollectionAssertAreEqual_NoFix_IComparer_TestCodeFix(string assertion) + { + Nunit3VerifyNoFix("ICollection expected, ICollection actual, IComparer comparer", assertion); + Nunit3VerifyNoFix("IEnumerable expected, IEnumerable actual, IComparer comparer", assertion); + } + [DataTestMethod] [AssertionCodeFix( oldAssertion: "CollectionAssert.AreEqual(expected, actual{0});", @@ -1253,6 +1273,23 @@ public void Nunit4_CollectionAssertAreEqual_TestCodeFix(string oldAssertion, str Nunit4VerifyFix("ICollection expected, ICollection actual", oldAssertion, newAssertion); } + [DataTestMethod] + [AssertionDiagnostic("CollectionAssert.AreEqual(expected, actual{0});")] + [Implemented] + public void Nunit4_CollectionAssertAreEqual_NoFix_NonGenericIEnumerable_TestCodeFix(string assertion) + { + Nunit4VerifyNoFix("IEnumerable expected, IEnumerable actual", assertion); + } + + [DataTestMethod] + [AssertionDiagnostic("CollectionAssert.AreEqual(expected, actual, comparer{0});")] + [Implemented] + public void Nunit4_CollectionAssertAreEqual_NoFix_IComparer_TestCodeFix(string assertion) + { + Nunit4VerifyNoFix("ICollection expected, ICollection actual, IComparer comparer", assertion); + Nunit4VerifyNoFix("IEnumerable expected, IEnumerable actual, IComparer comparer", assertion); + } + [DataTestMethod] [AssertionDiagnostic("CollectionAssert.AreNotEqual(expected, actual{0});")] [AssertionDiagnostic("Assert.That(actual, Is.Not.EqualTo(expected){0});", ignore: true)] @@ -1511,6 +1548,39 @@ public void Nunit3_CollectionAssertDoesNotContain_WithCasting_TestCodeFix(string public void Nunit4_CollectionAssertDoesNotContain_WithCasting_TestCodeFix(string methodArguments, string oldAssertion, string newAssertion) => Nunit4VerifyFix(methodArguments, oldAssertion, newAssertion); + [DataTestMethod] + [AssertionDiagnostic("CollectionAssert.AllItemsAreInstancesOfType(actual, typeof(string){0});")] + [AssertionDiagnostic("CollectionAssert.AllItemsAreInstancesOfType(actual, type{0});")] + [Implemented] + public void Nunit3_CollectionAssertAllItemsAreInstancesOfType_TestAnalyzer(string assertion) => Nunit3VerifyDiagnostic("IEnumerable actual, Type type", assertion); + + [DataTestMethod] + [AssertionDiagnostic("CollectionAssert.AllItemsAreInstancesOfType(actual, typeof(string){0});")] + [AssertionDiagnostic("CollectionAssert.AllItemsAreInstancesOfType(actual, type{0});")] + [Implemented] + public void Nunit4_CollectionAssertAllItemsAreInstancesOfType_TestAnalyzer(string assertion) => Nunit4VerifyDiagnostic("IEnumerable actual, Type type", assertion); + + [DataTestMethod] + [AssertionCodeFix( + oldAssertion: "CollectionAssert.AllItemsAreInstancesOfType(actual, typeof(string){0});", + newAssertion: "actual.Should().AllBeOfType({0});")] + [AssertionCodeFix( + oldAssertion: "CollectionAssert.AllItemsAreInstancesOfType(actual, type{0});", + newAssertion: "actual.Should().AllBeOfType(type{0});")] + [Implemented] + public void Nunit3_CollectionAssertAllItemsAreInstancesOfType_TestCodeFix(string oldAssertion, string newAssertion) => Nunit3VerifyFix("IEnumerable actual, Type type", oldAssertion, newAssertion); + + [DataTestMethod] + [AssertionCodeFix( + oldAssertion: "CollectionAssert.AllItemsAreInstancesOfType(actual, typeof(string){0});", + newAssertion: "actual.Should().AllBeOfType({0});")] + [AssertionCodeFix( + oldAssertion: "CollectionAssert.AllItemsAreInstancesOfType(actual, type{0});", + newAssertion: "actual.Should().AllBeOfType(type{0});")] + [Implemented] + public void Nunit4_CollectionAssertAllItemsAreInstancesOfType_TestCodeFix(string oldAssertion, string newAssertion) => Nunit4VerifyFix("IEnumerable actual, Type type", oldAssertion, newAssertion); + + #endregion private void Nunit3VerifyDiagnostic(string methodArguments, string assertion) diff --git a/src/FluentAssertions.Analyzers/Tips/NunitCodeFixProvider.cs b/src/FluentAssertions.Analyzers/Tips/NunitCodeFixProvider.cs index e1d5a754..8c9d56af 100644 --- a/src/FluentAssertions.Analyzers/Tips/NunitCodeFixProvider.cs +++ b/src/FluentAssertions.Analyzers/Tips/NunitCodeFixProvider.cs @@ -208,15 +208,47 @@ private CreateChangedDocument TryComputeFixForNunitClassicAssert(IInvocationOper private CreateChangedDocument TryComputeFixForCollectionAssert(IInvocationOperation invocation, CodeFixContext context, NunitCodeFixContext t) { + /** + public static void AllItemsAreNotNull(IEnumerable collection) + public static void AllItemsAreNotNull(IEnumerable collection, string message, params object[] args) + public static void AllItemsAreUnique(IEnumerable collection) + public static void AllItemsAreUnique(IEnumerable collection, string message, params object[] args) + public static void AreEqual(IEnumerable expected, IEnumerable actual, IComparer comparer) + public static void AreEqual(IEnumerable expected, IEnumerable actual, IComparer comparer, string message, params object[] args) + public static void AreEquivalent(IEnumerable expected, IEnumerable actual) + public static void AreEquivalent(IEnumerable expected, IEnumerable actual, string message, params object[] args) + public static void AreNotEqual(IEnumerable expected, IEnumerable actual, IComparer comparer) + public static void AreNotEqual(IEnumerable expected, IEnumerable actual, IComparer comparer, string message, params object[] args) + public static void AreNotEquivalent(IEnumerable expected, IEnumerable actual) + public static void AreNotEquivalent(IEnumerable expected, IEnumerable actual, string message, params object[] args) + public static void IsNotSubsetOf(IEnumerable subset, IEnumerable superset) + public static void IsNotSubsetOf(IEnumerable subset, IEnumerable superset, string message, params object[] args) + public static void IsSubsetOf(IEnumerable subset, IEnumerable superset) + public static void IsSubsetOf(IEnumerable subset, IEnumerable superset, string message, params object[] args) + public static void IsNotSupersetOf(IEnumerable superset, IEnumerable subset) + public static void IsNotSupersetOf(IEnumerable superset, IEnumerable subset, string message, params object[] args) + public static void IsSupersetOf(IEnumerable superset, IEnumerable subset) + public static void IsSupersetOf(IEnumerable superset, IEnumerable subset, string message, params object[] args) + public static void IsOrdered(IEnumerable collection, string message, params object[] args) + public static void IsOrdered(IEnumerable collection) + public static void IsOrdered(IEnumerable collection, IComparer comparer, string message, params object[] args) + public static void IsOrdered(IEnumerable collection, IComparer comparer) + */ + + if (IsArgumentTypeOfNonGenericEnumerable(invocation, argumentIndex: 0)) + { + return null; + } + switch (invocation.TargetMethod.Name) { - case "IsEmpty" when !IsArgumentTypeOfNonGenericEnumerable(invocation, argumentIndex: 0): // CollectionAssert.IsEmpty(IEnumerable collection) + case "IsEmpty": // CollectionAssert.IsEmpty(IEnumerable collection) return DocumentEditorUtils.RenameMethodToSubjectShouldAssertion(invocation, context, "BeEmpty", subjectIndex: 0, argumentsToRemove: []); - case "IsNotEmpty" when !IsArgumentTypeOfNonGenericEnumerable(invocation, argumentIndex: 0): // CollectionAssert.IsNotEmpty(IEnumerable collection) + case "IsNotEmpty": // CollectionAssert.IsNotEmpty(IEnumerable collection) return DocumentEditorUtils.RenameMethodToSubjectShouldAssertion(invocation, context, "NotBeEmpty", subjectIndex: 0, argumentsToRemove: []); - case "AreEqual" when !IsArgumentTypeOfNonGenericEnumerable(invocation, argumentIndex: 0): // CollectionAssert.AreEqual(IEnumerable expected, IEnumerable actual) + case "AreEqual" when !IsArgumentTypeOf(invocation, argumentIndex: 2, t.IComparer): // CollectionAssert.AreEqual(IEnumerable expected, IEnumerable actual) return DocumentEditorUtils.RenameMethodToSubjectShouldAssertion(invocation, context, "Equal", subjectIndex: 1, argumentsToRemove: []); - case "AreNotEqual" when !IsArgumentTypeOfNonGenericEnumerable(invocation, argumentIndex: 0): // CollectionAssert.AreNotEqual(IEnumerable notExpected, IEnumerable actual) + case "AreNotEqual" when !IsArgumentTypeOf(invocation, argumentIndex: 2, t.IComparer): // CollectionAssert.AreNotEqual(IEnumerable expected, IEnumerable actual) return DocumentEditorUtils.RenameMethodToSubjectShouldAssertion(invocation, context, "NotEqual", subjectIndex: 1, argumentsToRemove: []); case "Contains": // CollectionAssert.Contain(IEnumerable collection, object actual) return RewriteContainsAssertion(invocation, context, "Contain", @@ -228,6 +260,15 @@ private CreateChangedDocument TryComputeFixForCollectionAssert(IInvocationOperat subject: invocation.Arguments[0], expectation: invocation.Arguments[1] ); + case "AllItemsAreInstancesOfType": // CollectionAssert.AllItemsAreInstancesOfType(IEnumerable collection, Type expectedType) + { + if (invocation.Arguments[1].Value is not ITypeOfOperation typeOf) + { + return DocumentEditorUtils.RenameMethodToSubjectShouldAssertion(invocation, context, "AllBeOfType", subjectIndex: 0, argumentsToRemove: []); + } + + return DocumentEditorUtils.RenameMethodToSubjectShouldGenericAssertion(invocation, ImmutableArray.Create(typeOf.TypeOperand), context, "AllBeOfType", subjectIndex: 0, argumentsToRemove: [1]); + } } return null; } @@ -318,8 +359,10 @@ private static bool IsPropertyOfSymbol(IOperation operation, string property, IN => operation is IPropertyReferenceOperation propertyReference && propertyReference.Property.Name == property && IsPropertyReferencedFromType(propertyReference, type); private static bool IsArgumentTypeOfNonGenericEnumerable(IInvocationOperation invocation, int argumentIndex) => IsArgumentTypeOf(invocation, argumentIndex, SpecialType.System_Collections_IEnumerable); - private static bool IsArgumentTypeOf(IInvocationOperation invocation, int argumentIndex, SpecialType specialType) - => invocation.Arguments[argumentIndex].Value.UnwrapConversion().Type.SpecialType == specialType; + private static bool IsArgumentTypeOf(IInvocationOperation invocation, int argumentIndex, SpecialType type) + => invocation.Arguments.Length > argumentIndex && invocation.Arguments[argumentIndex].IsTypeof(type); + private static bool IsArgumentTypeOf(IInvocationOperation invocation, int argumentIndex, INamedTypeSymbol type) + => invocation.Arguments.Length > argumentIndex && invocation.Arguments[argumentIndex].IsTypeof(type); public class NunitCodeFixContext(Compilation compilation) : TestingFrameworkCodeFixProvider.TestingFrameworkCodeFixContext(compilation) { diff --git a/src/FluentAssertions.Analyzers/Utilities/OperartionExtensions.cs b/src/FluentAssertions.Analyzers/Utilities/OperartionExtensions.cs index 66c6890e..5eacc01b 100644 --- a/src/FluentAssertions.Analyzers/Utilities/OperartionExtensions.cs +++ b/src/FluentAssertions.Analyzers/Utilities/OperartionExtensions.cs @@ -81,6 +81,12 @@ public static bool ImplementsOrIsInterface(this IInvocationOperation invocation, => invocation.TargetMethod.ContainingType.ImplementsOrIsInterface(type); public static bool ImplementsOrIsInterface(this IArgumentOperation argument, SpecialType type) => argument.Value.UnwrapConversion().Type.ImplementsOrIsInterface(type); + public static bool ImplementsOrIsInterface(this IArgumentOperation argument, INamedTypeSymbol type) + => argument.Value.UnwrapConversion().Type.ImplementsOrIsInterface(type); + public static bool IsTypeof(this IArgumentOperation argument, SpecialType type) + => argument.Value.UnwrapConversion().Type.SpecialType == type; + public static bool IsTypeof(this IArgumentOperation argument, INamedTypeSymbol type) + => argument.Value.UnwrapConversion().Type.EqualsSymbol(type); public static bool IsSameArgumentReference(this IArgumentOperation argument1, IArgumentOperation argument2) {