Skip to content

Commit

Permalink
Breaking: Respect NUnit class level parameters and drop support for c…
Browse files Browse the repository at this point in the history
…ustom TestName (#1249)
  • Loading branch information
SimonCropp authored Jul 20, 2024
1 parent 5e5f716 commit 0fc72c2
Show file tree
Hide file tree
Showing 35 changed files with 116 additions and 84 deletions.
5 changes: 4 additions & 1 deletion docs/mdsource/parameterised.source.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ When using a [TestFixtureSource](https://docs.nunit.org/articles/nunit/writing-t

snippet: TestFixtureSourceUsage.cs

Produces `TestFixtureSourceUsage(Value1,1).Test.verified.txt` and `TestFixtureSourceUsage(Value2,2).Test.verified.txt`.
Produces:

* `TestFixtureSourceUsage.Test_arg1=Value1_arg2=1.verified.txt`
* `TestFixtureSourceUsage.Test_arg1=Value2_arg2=2.verified.txt`


## xUnit
Expand Down
5 changes: 4 additions & 1 deletion docs/parameterised.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,10 @@ public class TestFixtureSourceUsage(string arg1, int arg2)
<sup><a href='/src/Verify.NUnit.Tests/TestFixtureSourceUsage.cs#L1-L26' title='Snippet source file'>snippet source</a> | <a href='#snippet-TestFixtureSourceUsage.cs' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Produces `TestFixtureSourceUsage(Value1,1).Test.verified.txt` and `TestFixtureSourceUsage(Value2,2).Test.verified.txt`.
Produces:

* `TestFixtureSourceUsage.Test_arg1=Value1_arg2=1.verified.txt`
* `TestFixtureSourceUsage.Test_arg1=Value2_arg2=2.verified.txt`


## xUnit
Expand Down
10 changes: 0 additions & 10 deletions src/Benchmarks/FileNameCleanerBenchmarks.cs

This file was deleted.

Empty file.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Value1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Value1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

2 changes: 2 additions & 0 deletions src/Verify.NUnit/GlobalUsings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
global using NUnit.Framework.Internal;
global using NUnit.Framework.Interfaces;
global using VerifyTests;

global using TestAdapter = NUnit.Framework.TestContext.TestAdapter;
127 changes: 97 additions & 30 deletions src/Verify.NUnit/Verifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,63 +31,130 @@ static InnerVerifier BuildVerifier(string sourceFile, VerifySettings settings, b
throw new("TestContext.CurrentContext.Test.Method is null. Verify can only be used from within a test method.");
}

if (!settings.HasParameters &&
adapter.Arguments.Length > 0)
var method = testMethod.MethodInfo;
var type = testMethod.TypeInfo.Type;

IReadOnlyList<string>? parameterNames;
if (settings.HasParameters)
{
settings.SetParameters(adapter.Arguments);
parameterNames = GetParameterNames(adapter);
}

var customName = !adapter.FullName.StartsWith($"{testMethod.TypeInfo.FullName}.{testMethod.Name}");
if (customName)
else
{

settings.typeName ??= adapter.GetTypeName();

settings.methodName ??= adapter.GetMethodName();
var (names, values) = GetParameterInfo(adapter);
settings.SetParameters(values);
parameterNames = names;
}

var type = testMethod.TypeInfo.Type;
VerifierSettings.AssignTargetAssembly(type.Assembly);

var method = testMethod.MethodInfo;

var pathInfo = GetPathInfo(sourceFile, type, method);
return new(
sourceFile,
settings,
type.NameWithParent(),
method.Name,
method.ParameterNames(),
parameterNames,
pathInfo);
}

static string GetMethodName(this TestContext.TestAdapter adapter)
static (IReadOnlyList<string>? names, object?[] values) GetParameterInfo(TestAdapter adapter)
{
var name = adapter.Name;
var indexOf = name.IndexOf('(');
var method = adapter.Method!;

if (indexOf != -1)
var methodParameterNames = method.MethodInfo.ParameterNames();

var parent = GetParent(adapter);

if (parent == null)
{
name = name[..indexOf];
return (methodParameterNames, adapter.Arguments);
}

return name.ReplaceInvalidFileNameChars();
var argumentsLength = parent.Arguments.Length;
if (argumentsLength == 0)
{
return (methodParameterNames, adapter.Arguments);
}

var names = GetConstructorParameterNames(method.TypeInfo.Type, argumentsLength);
if (methodParameterNames == null)
{
return (names.ToList(), parent.Arguments);
}

return (
[.. names, .. methodParameterNames],
[.. parent.Arguments, .. adapter.Arguments]);
}

static string GetTypeName(this TestContext.TestAdapter adapter)
static IReadOnlyList<string>? GetParameterNames(TestAdapter adapter)
{
var fullName = adapter.FullName.AsSpan();
var fullNameLength = fullName.Length - (adapter.Name.Length + 1);
var typeName = fullName[..fullNameLength];
var typeInfo = adapter.Method!.TypeInfo;
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
if (typeInfo.Namespace is not null)
var method = adapter.Method!;

var methodParameterNames = method.MethodInfo.ParameterNames();

var parent = GetParent(adapter);

if (parent == null)
{
return methodParameterNames;
}

var names = GetConstructorParameterNames(method.TypeInfo.Type, parent.Arguments.Length);
if (methodParameterNames == null)
{
return names.ToList();
}

return [.. names, .. methodParameterNames];
}

static ITest? GetParent(TestAdapter adapter)
{
var test = GetTest(adapter);
var parent = test.Parent;
if (parent is ParameterizedMethodSuite methodSuite)
{
return methodSuite.Parent;
}

return parent;
}

static Test GetTest(TestAdapter adapter)
{
var field = adapter
.GetType()
.GetField("_test", BindingFlags.Instance | BindingFlags.NonPublic)!;
return (Test) field.GetValue(adapter)!;
}

static IEnumerable<string> GetConstructorParameterNames(Type type, int argumentsLength)
{
IEnumerable<string>? names = null;
foreach (var constructor in type.GetConstructors(BindingFlags.Instance | BindingFlags.Public))
{
var parameters = constructor.GetParameters();
if (parameters.Length != argumentsLength)
{
continue;
}

if (names != null)
{
throw new($"Found multiple constructors with {argumentsLength} parameters. Unable to derive names of parameters. Instead use UseParameters to pass in explicit parameter.");
}

names = parameters.Select(_ => _.Name!);
}

if (names == null)
{
typeName = typeName[(typeInfo.Namespace.Length + 1)..];
throw new($"Could not find constructor with {argumentsLength} parameters.");
}

return typeName.ToString().Replace("\"", "")
.ReplaceInvalidFileNameChars();
return names;
}

static SettingsTask Verify(
Expand Down

This file was deleted.

6 changes: 0 additions & 6 deletions src/Verify.Tests/FileNameCleanerBenchmarksTests.cs

This file was deleted.

27 changes: 0 additions & 27 deletions src/Verify/FileNameCleaner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,33 +49,6 @@
static SearchValues<char> invalidFileNameSearchValues = SearchValues.Create(invalidFileNameChars);
#endif

public static string ReplaceInvalidFileNameChars(this string value)
{
var span = value.AsSpan();

var index = IndexOfInvalidChar(span);

if (index == -1)
{
return value;
}

Span<char> target = stackalloc char[value.Length];
span.CopyTo(target);

target[index] = '-';
index++;
for (; index < target.Length; index++)
{
if (IsInvalid(target[index]))
{
target[index] = '-';
}
}

return target.ToString();
}

static int IndexOfInvalidChar(CharSpan span) =>
#if NET8_0_OR_GREATER
span.IndexOfAny(invalidFileNameSearchValues);
Expand Down

0 comments on commit 0fc72c2

Please sign in to comment.