Skip to content
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
21 changes: 21 additions & 0 deletions src/FluentAssertions.Analyzers.TestUtils/GenerateCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,5 +233,26 @@ public static string GenericIListExpressionBodyAssertion(string assertion) => Ge
.AppendLine(" }")
.AppendLine("}")
.ToString();

public static string Nunit3Assertion(string methodArguments, string assertion) => new StringBuilder()
.AppendLine("using System;")
.AppendLine("using System.Collections.Generic;")
.AppendLine("using System.Collections.Immutable;")
.AppendLine("using System.Text.RegularExpressions;")
.AppendLine("using FluentAssertions;")
.AppendLine("using FluentAssertions.Extensions;")
.AppendLine("using NUnit.Framework;")
.AppendLine("using System.Threading.Tasks;")
.AppendLine("namespace TestNamespace")
.AppendLine("{")
.AppendLine(" class TestClass")
.AppendLine(" {")
.AppendLine($" void TestMethod({methodArguments})")
.AppendLine(" {")
.AppendLine($" {assertion}")
.AppendLine(" }")
.AppendLine(" }")
.AppendLine("}")
.ToString();
}
}
2 changes: 2 additions & 0 deletions src/FluentAssertions.Analyzers.TestUtils/PackageReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public class PackageReference

public static PackageReference MSTestTestFramework_3_1_1 { get; } = new("MSTest.TestFramework", "3.1.1", "lib/netstandard2.0/");
public static PackageReference XunitAssert_2_5_1 { get; } = new("xunit.assert", "2.5.1", "lib/netstandard1.1/");
public static PackageReference Nunit_3_14_0 { get; } = new("NUnit", "3.14.0", "lib/netstandard2.0/");
public static PackageReference Nunit_4_0_1 { get; } = new("NUnit", "4.0.1", "lib/net6.0/");

public static PackageReference FluentAssertions(string version) => new("FluentAssertions", version, "lib/netstandard2.0/");
}
106 changes: 106 additions & 0 deletions src/FluentAssertions.Analyzers.Tests/Tips/NunitTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using FluentAssertions.Analyzers.TestUtils;
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace FluentAssertions.Analyzers.Tests.Tips;

[TestClass]
public class NunitTests
{

[DataTestMethod]
[AssertionDiagnostic("Assert.True(actual{0});")]
[AssertionDiagnostic("Assert.True(bool.Parse(\"true\"){0});")]
[AssertionDiagnostic("Assert.IsTrue(actual{0});")]
[AssertionDiagnostic("Assert.IsTrue(bool.Parse(\"true\"){0});")]
[Implemented]
public void AssertTrue_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic("bool actual", assertion);

[DataTestMethod]
[AssertionCodeFix(
oldAssertion: "Assert.True(actual{0});",
newAssertion: "actual.Should().BeTrue({0});")]
[AssertionCodeFix(
oldAssertion: "Assert.True(bool.Parse(\"true\"){0});",
newAssertion: "bool.Parse(\"true\").Should().BeTrue({0});")]
[AssertionCodeFix(
oldAssertion: "Assert.True(!actual{0});",
newAssertion: "(!actual).Should().BeTrue({0});")]
[AssertionCodeFix(
oldAssertion: "Assert.True(actual == false{0});",
newAssertion: "(actual == false).Should().BeTrue({0});")]
[AssertionCodeFix(
oldAssertion: "Assert.IsTrue(actual{0});",
newAssertion: "actual.Should().BeTrue({0});")]
[AssertionCodeFix(
oldAssertion: "Assert.IsTrue(bool.Parse(\"true\"){0});",
newAssertion: "bool.Parse(\"true\").Should().BeTrue({0});")]
[AssertionCodeFix(
oldAssertion: "Assert.IsTrue(!actual{0});",
newAssertion: "(!actual).Should().BeTrue({0});")]
[AssertionCodeFix(
oldAssertion: "Assert.IsTrue(actual == false{0});",
newAssertion: "(actual == false).Should().BeTrue({0});")]
[Implemented]
public void AssertTrue_TestCodeFix(string oldAssertion, string newAssertion)
=> VerifyCSharpFix("bool actual", oldAssertion, newAssertion);

[DataTestMethod]
[AssertionDiagnostic("Assert.False(actual{0});")]
[AssertionDiagnostic("Assert.False(bool.Parse(\"false\"){0});")]
[AssertionDiagnostic("Assert.IsFalse(actual{0});")]
[AssertionDiagnostic("Assert.IsFalse(bool.Parse(\"false\"){0});")]
[Implemented]
public void AssertFalse_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic("bool actual", assertion);

[DataTestMethod]
[AssertionCodeFix(
oldAssertion: "Assert.False(actual{0});",
newAssertion: "actual.Should().BeFalse({0});")]
[AssertionCodeFix(
oldAssertion: "Assert.False(bool.Parse(\"false\"){0});",
newAssertion: "bool.Parse(\"false\").Should().BeFalse({0});")]
[AssertionCodeFix(
oldAssertion: "Assert.IsFalse(actual{0});",
newAssertion: "actual.Should().BeFalse({0});")]
[AssertionCodeFix(
oldAssertion: "Assert.IsFalse(bool.Parse(\"false\"){0});",
newAssertion: "bool.Parse(\"false\").Should().BeFalse({0});")]
[Implemented]
public void AssertFalse_TestCodeFix(string oldAssertion, string newAssertion)
=> VerifyCSharpFix("bool actual", oldAssertion, newAssertion);

private void VerifyCSharpDiagnostic(string methodArguments, string assertion)
{
var source = GenerateCode.Nunit3Assertion(methodArguments, assertion);
DiagnosticVerifier.VerifyDiagnostic(new DiagnosticVerifierArguments()
.WithAllAnalyzers()
.WithSources(source)
.WithPackageReferences(PackageReference.FluentAssertions_6_12_0, PackageReference.Nunit_3_14_0)
.WithExpectedDiagnostics(new DiagnosticResult
{
Id = AssertAnalyzer.NUnitRule.Id,
Message = AssertAnalyzer.Message,
Locations = new DiagnosticResultLocation[]
{
new("Test0.cs", 15, 13)
},
Severity = DiagnosticSeverity.Info
})
);
}

private void VerifyCSharpFix(string methodArguments, string oldAssertion, string newAssertion)
{
var oldSource = GenerateCode.Nunit3Assertion(methodArguments, oldAssertion);
var newSource = GenerateCode.Nunit3Assertion(methodArguments, newAssertion);

DiagnosticVerifier.VerifyFix(new CodeFixVerifierArguments()
.WithDiagnosticAnalyzer<AssertAnalyzer>()
.WithCodeFixProvider<NunitCodeFixProvider>()
.WithSources(oldSource)
.WithFixedSources(newSource)
.WithPackageReferences(PackageReference.FluentAssertions_6_12_0, PackageReference.Nunit_3_14_0)
);
}
}
13 changes: 6 additions & 7 deletions src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,12 @@ public override void Initialize(AnalysisContext context)
context.RegisterOperationAction(analyzerContext.AnalyzeMsTestThrow, OperationKind.Throw);
}

