Skip to content

Commit

Permalink
Fix buffered Window bugs (#586)
Browse files Browse the repository at this point in the history
* Update `Window` tests to cover bug
* Update `WindowLeft` tests to cover bug
* Update `WindowRight` tests to cover bug
* Fix bug in buffered `Window` implementations
  • Loading branch information
viceroypenguin authored Nov 24, 2023
1 parent f75040c commit 7126989
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 279 deletions.
6 changes: 3 additions & 3 deletions Source/SuperLinq/Window.Buffered.Impl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ private static IEnumerable<TResult> WindowImpl<TSource, TResult>(
}
else
{
array.AsSpan()[1..].CopyTo(array);
array[^1] = i;
array.AsSpan()[1..n].CopyTo(array);
array[n - 1] = i;

yield return projector(new ArraySegment<TSource>(array));
yield return projector(new ArraySegment<TSource>(array, 0, n));
}
}

Expand Down
72 changes: 0 additions & 72 deletions Tests/SuperLinq.Test/WindowBufferedTest.cs

This file was deleted.

74 changes: 0 additions & 74 deletions Tests/SuperLinq.Test/WindowLeftBufferedTest.cs

This file was deleted.

72 changes: 55 additions & 17 deletions Tests/SuperLinq.Test/WindowLeftTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,28 @@ public partial class WindowLeftTest
public void WindowLeftIsLazy()
{
_ = new BreakingSequence<int>().WindowLeft(1);
_ = new BreakingSequence<int>().WindowLeft(1, BreakingFunc.Of<IReadOnlyList<int>, int>());
_ = new BreakingSequence<int>().WindowLeft(new int[3], BreakingFunc.Of<IReadOnlyList<int>, int>());
_ = new BreakingSequence<int>().WindowLeft(new int[3], 1, BreakingFunc.Of<IReadOnlyList<int>, int>());
}

[Fact]
public void WindowLeftNegativeWindowSizeException()
{
var sequence = Enumerable.Repeat(1, 10);
_ = Assert.Throws<ArgumentOutOfRangeException>(() =>
new BreakingSequence<int>().WindowLeft(-5));

_ = Assert.Throws<ArgumentOutOfRangeException>(() =>
new BreakingSequence<int>().WindowLeft(-5, SuperEnumerable.Identity));

_ = Assert.Throws<ArgumentOutOfRangeException>(() =>
new BreakingSequence<int>().WindowLeft([], -5, SuperEnumerable.Identity));

_ = Assert.Throws<ArgumentOutOfRangeException>(() =>
sequence.WindowLeft(-5));
new BreakingSequence<int>().WindowLeft(new int[5], 6, SuperEnumerable.Identity));

_ = new BreakingSequence<int>()
.WindowLeft(new int[5], 5, SuperEnumerable.Identity);
}

public static IEnumerable<object[]> GetThreeElementSequences() =>
Expand Down Expand Up @@ -76,47 +89,72 @@ public void WindowModifiedDoesNotAffectPreviousWindow(IDisposableEnumerable<int>
}
}

public enum WindowMethod
{
Traditional,
BufferSize,
BufferArray,
BufferSizeArray,
}

private static IEnumerable<object[]> GetWindowTestSequences(IEnumerable<int> source)
{
foreach (var seq in source.GetListSequences())
yield return new object[] { seq, WindowMethod.Traditional, };
yield return new object[] { source.AsTestingSequence(maxEnumerations: 2), WindowMethod.BufferSize, };
yield return new object[] { source.AsTestingSequence(maxEnumerations: 2), WindowMethod.BufferArray, };
yield return new object[] { source.AsTestingSequence(maxEnumerations: 2), WindowMethod.BufferSizeArray, };
}

private static IEnumerable<IList<T>> GetWindows<T>(
IEnumerable<T> seq,
WindowMethod method,
int size) =>
method switch
{
WindowMethod.Traditional => seq.WindowLeft(size),
WindowMethod.BufferSize => seq.WindowLeft(size, arr => arr.ToList()),
WindowMethod.BufferArray => seq.WindowLeft(new T[size], arr => arr.ToList()),
WindowMethod.BufferSizeArray => seq.WindowLeft(new T[size + 10], size, arr => arr.ToList()),
_ => throw new NotSupportedException(),
};

public static IEnumerable<object[]> GetEmptySequences() =>
Enumerable.Empty<int>()
.GetListSequences()
.Select(x => new object[] { x });
GetWindowTestSequences(Enumerable.Empty<int>());

[Theory]
[MemberData(nameof(GetEmptySequences))]
public void WindowLeftEmptySequence(IDisposableEnumerable<int> seq)
public void WindowLeftEmptySequence(IDisposableEnumerable<int> seq, WindowMethod wm)
{
using (seq)
{
var result = seq.WindowLeft(5);
var result = GetWindows(seq, wm, 5);
result.AssertSequenceEqual();
}
}

public static IEnumerable<object[]> GetHundredElementSequences() =>
Enumerable.Range(0, 100)
.GetListSequences()
.Select(x => new object[] { x });
GetWindowTestSequences(Enumerable.Range(0, 100));

[Theory]
[MemberData(nameof(GetHundredElementSequences))]
public void WindowLeftOfSingleElement(IDisposableEnumerable<int> seq)
public void WindowLeftOfSingleElement(IDisposableEnumerable<int> seq, WindowMethod wm)
{
using (seq)
{
var result = seq.WindowLeft(1);

var result = GetWindows(seq, wm, 1);
foreach (var (actual, expected) in result.Zip(Enumerable.Range(0, 100)))
Assert.Equal(SuperEnumerable.Return(expected), actual);
}
}

[Theory]
[MemberData(nameof(GetHundredElementSequences))]
public void WindowLeftWithWindowSizeLargerThanSequence(IDisposableEnumerable<int> seq)
public void WindowLeftWithWindowSizeSmallerThanSequence(IDisposableEnumerable<int> seq, WindowMethod wm)
{
using (seq)
{
var result = seq.WindowLeft(10);
var result = GetWindows(seq, wm, 10);
result.AssertSequenceEqual(
Enumerable.Range(0, 100)
.Select(i => Enumerable.Range(i, Math.Min(10, 100 - i))));
Expand All @@ -125,11 +163,11 @@ public void WindowLeftWithWindowSizeLargerThanSequence(IDisposableEnumerable<int

[Theory]
[MemberData(nameof(GetHundredElementSequences))]
public void WindowLeftWithWindowSizeSmallerThanSequence(IDisposableEnumerable<int> seq)
public void WindowLeftWithWindowSizeLargerThanSequence(IDisposableEnumerable<int> seq, WindowMethod wm)
{
using (seq)
{
var result = seq.WindowLeft(110);
var result = GetWindows(seq, wm, 110);
result.AssertSequenceEqual(
Enumerable.Range(0, 100)
.Select(i => Enumerable.Range(i, 100 - i)));
Expand Down
74 changes: 0 additions & 74 deletions Tests/SuperLinq.Test/WindowRightBufferedTest.cs

This file was deleted.

Loading

0 comments on commit 7126989

Please sign in to comment.