Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add UsingTestingSequence to enforce simpler & correct usage #475

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
9 changes: 3 additions & 6 deletions MoreLinq.Test/CountDownTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,9 @@ static IEnumerable<T> GetData<T>(Func<int[], int, int?[], T> selector)
.SetName($"{nameof(WithSequence)}({{ {string.Join(", ", e.Source)} }}, {e.Count})");

[TestCaseSource(nameof(SequenceData))]
public IEnumerable<(int, int?)> WithSequence(int[] xs, int count)
{
using var ts = xs.Select(x => x).AsTestingSequence();
foreach (var e in ts.CountDown(count, ValueTuple.Create))
yield return e;
}
public IEnumerable<(int, int?)> WithSequence(int[] xs, int count) =>
xs.Select(x => x)
.UsingTestingSequence(ts => ts.CountDown(count, ValueTuple.Create));

static readonly IEnumerable<TestCaseData> ListData =
from e in GetData((xs, count, countdown) => new
Expand Down
56 changes: 40 additions & 16 deletions MoreLinq.Test/EndsWithTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
namespace MoreLinq.Test
{
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using NUnit.Framework;

[TestFixture]
Expand All @@ -29,66 +28,91 @@ public class EndsWithTest
[TestCase(new[] {1, 2, 3}, new[] {0, 1, 2, 3}, ExpectedResult = false)]
public bool EndsWithWithIntegers(IEnumerable<int> first, IEnumerable<int> second)
{
return first.EndsWith(second);
using var fts = first.AsTestingSequence();
using var sts = second.AsTestingSequence();
return fts.EndsWith(sts);
}

[TestCase(new[] {'1', '2', '3'}, new[] {'2', '3'}, ExpectedResult = true)]
[TestCase(new[] {'1', '2', '3'}, new[] {'1', '2', '3'}, ExpectedResult = true)]
[TestCase(new[] {'1', '2', '3'}, new[] {'0', '1', '2', '3'}, ExpectedResult = false)]
public bool EndsWithWithChars(IEnumerable<char> first, IEnumerable<char> second)
{
return first.EndsWith(second);
using var fts = first.AsTestingSequence();
using var sts = second.AsTestingSequence();
return fts.EndsWith(sts);
}

[TestCase("123", "23", ExpectedResult = true)]
[TestCase("123", "123", ExpectedResult = true)]
[TestCase("123", "0123", ExpectedResult = false)]
public bool EndsWithWithStrings(string first, string second)
{
// Conflict with String.EndsWith(), which has precedence in this case
return MoreEnumerable.EndsWith(first, second);
using var fts = first.AsTestingSequence();
using var sts = second.AsTestingSequence();
return fts.EndsWith(sts);
}

[Test]
public void EndsWithReturnsTrueIfBothEmpty()
{
Assert.That(new int[0].EndsWith(new int[0]), Is.True);
using var fts = TestingSequence.Of<int>();
using var sts = TestingSequence.Of<int>();
Assert.That(fts.EndsWith(sts), Is.True);
}

[Test]
public void EndsWithReturnsFalseIfOnlyFirstIsEmpty()
{
Assert.That(new int[0].EndsWith(new[] {1,2,3}), Is.False);
using var fts = TestingSequence.Of<int>();
using var sts = TestingSequence.Of(1, 2, 3);
Assert.That(fts.EndsWith(sts), Is.False);
}

[TestCase("", "", ExpectedResult = true)]
[TestCase("1", "", ExpectedResult = true)]
public bool EndsWithReturnsTrueIfSecondIsEmpty(string first, string second)
{
// Conflict with String.EndsWith(), which has precedence in this case
return MoreEnumerable.EndsWith(first, second);
using var fts = first.AsTestingSequence();
using var sts = second.AsTestingSequence();
return fts.EndsWith(sts);
}

[Test]
public void EndsWithDisposesBothSequenceEnumerators()
{
using var first = TestingSequence.Of(1,2,3);
using var first = TestingSequence.Of(1, 2, 3);
using var second = TestingSequence.Of(1);

first.EndsWith(second);
}

[Test]
[SuppressMessage("ReSharper", "RedundantArgumentDefaultValue")]
public void EndsWithUsesSpecifiedEqualityComparerOrDefault()
public void EndsWithUsesDefaultEqualityComparerByDefault()
{
var first = new[] {1,2,3};
var second = new[] {4,5,6};
using var first = TestingSequence.Of(1, 2, 3);
using var second = TestingSequence.Of(4, 5, 6);

Assert.That(first.EndsWith(second), Is.False);
}

[Test]
public void EndsWithUsesDefaultEqualityComparerWhenNullSpecified()
{
using var first = TestingSequence.Of(1, 2, 3);
using var second = TestingSequence.Of(4, 5, 6);

Assert.That(first.EndsWith(second, null), Is.False);
Assert.That(first.EndsWith(second, EqualityComparer.Create<int>(delegate { return false; })), Is.False);
Assert.That(first.EndsWith(second, EqualityComparer.Create<int>(delegate { return true; })), Is.True);
}

[Test]
[TestCase(false, ExpectedResult = false)]
[TestCase(true, ExpectedResult = true)]
public bool EndsWithUsesSpecifiedEqualityComparer(bool result)
{
using var first = TestingSequence.Of(1, 2, 3);
using var second = TestingSequence.Of(4, 5, 6);
return first.EndsWith(second, EqualityComparer.Create<int>((_, _) => result));
}

[TestCase(SourceKind.BreakingCollection)]
Expand Down
32 changes: 16 additions & 16 deletions MoreLinq.Test/FoldTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,22 @@ public void Fold()
{
const string alphabet = "abcdefghijklmnopqrstuvwxyz";

using (var ts = alphabet.Take( 1).AsTestingSequence()) Assert.That(ts.Fold(a => string.Join(string.Empty, a )), Is.EqualTo("a" ), "fold 1" );
using (var ts = alphabet.Take( 2).AsTestingSequence()) Assert.That(ts.Fold((a, b ) => string.Join(string.Empty, a, b )), Is.EqualTo("ab" ), "fold 2" );
using (var ts = alphabet.Take( 3).AsTestingSequence()) Assert.That(ts.Fold((a, b, c ) => string.Join(string.Empty, a, b, c )), Is.EqualTo("abc" ), "fold 3" );
using (var ts = alphabet.Take( 4).AsTestingSequence()) Assert.That(ts.Fold((a, b, c, d ) => string.Join(string.Empty, a, b, c, d )), Is.EqualTo("abcd" ), "fold 4" );
using (var ts = alphabet.Take( 5).AsTestingSequence()) Assert.That(ts.Fold((a, b, c, d, e ) => string.Join(string.Empty, a, b, c, d, e )), Is.EqualTo("abcde" ), "fold 5" );
using (var ts = alphabet.Take( 6).AsTestingSequence()) Assert.That(ts.Fold((a, b, c, d, e, f ) => string.Join(string.Empty, a, b, c, d, e, f )), Is.EqualTo("abcdef" ), "fold 6" );
using (var ts = alphabet.Take( 7).AsTestingSequence()) Assert.That(ts.Fold((a, b, c, d, e, f, g ) => string.Join(string.Empty, a, b, c, d, e, f, g )), Is.EqualTo("abcdefg" ), "fold 7" );
using (var ts = alphabet.Take( 8).AsTestingSequence()) Assert.That(ts.Fold((a, b, c, d, e, f, g, h ) => string.Join(string.Empty, a, b, c, d, e, f, g, h )), Is.EqualTo("abcdefgh" ), "fold 8" );
using (var ts = alphabet.Take( 9).AsTestingSequence()) Assert.That(ts.Fold((a, b, c, d, e, f, g, h, i ) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i )), Is.EqualTo("abcdefghi" ), "fold 9" );
using (var ts = alphabet.Take(10).AsTestingSequence()) Assert.That(ts.Fold((a, b, c, d, e, f, g, h, i, j ) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i, j )), Is.EqualTo("abcdefghij" ), "fold 10");
using (var ts = alphabet.Take(11).AsTestingSequence()) Assert.That(ts.Fold((a, b, c, d, e, f, g, h, i, j, k ) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i, j, k )), Is.EqualTo("abcdefghijk" ), "fold 11");
using (var ts = alphabet.Take(12).AsTestingSequence()) Assert.That(ts.Fold((a, b, c, d, e, f, g, h, i, j, k, l ) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i, j, k, l )), Is.EqualTo("abcdefghijkl" ), "fold 12");
using (var ts = alphabet.Take(13).AsTestingSequence()) Assert.That(ts.Fold((a, b, c, d, e, f, g, h, i, j, k, l, m ) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i, j, k, l, m )), Is.EqualTo("abcdefghijklm" ), "fold 13");
using (var ts = alphabet.Take(14).AsTestingSequence()) Assert.That(ts.Fold((a, b, c, d, e, f, g, h, i, j, k, l, m, n ) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i, j, k, l, m, n )), Is.EqualTo("abcdefghijklmn" ), "fold 14");
using (var ts = alphabet.Take(15).AsTestingSequence()) Assert.That(ts.Fold((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o ) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o )), Is.EqualTo("abcdefghijklmno" ), "fold 15");
using (var ts = alphabet.Take(16).AsTestingSequence()) Assert.That(ts.Fold((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)), Is.EqualTo("abcdefghijklmnop"), "fold 16");
Assert.That(alphabet.Take( 1).UsingTestingSequence(ts => ts.Fold(a => string.Join(string.Empty, a ))), Is.EqualTo("a" ), "fold 1" );
Assert.That(alphabet.Take( 2).UsingTestingSequence(ts => ts.Fold((a, b ) => string.Join(string.Empty, a, b ))), Is.EqualTo("ab" ), "fold 2" );
Assert.That(alphabet.Take( 3).UsingTestingSequence(ts => ts.Fold((a, b, c ) => string.Join(string.Empty, a, b, c ))), Is.EqualTo("abc" ), "fold 3" );
Assert.That(alphabet.Take( 4).UsingTestingSequence(ts => ts.Fold((a, b, c, d ) => string.Join(string.Empty, a, b, c, d ))), Is.EqualTo("abcd" ), "fold 4" );
Assert.That(alphabet.Take( 5).UsingTestingSequence(ts => ts.Fold((a, b, c, d, e ) => string.Join(string.Empty, a, b, c, d, e ))), Is.EqualTo("abcde" ), "fold 5" );
Assert.That(alphabet.Take( 6).UsingTestingSequence(ts => ts.Fold((a, b, c, d, e, f ) => string.Join(string.Empty, a, b, c, d, e, f ))), Is.EqualTo("abcdef" ), "fold 6" );
Assert.That(alphabet.Take( 7).UsingTestingSequence(ts => ts.Fold((a, b, c, d, e, f, g ) => string.Join(string.Empty, a, b, c, d, e, f, g ))), Is.EqualTo("abcdefg" ), "fold 7" );
Assert.That(alphabet.Take( 8).UsingTestingSequence(ts => ts.Fold((a, b, c, d, e, f, g, h ) => string.Join(string.Empty, a, b, c, d, e, f, g, h ))), Is.EqualTo("abcdefgh" ), "fold 8" );
Assert.That(alphabet.Take( 9).UsingTestingSequence(ts => ts.Fold((a, b, c, d, e, f, g, h, i ) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i ))), Is.EqualTo("abcdefghi" ), "fold 9" );
Assert.That(alphabet.Take(10).UsingTestingSequence(ts => ts.Fold((a, b, c, d, e, f, g, h, i, j ) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i, j ))), Is.EqualTo("abcdefghij" ), "fold 10");
Assert.That(alphabet.Take(11).UsingTestingSequence(ts => ts.Fold((a, b, c, d, e, f, g, h, i, j, k ) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i, j, k ))), Is.EqualTo("abcdefghijk" ), "fold 11");
Assert.That(alphabet.Take(12).UsingTestingSequence(ts => ts.Fold((a, b, c, d, e, f, g, h, i, j, k, l ) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i, j, k, l ))), Is.EqualTo("abcdefghijkl" ), "fold 12");
Assert.That(alphabet.Take(13).UsingTestingSequence(ts => ts.Fold((a, b, c, d, e, f, g, h, i, j, k, l, m ) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i, j, k, l, m ))), Is.EqualTo("abcdefghijklm" ), "fold 13");
Assert.That(alphabet.Take(14).UsingTestingSequence(ts => ts.Fold((a, b, c, d, e, f, g, h, i, j, k, l, m, n ) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i, j, k, l, m, n ))), Is.EqualTo("abcdefghijklmn" ), "fold 14");
Assert.That(alphabet.Take(15).UsingTestingSequence(ts => ts.Fold((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o ) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o ))), Is.EqualTo("abcdefghijklmno" ), "fold 15");
Assert.That(alphabet.Take(16).UsingTestingSequence(ts => ts.Fold((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => string.Join(string.Empty, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p))), Is.EqualTo("abcdefghijklmnop"), "fold 16");
}
}
}
37 changes: 19 additions & 18 deletions MoreLinq.Test/RankTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ public void TestRankByIsLazy()
public void TestRankNullComparer()
{
var sequence = Enumerable.Repeat(1, 10);
sequence.AsTestingSequence().Rank(null).AssertSequenceEqual(sequence);
sequence.UsingTestingSequence(ts => ts.Rank(null))
.AssertSequenceEqual(sequence);
}

