Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Migrate xunit to IOperation #270

Merged
merged 1 commit into from
Dec 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/FluentAssertions.Analyzers.Tests/Tips/SanityTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using FluentAssertions.Analyzers.TestUtils;
using FluentAssertions.Analyzers.Xunit;
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.TestTools.UnitTesting;

Expand Down Expand Up @@ -316,8 +315,8 @@ public static void True(bool input)
.WithPackageReferences(PackageReference.XunitAssert_2_5_1, PackageReference.FluentAssertions_6_12_0)
.WithExpectedDiagnostics(new DiagnosticResult()
{
Id = AssertTrueAnalyzer.DiagnosticId,
Message = AssertTrueAnalyzer.Message,
Id = AssertAnalyzer.XunitRule.Id,
Message = AssertAnalyzer.Message,
Severity = DiagnosticSeverity.Info,
Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 9) }
})
Expand Down
164 changes: 78 additions & 86 deletions src/FluentAssertions.Analyzers.Tests/Tips/XunitTests.cs

Large diffs are not rendered by default.

9 changes: 4 additions & 5 deletions src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
{
public static readonly string Message = "Use FluentAssertions equivalent";
public static readonly DiagnosticDescriptor XunitRule = new(
"FAA0002",

Check warning on line 40 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, Release)

Check warning on line 40 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, Release)

Check warning on line 40 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, Debug)

Check warning on line 40 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, Debug)

Check warning on line 40 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / Performance regression check

Check warning on line 40 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, Debug)

Check warning on line 40 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, Debug)

Check warning on line 40 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, Release)

Check warning on line 40 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, Release)

Check warning on line 40 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest, Debug)

Check warning on line 40 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest, Debug)

Check warning on line 40 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest, Release)

Check warning on line 40 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest, Release)

title: "Replace Xunit assertion with Fluent Assertions equivalent",
messageFormat: Message,
description: "",
Expand All @@ -46,7 +46,7 @@
isEnabledByDefault: true);

public static readonly DiagnosticDescriptor MSTestsRule = new(
"FAA0003",

Check warning on line 49 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, Release)

Check warning on line 49 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, Release)

Check warning on line 49 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, Debug)

Check warning on line 49 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, Debug)

Check warning on line 49 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / Performance regression check

Check warning on line 49 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, Debug)

Check warning on line 49 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, Debug)

Check warning on line 49 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, Release)

Check warning on line 49 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, Release)

Check warning on line 49 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest, Debug)

Check warning on line 49 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest, Debug)

Check warning on line 49 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest, Release)

Check warning on line 49 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest, Release)

title: "Replace MSTests assertion with Fluent Assertions equivalent",
messageFormat: Message,
description: "",
Expand All @@ -55,7 +55,7 @@
isEnabledByDefault: true);

public static readonly DiagnosticDescriptor NUnitRule = new(
"FAA0004",

Check warning on line 58 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, Release)

Check warning on line 58 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, Release)

Check warning on line 58 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, Debug)

Check warning on line 58 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, Debug)

Check warning on line 58 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / Performance regression check

Check warning on line 58 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, Debug)

Check warning on line 58 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, Debug)

Check warning on line 58 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, Release)

Check warning on line 58 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, Release)

Check warning on line 58 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest, Debug)

Check warning on line 58 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest, Debug)

Check warning on line 58 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest, Release)

Check warning on line 58 in src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest, Release)

title: "Replace NUnit assertion with Fluent Assertions equivalent",
messageFormat: Message,
description: "",
Expand All @@ -77,11 +77,10 @@

var analyzerContext = new AnalyzerContext(context.Compilation);

// TODO: enable xunit
// if (analyzerContext.IsXUnitAvailable)
// {
// context.RegisterOperationAction(analyzerContext.AnalyzeXunitInvocation, OperationKind.Invocation);
// }
if (analyzerContext.IsXUnitAvailable)
{
context.RegisterOperationAction(analyzerContext.AnalyzeXunitInvocation, OperationKind.Invocation);
}

