Skip to content
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
162 changes: 162 additions & 0 deletions TUnit.Core.SourceGenerator.Tests/MatrixTests.Test.verified.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1730,4 +1730,166 @@ file partial class MatrixTests : global::TUnit.Core.Interfaces.SourceGenerator.I
}
}


// <auto-generated/>
#pragma warning disable
using global::System.Linq;
using global::System.Reflection;
using global::TUnit.Core;
using global::TUnit.Core.Extensions;

namespace TUnit.SourceGenerated;

[global::System.Diagnostics.StackTraceHidden]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
file partial class MatrixTests : global::TUnit.Core.Interfaces.SourceGenerator.ITestSource
{
[global::System.Runtime.CompilerServices.ModuleInitializer]
public static void Initialise()
{
global::TUnit.Core.SourceRegistrar.Register(new MatrixTests());
}
public global::System.Collections.Generic.IReadOnlyList<SourceGeneratedTestNode> CollectTests(string sessionId)
{
return Tests0(sessionId);
}
private global::System.Collections.Generic.List<SourceGeneratedTestNode> Tests0(string sessionId)
{
global::System.Collections.Generic.List<SourceGeneratedTestNode> nodes = [];
var classDataIndex = 0;
var testMethodDataIndex = 0;
try
{
var testInformation = new global::TUnit.Core.SourceGeneratedMethodInformation
{
Type = typeof(global::TUnit.TestProject.MatrixTests),
Name = "Exclusion",
GenericTypeCount = 0,
ReturnType = typeof(global::System.Threading.Tasks.Task),
Attributes =
[
new global::TUnit.Core.TestAttribute(),
new global::TUnit.Core.MatrixDataSourceAttribute(),
new global::TUnit.Core.MatrixExclusionAttribute(1, 1),
new global::TUnit.Core.MatrixExclusionAttribute(2, 2),
new global::TUnit.Core.MatrixExclusionAttribute(3, 3)
],
Parameters =
[
new global::TUnit.Core.SourceGeneratedParameterInformation<int>
{
Name = "item",
Attributes =
[
new global::TUnit.Core.MatrixMethodAttribute<global::TUnit.TestProject.MatrixTests>("EnumerableMethod")
],
},
new global::TUnit.Core.SourceGeneratedParameterInformation<int>
{
Name = "item2",
Attributes =
[
new global::TUnit.Core.MatrixMethodAttribute<global::TUnit.TestProject.MatrixTests>("EnumerableMethod")
],
},
],
Class = global::TUnit.Core.SourceGeneratedClassInformation.GetOrAdd("global::TUnit.TestProject.MatrixTests", () => new global::TUnit.Core.SourceGeneratedClassInformation
{
Type = typeof(global::TUnit.TestProject.MatrixTests),
Assembly = global::TUnit.Core.SourceGeneratedAssemblyInformation.GetOrAdd("MatrixTests", () => new global::TUnit.Core.SourceGeneratedAssemblyInformation
{
Name = "MatrixTests",
Attributes = [],
}),
Name = "MatrixTests",
Namespace = "TUnit.TestProject",
Attributes = [],
Parameters = [],
Properties = [],
}),
};

var testBuilderContext = new global::TUnit.Core.TestBuilderContext();
var testBuilderContextAccessor = new global::TUnit.Core.TestBuilderContextAccessor(testBuilderContext);
var methodArgDataGeneratorMetadata = new DataGeneratorMetadata
{
Type = global::TUnit.Core.Enums.DataGeneratorType.TestParameters,
TestBuilderContext = testBuilderContextAccessor,
TestInformation = testInformation,
MembersToGenerate =
[
new global::TUnit.Core.SourceGeneratedParameterInformation<int>
{
Name = "item",
Attributes =
[
new global::TUnit.Core.MatrixMethodAttribute<global::TUnit.TestProject.MatrixTests>("EnumerableMethod")
],
},
new global::TUnit.Core.SourceGeneratedParameterInformation<int>
{
Name = "item2",
Attributes =
[
new global::TUnit.Core.MatrixMethodAttribute<global::TUnit.TestProject.MatrixTests>("EnumerableMethod")
],
},
],
TestSessionId = sessionId,
};
var methodDataAttribute = new global::TUnit.Core.MatrixDataSourceAttribute();

var methodArgGeneratedDataArray = methodDataAttribute.GenerateDataSources(methodArgDataGeneratorMetadata);

foreach (var methodArgGeneratedDataAccessor in methodArgGeneratedDataArray)
{
testMethodDataIndex++;

var methodArgGeneratedData = methodArgGeneratedDataAccessor();
int methodArg = global::TUnit.Core.Helpers.CastHelper.Cast<int>(methodArgGeneratedData[0]);
int methodArg1 = global::TUnit.Core.Helpers.CastHelper.Cast<int>(methodArgGeneratedData[1]);
var resettableClassFactoryDelegate = () => new ResettableLazy<global::TUnit.TestProject.MatrixTests>(() =>
new global::TUnit.TestProject.MatrixTests()
, sessionId, testBuilderContext);

var resettableClassFactory = resettableClassFactoryDelegate();

nodes.Add(new TestMetadata<global::TUnit.TestProject.MatrixTests>
{
TestId = $"global::TUnit.Core.MatrixDataSourceAttribute:{testMethodDataIndex}:TL-GAC0:TUnit.TestProject.MatrixTests.Exclusion(int,int):0",
TestClassArguments = [],
TestMethodArguments = [methodArg, methodArg1],
TestClassProperties = [],
CurrentRepeatAttempt = 0,
RepeatLimit = 0,
ResettableClassFactory = resettableClassFactory,
TestMethodFactory = (classInstance, cancellationToken) => AsyncConvert.Convert(() => classInstance.Exclusion(methodArg, methodArg1)),
TestFilePath = @"",
TestLineNumber = 123,
TestMethod = testInformation,
TestBuilderContext = testBuilderContext,
});
resettableClassFactory = resettableClassFactoryDelegate();
testBuilderContext = new();
testBuilderContextAccessor.Current = testBuilderContext;
}
}
catch (global::System.Exception exception)
{
nodes.Add(new global::TUnit.Core.FailedInitializationTest
{
TestId = $"global::TUnit.Core.MatrixDataSourceAttribute:{testMethodDataIndex}:TL-GAC0:TUnit.TestProject.MatrixTests.Exclusion(int,int):0",
TestClass = typeof(global::TUnit.TestProject.MatrixTests),
ReturnType = typeof(global::System.Threading.Tasks.Task),
ParameterTypeFullNames = [typeof(int), typeof(int)],
TestName = "Exclusion",
TestFilePath = @"",
TestLineNumber = 123,
Exception = exception,
});
}
return nodes;
}
}

]
2 changes: 1 addition & 1 deletion TUnit.Core.SourceGenerator.Tests/MatrixTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ public Task Test() => RunTest(Path.Combine(Git.RootDirectory.FullName,
},
async generatedFiles =>
{
await Assert.That(generatedFiles.Length).IsEqualTo(11);
await Assert.That(generatedFiles.Length).IsEqualTo(12);
});
}
19 changes: 18 additions & 1 deletion TUnit.Core/Attributes/TestData/MatrixDataSourceAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace TUnit.Core;
using TUnit.Core.Enums;

