Skip to content

Commit

Permalink
xunit: support for BooleanAsserts (#131)
Browse files Browse the repository at this point in the history
* add BooleanAsserts

* add xunit to tests

* introduce base codeFixer for testing libraries
  • Loading branch information
Meir017 authored Jan 11, 2022
1 parent 7a34a87 commit 799c193
Show file tree
Hide file tree
Showing 38 changed files with 344 additions and 83 deletions.
5 changes: 4 additions & 1 deletion src/FluentAssertions.Analyzers.Tests/DiagnosticVerifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
using Microsoft.CodeAnalysis.CSharp;
using System.Reflection;

using XunitAssert = Xunit.Assert;

namespace FluentAssertions.Analyzers.Tests
{
/// <summary>
Expand All @@ -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"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.0.0" />
<PackageReference Include="MSTest.TestFramework" Version="2.0.0" />
<PackageReference Include="xunit.assert" Version="2.4.1" />
</ItemGroup>

<ItemGroup>
Expand Down
19 changes: 19 additions & 0 deletions src/FluentAssertions.Analyzers.Tests/GenerateCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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(" {")
Expand Down
90 changes: 90 additions & 0 deletions src/FluentAssertions.Analyzers.Tests/Tips/XunitTests.cs
Original file line number Diff line number Diff line change
@@ -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<AssertTrueAnalyzer>("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<AssertTrueCodeFix, AssertTrueAnalyzer>("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<AssertFalseAnalyzer>("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<AssertFalseCodeFix, AssertFalseAnalyzer>("bool actual", oldAssertion, newAssertion);

private void VerifyCSharpDiagnostic<TDiagnosticAnalyzer>(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<TCodeFixProvider, TDiagnosticAnalyzer>(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<TCodeFixProvider, TDiagnosticAnalyzer>(oldSource, newSource);
}
}
}
6 changes: 6 additions & 0 deletions src/FluentAssertions.Analyzers/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreEqual.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> FixableDiagnosticIds => ImmutableArray.Create(AssertAreEqualAnalyzer.DiagnosticId);

Expand All @@ -90,12 +90,12 @@ protected override async Task<ExpressionSyntax> 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}");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> FixableDiagnosticIds => ImmutableArray.Create(AssertAreNotEqualAnalyzer.DiagnosticId);

Expand All @@ -91,12 +91,12 @@ protected override async Task<ExpressionSyntax> 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}");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> FixableDiagnosticIds => ImmutableArray.Create(AssertAreNotSameAnalyzer.DiagnosticId);

protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties)
=> RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreNotSame", "NotBeSameAs", "Assert");
=> RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreNotSame", "NotBeSameAs");
}
}
4 changes: 2 additions & 2 deletions src/FluentAssertions.Analyzers/Tips/MsTest/AssertAreSame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> FixableDiagnosticIds => ImmutableArray.Create(AssertAreSameAnalyzer.DiagnosticId);

protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties)
=> RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreSame", "BeSameAs", "Assert");
=> RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "AreSame", "BeSameAs");
}
}
4 changes: 2 additions & 2 deletions src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsFalse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> FixableDiagnosticIds => ImmutableArray.Create(CollectionShouldBeEmptyAnalyzer.DiagnosticId);

protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties)
=> RenameMethodAndReplaceWithSubjectShould(expression, "IsFalse", "BeFalse", "Assert");
=> RenameMethodAndReplaceWithSubjectShould(expression, "IsFalse", "BeFalse");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> 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<MemberAccessExpressionSyntax>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> 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<MemberAccessExpressionSyntax>()
Expand Down
4 changes: 2 additions & 2 deletions src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsNotNull.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> FixableDiagnosticIds => ImmutableArray.Create(AssertIsNotNullAnalyzer.DiagnosticId);

protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties)
=> RenameMethodAndReplaceWithSubjectShould(expression, "IsNotNull", "NotBeNull", "Assert");
=> RenameMethodAndReplaceWithSubjectShould(expression, "IsNotNull", "NotBeNull");
}
}
4 changes: 2 additions & 2 deletions src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsNull.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> FixableDiagnosticIds => ImmutableArray.Create(AssertIsNullAnalyzer.DiagnosticId);

protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties)
=> RenameMethodAndReplaceWithSubjectShould(expression, "IsNull", "BeNull", "Assert");
=> RenameMethodAndReplaceWithSubjectShould(expression, "IsNull", "BeNull");
}
}
4 changes: 2 additions & 2 deletions src/FluentAssertions.Analyzers/Tips/MsTest/AssertIsTrue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> FixableDiagnosticIds => ImmutableArray.Create(CollectionShouldBeEmptyAnalyzer.DiagnosticId);

protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties)
=> RenameMethodAndReplaceWithSubjectShould(expression, "IsTrue", "BeTrue", "Assert");
=> RenameMethodAndReplaceWithSubjectShould(expression, "IsTrue", "BeTrue");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> FixableDiagnosticIds => ImmutableArray.Create(AssertThrowsExceptionAnalyzer.DiagnosticId);

protected override ExpressionSyntax GetNewExpression(ExpressionSyntax expression, FluentAssertionsDiagnosticProperties properties)
=> RenameMethodAndReplaceWithSubjectShould(expression, "ThrowsException", "ThrowExactly", "Assert");
=> RenameMethodAndReplaceWithSubjectShould(expression, "ThrowsException", "ThrowExactly");
}
}
Loading

0 comments on commit 799c193

Please sign in to comment.