if (analyzerContext.IsMSTestsAvailable)
{
Expand Down
15 changes: 13 additions & 2 deletions src/FluentAssertions.Analyzers/Tips/DocumentEditorUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static CreateChangedDocument RenameMethodToSubjectShouldAssertion(IInvoca

return await RewriteExpression(invocationExpression, [
..Array.ConvertAll(argumentsToRemove, arg => new RemoveNodeAction(invocationExpression.ArgumentList.Arguments[arg])),
new SubjectShouldAssertionAction(argumentIndex, newName)
new SubjectShouldAssertionAction(argumentIndex, newName)
], context, ctx);
};

Expand All @@ -33,7 +33,18 @@ public static CreateChangedDocument RenameMethodToSubjectShouldGenericAssertion(

return await RewriteExpression(invocationExpression, [
..Array.ConvertAll(argumentsToRemove, arg => new RemoveNodeAction(invocationExpression.ArgumentList.Arguments[arg])),
new SubjectShouldGenericAssertionAction(argumentIndex, newName, genericTypes)
new SubjectShouldGenericAssertionAction(argumentIndex, newName, genericTypes)
], context, ctx);
};

public static CreateChangedDocument RenameMethodToSubjectShouldAssertionWithOptionsLambda(IInvocationOperation invocation, CodeFixContext context, string newName, int argumentIndex, int optionsIndex)
=> async ctx =>
{
var invocationExpression = (InvocationExpressionSyntax)invocation.Syntax;

return await RewriteExpression(invocationExpression, [
new SubjectShouldAssertionAction(argumentIndex, newName),
new CreateEquivalencyAssertionOptionsLambda(optionsIndex)
], context, ctx);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;

namespace FluentAssertions.Analyzers;

public class CreateEquivalencyAssertionOptionsLambda : IEditAction
{
private readonly int _argumentIndex;

public CreateEquivalencyAssertionOptionsLambda(int argumentIndex)
{
_argumentIndex = argumentIndex;
}

public void Apply(DocumentEditor editor, InvocationExpressionSyntax invocationExpression)
{
const string lambdaParameter = "options";
const string equivalencyAssertionOptionsMethod = "Using";

var generator = editor.Generator;
var optionsParameter = invocationExpression.ArgumentList.Arguments[_argumentIndex];

var equivalencyAssertionLambda = generator.ValueReturningLambdaExpression(lambdaParameter, generator.InvocationExpression(generator.MemberAccessExpression(generator.IdentifierName(lambdaParameter), equivalencyAssertionOptionsMethod), optionsParameter));
editor.ReplaceNode(optionsParameter.Expression, equivalencyAssertionLambda);
}
}
360 changes: 142 additions & 218 deletions src/FluentAssertions.Analyzers/Tips/MsTestCodeFixProvider.cs

Large diffs are not rendered by default.

136 changes: 136 additions & 0 deletions src/FluentAssertions.Analyzers/Tips/TestingFrameworkCodeFixProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using FluentAssertions.Analyzers.Utilities;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Operations;
using CreateChangedDocument = System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task<Microsoft.CodeAnalysis.Document>>;

namespace FluentAssertions.Analyzers;

public abstract class TestingFrameworkCodeFixProvider : CodeFixProvider
{
protected const string Title = "Replace with FluentAssertions";

public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;

public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);
var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken);

var testContext = new TestingFrameworkCodeFixContext(semanticModel.Compilation);
foreach (var diagnostic in context.Diagnostics)
{
var node = root.FindNode(diagnostic.Location.SourceSpan);
if (node is not InvocationExpressionSyntax invocationExpression)
{
continue;
}

var operation = semanticModel.GetOperation(invocationExpression, context.CancellationToken);
if (operation is not IInvocationOperation invocation)
{
continue;
}

var fix = TryComputeFix(invocation, context, testContext, diagnostic);
if (fix is not null)
{
context.RegisterCodeFix(CodeAction.Create(Title, fix, equivalenceKey: Title), diagnostic);
}
}
}

protected abstract CreateChangedDocument TryComputeFix(IInvocationOperation invocation, CodeFixContext context, TestingFrameworkCodeFixContext t, Diagnostic diagnostic);

protected static bool ArgumentsAreTypeOf(IInvocationOperation invocation, params ITypeSymbol[] types) => ArgumentsAreTypeOf(invocation, 0, types);
protected static bool ArgumentsAreTypeOf(IInvocationOperation invocation, int startFromIndex, params ITypeSymbol[] types)
{
if (invocation.TargetMethod.Parameters.Length != types.Length + startFromIndex)
{
return false;
}

for (int i = startFromIndex; i < types.Length; i++)
{
if (!invocation.TargetMethod.Parameters[i].Type.EqualsSymbol(types[i]))
{
return false;
}
}

return true;
}

