Skip to content

Commit

Permalink
add support for xunit StringAsserts DoesNotMatches (#225)
Browse files Browse the repository at this point in the history
  • Loading branch information
Meir017 committed Sep 28, 2023
1 parent 4baf515 commit 65f5fc5
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 0 deletions.
29 changes: 29 additions & 0 deletions src/FluentAssertions.Analyzers.Tests/Tips/XunitTests.cs
Expand Up @@ -396,6 +396,35 @@ public void AssertStringMatches_String_TestCodeFix(string oldAssertion, string n
public void AssertStringMatches_Regex_TestCodeFix(string oldAssertion, string newAssertion)
=> VerifyCSharpFix<AssertMatchesCodeFix, AssertMatchesAnalyzer>("string actual, Regex expectedRegex", oldAssertion, newAssertion);

[DataTestMethod]
[DataRow("Assert.DoesNotMatch(expectedRegexPattern, actual);")]
[Implemented]
public void AssertStringDoesNotMatch_String_TestAnalyzer(string assertion) =>
VerifyCSharpDiagnostic<AssertDoesNotMatchAnalyzer>("string actual, string expectedRegexPattern", assertion);

[DataTestMethod]
[DataRow(
/* oldAssertion: */ "Assert.DoesNotMatch(expectedRegexPattern, actual);",
/* newAssertion: */ "actual.Should().NotMatchRegex(expectedRegexPattern);")]
[Implemented]
public void AssertStringDoesNotMatch_String_TestCodeFix(string oldAssertion, string newAssertion)
=> VerifyCSharpFix<AssertDoesNotMatchCodeFix, AssertDoesNotMatchAnalyzer>("string actual, string expectedRegexPattern", oldAssertion, newAssertion);

[DataTestMethod]
[DataRow("Assert.DoesNotMatch(expectedRegex, actual);")]
[Implemented]
public void AssertStringDoesNotMatch_Regex_TestAnalyzer(string assertion) =>
VerifyCSharpDiagnostic<AssertDoesNotMatchAnalyzer>("string actual, Regex expectedRegex", assertion);

[DataTestMethod]
[DataRow(
/* oldAssertion: */ "Assert.DoesNotMatch(expectedRegex, actual);",
/* newAssertion: */ "actual.Should().NotMatchRegex(expectedRegex);")]
[Implemented]
public void AssertStringDoesNotMatch_Regex_TestCodeFix(string oldAssertion, string newAssertion)
=> VerifyCSharpFix<AssertDoesNotMatchCodeFix, AssertDoesNotMatchAnalyzer>("string actual, Regex expectedRegex", oldAssertion, newAssertion);


private void VerifyCSharpDiagnostic<TDiagnosticAnalyzer>(string methodArguments, string assertion) where TDiagnosticAnalyzer : Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer, new()
{
var source = GenerateCode.XunitAssertion(methodArguments, assertion);
Expand Down
1 change: 1 addition & 0 deletions src/FluentAssertions.Analyzers/Constants.cs
Expand Up @@ -132,6 +132,7 @@ public static class Xunit
public const string AssertContains = $"{DiagnosticProperties.IdPrefix}0710";
public const string AssertDoesNotContain = $"{DiagnosticProperties.IdPrefix}0711";
public const string AssertMatches = $"{DiagnosticProperties.IdPrefix}0712";
public const string AssertDoesNotMatch = $"{DiagnosticProperties.IdPrefix}0713";
}
}

Expand Down
58 changes: 58 additions & 0 deletions src/FluentAssertions.Analyzers/Tips/Xunit/AssertDoesNotMatch.cs
@@ -0,0 +1,58 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using FluentAssertions.Analyzers.Utilities;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;

namespace FluentAssertions.Analyzers.Xunit;

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class AssertDoesNotMatchAnalyzer : XunitAnalyzer
{
public const string DiagnosticId = Constants.Tips.Xunit.AssertDoesNotMatch;
public const string Category = Constants.Tips.Category;

public const string Message = "Use .Should().NotMatchRegex()";

protected override DiagnosticDescriptor Rule => new(DiagnosticId, Title, Message, Category, DiagnosticSeverity.Info, true);

protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors => new FluentAssertionsCSharpSyntaxVisitor[]
{
new AssertDoesNotMatchStringSyntaxVisitor()
};

//public static void DoesNotMatch(string expectedRegexPattern, string? actualString)
//public static void DoesNotMatch(Regex expectedRegex, string? actualString)
public class AssertDoesNotMatchStringSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
{
public AssertDoesNotMatchStringSyntaxVisitor() : base(
MemberValidator.ArgumentsMatch("DoesNotMatch",
ArgumentValidator.IsAnyType(TypeSelector.GetStringType, TypeSelector.GetRegexType),
ArgumentValidator.IsType(TypeSelector.GetStringType))
)
{
}
}
}

[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertDoesNotMatchCodeFix)), Shared]
public class AssertDoesNotMatchCodeFix : XunitCodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(AssertDoesNotMatchAnalyzer.DiagnosticId);

protected override ExpressionSyntax GetNewExpression(
ExpressionSyntax expression,
FluentAssertionsDiagnosticProperties properties)
{
switch (properties.VisitorName)
{
case nameof(AssertDoesNotMatchAnalyzer.AssertDoesNotMatchStringSyntaxVisitor):
return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "DoesNotMatch", "NotMatchRegex");
default:
throw new System.InvalidOperationException($"Invalid visitor name - {properties.VisitorName}");
}
}
}

0 comments on commit 65f5fc5

Please sign in to comment.