Skip to content

Commit

Permalink
+ GroupBy, some fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
akarnokd committed Oct 25, 2018
1 parent 85615e1 commit c0a382c
Show file tree
Hide file tree
Showing 11 changed files with 646 additions and 4 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ finally
- `Filter` - prevent items from passing through which don't pass a predicate
- `First` - signals the first item of the async sequence
- `FlatMap` - map the source items into `IAsyncEnumerable`s and merge their values into a single async sequence
- `GroupBy` - groups the source elements into distinct async groups
- `IgnoreElements` - ignores items and ends when the source async sequence ends
- `Last` - signals the last item of the async sequence
- `Map` - transform one source value into some other value
Expand All @@ -85,6 +86,7 @@ finally
- `TakeUntil` - take items from the main source until a secondary async sequence signals an item or completes
- `TakeWhile` - take items while predicate is true and stop when it turns false
- `Timeout` - signal an error if the next item doesn't arrive within the specified time
- `ToList` - collects all items into a List and signals it as the single result of the async sequence

## End-consumers

Expand Down
122 changes: 122 additions & 0 deletions async-enumerable-dotnet-test/GroupByTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
using System;
using Xunit;
using async_enumerable_dotnet;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;

namespace async_enumerable_dotnet_test
{
public class GroupByTest
{
[Fact]
public async void Normal_Same_Group()
{
await AsyncEnumerable.Range(1, 10)
.GroupBy(k => 1)
.FlatMap(v => v.ToList())
.AssertResult(
ListOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
);
}

[Fact]
public async void Normal_Distinct_Group()
{
await AsyncEnumerable.Range(1, 10)
.GroupBy(k => k)
.FlatMap(v => v.ToList())
.AssertResultSet(
ListComparer<int>.Default,
ListOf(1),
ListOf(2),
ListOf(3),
ListOf(4),
ListOf(5),
ListOf(6),
ListOf(7),
ListOf(8),
ListOf(9),
ListOf(10)
);
}

[Fact]
public async void Normal_Mixed()
{
var disposed = 0;

await AsyncEnumerable.Range(1, 10)
.DoOnDispose(() => disposed++)
.GroupBy(k => k % 2)
.FlatMap(v => v.ToList())
.AssertResultSet(
ListComparer<int>.Default,
ListOf(1, 3, 5, 7, 9),
ListOf(2, 4, 6, 8, 10)
);

Assert.Equal(1, disposed);
}

[Fact]
public async void Normal_Ordered()
{
await AsyncEnumerable.Range(1, 10)
.GroupBy(k => k < 6)
.FlatMap(v => v.ToList())
.AssertResultSet(
ListComparer<int>.Default,
ListOf(1, 2, 3, 4, 5),
ListOf(6, 7, 8, 9, 10)
);
}

[Fact]
public async void Take_2_Groups()
{
await AsyncEnumerable.Range(1, 10)
.GroupBy(k => k % 3)
.Take(2)
.FlatMap(v => v.ToList())
.AssertResultSet(
ListComparer<int>.Default,
ListOf(1, 4, 7, 10),
ListOf(2, 5, 8)
);
}

[Fact]
public async void Take_1_Of_Each_Group()
{
await AsyncEnumerable.Range(1, 10)
.GroupBy(k => k)
.FlatMap(v => v.Take(1))
.AssertResultSet(
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
);
}

[Fact]
public async void Take_1_Of_Each_Group_Two_Groups_Total()
{
var disposed = 0;

await AsyncEnumerable.Range(1, 10)
.DoOnDispose(() => disposed++)
.GroupBy(k => k)
.Take(2)
.FlatMap(v => v.Take(1))
.AssertResultSet(
1, 2
);

Assert.Equal(1, disposed);
}

static List<int> ListOf(params int[] values)
{
return new List<int>(values);
}
}
}
32 changes: 32 additions & 0 deletions async-enumerable-dotnet-test/ListComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace async_enumerable_dotnet_test
{
internal sealed class ListComparer<T> : IEqualityComparer<IList<T>>
{
internal static readonly ListComparer<T> Default = new ListComparer<T>();

public bool Equals(IList<T> x, IList<T> y)
{
return x.SequenceEqual(y);
}

public int GetHashCode(IList<T> obj)
{
var hash = 19;

unchecked
{
foreach (var t in obj)
{
hash = hash * 31 + (t != null ? t.GetHashCode() : 0);
}
}

return hash;
}
}
}
35 changes: 32 additions & 3 deletions async-enumerable-dotnet-test/TestHelper.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using async_enumerable_dotnet;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
Expand Down Expand Up @@ -35,15 +36,22 @@ public static async ValueTask AssertResult<T>(this IAsyncEnumerator<T> source, p
}
}

