Skip to content

feat: add nunit collectionassert.isempty assertions #341

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

Merged
merged 2 commits into from
May 18, 2024
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
8 changes: 8 additions & 0 deletions docs/NunitAnalyzer.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ var collection = new List<int>();
// old assertion:
Assert.IsEmpty(collection);
Assert.That(collection, Is.Empty);
CollectionAssert.IsEmpty(collection);

// new assertion:
collection.Should().BeEmpty();
Expand All @@ -194,6 +195,9 @@ Assert.IsEmpty(collection); /* fail message: Expected: <empty>
Assert.That(collection, Is.Empty); /* fail message: Expected: <empty>
But was: < 1, 2, 3 >
*/
CollectionAssert.IsEmpty(collection); /* fail message: Expected: <empty>
But was: < 1, 2, 3 >
*/

// new assertion:
collection.Should().BeEmpty(); /* fail message: Expected collection to be empty, but found {1, 2, 3}. */
Expand All @@ -208,6 +212,7 @@ var collection = new List<int> { 1, 2, 3 };
// old assertion:
Assert.IsNotEmpty(collection);
Assert.That(collection, Is.Not.Empty);
CollectionAssert.IsNotEmpty(collection);

// new assertion:
collection.Should().NotBeEmpty();
Expand All @@ -225,6 +230,9 @@ Assert.IsNotEmpty(collection); /* fail message: Expected: not <empty>
Assert.That(collection, Is.Not.Empty); /* fail message: Expected: not <empty>
But was: <empty>
*/
CollectionAssert.IsNotEmpty(collection); /* fail message: Expected: not <empty>
But was: <empty>
*/

// new assertion:
collection.Should().NotBeEmpty(); /* fail message: Expected collection not to be empty. */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Assert = NUnit.Framework.Assert;
using CollectionAssert = NUnit.Framework.CollectionAssert;
using System.Collections.Generic;
using NUnit.Framework;
using FluentAssertions;
Expand Down Expand Up @@ -271,6 +272,7 @@ public void AssertIsEmpty()
// old assertion:
Assert.IsEmpty(collection);
Assert.That(collection, Is.Empty);
CollectionAssert.IsEmpty(collection);

// new assertion:
collection.Should().BeEmpty();
Expand All @@ -296,6 +298,16 @@ public void AssertIsEmpty_Failure_OldAssertion_1()
Assert.That(collection, Is.Empty);
}

[TestMethod, ExpectedTestFrameworkException]
public void AssertIsEmpty_Failure_OldAssertion_2()
{
// arrange
var collection = new List<int> { 1, 2, 3 };

// old assertion:
CollectionAssert.IsEmpty(collection);
}

[TestMethod, ExpectedTestFrameworkException]
public void AssertIsEmpty_Failure_NewAssertion()
{
Expand All @@ -315,6 +327,7 @@ public void AssertIsNotEmpty()
// old assertion:
Assert.IsNotEmpty(collection);
Assert.That(collection, Is.Not.Empty);
CollectionAssert.IsNotEmpty(collection);

// new assertion:
collection.Should().NotBeEmpty();
Expand All @@ -340,6 +353,16 @@ public void AssertIsNotEmpty_Failure_OldAssertion_1()
Assert.That(collection, Is.Not.Empty);
}

[TestMethod, ExpectedTestFrameworkException]
public void AssertIsNotEmpty_Failure_OldAssertion_2()
{
// arrange
var collection = new List<int>();

// old assertion:
CollectionAssert.IsNotEmpty(collection);
}