/// <summary>
Expand All @@ -61,7 +62,8 @@ public void TestRankNullComparer()
public void TestRankByNullComparer()
{
var sequence = Enumerable.Repeat(1, 10);
sequence.AsTestingSequence().RankBy(x => x, null).AssertSequenceEqual(sequence);
sequence.UsingTestingSequence(ts => ts.RankBy(x => x, null))
.AssertSequenceEqual(sequence);
}

/// <summary>
Expand All @@ -73,11 +75,11 @@ public void TestRankDescendingSequence()
{
const int count = 100;
var sequence = Enumerable.Range(456, count).Reverse();
var result = sequence.AsTestingSequence().Rank().ToArray();
var expectedResult = Enumerable.Range(1, count);

var result = sequence.UsingTestingSequence(ts => ts.Rank());

Assert.That(result.Length, Is.EqualTo(count));
Assert.That(result, Is.EqualTo(expectedResult));
Assert.That(result, Is.EqualTo(Enumerable.Range(1, count)));
}

/// <summary>
Expand All @@ -89,11 +91,11 @@ public void TestRankByAscendingSeries()
{
const int count = 100;
var sequence = Enumerable.Range(456, count);
var result = sequence.AsTestingSequence().Rank().ToArray();
var expectedResult = Enumerable.Range(1, count).Reverse();

var result = sequence.UsingTestingSequence(ts => ts.Rank());

Assert.That(result.Length, Is.EqualTo(count));
Assert.That(result, Is.EqualTo(expectedResult));
Assert.That(result, Is.EqualTo(Enumerable.Range(1, count).Reverse()));
}