public static async ValueTask AssertResultSet<T>(this IAsyncEnumerable<T> source, params T[] values)
public static ValueTask AssertResultSet<T>(this IAsyncEnumerable<T> source, params T[] values)
{
var set = new HashSet<T>(values);
return AssertResultSet(source, EqualityComparer<T>.Default, values);
}

public static async ValueTask AssertResultSet<T>(this IAsyncEnumerable<T> source, IEqualityComparer<T> comparer, params T[] values)
{
var set = new HashSet<T>(values, comparer);
var en = source.GetAsyncEnumerator();
try
{
while (await en.MoveNextAsync())
{
Assert.True(set.Remove(en.Current));
var c = en.Current;
Assert.Contains(c, set);
Assert.True(set.Remove(c), "Unexpected item: " + AsString(c));
}

Assert.Empty(set);
Expand All @@ -54,6 +62,27 @@ public static async ValueTask AssertResultSet<T>(this IAsyncEnumerable<T> source
}
}

static string AsString(object obj)
{
if (obj is IEnumerable en)
{
var sb = new StringBuilder("[");
var i = 0;
foreach (var o in en)
{
if (i != 0)
{
sb.Append(", ");
}
sb.Append(o);
i++;
}
sb.Append("]");
return sb.ToString();
}
return obj != null ? obj.ToString() : "null";
}

public static ValueTask AssertFailure<T>(this IAsyncEnumerable<T> source, Type exception, params T[] values)
{
return AssertFailure(source.GetAsyncEnumerator(), exception, values);
Expand Down
40 changes: 40 additions & 0 deletions async-enumerable-dotnet-test/TestHelperTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using Xunit;
using async_enumerable_dotnet;
using System.Threading.Tasks;
using System.Collections.Generic;
using static async_enumerable_dotnet_test.GroupByTest;

namespace async_enumerable_dotnet_test
{
public class TestHelperTest
{
[Fact]
public async void AssertResultSet()
{
await AsyncEnumerable.Range(1, 3)
.AssertResultSet(1, 2, 3);
}

[Fact]
public async void AssertResultSet_List()
{
await AsyncEnumerable.FromArray(new List<int>(new [] { 1, 2, 3 }))
.AssertResultSet(
ListComparer<int>.Default,
new List<int>(new[] { 1, 2, 3 }));
}

[Fact]
public void HashSet_Contains()
{
var set = new HashSet<IList<int>>(ListComparer<int>.Default);

set.Add(new List<int>(new[] { 1, 2, 3 }));

Assert.Contains(new List<int>(new[] { 1, 2, 3 }), set);

Assert.True(set.Remove(new List<int>(new[] { 1, 2, 3 })));
}
}
}
35 changes: 35 additions & 0 deletions async-enumerable-dotnet-test/ToListTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using Xunit;
using async_enumerable_dotnet;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace async_enumerable_dotnet_test
{
public class ToListTest
{
[Fact]
public async void Normal()
{
await AsyncEnumerable.Range(1, 5)
.ToList()
.AssertResult(new List<int>(new[] { 1, 2, 3, 4, 5 }));
}

[Fact]
public async void Empty()
{
await AsyncEnumerable.Empty<int>()
.ToList()
.AssertResult(new List<int>());
}

[Fact]
public async void Error()
{
await AsyncEnumerable.Error<int>(new InvalidOperationException())
.ToList()
.AssertFailure(typeof(InvalidOperationException));
}
}
}
Loading

0 comments on commit c0a382c

Please sign in to comment.