Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ public static readonly (string Constant, Type Type)[] FullNameOfTypeSource =
(nameof(NUnitFrameworkConstants.FullNameOfActualValueDelegate), typeof(ActualValueDelegate<>)),
(nameof(NUnitFrameworkConstants.FullNameOfDelayedConstraint), typeof(DelayedConstraint)),
(nameof(NUnitFrameworkConstants.FullNameOfTestDelegate), typeof(TestDelegate)),
(nameof(NUnitFrameworkConstants.FullNameOfAsyncTestDelegate), typeof(AsyncTestDelegate)),
(nameof(NUnitFrameworkConstants.FullNameOfThrows), typeof(Throws)),
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -391,14 +391,14 @@ public void NoDiagnosticWhenActualAndExpectedTypesAreSameWithLambdaActualValue()
}

[Test]
public void AnalyzeWhenActualAndExpectedTypesAreSameWithFuncActualValue()
public void NoDiagnosticWhenActualAndExpectedTypesAreSameWithFuncActualValue()
{
var testCode = TestUtility.WrapInTestMethod(@"
Func<string> actual = () => """";
var expected = """";
Assert.That(actual, Is.EqualTo(expected));");
Assert.That(actual, Is.EqualTo(expected));");

RoslynAssert.Diagnostics(analyzer, expectedDiagnostic, testCode);
RoslynAssert.Valid(analyzer, testCode);
}

[Test]
Expand Down Expand Up @@ -1153,5 +1153,27 @@ public void AnalyzeOnNullableDouble()

RoslynAssert.Valid(analyzer, testCode);
}