namespace TUnit.Core;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class MatrixDataSourceAttribute : NonTypedDataSourceGeneratorAttribute
Expand All @@ -16,12 +18,27 @@ public sealed class MatrixDataSourceAttribute : NonTypedDataSourceGeneratorAttri
throw new Exception("[MatrixDataSource] only supports parameterised tests");
}

var exclusions = GetExclusions(dataGeneratorMetadata.Type == DataGeneratorType.TestParameters
? dataGeneratorMetadata.TestInformation.Attributes : dataGeneratorMetadata.TestInformation.Class.Attributes);

foreach (var row in GetMatrixValues(parameterInformation.Select(GetAllArguments)))
{
if (exclusions.Any(e => e.SequenceEqual(row)))
{
continue;
}

yield return () => row.ToArray();
}
}

private object?[][] GetExclusions(Attribute[] attributes)
{
return attributes.OfType<MatrixExclusionAttribute>()
.Select(x => x.Objects)
.ToArray();
}

private IReadOnlyList<object?> GetAllArguments(SourceGeneratedParameterInformation sourceGeneratedParameterInformation)
{
var matrixAttribute = sourceGeneratedParameterInformation.Attributes.OfType<MatrixAttribute>().FirstOrDefault();
Expand Down
7 changes: 7 additions & 0 deletions TUnit.Core/Attributes/TestData/MatrixExclusionAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TUnit.Core;

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)]
public class MatrixExclusionAttribute(params object?[]? objects) : TUnitAttribute
{
public object?[] Objects { get; } = objects ?? [ null ];
}
12 changes: 12 additions & 0 deletions TUnit.TestProject/MatrixTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,18 @@ public async Task Method4(
{
await Task.CompletedTask;
}

[Test]
[MatrixDataSource]
[MatrixExclusion(1, 1)]
[MatrixExclusion(2, 2)]
[MatrixExclusion(3, 3)]
public async Task Exclusion(
[MatrixMethod<MatrixTests>(nameof(EnumerableMethod))] int item,
[MatrixMethod<MatrixTests>(nameof(EnumerableMethod))] int item2)
{
await Task.CompletedTask;
}

public enum CountToTenEnum
{
Expand Down
51 changes: 51 additions & 0 deletions docs/docs/tutorial-basics/matrix-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,54 @@ public class MyTestClass
}
}
```

## Matrix Exclusions

You can also add a `[MatrixExclusion(...)]` attribute to your tests.
This works similar to the `[Arguments(...)]` attribute, and if objects match a generated matrix test case, it'll be ignored.

This helps you exclude specific one-off scenarios without having to complicate your tests with `if` conditions.

```csharp
using TUnit.Assertions;
using TUnit.Assertions.Extensions;
using TUnit.Assertions.Extensions.Is;
using TUnit.Core;

namespace MyTestProject;

public class MyTestClass
{
[Test]
[MatrixDataSource]
[MatrixExclusion(1, 1)]
[MatrixExclusion(2, 2)]
[MatrixExclusion(3, 3)]
public async Task MyTest(
[MatrixRange<int>(1, 3)] int value1,
[MatrixRange<int>(1, 3)] int value2
)
{
...
}
}
```

Whereas the above Matrix would usually generate:
- 1, 1
- 1, 2
- 1, 3
- 2, 1
- 2, 2
- 2, 3
- 3, 1
- 3, 2
- 3, 3

Because of the exclusion attributes, it'll only generate:
- 1, 2
- 1, 3
- 2, 1
- 2, 3
- 3, 1
- 3, 2
Loading