Skip to content

Commit

Permalink
Merge pull request #79 from TSRBerry/feature/unsigned-range
Browse files Browse the repository at this point in the history
CombinatorialRangeAttribute: Add uint support
  • Loading branch information
AArnott authored Jul 18, 2023
2 parents 305a4d1 + 62361d8 commit dcb36ed
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 0 deletions.
65 changes: 65 additions & 0 deletions src/Xunit.Combinatorial/CombinatorialRangeAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,71 @@ public CombinatorialRangeAttribute(int from, int to, int step)
this.Values = values;
}

/// <summary>
/// Initializes a new instance of the <see cref="CombinatorialRangeAttribute"/> class.
/// </summary>
/// <param name="from">The value at the beginning of the range.</param>
/// <param name="count">
/// The quantity of consecutive integer values to include.
/// Cannot be less than 1, which would conceptually result in zero test cases.
/// </param>
public CombinatorialRangeAttribute(uint from, uint count)
{
if (count < 1)
{
throw new ArgumentOutOfRangeException(nameof(count));
}

object[] values = new object[count];
for (uint i = 0; i < count; i++)
{
values[i] = from + i;
}

this.Values = values;
}

/// <summary>
/// Initializes a new instance of the <see cref="CombinatorialRangeAttribute"/> class.
/// </summary>
/// <param name="from">The value at the beginning of the range.</param>
/// <param name="to">
/// The value at the end of the range.
/// Cannot be less than "from" parameter.
/// When "to" and "from" are equal, CombinatorialValues is more appropriate.
/// </param>
/// <param name="step">
/// The number of unsigned integers to step for each value in result.
/// Cannot be less than one. Stepping zero is not useful.
/// Stepping over "to" does not add another value to the range.
/// </param>
public CombinatorialRangeAttribute(uint from, uint to, uint step)
{
if (step == 0)
{
throw new ArgumentOutOfRangeException(nameof(step));
}

var values = new List<uint>();

if (from < to)
{
for (uint i = from; i <= to; i += step)
{
values.Add(i);
}
}
else
{
for (uint i = from; i >= to && i <= from; i -= step)
{
values.Add(i);
}
}

this.Values = values.Cast<object>().ToArray();
}

/// <summary>
/// Gets the values that should be passed to this parameter on the test method.
/// </summary>
Expand Down
57 changes: 57 additions & 0 deletions test/Xunit.Combinatorial.Tests/CombinatorialRangeAttributeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,40 @@ public void IntegerStep_InvalidIntervalAndStep_ArgOutOfRange(int from, int to, i
Assert.Throws<ArgumentOutOfRangeException>(() => new CombinatorialRangeAttribute(from, to, step));
}

[Theory]
[InlineData(0u, 5u)]
public void CountOfUnsignedIntegers_HappyPath_SetsAttributeWithRange(uint from, uint count)
{
object[] values = UnsignedSequence(from, from + count - 1u, 1u).Cast<object>().ToArray();
var attribute = new CombinatorialRangeAttribute(from, count);
Assert.Equal(values, attribute.Values);
}

[Theory]
[InlineData(0u, 0u)]
public void CountOfUnsignedIntegers_ZeroCount_ArgOutOfRange(uint from, uint count)
{
Assert.Throws<ArgumentOutOfRangeException>(() => new CombinatorialRangeAttribute(from, count));
}

[Theory]
[InlineData(0u, 7u, 2u)]
[InlineData(0u, 8u, 2u)]
[InlineData(7u, 0u, 2u)]
public void UnsignedIntegerStep_HappyPath_SetsAttributeWithRange(uint from, uint to, uint step)
{
object[] expectedValues = UnsignedSequence(from, to, step).Cast<object>().ToArray();

var attribute = new CombinatorialRangeAttribute(from, to, step);
Assert.Equal(expectedValues, attribute.Values);
}

internal static IEnumerable<int> Sequence(int from, int to, int step)
=> step >= 0 ? SequenceIterator(from, to, step) : SequenceReverseIterator(from, to, step);

internal static IEnumerable<uint> UnsignedSequence(uint from, uint to, uint step)
=> from < to ? UnsignedSequenceIterator(from, to, step) : UnsignedSequenceReverseIterator(from, to, step);

private static IEnumerable<int> SequenceIterator(int from, int to, int step)
{
int value = from;
Expand All @@ -70,4 +101,30 @@ private static IEnumerable<int> SequenceReverseIterator(int from, int to, int st
}
}
}

private static IEnumerable<uint> UnsignedSequenceIterator(uint from, uint to, uint step)
{
uint value = from;
while (value <= to)
{
yield return value;
unchecked
{
value += step;
}
}
}

private static IEnumerable<uint> UnsignedSequenceReverseIterator(uint from, uint to, uint step)
{
uint value = from;
while (value >= to && value <= from)
{
yield return value;
unchecked
{
value -= step;
}
}
}
}

0 comments on commit dcb36ed

Please sign in to comment.