Skip to content

Commit

Permalink
Add support for Generic Nullable parameters (nunit#4872)
Browse files Browse the repository at this point in the history
* Add support for Generic Nullable parameters

* Tests  `null` can be resolved if matching non-null value
manfred-brands authored Nov 2, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 02592ca commit 2a0ec35
Showing 4 changed files with 65 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/NUnitFramework/framework/Internal/GenericMethodHelper.cs
Original file line number Diff line number Diff line change
@@ -108,6 +108,10 @@ private void TryApplyArgType(Type parmType, Type argType)
TryApplyArgType(genericArgTypes[i], argTypes[i]);
}
}
else if (Reflect.IsNullable(parmType) && !argType.IsClass)
{
ApplyArgType(genericArgTypes[0], argType);
}
}
}

2 changes: 1 addition & 1 deletion src/NUnitFramework/framework/Internal/Reflect.cs
Original file line number Diff line number Diff line change
@@ -336,7 +336,7 @@ internal static bool IsAssignableFromNull(Type type)
return !type.IsValueType || IsNullable(type);
}

private static bool IsNullable(Type type)
internal static bool IsNullable(Type type)
{
// Compare with https://github.com/dotnet/coreclr/blob/bb01fb0d954c957a36f3f8c7aad19657afc2ceda/src/mscorlib/src/System/Nullable.cs#L152-L157
return type.IsGenericType
42 changes: 42 additions & 0 deletions src/NUnitFramework/tests/Attributes/TestCaseAttributeTests.cs
Original file line number Diff line number Diff line change
@@ -875,5 +875,47 @@ public void ExplicitTypeArgsWithGenericConstraintSatisfied<T>(int input)
Assert.That(convertedValue, Is.TypeOf<T>());
Assert.That(convertedValue, Is.Not.TypeOf(input.GetType()));
}

[TestCase(0, TypeArgs = [typeof(int)])]
#if NET6_0_OR_GREATER
[TestCase<int>(0)]
#endif
[TestCase(0)]
[TestCase(1L)]
[TestCase(2UL)]
[TestCase(3F)]
[TestCase(4D)]
public void GenericNullable<TValue>(TValue? value)
where TValue : struct, IConvertible
{
Assert.That(value, Is.Not.Null);
int index = value.Value.ToInt32(null);
#pragma warning disable NUnit2021 // Incompatible types for EqualTo constraint
Assert.That(value.Value, Is.EqualTo(index));
#pragma warning restore NUnit2021 // Incompatible types for EqualTo constraint
Assert.That(value.Value, Is.InstanceOf(ExpectedType[index]));
}

private static readonly Type[] ExpectedType = [typeof(int), typeof(long), typeof(ulong), typeof(float), typeof(double)];

[TestCase("Hello", null)]
[TestCase(null, "World")]
[TestCase("Hello", "World")]
public void GenericNullableClass<TValue>(TValue? greeting, TValue? to)
where TValue : class
{
Assert.That(greeting, Is.Null.Or.Not.Null);
Assert.That(to, Is.Not.Null.Or.Null);
}

[TestCase(3, null)]
[TestCase(null, 4.0)]
[TestCase(3, 4)]
public void GenericNullableStruct<TValue>(TValue? greeting, TValue? to)
where TValue : struct
{
Assert.That(greeting, Is.Null.Or.Not.Null);
Assert.That(to, Is.Not.Null.Or.Null);
}
}
}
18 changes: 18 additions & 0 deletions src/NUnitFramework/tests/Attributes/TestCaseSourceTests.cs
Original file line number Diff line number Diff line change
@@ -756,6 +756,24 @@ private static async IAsyncEnumerable<TestCaseData> AsyncEnumerableTestCases()
await Task.Delay(100); // Simulate another asynchronous operation
yield return new TestCaseData(51, 51);
}

#region Generic Nullable

[TestCaseSource(nameof(GenericNullableSource))]
public void GenericNullableTest<TValue>(TValue? value)
where TValue : struct, IConvertible
{
Assert.That(value, Is.Not.Null);
int index = value.Value.ToInt32(null);
#pragma warning disable NUnit2021 // Incompatible types for EqualTo constraint
Assert.That(value.Value, Is.EqualTo(index));
#pragma warning restore NUnit2021 // Incompatible types for EqualTo constraint
Assert.That(value.Value, Is.InstanceOf(GenericNullableSource[index].GetType()));
}

private static readonly object[] GenericNullableSource = [0, 1L, 2UL, 3F, 4D];

#endregion
}

public class TestSourceMayBeInherited

0 comments on commit 2a0ec35

Please sign in to comment.