Skip to content

Commit

Permalink
Merge pull request #97 from AArnott/fixes
Browse files Browse the repository at this point in the history
Syntax touch-ups
  • Loading branch information
AArnott authored Oct 2, 2024
2 parents a88e3ec + 84347d7 commit 944ba62
Show file tree
Hide file tree
Showing 16 changed files with 1,524 additions and 1,547 deletions.
117 changes: 58 additions & 59 deletions src/Xunit.Combinatorial/CombinatorialDataAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,82 +4,81 @@
using System.Reflection;
using Xunit.Sdk;

namespace Xunit
namespace Xunit;

/// <summary>
/// Provides a test method decorated with a <see cref="TheoryAttribute"/>
/// with arguments to run every possible combination of values for the
/// parameters taken by the test method.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class CombinatorialDataAttribute : DataAttribute
{
/// <summary>
/// Provides a test method decorated with a <see cref="TheoryAttribute"/>
/// with arguments to run every possible combination of values for the
/// parameters taken by the test method.
/// Initializes a new instance of the <see cref="CombinatorialDataAttribute"/> class.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class CombinatorialDataAttribute : DataAttribute
public CombinatorialDataAttribute()
{
}

/// <inheritdoc />
public override IEnumerable<object?[]> GetData(MethodInfo testMethod)
{
/// <summary>
/// Initializes a new instance of the <see cref="CombinatorialDataAttribute"/> class.
/// </summary>
public CombinatorialDataAttribute()
Requires.NotNull(testMethod, nameof(testMethod));

ParameterInfo[]? parameters = testMethod.GetParameters();
if (parameters.Length == 0)
{
return Enumerable.Empty<object[]>();
}

/// <inheritdoc />
public override IEnumerable<object?[]> GetData(MethodInfo testMethod)
var values = new List<object?>[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
Requires.NotNull(testMethod, nameof(testMethod));

ParameterInfo[]? parameters = testMethod.GetParameters();
if (parameters.Length == 0)
{
return Enumerable.Empty<object[]>();
}
values[i] = ValuesUtilities.GetValuesFor(parameters[i]).ToList();
}

var values = new List<object?>[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
values[i] = ValuesUtilities.GetValuesFor(parameters[i]).ToList();
}
object[]? currentValues = new object[parameters.Length];
return this.FillCombinations(parameters, values, currentValues, 0);
}

object[]? currentValues = new object[parameters.Length];
return this.FillCombinations(parameters, values, currentValues, 0);
}
/// <summary>
/// Produces a sequence of argument arrays that capture every possible
/// combination of values.
/// </summary>
/// <param name="parameters">The parameters taken by the test method.</param>
/// <param name="candidateValues">An array of each argument's list of possible values.</param>
/// <param name="currentValues">An array that is being recursively initialized with a set of arguments to pass to the test method.</param>
/// <param name="index">The index into <paramref name="currentValues"/> that this particular invocation should rotate through <paramref name="candidateValues"/> for.</param>
/// <returns>A sequence of all combinations of arguments from <paramref name="candidateValues"/>, starting at <paramref name="index"/>.</returns>
private IEnumerable<object?[]> FillCombinations(ParameterInfo[] parameters, List<object?>[] candidateValues, object?[] currentValues, int index)
{
Requires.NotNull(parameters, nameof(parameters));
Requires.NotNull(candidateValues, nameof(candidateValues));
Requires.NotNull(currentValues, nameof(currentValues));
Requires.Argument(parameters.Length == candidateValues.Length, nameof(candidateValues), $"Expected to have same array length as {nameof(parameters)}");
Requires.Argument(parameters.Length == currentValues.Length, nameof(currentValues), $"Expected to have same array length as {nameof(parameters)}");
Requires.Range(index >= 0 && index < parameters.Length, nameof(index));

/// <summary>
/// Produces a sequence of argument arrays that capture every possible
/// combination of values.
/// </summary>
/// <param name="parameters">The parameters taken by the test method.</param>
/// <param name="candidateValues">An array of each argument's list of possible values.</param>
/// <param name="currentValues">An array that is being recursively initialized with a set of arguments to pass to the test method.</param>
/// <param name="index">The index into <paramref name="currentValues"/> that this particular invocation should rotate through <paramref name="candidateValues"/> for.</param>
/// <returns>A sequence of all combinations of arguments from <paramref name="candidateValues"/>, starting at <paramref name="index"/>.</returns>
private IEnumerable<object?[]> FillCombinations(ParameterInfo[] parameters, List<object?>[] candidateValues, object?[] currentValues, int index)
foreach (object? value in candidateValues[index])
{
Requires.NotNull(parameters, nameof(parameters));
Requires.NotNull(candidateValues, nameof(candidateValues));
Requires.NotNull(currentValues, nameof(currentValues));
Requires.Argument(parameters.Length == candidateValues.Length, nameof(candidateValues), $"Expected to have same array length as {nameof(parameters)}");
Requires.Argument(parameters.Length == currentValues.Length, nameof(currentValues), $"Expected to have same array length as {nameof(parameters)}");
Requires.Range(index >= 0 && index < parameters.Length, nameof(index));
currentValues[index] = value;

foreach (object? value in candidateValues[index])
if (index + 1 < parameters.Length)
{
currentValues[index] = value;

if (index + 1 < parameters.Length)
{
foreach (object?[] result in this.FillCombinations(parameters, candidateValues, currentValues, index + 1))
{
yield return result;
}
}
else
foreach (object?[] result in this.FillCombinations(parameters, candidateValues, currentValues, index + 1))
{
// We're the tail end, so just produce the value.
// Copy the array before returning since we're about to mutate currentValues
object[] finalSet = new object[currentValues.Length];
Array.Copy(currentValues, finalSet, currentValues.Length);
yield return finalSet;
yield return result;
}
}
else
{
// We're the tail end, so just produce the value.
// Copy the array before returning since we're about to mutate currentValues
object[] finalSet = new object[currentValues.Length];
Array.Copy(currentValues, finalSet, currentValues.Length);
yield return finalSet;
}
}
}
}
Loading

0 comments on commit 944ba62

Please sign in to comment.