[TestMethod, ExpectedTestFrameworkException]
public void AssertIsNotEmpty_Failure_NewAssertion()
{
Expand Down
16 changes: 16 additions & 0 deletions src/FluentAssertions.Analyzers.Tests/Tips/NunitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ public void Nunit4_AssertIsNaN_TestAnalyzer(string assertion)
[DataTestMethod]
[AssertionDiagnostic("Assert.IsEmpty(actual{0});")]
[AssertionDiagnostic("Assert.That(actual, Is.Empty{0});")]
[AssertionDiagnostic("CollectionAssert.IsEmpty(actual{0});")]
[Implemented]
public void Nunit3_AssertIsEmpty_TestAnalyzer(string assertion)
{
Expand All @@ -284,6 +285,7 @@ public void Nunit3_AssertIsEmpty_TestAnalyzer(string assertion)
[DataTestMethod]
[AssertionDiagnostic("ClassicAssert.IsEmpty(actual{0});")]
[AssertionDiagnostic("Assert.That(actual, Is.Empty);")]
[AssertionDiagnostic("CollectionAssert.IsEmpty(actual{0});")]
[Implemented]
public void Nunit4_AssertIsEmpty_TestAnalyzer(string assertion)
{
Expand All @@ -300,6 +302,9 @@ public void Nunit4_AssertIsEmpty_TestAnalyzer(string assertion)
[AssertionCodeFix(
oldAssertion: "Assert.That(actual, Is.Empty{0});",
newAssertion: "actual.Should().BeEmpty({0});")]
[AssertionCodeFix(
oldAssertion: "CollectionAssert.IsEmpty(actual{0});",
newAssertion: "actual.Should().BeEmpty({0});")]
[Implemented]
public void Nunit3_AssertIsEmpty_TestCodeFix(string oldAssertion, string newAssertion)
{
Expand All @@ -316,6 +321,9 @@ public void Nunit3_AssertIsEmpty_TestCodeFix(string oldAssertion, string newAsse
[AssertionCodeFix(
oldAssertion: "Assert.That(actual, Is.Empty);",
newAssertion: "actual.Should().BeEmpty();")]
[AssertionCodeFix(
oldAssertion: "CollectionAssert.IsEmpty(actual{0});",
newAssertion: "actual.Should().BeEmpty({0});")]
[Implemented]
public void Nunit4_AssertIsEmpty_TestCodeFix(string oldAssertion, string newAssertion)
{
Expand All @@ -329,6 +337,7 @@ public void Nunit4_AssertIsEmpty_TestCodeFix(string oldAssertion, string newAsse
[DataTestMethod]
[AssertionDiagnostic("Assert.IsNotEmpty(actual{0});")]
[AssertionDiagnostic("Assert.That(actual, Is.Not.Empty{0});")]
[AssertionDiagnostic("CollectionAssert.IsNotEmpty(actual{0});")]
[Implemented]
public void Nunit3_AssertIsNotEmpty_TestAnalyzer(string assertion)
{
Expand All @@ -341,6 +350,7 @@ public void Nunit3_AssertIsNotEmpty_TestAnalyzer(string assertion)
[DataTestMethod]
[AssertionDiagnostic("ClassicAssert.IsNotEmpty(actual{0});")]
[AssertionDiagnostic("Assert.That(actual, Is.Not.Empty);")]
[AssertionDiagnostic("CollectionAssert.IsNotEmpty(actual{0});")]
[Implemented]
public void Nunit4_AssertIsNotEmpty_TestAnalyzer(string assertion)
{
Expand All @@ -357,6 +367,9 @@ public void Nunit4_AssertIsNotEmpty_TestAnalyzer(string assertion)
[AssertionCodeFix(
oldAssertion: "Assert.That(actual, Is.Not.Empty{0});",
newAssertion: "actual.Should().NotBeEmpty({0});")]
[AssertionCodeFix(
oldAssertion: "CollectionAssert.IsNotEmpty(actual{0});",
newAssertion: "actual.Should().NotBeEmpty({0});")]
[Implemented]
public void Nunit3_AssertIsNotEmpty_TestCodeFix(string oldAssertion, string newAssertion)
{
Expand All @@ -373,6 +386,9 @@ public void Nunit3_AssertIsNotEmpty_TestCodeFix(string oldAssertion, string newA
[AssertionCodeFix(
oldAssertion: "Assert.That(actual, Is.Not.Empty);",
newAssertion: "actual.Should().NotBeEmpty();")]
[AssertionCodeFix(
oldAssertion: "CollectionAssert.IsNotEmpty(actual{0});",
newAssertion: "actual.Should().NotBeEmpty({0});")]
[Implemented]
public void Nunit4_AssertIsNotEmpty_TestCodeFix(string oldAssertion, string newAssertion)
{
Expand Down
2 changes: 1 addition & 1 deletion src/FluentAssertions.Analyzers/Tips/AssertAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ private sealed class AnalyzerContext(Compilation compilation)

private readonly INamedTypeSymbol _nunitAssertionExceptionSymbol = compilation.GetTypeByMetadataName("NUnit.Framework.AssertionException");
private readonly INamedTypeSymbol _nunitAssertSymbol = compilation.GetTypeByMetadataName("NUnit.Framework.Assert");
private readonly INamedTypeSymbol _nunitCollectionAssertSymbol = compilation.GetTypeByMetadataName("NUnit.Framework.CollectionAssert");
private readonly INamedTypeSymbol _nunitCollectionAssertSymbol = compilation.GetTypeByMetadataName("NUnit.Framework.CollectionAssert") ?? compilation.GetTypeByMetadataName("NUnit.Framework.Legacy.CollectionAssert");
private readonly INamedTypeSymbol _nunitDirectoryAssertSymbol = compilation.GetTypeByMetadataName("NUnit.Framework.DirectoryAssert");
private readonly INamedTypeSymbol _nunitFileAssertSymbol = compilation.GetTypeByMetadataName("NUnit.Framework.FileAssert");
private readonly INamedTypeSymbol _nunitStringAssertSymbol = compilation.GetTypeByMetadataName("NUnit.Framework.StringAssert");
Expand Down
39 changes: 23 additions & 16 deletions src/FluentAssertions.Analyzers/Tips/NunitCodeFixProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ protected override CreateChangedDocument TryComputeFixCore(IInvocationOperation
"Assert" when invocation.TargetMethod.Name is "That" => TryComputeFixForNunitThat(invocation, context, t),
"Assert" when isNunit3 => TryComputeFixForNunitClassicAssert(invocation, context, t),
"ClassicAssert" when isNunit4 => TryComputeFixForNunitClassicAssert(invocation, context, t),
//"StringAssert" => TryComputeFixForStringAssert(invocation, context, testContext),
//"CollectionAssert" => TryComputeFixForCollectionAssert(invocation, context, testContext),
//"StringAssert" => TryComputeFixForStringAssert(invocation, context, t),
"CollectionAssert" => TryComputeFixForCollectionAssert(invocation, context, t),
_ => null
};
}
Expand All @@ -52,17 +52,9 @@ private CreateChangedDocument TryComputeFixForNunitClassicAssert(IInvocationOper
return DocumentEditorUtils.RenameMethodToSubjectShouldAssertion(invocation, context, "NotBeNull", subjectIndex: 0, argumentsToRemove: []);
case "IsNaN": // Assert.IsNaN(double actual)
return null;
case "IsEmpty": // Assert.IsEmpty(IEnumerable collection) | Assert.IsEmpty(string s)
if (invocation.Arguments[0].Value.UnwrapConversion().Type.SpecialType is SpecialType.System_Collections_IEnumerable)
{
return null;
}
case "IsEmpty" when !IsArgumentTypeOfNonGenericEnumerable(invocation, argumentIndex: 0): // Assert.IsEmpty(IEnumerable collection) | Assert.IsEmpty(string s)
return DocumentEditorUtils.RenameMethodToSubjectShouldAssertion(invocation, context, "BeEmpty", subjectIndex: 0, argumentsToRemove: []);
case "IsNotEmpty": // Assert.IsNotEmpty(IEnumerable collection) | Assert.IsNotEmpty(string s)
if (invocation.Arguments[0].Value.UnwrapConversion().Type.SpecialType is SpecialType.System_Collections_IEnumerable)
{
return null;
}
case "IsNotEmpty" when !IsArgumentTypeOfNonGenericEnumerable(invocation, argumentIndex: 0): // Assert.IsNotEmpty(IEnumerable collection) | Assert.IsNotEmpty(string s)
return DocumentEditorUtils.RenameMethodToSubjectShouldAssertion(invocation, context, "NotBeEmpty", subjectIndex: 0, argumentsToRemove: []);
case "Zero": // Assert.Zero(int anObject)
return DocumentEditorUtils.RewriteExpression(invocation, [
Expand Down Expand Up @@ -231,13 +223,25 @@ private CreateChangedDocument TryComputeFixForNunitClassicAssert(IInvocationOper
return null;
}

private CreateChangedDocument TryComputeFixForCollectionAssert(IInvocationOperation invocation, CodeFixContext context, NunitCodeFixContext t)
{
switch (invocation.TargetMethod.Name)
{
case "IsEmpty" when !IsArgumentTypeOfNonGenericEnumerable(invocation, argumentIndex: 0): // CollectionAssert.IsEmpty(IEnumerable collection)
return DocumentEditorUtils.RenameMethodToSubjectShouldAssertion(invocation, context, "BeEmpty", subjectIndex: 0, argumentsToRemove: []);
case "IsNotEmpty" when !IsArgumentTypeOfNonGenericEnumerable(invocation, argumentIndex: 0) : // CollectionAssert.IsNotEmpty(IEnumerable collection)
return DocumentEditorUtils.RenameMethodToSubjectShouldAssertion(invocation, context, "NotBeEmpty", subjectIndex: 0, argumentsToRemove: []);
}
return null;
}

private CreateChangedDocument TryComputeFixForNunitThat(IInvocationOperation invocation, CodeFixContext context, NunitCodeFixContext t)
{
// Assert.That(condition)
if (invocation.Arguments[0].Value.Type.EqualsSymbol(t.Boolean)
&& (invocation.Arguments.Length is 1
|| (invocation.Arguments.Length >= 2
&& (invocation.Arguments[1].Value.Type.EqualsSymbol(t.NUnitString)
&& (invocation.Arguments.Length is 1
|| (invocation.Arguments.Length >= 2
&& (invocation.Arguments[1].Value.Type.EqualsSymbol(t.NUnitString)
|| invocation.Arguments[1].Value.Type.EqualsSymbol(t.String))
)
)
Expand All @@ -259,7 +263,7 @@ private CreateChangedDocument TryComputeFixForNunitThat(IInvocationOperation inv
return RenameAssertThatAssertionToSubjectShouldAssertion("BeNull");
else if (IsPropertyOfSymbol(constraint, "Not", "Null", t.Is)) // Assert.That(subject, Is.Not.Null)
return RenameAssertThatAssertionToSubjectShouldAssertion("NotBeNull");
else if (subject.Type.SpecialType is not SpecialType.System_Collections_IEnumerable)
else if (!IsArgumentTypeOfNonGenericEnumerable(invocation, argumentIndex: 0))
{
if (IsPropertyOfSymbol(constraint, "Empty", t.Is)) // Assert.That(subject, Is.Empty)
return RenameAssertThatAssertionToSubjectShouldAssertion("BeEmpty");
Expand Down Expand Up @@ -290,6 +294,9 @@ private static bool IsPropertyOfSymbol(IPropertyReferenceOperation propertyRefer
private static bool IsPropertyOfSymbol(IOperation operation, string property, INamedTypeSymbol type)
=> operation is IPropertyReferenceOperation propertyReference && propertyReference.Property.Name == property && IsPropertyReferencedFromType(propertyReference, type);

private static bool IsArgumentTypeOfNonGenericEnumerable(IInvocationOperation invocation, int argumentIndex) => IsArgumentTypeOf(invocation, argumentIndex, SpecialType.System_Collections_IEnumerable);
private static bool IsArgumentTypeOf(IInvocationOperation invocation, int argumentIndex, SpecialType specialType)
=> invocation.Arguments[argumentIndex].Value.UnwrapConversion().Type.SpecialType == specialType;
public class NunitCodeFixContext(Compilation compilation) : TestingFrameworkCodeFixProvider.TestingFrameworkCodeFixContext(compilation)
{
public INamedTypeSymbol Is { get; } = compilation.GetTypeByMetadataName("NUnit.Framework.Is");
Expand Down