Skip to content

Commit d0c10eb

Browse files
authored
add support for xunit TypeAsserts IsNotType (#241)
1 parent 29311b3 commit d0c10eb

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

src/FluentAssertions.Analyzers.Tests/Tips/XunitTests.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,28 @@ public void AssertIsType_TestAnalyzer(string assertion) =>
620620
public void AssertIsType_TestCodeFix(string oldAssertion, string newAssertion)
621621
=> VerifyCSharpFix<AssertIsTypeCodeFix, AssertIsTypeAnalyzer>("string actual, Type expected", oldAssertion, newAssertion);
622622

623+
[DataTestMethod]
624+
[DataRow("Assert.IsNotType(expected, actual);")]
625+
[DataRow("Assert.IsNotType(typeof(string), actual);")]
626+
[DataRow("Assert.IsNotType<string>(actual);")]
627+
[Implemented]
628+
public void AssertIsNotType_TestAnalyzer(string assertion) =>
629+
VerifyCSharpDiagnostic<AssertIsNotTypeAnalyzer>("string actual, Type expected", assertion);
630+
631+
[DataTestMethod]
632+
[DataRow(
633+
/* oldAssertion: */ "Assert.IsNotType(expected, actual);",
634+
/* newAssertion: */ "actual.Should().NotBeOfType(expected);")]
635+
[DataRow(
636+
/* oldAssertion: */ "Assert.IsNotType(typeof(string), actual);",
637+
/* newAssertion: */ "actual.Should().NotBeOfType<string>();")]
638+
[DataRow(
639+
/* oldAssertion: */ "Assert.IsNotType<string>(actual);",
640+
/* newAssertion: */ "actual.Should().NotBeOfType<string>();")]
641+
[Implemented]
642+
public void AssertIsNotType_TestCodeFix(string oldAssertion, string newAssertion)
643+
=> VerifyCSharpFix<AssertIsNotTypeCodeFix, AssertIsNotTypeAnalyzer>("string actual, Type expected", oldAssertion, newAssertion);
644+
623645
private void VerifyCSharpDiagnostic<TDiagnosticAnalyzer>(string methodArguments, string assertion) where TDiagnosticAnalyzer : Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer, new()
624646
{
625647
var source = GenerateCode.XunitAssertion(methodArguments, assertion);

src/FluentAssertions.Analyzers/Constants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ public static class Xunit
140140
public const string AssertIsAssignableFrom = $"{DiagnosticProperties.IdPrefix}0718";
141141
public const string AssertIsNotAssignableFrom = $"{DiagnosticProperties.IdPrefix}0719";
142142
public const string AssertIsType = $"{DiagnosticProperties.IdPrefix}0720";
143+
public const string AssertIsNotType = $"{DiagnosticProperties.IdPrefix}0721";
143144
}
144145
}
145146

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System.Collections.Generic;
2+
using System.Collections.Immutable;
3+
using System.Composition;
4+
using System.Linq;
5+
using FluentAssertions.Analyzers.Utilities;
6+
using Microsoft.CodeAnalysis;
7+
using Microsoft.CodeAnalysis.CodeFixes;
8+
using Microsoft.CodeAnalysis.CSharp.Syntax;
9+
using Microsoft.CodeAnalysis.Diagnostics;
10+
using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
11+
12+
namespace FluentAssertions.Analyzers.Xunit;
13+
14+
[DiagnosticAnalyzer(LanguageNames.CSharp)]
15+
public class AssertIsNotTypeAnalyzer : XunitAnalyzer
16+
{
17+
public const string DiagnosticId = Constants.Tips.Xunit.AssertIsNotType;
18+
public const string Category = Constants.Tips.Category;
19+
20+
public const string Message = "Use .Should().NotBeOfType().";
21+
22+
protected override DiagnosticDescriptor Rule => new(DiagnosticId, Title, Message, Category, DiagnosticSeverity.Info, true);
23+
24+
protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors => new FluentAssertionsCSharpSyntaxVisitor[]
25+
{
26+
new AssertIsNotTypeGenericTypeSyntaxVisitor(),
27+
new AssertIsNotTypeTypeSyntaxVisitor()
28+
};
29+
30+
//public static T IsNotType<T>(object? @object)
31+
public class AssertIsNotTypeGenericTypeSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
32+
{
33+
public AssertIsNotTypeGenericTypeSyntaxVisitor() : base(
34+
MemberValidator.HasArguments("IsNotType", 1)
35+
)
36+
{
37+
}
38+
}
39+
40+
//public static T IsNotType(Type expectedType, object? @object)
41+
public class AssertIsNotTypeTypeSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
42+
{
43+
public AssertIsNotTypeTypeSyntaxVisitor() : base(
44+
MemberValidator.HasArguments("IsNotType", 2)
45+
)
46+
{
47+
}
48+
}
49+
}
50+
51+
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertIsNotTypeCodeFix)), Shared]
52+
public class AssertIsNotTypeCodeFix : XunitCodeFixProvider
53+
{
54+
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(AssertIsNotTypeAnalyzer.DiagnosticId);
55+
56+
protected override ExpressionSyntax GetNewExpression(
57+
ExpressionSyntax expression,
58+
FluentAssertionsDiagnosticProperties properties)
59+
{
60+
switch (properties.VisitorName)
61+
{
62+
case nameof(AssertIsNotTypeAnalyzer.AssertIsNotTypeGenericTypeSyntaxVisitor):
63+
return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "IsNotType", "NotBeOfType");
64+
case nameof(AssertIsNotTypeAnalyzer.AssertIsNotTypeTypeSyntaxVisitor):
65+
var newExpression = RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "IsNotType", "NotBeOfType");
66+
return ReplaceTypeOfArgumentWithGenericTypeIfExists(newExpression, "NotBeOfType");
67+
default:
68+
throw new System.InvalidOperationException($"Invalid visitor name - {properties.VisitorName}");
69+
}
70+
}
71+
}

0 commit comments

Comments
 (0)