[Test]
public void AnalyzeOnFuncReturningDouble()
{
var testCode = TestUtility.WrapInTestMethod(@$"
Func<double> actual = () => Math.PI;
Assert.That(actual, Is.Not.NaN);
Assert.That(actual, Is.EqualTo(Math.PI));
");
RoslynAssert.Valid(analyzer, testCode);
}

[Test]
public void AnalyzeOnAsyncFuncReturningDouble()
{
var testCode = TestUtility.WrapInTestMethod(@$"
Func<Task<double>> actual = () => Task.FromResult(Math.PI);
Assert.That(actual, Is.Not.NaN);
Assert.That(actual, Is.EqualTo(Math.PI));
");
RoslynAssert.Valid(analyzer, testCode);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System;
using System.Threading.Tasks;
using Gu.Roslyn.Asserts;
using Microsoft.CodeAnalysis.Diagnostics;
using NUnit.Analyzers.Constants;
Expand Down Expand Up @@ -132,109 +130,13 @@ public void ValidWhenActualIsFunc(string constraint)

[TestCase("Is.Null")]
[TestCase("Is.Not.Null")]
public void AnalyzeWhenActualIsTestDelegate(string constraint)
public void ValidWhenActualIsTestDelegate(string constraint)
{
var testCode = TestUtility.WrapInTestMethod($@"
Action<bool> action = b => {{ }};
Assert.That(() => action(true), {constraint});");
Assert.That(() => action(true), {constraint});");

RoslynAssert.Diagnostics(analyzer, expectedDiagnostic, testCode);
}

[Test]
public void ActualNUnitFunction()
{
bool functionCalled = false;

#pragma warning disable IDE0039 // Use local function
Func<bool> function = () =>
{
functionCalled = true;
return false;
};
#pragma warning restore IDE0039 // Use local function

Assert.Multiple(() =>
{
Assert.That(function, Is.Not.Null);
Assert.That(functionCalled, Is.False);

#pragma warning disable NUnit2057 // Unnecessary DelegateCreation
Assert.That(() => function, Is.Not.Null);
#pragma warning restore NUnit2057 // Unnecessary DelegateCreation
Assert.That(functionCalled, Is.False);

#pragma warning disable NUnit2057 // Unnecessary DelegateCreation
#pragma warning disable NUnit2023 // Invalid NullConstraint usage
Assert.That(() => function(), Is.Not.Null);
#pragma warning restore NUnit2023 // Invalid NullConstraint usage
#pragma warning restore NUnit2057 // Unnecessary DelegateCreation
Assert.That(functionCalled, Is.True);
});
}

[Test]
public void ActualNUnitAsyncFunction()
{
bool functionCalled = false;

#pragma warning disable IDE0039 // Use local function
Func<Task<bool>> asyncFunction = () =>
{
functionCalled = true;
return Task.FromResult(false);
};
#pragma warning restore IDE0039 // Use local function

Assert.Multiple(() =>
{
Assert.That(asyncFunction, Is.Not.Null);
Assert.That(functionCalled, Is.False);

#pragma warning disable NUnit2057 // Unnecessary DelegateCreation
Assert.That(() => asyncFunction, Is.Not.Null);
#pragma warning restore NUnit2057 // Unnecessary DelegateCreation
Assert.That(functionCalled, Is.False);

#pragma warning disable NUnit2057 // Unnecessary DelegateCreation
#pragma warning disable NUnit2023 // Invalid NullConstraint usage
Assert.That(() => asyncFunction(), Is.Not.Null);
#pragma warning restore NUnit2023 // Invalid NullConstraint usage
#pragma warning restore NUnit2057 // Unnecessary DelegateCreation
Assert.That(functionCalled, Is.True);
});
}

[Test]
public void ActualNUnitForAction()
{
bool actionCalled = false;

#pragma warning disable IDE0039 // Use local function
Action action = () => actionCalled = true;
#pragma warning restore IDE0039 // Use local function

Assert.Multiple(() =>
{
Assert.That(action, Is.Not.Null);
Assert.That(actionCalled, Is.False);

#pragma warning disable NUnit2057 // Unnecessary DelegateCreation
Assert.That(() => action, Is.Not.Null);
#pragma warning restore NUnit2057 // Unnecessary DelegateCreation
Assert.That(actionCalled, Is.False);

#pragma warning disable NUnit2057 // Unnecessary DelegateCreation
#pragma warning disable NUnit2023 // Invalid NullConstraint usage
Assert.That(() => action(), Is.Not.Null);
#pragma warning restore NUnit2023 // Invalid NullConstraint usage
#pragma warning restore NUnit2057 // Unnecessary DelegateCreation

#if EXPECT_TEST_DELEGATE_TO_BE_CALLED
// The above test succeeds, but does not call the action!
Assert.That(actionCalled, Is.True);
#endif
});
RoslynAssert.Valid(analyzer, testCode);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -284,14 +284,14 @@ public void NoDiagnosticWhenActualAndExpectedTypesAreSameWithLambdaActualValue()
}

[Test]
public void AnalyzeWhenActualAndExpectedTypesAreSameWithFuncActualValue()
public void NoDiagnosticWhenActualAndExpectedTypesAreSameWithFuncActualValue()
{
var testCode = TestUtility.WrapInTestMethod(@"
Func<string> actual = () => """";
var expected = """";
Assert.That(actual, Is.SameAs(expected));");
Assert.That(actual, Is.SameAs(expected));");

RoslynAssert.Diagnostics(analyzer, expectedDiagnostic, testCode);
RoslynAssert.Valid(analyzer, testCode);
}

[Test]
Expand Down
1 change: 1 addition & 0 deletions src/nunit.analyzers/Constants/NUnitFrameworkConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ internal abstract class NUnitFrameworkConstants
public const string FullNameOfActualValueDelegate = "NUnit.Framework.Constraints.ActualValueDelegate`1";
public const string FullNameOfDelayedConstraint = "NUnit.Framework.Constraints.DelayedConstraint";
public const string FullNameOfTestDelegate = "NUnit.Framework.TestDelegate";
public const string FullNameOfAsyncTestDelegate = "NUnit.Framework.AsyncTestDelegate";
public const string FullNameOfThrows = "NUnit.Framework.Throws";

public const string PrefixOfAllEqualToConstraints = "NUnit.Framework.Constraints.Equal";
Expand Down
7 changes: 4 additions & 3 deletions src/nunit.analyzers/Helpers/AssertHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,16 @@ public static ITypeSymbol UnwrapActualType(ITypeSymbol actualType)
if (actualType is INamedTypeSymbol namedType)
{
var fullTypeName = namedType.GetFullMetadataName();
if (fullTypeName == NUnitFrameworkConstants.FullNameOfActualValueDelegate ||
fullTypeName == NUnitFrameworkConstants.FullNameOfTestDelegate)
if (fullTypeName is NUnitFrameworkConstants.FullNameOfActualValueDelegate
or "System.Func`1")
{
ITypeSymbol returnType = namedType.DelegateInvokeMethod!.ReturnType;
Comment thread
manfred-brands marked this conversation as resolved.

if (returnType.IsAwaitable(out ITypeSymbol? awaitReturnType))
returnType = awaitReturnType;

return returnType;
// Func<Task> returns Void, so don't consider that as the actual type.
return returnType.SpecialType == SpecialType.System_Void ? actualType : returnType;
}
}

Expand Down
Loading