/// <summary>
Expand All @@ -104,7 +106,7 @@ public void TestRankEquivalentItems()
{
const int count = 100;
var sequence = Enumerable.Repeat(1234, count);
var result = sequence.AsTestingSequence().Rank().ToArray();
var result = sequence.UsingTestingSequence(ts => ts.Rank());

Assert.That(result.Length, Is.EqualTo(count));
Assert.That(result, Is.EqualTo(Enumerable.Repeat(1, count)));
Expand All @@ -120,7 +122,8 @@ public void TestRankGroupedItems()
var sequence = Enumerable.Range(0, count)
.Concat(Enumerable.Range(0, count))
.Concat(Enumerable.Range(0, count));
var result = sequence.AsTestingSequence().Rank();

var result = sequence.UsingTestingSequence(ts => ts.Rank());

Assert.That(result.Distinct().Count(), Is.EqualTo(count));
Assert.That(result, Is.EqualTo(sequence.Reverse().Select(x => x + 1)));
Expand All @@ -132,11 +135,8 @@ public void TestRankGroupedItems()
[Test]
public void TestRankOfHighestItemIsOne()
{
const int count = 10;
var sequence = Enumerable.Range(1, count);
var result = sequence.AsTestingSequence().Rank();

Assert.That(result.OrderBy(x => x).First(), Is.EqualTo(1));
using var ts = Enumerable.Range(1, 10).AsTestingSequence();
Assert.That(ts.Rank().OrderBy(x => x).First(), Is.EqualTo(1));
}

/// <summary>
Expand All @@ -156,7 +156,8 @@ public void TestRankByKeySelector()
new { Name = "Jim", Age = 74, ExpectedRank = 1 },
new { Name = "Jes", Age = 11, ExpectedRank = 8 },
};
var result = sequence.AsTestingSequence().RankBy(x => x.Age).ToArray();
var result = sequence.UsingTestingSequence(ts =>
ts.RankBy(x => x.Age));

