diff --git a/src/FluentAssertions.Analyzers.Tests/DiagnosticVerifier.cs b/src/FluentAssertions.Analyzers.Tests/DiagnosticVerifier.cs index 1fff12ad..49e83bc1 100644 --- a/src/FluentAssertions.Analyzers.Tests/DiagnosticVerifier.cs +++ b/src/FluentAssertions.Analyzers.Tests/DiagnosticVerifier.cs @@ -16,6 +16,8 @@ using Microsoft.CodeAnalysis.CSharp; using System.Reflection; +using XunitAssert = Xunit.Assert; + namespace FluentAssertions.Analyzers.Tests { /// @@ -34,7 +36,8 @@ static DiagnosticVerifier() typeof(Compilation), // Microsoft.CodeAnalysis typeof(AssertionScope), // FluentAssertions.Core typeof(AssertionExtensions), // FluentAssertions - typeof(Microsoft.VisualStudio.TestTools.UnitTesting.Assert) // MsTest + typeof(Microsoft.VisualStudio.TestTools.UnitTesting.Assert), // MsTest + typeof(XunitAssert), // Xunit }.Select(type => type.GetTypeInfo().Assembly.Location) .Append(GetSystemAssemblyPathByName("System.Globalization.dll")) .Append(GetSystemAssemblyPathByName("System.Text.RegularExpressions.dll")) diff --git a/src/FluentAssertions.Analyzers.Tests/FluentAssertions.Analyzers.Tests.csproj b/src/FluentAssertions.Analyzers.Tests/FluentAssertions.Analyzers.Tests.csproj index 38980a99..afa56a08 100644 --- a/src/FluentAssertions.Analyzers.Tests/FluentAssertions.Analyzers.Tests.csproj +++ b/src/FluentAssertions.Analyzers.Tests/FluentAssertions.Analyzers.Tests.csproj @@ -11,6 +11,7 @@ + diff --git a/src/FluentAssertions.Analyzers.Tests/GenerateCode.cs b/src/FluentAssertions.Analyzers.Tests/GenerateCode.cs index f00c1403..143bbe6b 100644 --- a/src/FluentAssertions.Analyzers.Tests/GenerateCode.cs +++ b/src/FluentAssertions.Analyzers.Tests/GenerateCode.cs @@ -194,6 +194,25 @@ public static string GenericIListExpressionBodyAssertion(string assertion) => Ge .AppendLine("}") .ToString(); + public static string XunitAssertion(string methodArguments, string assertion) => new StringBuilder() + .AppendLine("using System;") + .AppendLine("using FluentAssertions;") + .AppendLine("using FluentAssertions.Extensions;") + .AppendLine("using Xunit;") + .AppendLine("using System.Threading.Tasks;") + .AppendLine("namespace TestNamespace") + .AppendLine("{") + .AppendLine(" class TestClass") + .AppendLine(" {") + .AppendLine($" void TestMethod({methodArguments})") + .AppendLine(" {") + .AppendLine($" {assertion}") + .AppendLine(" }") + .AppendLine(" }") + .AppendMainMethod() + .AppendLine("}") + .ToString(); + private static StringBuilder AppendMainMethod(this StringBuilder builder) => builder .AppendLine(" class Program") .AppendLine(" {") diff --git a/src/FluentAssertions.Analyzers.Tests/Tips/XunitTests.cs b/src/FluentAssertions.Analyzers.Tests/Tips/XunitTests.cs new file mode 100644 index 00000000..e2fc95b6 --- /dev/null +++ b/src/FluentAssertions.Analyzers.Tests/Tips/XunitTests.cs @@ -0,0 +1,90 @@ +using Microsoft.CodeAnalysis; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using FluentAssertions.Analyzers.Xunit; + +namespace FluentAssertions.Analyzers.Tests.Tips +{ + [TestClass] + public class XunitTests + { + [DataTestMethod] + [DataRow("Assert.True(actual);")] + [DataRow("Assert.True(actual, \"because it's possible\");")] + [DataRow("Assert.True(bool.Parse(\"true\"));")] + [DataRow("Assert.True(bool.Parse(\"true\"), \"because it's possible\");")] + [Implemented] + public void AssertTrue_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic("bool actual", assertion); + + [DataTestMethod] + [DataRow( + /* oldAssertion: */ "Assert.True(actual);", + /* newAssertion: */ "actual.Should().BeTrue();")] + [DataRow( + /* oldAssertion: */ "Assert.True(actual, \"because it's possible\");", + /* newAssertion: */ "actual.Should().BeTrue(\"because it's possible\");")] + [DataRow( + /* oldAssertion: */ "Assert.True(bool.Parse(\"true\"));", + /* newAssertion: */ "bool.Parse(\"true\").Should().BeTrue();")] + [DataRow( + /* oldAssertion: */ "Assert.True(bool.Parse(\"true\"), \"because it's possible\");", + /* newAssertion: */ "bool.Parse(\"true\").Should().BeTrue(\"because it's possible\");")] + [Implemented] + public void AssertTrue_TestCodeFix(string oldAssertion, string newAssertion) + => VerifyCSharpFix("bool actual", oldAssertion, newAssertion); + + [DataTestMethod] + [DataRow("Assert.False(actual);")] + [DataRow("Assert.False(actual, \"because it's possible\");")] + [DataRow("Assert.False(bool.Parse(\"false\"));")] + [DataRow("Assert.False(bool.Parse(\"false\"), \"because it's possible\");")] + [Implemented] + public void AssertFalse_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic("bool actual", assertion); + + [DataTestMethod] + [DataRow( + /* oldAssertion: */ "Assert.False(actual);", + /* newAssertion: */ "actual.Should().BeFalse();")] + [DataRow( + /* oldAssertion: */ "Assert.False(actual, \"because it's possible\");", + /* newAssertion: */ "actual.Should().BeFalse(\"because it's possible\");")] + [DataRow( + /* oldAssertion: */ "Assert.False(bool.Parse(\"false\"));", + /* newAssertion: */ "bool.Parse(\"false\").Should().BeFalse();")] + [DataRow( + /* oldAssertion: */ "Assert.False(bool.Parse(\"false\"), \"because it's possible\");", + /* newAssertion: */ "bool.Parse(\"false\").Should().BeFalse(\"because it's possible\");")] + [Implemented] + public void AssertFalse_TestCodeFix(string oldAssertion, string newAssertion) + => VerifyCSharpFix("bool actual", oldAssertion, newAssertion); + + private void VerifyCSharpDiagnostic(string methodArguments, string assertion) where TDiagnosticAnalyzer : Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer, new() + { + var source = GenerateCode.XunitAssertion(methodArguments, assertion); + + var type = typeof(TDiagnosticAnalyzer); + var diagnosticId = (string)type.GetField("DiagnosticId").GetValue(null); + var message = (string)type.GetField("Message").GetValue(null); + + DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(source, new DiagnosticResult + { + Id = diagnosticId, + Message = message, + Locations = new DiagnosticResultLocation[] + { + new DiagnosticResultLocation("Test0.cs", 12, 13) + }, + Severity = DiagnosticSeverity.Info + }); + } + + private void VerifyCSharpFix(string methodArguments, string oldAssertion, string newAssertion) + where TCodeFixProvider : Microsoft.CodeAnalysis.CodeFixes.CodeFixProvider, new() + where TDiagnosticAnalyzer : Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer, new() + { + var oldSource = GenerateCode.XunitAssertion(methodArguments, oldAssertion); + var newSource = GenerateCode.XunitAssertion(methodArguments, newAssertion); + + DiagnosticVerifier.VerifyCSharpFix(oldSource, newSource); + } + } +} diff --git a/src/FluentAssertions.Analyzers/Constants.cs b/src/FluentAssertions.Analyzers/Constants.cs index b0518324..cc5f5193 100644 --- a/src/FluentAssertions.Analyzers/Constants.cs +++ b/src/FluentAssertions.Analyzers/Constants.cs @@ -115,6 +115,12 @@ public static class MsTest public const string CollectionAssertIsSubsetOf = nameof(CollectionAssertIsSubsetOf); public const string CollectionAssertIsNotSubsetOf = nameof(CollectionAssertIsNotSubsetOf); } + + public static class Xunit + { + public const string AssertTrue = nameof(AssertTrue); + public const string AssertFalse = nameof(AssertFalse); + } } public static class CodeSmell diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreEqual.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreEqual.cs index afb5e631..6f7bb96e 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreEqual.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreEqual.cs @@ -80,7 +80,7 @@ public AssertObjectAreEqualSyntaxVisitor() : base(new MemberValidator("AreEqual" } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertAreEqualCodeFix)), Shared] - public class AssertAreEqualCodeFix : MsTestCodeFixProvider + public class AssertAreEqualCodeFix : MsTestAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AssertAreEqualAnalyzer.DiagnosticId); @@ -90,12 +90,12 @@ protected override async Task GetNewExpressionAsync(Expression { case nameof(AssertAreEqualAnalyzer.AssertFloatAreEqualWithDeltaSyntaxVisitor): case nameof(AssertAreEqualAnalyzer.AssertDoubleAreEqualWithDeltaSyntaxVisitor): - return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreEqual", "BeApproximately", "Assert"); + return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreEqual", "BeApproximately"); case nameof(AssertAreEqualAnalyzer.AssertObjectAreEqualSyntaxVisitor): - return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreEqual", "Be", "Assert"); + return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreEqual", "Be"); case nameof(AssertAreEqualAnalyzer.AssertStringAreEqualSyntaxVisitor): var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - return GetNewExpressionForAreNotEqualOrAreEqualStrings(expression, semanticModel, "AreEqual", "Be", "BeEquivalentTo", "Assert"); + return GetNewExpressionForAreNotEqualOrAreEqualStrings(expression, semanticModel, "AreEqual", "Be", "BeEquivalentTo"); default: throw new System.InvalidOperationException($"Invalid visitor name - {properties.VisitorName}"); } diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreNotEqual.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreNotEqual.cs index a3030fe2..eae855d9 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreNotEqual.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreNotEqual.cs @@ -81,7 +81,7 @@ public AssertObjectAreNotEqualSyntaxVisitor() : base(new MemberValidator("AreNot } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertAreNotEqualCodeFix)), Shared] - public class AssertAreNotEqualCodeFix : MsTestCodeFixProvider + public class AssertAreNotEqualCodeFix : MsTestAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AssertAreNotEqualAnalyzer.DiagnosticId); @@ -91,12 +91,12 @@ protected override async Task GetNewExpressionAsync(Expression { case nameof(AssertAreNotEqualAnalyzer.AssertFloatAreNotEqualWithDeltaSyntaxVisitor): case nameof(AssertAreNotEqualAnalyzer.AssertDoubleAreNotEqualWithDeltaSyntaxVisitor): - return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreNotEqual", "NotBeApproximately", "Assert"); + return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreNotEqual", "NotBeApproximately"); case nameof(AssertAreNotEqualAnalyzer.AssertObjectAreNotEqualSyntaxVisitor): - return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreNotEqual", "NotBe", "Assert"); + return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreNotEqual", "NotBe"); case nameof(AssertAreNotEqualAnalyzer.AssertStringAreNotEqualSyntaxVisitor): var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - return GetNewExpressionForAreNotEqualOrAreEqualStrings(expression, semanticModel, "AreNotEqual", "NotBe", "NotBeEquivalentTo", "Assert"); + return GetNewExpressionForAreNotEqualOrAreEqualStrings(expression, semanticModel, "AreNotEqual", "NotBe", "NotBeEquivalentTo"); default: throw new System.InvalidOperationException($"Invalid visitor name - {properties.VisitorName}"); } diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreNotSame.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreNotSame.cs index 57199778..e5d607db 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreNotSame.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreNotSame.cs @@ -34,11 +34,11 @@ public AssertAreNotSameSyntaxVisitor() : base(new MemberValidator("AreNotSame")) } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertAreNotSameCodeFix)), Shared] - public class AssertAreNotSameCodeFix : MsTestCodeFixProvider + public class AssertAreNotSameCodeFix : MsTestAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AssertAreNotSameAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) - => RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreNotSame", "NotBeSameAs", "Assert"); + => RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreNotSame", "NotBeSameAs"); } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreSame.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreSame.cs index fadc4518..170ca20f 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreSame.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreSame.cs @@ -34,11 +34,11 @@ public AssertAreSameSyntaxVisitor() : base(new MemberValidator("AreSame")) } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertAreSameCodeFix)), Shared] - public class AssertAreSameCodeFix : MsTestCodeFixProvider + public class AssertAreSameCodeFix : MsTestAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AssertAreSameAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) - => RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreSame", "BeSameAs", "Assert"); + => RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreSame", "BeSameAs"); } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsFalse.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsFalse.cs index ed40c402..1bf0b759 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsFalse.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsFalse.cs @@ -34,11 +34,11 @@ public AssertIsFalseSyntaxVisitor() : base(new MemberValidator("IsFalse")) } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertIsFalseCodeFix)), Shared] - public class AssertIsFalseCodeFix : MsTestCodeFixProvider + public class AssertIsFalseCodeFix : MsTestAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CollectionShouldBeEmptyAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) - => RenameMethodAndReplaceWithSubjectShould(expression, "IsFalse", "BeFalse", "Assert"); + => RenameMethodAndReplaceWithSubjectShould(expression, "IsFalse", "BeFalse"); } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsInstanceOfType.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsInstanceOfType.cs index a846ca9f..b0a06696 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsInstanceOfType.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsInstanceOfType.cs @@ -36,13 +36,13 @@ public AssertIsInstanceOfTypeSyntaxVisitor() : base(new MemberValidator("IsInsta } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertIsInstanceOfTypeCodeFix)), Shared] - public class AssertIsInstanceOfTypeCodeFix : MsTestCodeFixProvider + public class AssertIsInstanceOfTypeCodeFix : MsTestAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AssertIsInstanceOfTypeAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - var newExpression = RenameMethodAndReplaceWithSubjectShould(expression, "IsInstanceOfType", "BeOfType", "Assert"); + var newExpression = RenameMethodAndReplaceWithSubjectShould(expression, "IsInstanceOfType", "BeOfType"); var beOfType = newExpression.DescendantNodes() .OfType() diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsNotInstanceOfType.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsNotInstanceOfType.cs index 9a246b57..829e7108 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsNotInstanceOfType.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsNotInstanceOfType.cs @@ -36,13 +36,13 @@ public AssertIsNotInstanceOfTypeSyntaxVisitor() : base(new MemberValidator("IsNo } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertIsNotInstanceOfTypeCodeFix)), Shared] - public class AssertIsNotInstanceOfTypeCodeFix : MsTestCodeFixProvider + public class AssertIsNotInstanceOfTypeCodeFix : MsTestAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AssertIsNotInstanceOfTypeAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - var newExpression = RenameMethodAndReplaceWithSubjectShould(expression, "IsNotInstanceOfType", "NotBeOfType", "Assert"); + var newExpression = RenameMethodAndReplaceWithSubjectShould(expression, "IsNotInstanceOfType", "NotBeOfType"); var beOfType = newExpression.DescendantNodes() .OfType() diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsNotNull.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsNotNull.cs index dd5a2273..6842997f 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsNotNull.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsNotNull.cs @@ -34,11 +34,11 @@ public AssertIsNotNullSyntaxVisitor() : base(new MemberValidator("IsNotNull")) } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertIsNotNullCodeFix)), Shared] - public class AssertIsNotNullCodeFix : MsTestCodeFixProvider + public class AssertIsNotNullCodeFix : MsTestAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AssertIsNotNullAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) - => RenameMethodAndReplaceWithSubjectShould(expression, "IsNotNull", "NotBeNull", "Assert"); + => RenameMethodAndReplaceWithSubjectShould(expression, "IsNotNull", "NotBeNull"); } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsNull.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsNull.cs index e6222c42..3eb6b086 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsNull.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsNull.cs @@ -34,11 +34,11 @@ public AssertIsNullSyntaxVisitor() : base(new MemberValidator("IsNull")) } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertIsNullCodeFix)), Shared] - public class AssertIsNullCodeFix : MsTestCodeFixProvider + public class AssertIsNullCodeFix : MsTestAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AssertIsNullAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) - => RenameMethodAndReplaceWithSubjectShould(expression, "IsNull", "BeNull", "Assert"); + => RenameMethodAndReplaceWithSubjectShould(expression, "IsNull", "BeNull"); } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsTrue.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsTrue.cs index 1cd0c784..059f77de 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsTrue.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsTrue.cs @@ -34,11 +34,11 @@ public AssertIsTrueSyntaxVisitor() : base(new MemberValidator("IsTrue")) } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertIsTrueCodeFix)), Shared] - public class AssertIsTrueCodeFix : MsTestCodeFixProvider + public class AssertIsTrueCodeFix : MsTestAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CollectionShouldBeEmptyAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) - => RenameMethodAndReplaceWithSubjectShould(expression, "IsTrue", "BeTrue", "Assert"); + => RenameMethodAndReplaceWithSubjectShould(expression, "IsTrue", "BeTrue"); } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertThrowsException.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertThrowsException.cs index f3a042c1..71a65e11 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertThrowsException.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertThrowsException.cs @@ -34,11 +34,11 @@ public AssertThrowsExceptionSyntaxVisitor() : base(new MemberValidator("ThrowsEx } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertThrowsExceptionCodeFix)), Shared] - public class AssertThrowsExceptionCodeFix : MsTestCodeFixProvider + public class AssertThrowsExceptionCodeFix : MsTestAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AssertThrowsExceptionAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) - => RenameMethodAndReplaceWithSubjectShould(expression, "ThrowsException", "ThrowExactly", "Assert"); + => RenameMethodAndReplaceWithSubjectShould(expression, "ThrowsException", "ThrowExactly"); } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertThrowsExceptionAsync.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertThrowsExceptionAsync.cs index a77b2978..f53205a7 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/AssertThrowsExceptionAsync.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/AssertThrowsExceptionAsync.cs @@ -34,11 +34,11 @@ public AssertThrowsExceptionAsyncSyntaxVisitor() : base(new MemberValidator("Thr } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertThrowsExceptionAsyncCodeFix)), Shared] - public class AssertThrowsExceptionAsyncCodeFix : MsTestCodeFixProvider + public class AssertThrowsExceptionAsyncCodeFix : MsTestAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AssertThrowsExceptionAsyncAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) - => RenameMethodAndReplaceWithSubjectShould(expression, "ThrowsExceptionAsync", "ThrowExactlyAsync", "Assert"); + => RenameMethodAndReplaceWithSubjectShould(expression, "ThrowsExceptionAsync", "ThrowExactlyAsync"); } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAllItemsAreInstancesOfType.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAllItemsAreInstancesOfType.cs index 1f84710b..f1fec5a3 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAllItemsAreInstancesOfType.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAllItemsAreInstancesOfType.cs @@ -34,13 +34,13 @@ public CollectionAssertAllItemsAreInstancesOfTypeSyntaxVisitor() : base(new Memb } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CollectionAssertAllItemsAreInstancesOfTypeCodeFix)), Shared] - public class CollectionAssertAllItemsAreInstancesOfTypeCodeFix : MsTestCodeFixProvider + public class CollectionAssertAllItemsAreInstancesOfTypeCodeFix : MsTestCollectionAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CollectionAssertAllItemsAreInstancesOfTypeAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - var newExpression = RenameMethodAndReplaceWithSubjectShould(expression, "AllItemsAreInstancesOfType", "AllBeOfType", "CollectionAssert"); + var newExpression = RenameMethodAndReplaceWithSubjectShould(expression, "AllItemsAreInstancesOfType", "AllBeOfType"); var argumentsReplacer = NodeReplacement.RemoveFirstArgument("AllBeOfType"); var possibleNewExpression = GetNewExpression(newExpression, argumentsReplacer); diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAllItemsAreNotNull.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAllItemsAreNotNull.cs index 589d4a58..08c9c533 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAllItemsAreNotNull.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAllItemsAreNotNull.cs @@ -34,13 +34,13 @@ public CollectionAssertAllItemsAreNotNullSyntaxVisitor() : base(new MemberValida } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CollectionAssertAllItemsAreNotNullCodeFix)), Shared] - public class CollectionAssertAllItemsAreNotNullCodeFix : MsTestCodeFixProvider + public class CollectionAssertAllItemsAreNotNullCodeFix : MsTestCollectionAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CollectionAssertAllItemsAreNotNullAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - return RenameMethodAndReplaceWithSubjectShould(expression, "AllItemsAreNotNull", "NotContainNulls", "CollectionAssert"); + return RenameMethodAndReplaceWithSubjectShould(expression, "AllItemsAreNotNull", "NotContainNulls"); } } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAllItemsAreUnique.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAllItemsAreUnique.cs index 14aec7bd..9039f490 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAllItemsAreUnique.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAllItemsAreUnique.cs @@ -34,13 +34,13 @@ public CollectionAssertAllItemsAreUniqueSyntaxVisitor() : base(new MemberValidat } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CollectionAssertAllItemsAreUniqueCodeFix)), Shared] - public class CollectionAssertAllItemsAreUniqueCodeFix : MsTestCodeFixProvider + public class CollectionAssertAllItemsAreUniqueCodeFix : MsTestCollectionAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CollectionAssertAllItemsAreUniqueAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - return RenameMethodAndReplaceWithSubjectShould(expression, "AllItemsAreUnique", "OnlyHaveUniqueItems", "CollectionAssert"); + return RenameMethodAndReplaceWithSubjectShould(expression, "AllItemsAreUnique", "OnlyHaveUniqueItems"); } } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreEqual.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreEqual.cs index 6c6ed557..8a86c921 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreEqual.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreEqual.cs @@ -34,13 +34,13 @@ public CollectionAssertAreEqualSyntaxVisitor() : base(new MemberValidator("AreEq } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CollectionAssertAreEqualCodeFix)), Shared] - public class CollectionAssertAreEqualCodeFix : MsTestCodeFixProvider + public class CollectionAssertAreEqualCodeFix : MsTestCollectionAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CollectionAssertAreEqualAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreEqual", "Equal", "CollectionAssert"); + return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreEqual", "Equal"); } } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreEquivalent.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreEquivalent.cs index 43f5eb4b..127fe85c 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreEquivalent.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreEquivalent.cs @@ -34,13 +34,13 @@ public CollectionAssertAreEquivalentSyntaxVisitor() : base(new MemberValidator(" } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CollectionAssertAreEquivalentCodeFix)), Shared] - public class CollectionAssertAreEquivalentCodeFix : MsTestCodeFixProvider + public class CollectionAssertAreEquivalentCodeFix : MsTestCollectionAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CollectionAssertAreEquivalentAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreEquivalent", "BeEquivalentTo", "CollectionAssert"); + return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreEquivalent", "BeEquivalentTo"); } } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreNotEqual.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreNotEqual.cs index b01a6bad..4bb4fc88 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreNotEqual.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreNotEqual.cs @@ -34,13 +34,13 @@ public CollectionAssertAreNotEqualSyntaxVisitor() : base(new MemberValidator("Ar } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CollectionAssertAreNotEqualCodeFix)), Shared] - public class CollectionAssertAreNotEqualCodeFix : MsTestCodeFixProvider + public class CollectionAssertAreNotEqualCodeFix : MsTestCollectionAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CollectionAssertAreNotEqualAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreNotEqual", "NotEqual", "CollectionAssert"); + return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreNotEqual", "NotEqual"); } } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreNotEquivalent.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreNotEquivalent.cs index 0e9167ba..be696041 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreNotEquivalent.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertAreNotEquivalent.cs @@ -34,13 +34,13 @@ public CollectionAssertAreNotEquivalentSyntaxVisitor() : base(new MemberValidato } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CollectionAssertAreNotEquivalentCodeFix)), Shared] - public class CollectionAssertAreNotEquivalentCodeFix : MsTestCodeFixProvider + public class CollectionAssertAreNotEquivalentCodeFix : MsTestCollectionAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CollectionAssertAreNotEquivalentAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreNotEquivalent", "NotBeEquivalentTo", "CollectionAssert"); + return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreNotEquivalent", "NotBeEquivalentTo"); } } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertContains.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertContains.cs index 952f13da..151ca17b 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertContains.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertContains.cs @@ -34,13 +34,13 @@ public CollectionAssertContainsSyntaxVisitor() : base(new MemberValidator("Conta } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CollectionAssertContainsCodeFix)), Shared] - public class CollectionAssertContainsCodeFix : MsTestCodeFixProvider + public class CollectionAssertContainsCodeFix : MsTestCollectionAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CollectionAssertContainsAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - return RenameMethodAndReplaceWithSubjectShould(expression, "Contains", "Contain", "CollectionAssert"); + return RenameMethodAndReplaceWithSubjectShould(expression, "Contains", "Contain"); } } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertDoesNotContain.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertDoesNotContain.cs index 33ac849c..f86abe30 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertDoesNotContain.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertDoesNotContain.cs @@ -34,13 +34,13 @@ public CollectionAssertDoesNotContainSyntaxVisitor() : base(new MemberValidator( } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CollectionAssertDoesNotContainCodeFix)), Shared] - public class CollectionAssertDoesNotContainCodeFix : MsTestCodeFixProvider + public class CollectionAssertDoesNotContainCodeFix : MsTestCollectionAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CollectionAssertDoesNotContainAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - return RenameMethodAndReplaceWithSubjectShould(expression, "DoesNotContain", "NotContain", "CollectionAssert"); + return RenameMethodAndReplaceWithSubjectShould(expression, "DoesNotContain", "NotContain"); } } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertIsNotSubsetOf.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertIsNotSubsetOf.cs index 546e27fc..989e67dd 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertIsNotSubsetOf.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertIsNotSubsetOf.cs @@ -34,13 +34,13 @@ public CollectionAssertIsNotSubsetOfSyntaxVisitor() : base(new MemberValidator(" } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CollectionAssertIsNotSubsetOfCodeFix)), Shared] - public class CollectionAssertIsNotSubsetOfCodeFix : MsTestCodeFixProvider + public class CollectionAssertIsNotSubsetOfCodeFix : MsTestCollectionAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CollectionAssertIsNotSubsetOfAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "IsNotSubsetOf", "NotBeSubsetOf", "CollectionAssert"); + return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "IsNotSubsetOf", "NotBeSubsetOf"); } } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertIsSubsetOf.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertIsSubsetOf.cs index 01e9c0b9..bbcdd4e9 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertIsSubsetOf.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/CollectionAssertIsSubsetOf.cs @@ -34,13 +34,13 @@ public CollectionAssertIsSubsetOfSyntaxVisitor() : base(new MemberValidator("IsS } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CollectionAssertIsSubsetOfCodeFix)), Shared] - public class CollectionAssertIsSubsetOfCodeFix : MsTestCodeFixProvider + public class CollectionAssertIsSubsetOfCodeFix : MsTestCollectionAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CollectionAssertIsSubsetOfAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "IsSubsetOf", "BeSubsetOf", "CollectionAssert"); + return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "IsSubsetOf", "BeSubsetOf"); } } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/MsTestBase.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/MsTestBase.cs index 478545d8..b7803cae 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/MsTestBase.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/MsTestBase.cs @@ -35,36 +35,18 @@ public abstract class MsTestCollectionAssertAnalyzer : MsTestAnalyzer protected override bool ShouldAnalyzeVariableType(INamedTypeSymbol type, SemanticModel semanticModel) => type.Name == "CollectionAssert"; } - public abstract class MsTestCodeFixProvider : FluentAssertionsCodeFixProvider + public abstract class MsTestAssertCodeFixProvider : TestingLibraryCodeFixBase { - protected ExpressionSyntax RenameMethodAndReplaceWithSubjectShould(ExpressionSyntax expression, string oldName, string newName, string assert) - { - var rename = NodeReplacement.RenameAndRemoveFirstArgument(oldName, newName); - var newExpression = GetNewExpression(expression, rename); + protected override string AssertClassName => "Assert"; - return ReplaceIdentifier(newExpression, assert, Expressions.SubjectShould(rename.Argument.Expression)); - } - - protected ExpressionSyntax RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(ExpressionSyntax expression, string oldName, string newName, string assert) + protected ExpressionSyntax GetNewExpressionForAreNotEqualOrAreEqualStrings(ExpressionSyntax expression, SemanticModel semanticModel, string oldName, string newName, string newNameIgnoreCase) { var rename = NodeReplacement.RenameAndExtractArguments(oldName, newName); var newExpression = GetNewExpression(expression, rename); var actual = rename.Arguments[1]; - newExpression = ReplaceIdentifier(newExpression, assert, Expressions.SubjectShould(actual.Expression)); - - return GetNewExpression(newExpression, NodeReplacement.WithArguments(newName, rename.Arguments.RemoveAt(1))); - } - - protected ExpressionSyntax GetNewExpressionForAreNotEqualOrAreEqualStrings(ExpressionSyntax expression, SemanticModel semanticModel, string oldName, string newName, string newNameIgnoreCase, string assert) - { - var rename = NodeReplacement.RenameAndExtractArguments(oldName, newName); - var newExpression = GetNewExpression(expression, rename); - - var actual = rename.Arguments[1]; - - newExpression = ReplaceIdentifier(newExpression, assert, Expressions.SubjectShould(actual.Expression)); + newExpression = ReplaceIdentifier(newExpression, AssertClassName, Expressions.SubjectShould(actual.Expression)); var newArguments = rename.Arguments.Remove(actual); @@ -90,4 +72,14 @@ protected ExpressionSyntax GetNewExpressionForAreNotEqualOrAreEqualStrings(Expre return newExpression; } } + + public abstract class MsTestCollectionAssertCodeFixProvider : TestingLibraryCodeFixBase + { + protected override string AssertClassName => "CollectionAssert"; + } + + public abstract class MsTestStringAssertCodeFixProvider : TestingLibraryCodeFixBase + { + protected override string AssertClassName => "StringAssert"; + } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertContains.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertContains.cs index d99d65ed..3676d502 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertContains.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertContains.cs @@ -34,13 +34,13 @@ public StringAssertContainsSyntaxVisitor() : base(new MemberValidator("Contains" } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(StringAssertContainsCodeFix)), Shared] - public class StringAssertContainsCodeFix : MsTestCodeFixProvider + public class StringAssertContainsCodeFix : MsTestStringAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(StringAssertContainsAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "Contains", "Contain", "StringAssert"); + return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "Contains", "Contain"); } } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertDoesNotMatch.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertDoesNotMatch.cs index 201e0abe..ef8e891d 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertDoesNotMatch.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertDoesNotMatch.cs @@ -34,13 +34,13 @@ public StringAssertDoesNotMatchSyntaxVisitor() : base(new MemberValidator("DoesN } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(StringAssertDoesNotMatchCodeFix)), Shared] - public class StringAssertDoesNotMatchCodeFix : MsTestCodeFixProvider + public class StringAssertDoesNotMatchCodeFix : MsTestStringAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(StringAssertDoesNotMatchAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - return RenameMethodAndReplaceWithSubjectShould(expression, "DoesNotMatch", "NotMatchRegex", "StringAssert"); + return RenameMethodAndReplaceWithSubjectShould(expression, "DoesNotMatch", "NotMatchRegex"); } } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertEndsWith.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertEndsWith.cs index 6d4d3322..9bde1926 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertEndsWith.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertEndsWith.cs @@ -34,13 +34,13 @@ public StringAssertEndsWithSyntaxVisitor() : base(new MemberValidator("EndsWith" } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(StringAssertEndsWithCodeFix)), Shared] - public class StringAssertEndsWithCodeFix : MsTestCodeFixProvider + public class StringAssertEndsWithCodeFix : MsTestStringAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(StringAssertEndsWithAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "EndsWith", "EndWith", "StringAssert"); + return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "EndsWith", "EndWith"); } } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertMatches.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertMatches.cs index 5a1de0fe..791ee5d9 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertMatches.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertMatches.cs @@ -34,13 +34,13 @@ public StringAssertMatchesSyntaxVisitor() : base(new MemberValidator("Matches")) } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(StringAssertMatchesCodeFix)), Shared] - public class StringAssertMatchesCodeFix : MsTestCodeFixProvider + public class StringAssertMatchesCodeFix : MsTestStringAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(StringAssertMatchesAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - return RenameMethodAndReplaceWithSubjectShould(expression, "Matches", "MatchRegex", "StringAssert"); + return RenameMethodAndReplaceWithSubjectShould(expression, "Matches", "MatchRegex"); } } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertStartsWith.cs b/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertStartsWith.cs index 60b393b6..4a35b152 100644 --- a/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertStartsWith.cs +++ b/src/FluentAssertions.Analyzers/Tips/MsTest/StringAssertStartsWith.cs @@ -34,13 +34,13 @@ public StringAssertStartsWithSyntaxVisitor() : base(new MemberValidator("StartsW } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(StringAssertStartsWithCodeFix)), Shared] - public class StringAssertStartsWithCodeFix : MsTestCodeFixProvider + public class StringAssertStartsWithCodeFix : MsTestStringAssertCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(StringAssertStartsWithAnalyzer.DiagnosticId); protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) { - return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "StartsWith", "StartWith", "StringAssert"); + return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "StartsWith", "StartWith"); } } } \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/Xunit/AssertFalse.cs b/src/FluentAssertions.Analyzers/Tips/Xunit/AssertFalse.cs new file mode 100644 index 00000000..8e99f8e9 --- /dev/null +++ b/src/FluentAssertions.Analyzers/Tips/Xunit/AssertFalse.cs @@ -0,0 +1,46 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Composition; + +namespace FluentAssertions.Analyzers.Xunit +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class AssertFalseAnalyzer : XunitAnalyzer + { + public const string DiagnosticId = Constants.Tips.Xunit.AssertFalse; + public const string Category = Constants.Tips.Category; + + public const string Message = "Use .Should().BeFalse() instead."; + + protected override DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId, Title, Message, Category, DiagnosticSeverity.Info, true); + protected override IEnumerable Visitors + { + get + { + yield return new AssertFalseSyntaxVisitor(); + } + } + + public class AssertFalseSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor + { + public AssertFalseSyntaxVisitor() : base(new MemberValidator("False")) + { + } + } + } + + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertFalseCodeFix)), Shared] + public class AssertFalseCodeFix : XunitCodeFixProvider + { + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AssertFalseAnalyzer.DiagnosticId); + + protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) + { + return RenameMethodAndReplaceWithSubjectShould(expression, "False", "BeFalse"); + } + } +} \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/Xunit/AssertTrue.cs b/src/FluentAssertions.Analyzers/Tips/Xunit/AssertTrue.cs new file mode 100644 index 00000000..06c2e25b --- /dev/null +++ b/src/FluentAssertions.Analyzers/Tips/Xunit/AssertTrue.cs @@ -0,0 +1,46 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Composition; + +namespace FluentAssertions.Analyzers.Xunit +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class AssertTrueAnalyzer : XunitAnalyzer + { + public const string DiagnosticId = Constants.Tips.Xunit.AssertTrue; + public const string Category = Constants.Tips.Category; + + public const string Message = "Use .Should().BeTrue() instead."; + + protected override DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId, Title, Message, Category, DiagnosticSeverity.Info, true); + protected override IEnumerable Visitors + { + get + { + yield return new AssertTrueSyntaxVisitor(); + } + } + + public class AssertTrueSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor + { + public AssertTrueSyntaxVisitor() : base(new MemberValidator("True")) + { + } + } + } + + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertTrueCodeFix)), Shared] + public class AssertTrueCodeFix : XunitCodeFixProvider + { + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AssertTrueAnalyzer.DiagnosticId); + + protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties) + { + return RenameMethodAndReplaceWithSubjectShould(expression, "True", "BeTrue"); + } + } +} \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Tips/Xunit/XunitBase.cs b/src/FluentAssertions.Analyzers/Tips/Xunit/XunitBase.cs new file mode 100644 index 00000000..75717868 --- /dev/null +++ b/src/FluentAssertions.Analyzers/Tips/Xunit/XunitBase.cs @@ -0,0 +1,29 @@ +using FluentAssertions.Analyzers.Utilities; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Linq; + +namespace FluentAssertions.Analyzers.Xunit +{ + public abstract class XunitAnalyzer : FluentAssertionsAnalyzer + { + private static readonly NameSyntax XunitNamespace = SyntaxFactory.ParseName("Xunit"); + + protected override bool ShouldAnalyzeMethod(MethodDeclarationSyntax method) + { + var compilation = method.FirstAncestorOrSelf(); + + if (compilation == null) return false; + + return compilation.Usings.Any(usingDirective => usingDirective.Name.IsEquivalentTo(XunitNamespace)); + } + + protected override bool ShouldAnalyzeVariableType(INamedTypeSymbol type, SemanticModel semanticModel) => type.Name == "Assert"; + } + + public abstract class XunitCodeFixProvider : TestingLibraryCodeFixBase + { + protected override string AssertClassName => "Assert"; + } +} \ No newline at end of file diff --git a/src/FluentAssertions.Analyzers/Utilities/TestingLibraryCodeFixBase.cs b/src/FluentAssertions.Analyzers/Utilities/TestingLibraryCodeFixBase.cs new file mode 100644 index 00000000..b485bade --- /dev/null +++ b/src/FluentAssertions.Analyzers/Utilities/TestingLibraryCodeFixBase.cs @@ -0,0 +1,29 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace FluentAssertions.Analyzers.Utilities +{ + public abstract class TestingLibraryCodeFixBase : FluentAssertionsCodeFixProvider + { + protected abstract string AssertClassName { get; } + + protected ExpressionSyntax RenameMethodAndReplaceWithSubjectShould(ExpressionSyntax expression, string oldName, string newName) + { + var rename = NodeReplacement.RenameAndRemoveFirstArgument(oldName, newName); + var newExpression = GetNewExpression(expression, rename); + + return ReplaceIdentifier(newExpression, AssertClassName, Expressions.SubjectShould(rename.Argument.Expression)); + } + + protected ExpressionSyntax RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(ExpressionSyntax expression, string oldName, string newName) + { + var rename = NodeReplacement.RenameAndExtractArguments(oldName, newName); + var newExpression = GetNewExpression(expression, rename); + + var actual = rename.Arguments[1]; + + newExpression = ReplaceIdentifier(newExpression, AssertClassName, Expressions.SubjectShould(actual.Expression)); + + return GetNewExpression(newExpression, NodeReplacement.WithArguments(newName, rename.Arguments.RemoveAt(1))); + } + } +}