Skip to content

Commit

Permalink
Merge pull request #670 from Laniusexcubitor/support-equals-within
Browse files Browse the repository at this point in the history
Also support codefix for .Within
  • Loading branch information
manfred-brands authored Dec 31, 2023
2 parents eb2c8fb + 481af8e commit 903a11f
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,27 @@ public void Test()
fixTitle: ConstActualValueUsageCodeFix.SwapArgumentsDescription);
}

[TestCase(nameof(ClassicAssert.AreEqual))]
public void LiteralArgumentIsProvidedForClassicAssertWithDeltaCodeFix(string classicAssertMethod)
{
var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@"
public void Test()
{{
int expected = 5;
ClassicAssert.{classicAssertMethod}(expected, ↓1, double.Epsilon);
}}");

var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@"
public void Test()
{{
int expected = 5;
ClassicAssert.{classicAssertMethod}(1, expected, double.Epsilon);
}}");

RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode,
fixTitle: ConstActualValueUsageCodeFix.SwapArgumentsDescription);
}

[Test]
public void LiteralNamedArgumentIsProvidedForAreEqualCodeFix()
{
Expand Down Expand Up @@ -92,6 +113,27 @@ public void Test()
fixTitle: ConstActualValueUsageCodeFix.SwapArgumentsDescription);
}

[Test]
public void LiteralArgumentIsProvidedForAssertThatWithinCodeFix()
{
var code = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@"
public void Test()
{{
double expected = 5d;
Assert.That(↓1d, Is.EqualTo(expected).Within(double.Epsilon));
}}");

var fixedCode = TestUtility.WrapMethodInClassNamespaceAndAddUsings($@"
public void Test()
{{
double expected = 5d;
Assert.That(expected, Is.EqualTo(1d).Within(double.Epsilon));
}}");

RoslynAssert.CodeFix(analyzer, fix, expectedDiagnostic, code, fixedCode,
fixTitle: ConstActualValueUsageCodeFix.SwapArgumentsDescription);
}

[TestCase(nameof(Is.GreaterThan))]
[TestCase(nameof(Is.LessThan))]
public void NoCodeFixForNonSymmetricAssertThat(string isConstraint)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,26 +126,24 @@ private static bool TryFindArguments(SemanticModel semanticModel, InvocationExpr
if (constraintExpression is null)
return false;

expectedArgument = constraintExpression.ArgumentList.Arguments.FirstOrDefault()?.Expression;

if (expectedArgument is null)
return false;

if (constraintExpression.Expression is MemberAccessExpressionSyntax memberAccessExpression
&& SupportedIsConstraints.Contains(memberAccessExpression.Name.ToString()))
if (!IsSupportedIsConstraint(ref constraintExpression, out var memberAccessExpression))
{
var expressionString = memberAccessExpression.Expression.ToString();
return false;
}

// e.g. Is.EqualTo or Is.Not.EqualTo
if (expressionString == NUnitFrameworkConstants.NameOfIs
|| expressionString == $"{NUnitFrameworkConstants.NameOfIs}.{NUnitFrameworkConstants.NameOfIsNot}")
{
return true;
}
var expressionString = memberAccessExpression.Expression.ToString();

// e.g. Is.EqualTo or Is.Not.EqualTo
if (expressionString != NUnitFrameworkConstants.NameOfIs
&& expressionString != $"{NUnitFrameworkConstants.NameOfIs}.{NUnitFrameworkConstants.NameOfIsNot}")
{
// other cases are not supported
return false;
}

expectedArgument = constraintExpression.ArgumentList.Arguments.FirstOrDefault()?.Expression;

return expectedArgument is not null;
}

return false;
Expand All @@ -157,6 +155,30 @@ private static bool IsSupportedClassicAssert(IMethodSymbol methodSymbol)
SupportedClassicAsserts.Contains(methodSymbol.Name);
}

private static bool IsSupportedIsConstraint(ref InvocationExpressionSyntax invocationExpression, [NotNullWhen(true)]out MemberAccessExpressionSyntax? memberAccessExpression)
{
memberAccessExpression = invocationExpression.Expression as MemberAccessExpressionSyntax;
if (memberAccessExpression is null)
{
return false;
}

if (memberAccessExpression.Name.ToString() == NUnitFrameworkConstants.NameOfEqualConstraintWithin)
{
// e.g. Is.EqualTo(1).Within(1) or Is.Not.EqualTo(1).Within(1)
if (memberAccessExpression.Expression is not InvocationExpressionSyntax innerInvocationExpression
|| innerInvocationExpression.Expression is not MemberAccessExpressionSyntax left)
{
return false;
}

memberAccessExpression = left;
invocationExpression = innerInvocationExpression;
}

return SupportedIsConstraints.Contains(memberAccessExpression.Name.ToString());
}

private static bool IsSupportedStringAssert(IMethodSymbol methodSymbol)
{
return methodSymbol.ContainingType.IsStringAssert() && SupportedStringAsserts.Contains(methodSymbol.Name);
Expand Down

0 comments on commit 903a11f

Please sign in to comment.