protected static bool ArgumentsAreGenericTypeOf(IInvocationOperation invocation, params ITypeSymbol[] types)
{
const int generics = 1;
if (invocation.TargetMethod.Parameters.Length != types.Length)
{
return false;
}

if (invocation.TargetMethod.TypeArguments.Length != generics)
{
return false;
}

var genericType = invocation.TargetMethod.TypeArguments[0];

for (int i = 0; i < types.Length; i++)
{
if (invocation.TargetMethod.Parameters[i].Type is not INamedTypeSymbol parameterType)
{
return false;
}

if (parameterType.TypeArguments.IsEmpty && parameterType.EqualsSymbol(genericType))
{
continue;
}

if (parameterType.TypeArguments.Length != generics
|| !(parameterType.TypeArguments[0].EqualsSymbol(genericType) && parameterType.OriginalDefinition.EqualsSymbol(types[i])))
{
return false;
}
}

return true;
}

protected static bool ArgumentsCount(IInvocationOperation invocation, int arguments)
{
return invocation.TargetMethod.Parameters.Length == arguments;
}

protected sealed class TestingFrameworkCodeFixContext(Compilation compilation)
{
public INamedTypeSymbol Object { get; } = compilation.ObjectType;
public INamedTypeSymbol String { get; } = compilation.GetTypeByMetadataName("System.String");
public INamedTypeSymbol Int32 { get; } = compilation.GetTypeByMetadataName("System.Int32");
public INamedTypeSymbol Float { get; } = compilation.GetTypeByMetadataName("System.Single");
public INamedTypeSymbol Double { get; } = compilation.GetTypeByMetadataName("System.Double");
public INamedTypeSymbol Decimal { get; } = compilation.GetTypeByMetadataName("System.Decimal");
public INamedTypeSymbol Boolean { get; } = compilation.GetTypeByMetadataName("System.Boolean");
public INamedTypeSymbol Action { get; } = compilation.GetTypeByMetadataName("System.Action");
public INamedTypeSymbol Type { get; } = compilation.GetTypeByMetadataName("System.Type");
public INamedTypeSymbol DateTime { get; } = compilation.GetTypeByMetadataName("System.DateTime");
public INamedTypeSymbol TimeSpan { get; } = compilation.GetTypeByMetadataName("System.TimeSpan");
public INamedTypeSymbol FuncOfObject { get; } = compilation.GetTypeByMetadataName("System.Func`1").Construct(compilation.ObjectType);
public INamedTypeSymbol FuncOfTask { get; } = compilation.GetTypeByMetadataName("System.Func`1").Construct(compilation.GetTypeByMetadataName("System.Threading.Tasks.Task"));
public IArrayTypeSymbol ObjectArray { get; } = compilation.CreateArrayTypeSymbol(compilation.ObjectType);
public INamedTypeSymbol CultureInfo { get; } = compilation.GetTypeByMetadataName("System.Globalization.CultureInfo");
public INamedTypeSymbol StringComparison { get; } = compilation.GetTypeByMetadataName("System.StringComparison");
public INamedTypeSymbol Regex { get; } = compilation.GetTypeByMetadataName("System.Text.RegularExpressions.Regex");
public INamedTypeSymbol ICollection { get; } = compilation.GetTypeByMetadataName("System.Collections.ICollection");
public INamedTypeSymbol IComparer { get; } = compilation.GetTypeByMetadataName("System.Collections.IComparer");
public INamedTypeSymbol IEqualityComparerOfT1 { get; } = compilation.GetTypeByMetadataName("System.Collections.Generic.IEqualityComparer`1");
public INamedTypeSymbol IEnumerableOfT1 { get; } = compilation.GetTypeByMetadataName("System.Collections.Generic.IEnumerable`1");

public INamedTypeSymbol Identity { get; } = null;
}
}
74 changes: 0 additions & 74 deletions src/FluentAssertions.Analyzers/Tips/Xunit/AssertContains.cs

This file was deleted.

74 changes: 0 additions & 74 deletions src/FluentAssertions.Analyzers/Tips/Xunit/AssertDoesNotContain.cs

This file was deleted.

Loading
Loading