Assert.That(result.Length, Is.EqualTo(sequence.Length));
Assert.That(result, Is.EqualTo(sequence.Select(x => x.ExpectedRank)));
Expand All @@ -172,8 +173,8 @@ public void TestRankCustomComparer()
var ordinals = Enumerable.Range(1, count);
var sequence = ordinals.Select( x => new DateTime(2010,x,20-x) );
// invert the CompareTo operation to Rank in reverse order (ascending to descending)
var resultA = sequence.AsTestingSequence().Rank(Comparer.Create<DateTime>((a, b) => -a.CompareTo(b)));
var resultB = sequence.AsTestingSequence().RankBy(x => x.Day, Comparer.Create<int>((a, b) => -a.CompareTo(b)));
var resultA = sequence.UsingTestingSequence(ts => ts.Rank(Comparer.Create<DateTime>((a, b) => -a.CompareTo(b))));
var resultB = sequence.UsingTestingSequence(ts => ts.RankBy(x => x.Day, Comparer.Create<int>((a, b) => -a.CompareTo(b))));

Assert.That(resultA, Is.EqualTo(ordinals));
Assert.That(resultB, Is.EqualTo(ordinals.Reverse()));
Expand Down
19 changes: 19 additions & 0 deletions MoreLinq.Test/TestingSequence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,25 @@ internal static TestingSequence<T> AsTestingSequence<T>(this IEnumerable<T> sour
source != null
? new TestingSequence<T>(source)
: throw new ArgumentNullException(nameof(source));

public static TResult[] Use<T, TResult>(this TestingSequence<T> source,
Func<TestingSequence<T>, IEnumerable<TResult>> user)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (user == null) throw new ArgumentNullException(nameof(user));

return user(source).ToArray();
}

public static TResult[] UsingTestingSequence<T, TResult>(this IEnumerable<T> source,
Func<TestingSequence<T>, IEnumerable<TResult>> user)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (source is TestingSequence<T>) throw new ArgumentException("Source is already a testing sequence instance.");
if (user == null) throw new ArgumentNullException(nameof(user));

return source.AsTestingSequence().Use(user);
}
}

/// <summary>
Expand Down