diff --git a/docs/Nunit3Analyzer.md b/docs/Nunit3Analyzer.md index f379338..31b23ae 100644 --- a/docs/Nunit3Analyzer.md +++ b/docs/Nunit3Analyzer.md @@ -719,6 +719,10 @@ var collection = new object[] { 1, 2, 3 }; // old assertion: CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); +Assert.That(collection, Is.All.InstanceOf(typeof(int))); +Assert.That(collection, Is.All.InstanceOf()); +Assert.That(collection, Has.All.InstanceOf(typeof(int))); +Assert.That(collection, Has.All.InstanceOf()); // new assertion: collection.Should().AllBeOfType(); @@ -734,6 +738,22 @@ CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); /* fail me But was: < 1, 2, "3" > First non-matching item at index [2]: "3" */ +Assert.That(collection, Is.All.InstanceOf(typeof(int))); /* fail message: Expected: all items instance of + But was: < 1, 2, "3" > + First non-matching item at index [2]: "3" + */ +Assert.That(collection, Is.All.InstanceOf()); /* fail message: Expected: all items instance of + But was: < 1, 2, "3" > + First non-matching item at index [2]: "3" + */ +Assert.That(collection, Has.All.InstanceOf(typeof(int))); /* fail message: Expected: all items instance of + But was: < 1, 2, "3" > + First non-matching item at index [2]: "3" + */ +Assert.That(collection, Has.All.InstanceOf()); /* 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]". */ @@ -748,6 +768,8 @@ var type = typeof(int); // old assertion: CollectionAssert.AllItemsAreInstancesOfType(collection, type); +Assert.That(collection, Is.All.InstanceOf(type)); +Assert.That(collection, Has.All.InstanceOf(type)); // new assertion: collection.Should().AllBeOfType(type); @@ -764,6 +786,14 @@ CollectionAssert.AllItemsAreInstancesOfType(collection, type); /* fail message: But was: < 1, 2, "3" > First non-matching item at index [2]: "3" */ +Assert.That(collection, Is.All.InstanceOf(type)); /* fail message: Expected: all items instance of + But was: < 1, 2, "3" > + First non-matching item at index [2]: "3" + */ +Assert.That(collection, Has.All.InstanceOf(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 797c7e8..a51ad1b 100644 --- a/docs/Nunit4Analyzer.md +++ b/docs/Nunit4Analyzer.md @@ -796,6 +796,10 @@ var collection = new object[] { 1, 2, 3 }; // old assertion: CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); +Assert.That(collection, Is.All.InstanceOf(typeof(int))); +Assert.That(collection, Is.All.InstanceOf()); +Assert.That(collection, Has.All.InstanceOf(typeof(int))); +Assert.That(collection, Has.All.InstanceOf()); // new assertion: collection.Should().AllBeOfType(); @@ -812,6 +816,26 @@ CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); /* fail me But was: < 1, 2, "3" > First non-matching item at index [2]: "3" */ +Assert.That(collection, Is.All.InstanceOf(typeof(int))); /* fail message: Assert.That(collection, Is.All.InstanceOf(typeof(int))) + Expected: all items instance of + But was: < 1, 2, "3" > + First non-matching item at index [2]: "3" + */ +Assert.That(collection, Is.All.InstanceOf()); /* fail message: Assert.That(collection, Is.All.InstanceOf()) + Expected: all items instance of + But was: < 1, 2, "3" > + First non-matching item at index [2]: "3" + */ +Assert.That(collection, Has.All.InstanceOf(typeof(int))); /* fail message: Assert.That(collection, Has.All.InstanceOf(typeof(int))) + Expected: all items instance of + But was: < 1, 2, "3" > + First non-matching item at index [2]: "3" + */ +Assert.That(collection, Has.All.InstanceOf()); /* fail message: Assert.That(collection, Has.All.InstanceOf()) + 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]". */ @@ -826,6 +850,8 @@ var type = typeof(int); // old assertion: CollectionAssert.AllItemsAreInstancesOfType(collection, type); +Assert.That(collection, Is.All.InstanceOf(type)); +Assert.That(collection, Has.All.InstanceOf(type)); // new assertion: collection.Should().AllBeOfType(type); @@ -843,6 +869,16 @@ CollectionAssert.AllItemsAreInstancesOfType(collection, type); /* fail message: But was: < 1, 2, "3" > First non-matching item at index [2]: "3" */ +Assert.That(collection, Is.All.InstanceOf(type)); /* fail message: Assert.That(collection, Is.All.InstanceOf(type)) + Expected: all items instance of + But was: < 1, 2, "3" > + First non-matching item at index [2]: "3" + */ +Assert.That(collection, Has.All.InstanceOf(type)); /* fail message: Assert.That(collection, Has.All.InstanceOf(type)) + 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.Nunit3/Nunit3AnalyzerTests.cs b/src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs.Nunit3/Nunit3AnalyzerTests.cs index 49a8d78..c51c274 100644 --- a/src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs.Nunit3/Nunit3AnalyzerTests.cs +++ b/src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs.Nunit3/Nunit3AnalyzerTests.cs @@ -1087,13 +1087,17 @@ public void CollectionAssertAllItemsAreInstancesOfType() // old assertion: CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); + Assert.That(collection, Is.All.InstanceOf(typeof(int))); + Assert.That(collection, Is.All.InstanceOf()); + Assert.That(collection, Has.All.InstanceOf(typeof(int))); + Assert.That(collection, Has.All.InstanceOf()); // new assertion: collection.Should().AllBeOfType(); } [Test, ExpectedAssertionException] - public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion() + public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion_0() { // arrange var collection = new object[] { 1, 2, "3" }; @@ -1102,6 +1106,46 @@ public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion() CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); } + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion_1() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + + // old assertion: + Assert.That(collection, Is.All.InstanceOf(typeof(int))); + } + + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion_2() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + + // old assertion: + Assert.That(collection, Is.All.InstanceOf()); + } + + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion_3() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + + // old assertion: + Assert.That(collection, Has.All.InstanceOf(typeof(int))); + } + + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion_4() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + + // old assertion: + Assert.That(collection, Has.All.InstanceOf()); + } + [Test, ExpectedAssertionException] public void CollectionAssertAllItemsAreInstancesOfType_Failure_NewAssertion() { @@ -1121,13 +1165,15 @@ public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument() // old assertion: CollectionAssert.AllItemsAreInstancesOfType(collection, type); + Assert.That(collection, Is.All.InstanceOf(type)); + Assert.That(collection, Has.All.InstanceOf(type)); // new assertion: collection.Should().AllBeOfType(type); } [Test, ExpectedAssertionException] - public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_OldAssertion() + public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_OldAssertion_0() { // arrange var collection = new object[] { 1, 2, "3" }; @@ -1137,6 +1183,28 @@ public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_ CollectionAssert.AllItemsAreInstancesOfType(collection, type); } + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_OldAssertion_1() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + var type = typeof(int); + + // old assertion: + Assert.That(collection, Is.All.InstanceOf(type)); + } + + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_OldAssertion_2() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + var type = typeof(int); + + // old assertion: + Assert.That(collection, Has.All.InstanceOf(type)); + } + [Test, ExpectedAssertionException] public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_NewAssertion() { diff --git a/src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs.Nunit4/Nunit4AnalyzerTests.cs b/src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs.Nunit4/Nunit4AnalyzerTests.cs index fb82408..494c684 100644 --- a/src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs.Nunit4/Nunit4AnalyzerTests.cs +++ b/src/FluentAssertions.Analyzers.FluentAssertionAnalyzerDocs.Nunit4/Nunit4AnalyzerTests.cs @@ -1099,6 +1099,7 @@ public void CollectionAssertDoesNotContain_WithCasting_Failure_NewAssertion() collection.Should().NotContain((int)item); } + [Test] public void CollectionAssertAllItemsAreInstancesOfType() { @@ -1107,13 +1108,17 @@ public void CollectionAssertAllItemsAreInstancesOfType() // old assertion: CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); + Assert.That(collection, Is.All.InstanceOf(typeof(int))); + Assert.That(collection, Is.All.InstanceOf()); + Assert.That(collection, Has.All.InstanceOf(typeof(int))); + Assert.That(collection, Has.All.InstanceOf()); // new assertion: collection.Should().AllBeOfType(); } [Test, ExpectedAssertionException] - public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion() + public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion_0() { // arrange var collection = new object[] { 1, 2, "3" }; @@ -1122,6 +1127,46 @@ public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion() CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(int)); } + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion_1() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + + // old assertion: + Assert.That(collection, Is.All.InstanceOf(typeof(int))); + } + + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion_2() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + + // old assertion: + Assert.That(collection, Is.All.InstanceOf()); + } + + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion_3() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + + // old assertion: + Assert.That(collection, Has.All.InstanceOf(typeof(int))); + } + + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_Failure_OldAssertion_4() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + + // old assertion: + Assert.That(collection, Has.All.InstanceOf()); + } + [Test, ExpectedAssertionException] public void CollectionAssertAllItemsAreInstancesOfType_Failure_NewAssertion() { @@ -1141,13 +1186,15 @@ public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument() // old assertion: CollectionAssert.AllItemsAreInstancesOfType(collection, type); + Assert.That(collection, Is.All.InstanceOf(type)); + Assert.That(collection, Has.All.InstanceOf(type)); // new assertion: collection.Should().AllBeOfType(type); } [Test, ExpectedAssertionException] - public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_OldAssertion() + public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_OldAssertion_0() { // arrange var collection = new object[] { 1, 2, "3" }; @@ -1157,6 +1204,28 @@ public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_ CollectionAssert.AllItemsAreInstancesOfType(collection, type); } + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_OldAssertion_1() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + var type = typeof(int); + + // old assertion: + Assert.That(collection, Is.All.InstanceOf(type)); + } + + [Test, ExpectedAssertionException] + public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_OldAssertion_2() + { + // arrange + var collection = new object[] { 1, 2, "3" }; + var type = typeof(int); + + // old assertion: + Assert.That(collection, Has.All.InstanceOf(type)); + } + [Test, ExpectedAssertionException] public void CollectionAssertAllItemsAreInstancesOfType_WithTypeArgument_Failure_NewAssertion() { diff --git a/src/FluentAssertions.Analyzers.Tests/Tips/NunitTests.cs b/src/FluentAssertions.Analyzers.Tests/Tips/NunitTests.cs index 294ae51..4da56f9 100644 --- a/src/FluentAssertions.Analyzers.Tests/Tips/NunitTests.cs +++ b/src/FluentAssertions.Analyzers.Tests/Tips/NunitTests.cs @@ -1728,12 +1728,24 @@ public void Nunit4_CollectionAssertDoesNotContain_WithCasting_TestCodeFix(string [DataTestMethod] [AssertionDiagnostic("CollectionAssert.AllItemsAreInstancesOfType(actual, typeof(string){0});")] [AssertionDiagnostic("CollectionAssert.AllItemsAreInstancesOfType(actual, type{0});")] + [AssertionDiagnostic("Assert.That(actual, Is.All.InstanceOf(typeof(int)){0});")] + [AssertionDiagnostic("Assert.That(actual, Is.All.InstanceOf(){0});")] + [AssertionDiagnostic("Assert.That(actual, Is.All.InstanceOf(type){0});")] + [AssertionDiagnostic("Assert.That(actual, Has.All.InstanceOf(typeof(int)){0});")] + [AssertionDiagnostic("Assert.That(actual, Has.All.InstanceOf(){0});")] + [AssertionDiagnostic("Assert.That(actual, Has.All.InstanceOf(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});")] + [AssertionDiagnostic("Assert.That(actual, Is.All.InstanceOf(typeof(int)));")] + [AssertionDiagnostic("Assert.That(actual, Is.All.InstanceOf());")] + [AssertionDiagnostic("Assert.That(actual, Is.All.InstanceOf(type));")] + [AssertionDiagnostic("Assert.That(actual, Has.All.InstanceOf(typeof(int)));")] + [AssertionDiagnostic("Assert.That(actual, Has.All.InstanceOf());")] + [AssertionDiagnostic("Assert.That(actual, Has.All.InstanceOf(type));")] [Implemented] public void Nunit4_CollectionAssertAllItemsAreInstancesOfType_TestAnalyzer(string assertion) => Nunit4VerifyDiagnostic("IEnumerable actual, Type type", assertion); @@ -1744,6 +1756,24 @@ public void Nunit4_CollectionAssertDoesNotContain_WithCasting_TestCodeFix(string [AssertionCodeFix( oldAssertion: "CollectionAssert.AllItemsAreInstancesOfType(actual, type{0});", newAssertion: "actual.Should().AllBeOfType(type{0});")] + [AssertionCodeFix( + oldAssertion: "Assert.That(actual, Is.All.InstanceOf(typeof(int)){0});", + newAssertion: "actual.Should().AllBeOfType({0});")] + [AssertionCodeFix( + oldAssertion: "Assert.That(actual, Is.All.InstanceOf(){0});", + newAssertion: "actual.Should().AllBeOfType({0});")] + [AssertionCodeFix( + oldAssertion: "Assert.That(actual, Is.All.InstanceOf(type){0});", + newAssertion: "actual.Should().AllBeOfType(type{0});")] + [AssertionCodeFix( + oldAssertion: "Assert.That(actual, Has.All.InstanceOf(typeof(int)){0});", + newAssertion: "actual.Should().AllBeOfType({0});")] + [AssertionCodeFix( + oldAssertion: "Assert.That(actual, Has.All.InstanceOf(){0});", + newAssertion: "actual.Should().AllBeOfType({0});")] + [AssertionCodeFix( + oldAssertion: "Assert.That(actual, Has.All.InstanceOf(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); @@ -1754,6 +1784,24 @@ public void Nunit4_CollectionAssertDoesNotContain_WithCasting_TestCodeFix(string [AssertionCodeFix( oldAssertion: "CollectionAssert.AllItemsAreInstancesOfType(actual, type{0});", newAssertion: "actual.Should().AllBeOfType(type{0});")] + [AssertionCodeFix( + oldAssertion: "Assert.That(actual, Is.All.InstanceOf(typeof(int)));", + newAssertion: "actual.Should().AllBeOfType();")] + [AssertionCodeFix( + oldAssertion: "Assert.That(actual, Is.All.InstanceOf());", + newAssertion: "actual.Should().AllBeOfType();")] + [AssertionCodeFix( + oldAssertion: "Assert.That(actual, Is.All.InstanceOf(type));", + newAssertion: "actual.Should().AllBeOfType(type);")] + [AssertionCodeFix( + oldAssertion: "Assert.That(actual, Has.All.InstanceOf(typeof(int)));", + newAssertion: "actual.Should().AllBeOfType();")] + [AssertionCodeFix( + oldAssertion: "Assert.That(actual, Has.All.InstanceOf());", + newAssertion: "actual.Should().AllBeOfType();")] + [AssertionCodeFix( + oldAssertion: "Assert.That(actual, Has.All.InstanceOf(type));", + newAssertion: "actual.Should().AllBeOfType(type);")] [Implemented] public void Nunit4_CollectionAssertAllItemsAreInstancesOfType_TestCodeFix(string oldAssertion, string newAssertion) => Nunit4VerifyFix("IEnumerable actual, Type type", oldAssertion, newAssertion); diff --git a/src/FluentAssertions.Analyzers/Tips/NunitCodeFixProvider.cs b/src/FluentAssertions.Analyzers/Tips/NunitCodeFixProvider.cs index 6009732..be6c6ed 100644 --- a/src/FluentAssertions.Analyzers/Tips/NunitCodeFixProvider.cs +++ b/src/FluentAssertions.Analyzers/Tips/NunitCodeFixProvider.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; +using System.Linq; namespace FluentAssertions.Analyzers; @@ -472,6 +473,18 @@ private CreateChangedDocument TryComputeFixForNunitThat(IInvocationOperation inv return rewriter.Should("Equal", argument); else if (matcher.Is("Not", Method("EqualTo"), out argument)) return rewriter.Should("NotEqual", argument); + else if (matcher.Is("All", GenericMethod("InstanceOf"), out argument, out var genericType) + || matcher.Has("All", GenericMethod("InstanceOf"), out argument, out genericType)) + return rewriter.ShouldGeneric("AllBeOfType", genericType); + else if (matcher.Is("All", Method("InstanceOf"), out argument) + || matcher.Has("All", Method("InstanceOf"), out argument)) + { + if (argument.Value is ITypeOfOperation typeOf) + { + return rewriter.ShouldGeneric("AllBeOfType", typeOf.TypeOperand); + } + return rewriter.Should("AllBeOfType", argument); + } } if (matcher.Is("Zero")) return rewriter.Should("Be", g => g.LiteralExpression(0)); @@ -539,12 +552,30 @@ private class MethodInvocationMatcher(string name) : IOperationMatcher return (invocation.Instance, invocation.TargetMethod.ContainingType); } } + private class GenericMethodInvocationMatcher(string name) : IOperationMatcher + { + public IArgumentOperation Argument { get; private set; } + public ITypeSymbol TypeArgument { get; private set; } + public (IOperation op, ISymbol containingType) TryGetNext(IOperation operation) + { + if (operation is not IInvocationOperation invocation) return default; + if (invocation.TargetMethod.Name != name) return default; + if (!invocation.TargetMethod.IsGenericMethod) return default; + if (invocation.TargetMethod.TypeArguments.Length is not 1) return default; + + Argument = invocation.Arguments.FirstOrDefault(); + TypeArgument = invocation.TargetMethod.TypeArguments[0]; + + return (invocation.Instance, invocation.TargetMethod.ContainingType); + } + } private class PropertyReferenceMatcher(string name) : IOperationMatcher { public (IOperation op, ISymbol containingType) TryGetNext(IOperation operation) => operation is IPropertyReferenceOperation propertyReference && propertyReference.Property.Name == name ? (propertyReference.Instance, propertyReference.Member.ContainingType) : (null, null); } private static MethodInvocationMatcher Method(string name) => new MethodInvocationMatcher(name); + private static GenericMethodInvocationMatcher GenericMethod(string name) => new GenericMethodInvocationMatcher(name); private static PropertyReferenceMatcher Property(string name) => new PropertyReferenceMatcher(name); private static bool IsArgumentTypeOfNonGenericEnumerable(IInvocationOperation invocation, int argumentIndex) => IsArgumentTypeOf(invocation, argumentIndex, SpecialType.System_Collections_IEnumerable); @@ -568,9 +599,15 @@ private class AssertThatMatcher(IOperation constraint, NunitCodeFixContext t) { public bool Is(MethodInvocationMatcher methodMatcher, out IArgumentOperation argument) => Matches(t.Is, methodMatcher, out argument); public bool Is(string propertyMatcher, MethodInvocationMatcher methodMatcher, out IArgumentOperation argument) => Matches(t.Is, [Property(propertyMatcher)], methodMatcher, out argument); + public bool Is(string propertyMatcher, GenericMethodInvocationMatcher genericMethodMatcher, out IArgumentOperation argument, out ITypeSymbol genericType) + => Matches(t.Is, [Property(propertyMatcher)], genericMethodMatcher, out argument, out genericType); + public bool Is(PropertyReferenceMatcher[] propertyMatchers, GenericMethodInvocationMatcher genericMethodMatcher, out IArgumentOperation argument, out ITypeSymbol genericType) + => Matches(t.Is, propertyMatchers, genericMethodMatcher, out argument, out genericType); public bool Has(MethodInvocationMatcher methodMatcher, out IArgumentOperation argument) => Matches(t.Has, methodMatcher, out argument); public bool Has(string propertyMatcher, MethodInvocationMatcher methodMatcher, out IArgumentOperation argument) => Matches(t.Has, [Property(propertyMatcher)], methodMatcher, out argument); + public bool Has(string propertyMatcher, GenericMethodInvocationMatcher genericMethodMatcher, out IArgumentOperation argument, out ITypeSymbol genericType) + => Matches(t.Has, [Property(propertyMatcher)], genericMethodMatcher, out argument, out genericType); public bool Does(MethodInvocationMatcher methodMatcher, out IArgumentOperation argument) => Matches(t.Does, methodMatcher, out argument); public bool Contains(MethodInvocationMatcher methodMatcher, out IArgumentOperation argument) => Matches(t.Contains, methodMatcher, out argument); public bool Contains(string propertyMatcher, MethodInvocationMatcher methodMatcher, out IArgumentOperation argument) => Matches(t.Contains, [Property(propertyMatcher)], methodMatcher, out argument); @@ -589,6 +626,21 @@ private bool Matches(INamedTypeSymbol type, IOperationMatcher[] matchers, Method if (result) argument = methodMatcher.Argument; return result; } + private bool Matches(INamedTypeSymbol type, IOperationMatcher[] matchers, GenericMethodInvocationMatcher genericMethodMatcher, + out IArgumentOperation argument, out ITypeSymbol genericType) + { + argument = null; + genericType = null; + + var result = Matches(type, [.. matchers, genericMethodMatcher]); + if (result) + { + argument = genericMethodMatcher.Argument; + genericType = genericMethodMatcher.TypeArgument; + } + + return result; + } private bool Matches(INamedTypeSymbol type, params IOperationMatcher[] matchers) { IOperation currentOp = constraint; @@ -616,6 +668,10 @@ public CreateChangedDocument Should(string assertion) { return DocumentEditorUtils.RenameMethodToSubjectShouldAssertion(invocation, context, assertion, subjectIndex: 0, argumentsToRemove: [1]); } + public CreateChangedDocument ShouldGeneric(string assertion, ITypeSymbol genericType) + { + return DocumentEditorUtils.RenameMethodToSubjectShouldGenericAssertion(invocation, ImmutableArray.Create(genericType), context, assertion, subjectIndex: 0, argumentsToRemove: [1]); + } public CreateChangedDocument Should(string assertion, IArgumentOperation argument) => Should(assertion, _ => argument.Value.Syntax); public CreateChangedDocument Should(string assertion, Func argumentGenerator)