// TODO: enable NUnit
// if (analyzerContext.IsNUnitAvailable)
// {
// context.RegisterOperationAction(analyzerContext.AnalyzeNunitInvocation, OperationKind.Invocation);
// context.RegisterOperationAction(analyzerContext.AnalyzeNunitDynamicInvocation, OperationKind.DynamicInvocation);
// context.RegisterOperationAction(analyzerContext.AnalyzeNunitThrow, OperationKind.Throw);
// }
if (analyzerContext.IsNUnitAvailable)
{
context.RegisterOperationAction(analyzerContext.AnalyzeNunitInvocation, OperationKind.Invocation);
context.RegisterOperationAction(analyzerContext.AnalyzeNunitDynamicInvocation, OperationKind.DynamicInvocation);
context.RegisterOperationAction(analyzerContext.AnalyzeNunitThrow, OperationKind.Throw);
}
});
}

Expand Down
8 changes: 4 additions & 4 deletions src/FluentAssertions.Analyzers/Tips/MsTestCodeFixProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ public class MsTestCodeFixProvider : TestingFrameworkCodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(AssertAnalyzer.MSTestsRule.Id);

protected override CreateChangedDocument TryComputeFixCore(IInvocationOperation invocation, CodeFixContext context, TestingFrameworkCodeFixContext testContext, Diagnostic diagnostic)
protected override CreateChangedDocument TryComputeFixCore(IInvocationOperation invocation, CodeFixContext context, TestingFrameworkCodeFixContext t, Diagnostic diagnostic)
{
var assertType = invocation.TargetMethod.ContainingType;
return assertType.Name switch
{
"Assert" => TryComputeFixForAssert(invocation, context, testContext),
"StringAssert" => TryComputeFixForStringAssert(invocation, context, testContext),
"CollectionAssert" => TryComputeFixForCollectionAssert(invocation, context, testContext),
"Assert" => TryComputeFixForAssert(invocation, context, t),
"StringAssert" => TryComputeFixForStringAssert(invocation, context, t),
"CollectionAssert" => TryComputeFixForCollectionAssert(invocation, context, t),
_ => null
};
}
Expand Down
42 changes: 42 additions & 0 deletions src/FluentAssertions.Analyzers/Tips/NunitCodeFixProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Collections.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Operations;
using CreateChangedDocument = System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task<Microsoft.CodeAnalysis.Document>>;
using System;

namespace FluentAssertions.Analyzers;

[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(NunitCodeFixProvider)), Shared]
public class NunitCodeFixProvider : TestingFrameworkCodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(AssertAnalyzer.NUnitRule.Id);
protected override CreateChangedDocument TryComputeFixCore(IInvocationOperation invocation, CodeFixContext context, TestingFrameworkCodeFixContext t, Diagnostic diagnostic)
{
var assertType = invocation.TargetMethod.ContainingType;
return assertType.Name switch
{
"Assert" => TryComputeFixForAssert(invocation, context, t),
//"StringAssert" => TryComputeFixForStringAssert(invocation, context, testContext),
//"CollectionAssert" => TryComputeFixForCollectionAssert(invocation, context, testContext),
_ => null
};
}

private CreateChangedDocument TryComputeFixForAssert(IInvocationOperation invocation, CodeFixContext context, TestingFrameworkCodeFixContext t)
{
switch (invocation.TargetMethod.Name)
{
case "True":
case "IsTrue":
return DocumentEditorUtils.RenameMethodToSubjectShouldAssertion(invocation, context, "BeTrue", subjectIndex: 0, argumentsToRemove: []);

case "False":
case "IsFalse":
return DocumentEditorUtils.RenameMethodToSubjectShouldAssertion(invocation, context, "BeFalse", subjectIndex: 0, argumentsToRemove: []);
}

return null;
}
}