├── .gitattributes
├── .github
├── dependabot.yml
└── workflows
│ └── dotnet.yml
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── async-enumerable-dotnet-benchmark
├── Program.cs
└── async-enumerable-dotnet-benchmark.csproj
├── async-enumerable-dotnet-test
├── AllTest.cs
├── AmbTest.cs
├── AnyTest.cs
├── ArrayQueueTest.cs
├── AsyncEnumerableTest.cs
├── BufferBoundaryTest.cs
├── BufferTest.cs
├── CancellationHelperTest.cs
├── CollectTest.cs
├── CombineLatestTest.cs
├── ConcatMapEagerTest.cs
├── ConcatMapTest.cs
├── ConcatTest.cs
├── ConsumeTest.cs
├── CountTest.cs
├── CreateTest.cs
├── DebounceTest.cs
├── DefaultIfEmptyTest.cs
├── DeferTest.cs
├── DistinctTest.cs
├── DistinctUntilChangedTest.cs
├── DoOnDisposeTest.cs
├── DoOnNextTest.cs
├── ElementAtTest.cs
├── EmptyTest.cs
├── ErrorTest.cs
├── ExceptionHelperTest.cs
├── FilterTest.cs
├── FirstLastSingleAsyncTest.cs
├── FirstLastSingleTest.cs
├── FlatMapTest.cs
├── ForEachTest.cs
├── FromEnumerableTest.cs
├── FromObservableTest.cs
├── FromTaskFuncTest.cs
├── GroupByTest.cs
├── IgnoreElementsTest.cs
├── IntervalTest.cs
├── IsEmptyTest.cs
├── JustTest.cs
├── LatestTest.cs
├── LicenseHeader.cs
├── ListComparer.cs
├── MapTest.cs
├── MergeTest.cs
├── MergeWithTest.cs
├── MulticastAsyncEnumerableTest.cs
├── NeverTest.cs
├── OnErrorResumeNextTest.cs
├── PrefetchTest.cs
├── PublishTest.cs
├── QueueDrainHelperTest.cs
├── RangeTest.cs
├── ReduceTest.cs
├── RepeatTest.cs
├── ReplayAsyncEnumerableTest.cs
├── ReplayTest.cs
├── ResumeHelperTest.cs
├── RetryTest.cs
├── SampleTest.cs
├── ScanTest.cs
├── SkipLastTest.cs
├── SkipTest.cs
├── SkipUntilTest.cs
├── SkipWhileTest.cs
├── SlimResumeTest.cs
├── SwitchIfEmptyTest.cs
├── SwitchMapTest.cs
├── TakeLastTest.cs
├── TakeTest.cs
├── TakeUntilTest.cs
├── TakeWhileTest.cs
├── TestHelper.cs
├── TestHelperTest.cs
├── TestTaskRunnerTest.cs
├── TimeoutTest.cs
├── TimerTest.cs
├── ToCollectionTest.cs
├── ToEnumerableTest.cs
├── ToListTest.cs
├── ToObservableTest.cs
├── UnicastAsyncEnumerableTest.cs
├── UnitTest1.cs
├── UsingTest.cs
├── WithLatestFromTest.cs
├── ZipTest.cs
└── async-enumerable-dotnet-test.csproj
├── async-enumerable-dotnet.sln
└── async-enumerable-dotnet
├── AsyncEnumerable.cs
├── IAsyncEmitter.cs
├── IAsyncGroupedEnumerable.cs
├── MulticastAsyncEnumerable.cs
├── ReplayAsyncEnumerable.cs
├── TestTaskRunner.cs
├── UnicastAsyncEnumerable.cs
├── async-enumerable-dotnet.csproj
└── impl
├── All.cs
├── Amb.cs
├── Any.cs
├── ArrayQueue.cs
├── Buffer.cs
├── BufferBoundary.cs
├── CancellationHelper.cs
├── Collect.cs
├── CombineLatest.cs
├── Concat.cs
├── ConcatMap.cs
├── ConcatMapEager.cs
├── Count.cs
├── CreateEmitter.cs
├── Debounce.cs
├── DefaultIfEmpty.cs
├── Defer.cs
├── Distinct.cs
├── DistinctUntilChanged.cs
├── DoOnDispose.cs
├── DoOnNext.cs
├── ElementAt.cs
├── Empty.cs
├── EmptyHelper.cs
├── Error.cs
├── ExceptionHelper.cs
├── Filter.cs
├── FirstLastSingle.cs
├── FirstLastSingleAsync.cs
├── FlatMap.cs
├── ForEach.cs
├── FromArray.cs
├── FromEnumerable.cs
├── FromObservable.cs
├── FromTaskFunc.cs
├── GroupBy.cs
├── IgnoreElements.cs
├── Interval.cs
├── IsEmpty.cs
├── Just.cs
├── Latest.cs
├── Map.cs
├── Merge.cs
├── Multicast.cs
├── Never.cs
├── OnErrorResumeNext.cs
├── Prefetch.cs
├── Publish.cs
├── QueueDrainHelper.cs
├── Range.cs
├── Reduce.cs
├── Repeat.cs
├── Replay.cs
├── ResumeHelper.cs
├── Retry.cs
├── Sample.cs
├── Scan.cs
├── Skip.cs
├── SkipLast.cs
├── SkipUntil.cs
├── SkipWhile.cs
├── SlimResume.cs
├── SwitchIfEmpty.cs
├── SwitchMap.cs
├── Take.cs
├── TakeLast.cs
├── TakeUntil.cs
├── TakeWhile.cs
├── Timeout.cs
├── Timer.cs
├── ToCollection.cs
├── ToEnumerable.cs
├── ToObservable.cs
├── Using.cs
├── WithLatestFrom.cs
└── Zip.cs
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: nuget
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | time: "04:00"
8 | open-pull-requests-limit: 20
9 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet.yml:
--------------------------------------------------------------------------------
1 | name: .NET
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 | - name: Setup .NET
17 | uses: actions/setup-dotnet@v1
18 | with:
19 | dotnet-version: 3.1.x
20 | - name: Restore dependencies
21 | run: dotnet restore
22 | - name: Build
23 | run: dotnet build --no-restore
24 | - name: Test
25 | run: dotnet test --no-build --verbosity normal
26 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: csharp
2 | dotnet: 3.0.100
3 | mono: none
4 | # running in container causes test failures and 2x-3x longer build, use standalone instances
5 | sudo: required
6 |
7 | script:
8 | - dotnet test ./async-enumerable-dotnet-test/async-enumerable-dotnet-test.csproj -v m
--------------------------------------------------------------------------------
/async-enumerable-dotnet-benchmark/Program.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using async_enumerable_dotnet;
6 | using System;
7 | using System.Collections.Generic;
8 |
9 | namespace async_enumerable_dotnet_benchmark
10 | {
11 | // ReSharper disable once ClassNeverInstantiated.Global
12 | // ReSharper disable once ArrangeTypeModifiers
13 | class Program
14 | {
15 | ///
16 | /// Don't worry about this program yet. I'm using it to
17 | /// diagnose await hangs and internal state that is otherwise
18 | /// hard (or I don't know how) to debug as an XUnit test.
19 | ///
20 | ///
21 | // ReSharper disable once UnusedParameter.Local
22 | // ReSharper disable once ArrangeTypeMemberModifiers
23 | static void Main(string[] args)
24 | {
25 | for (var j = 0; j < 100000; j++)
26 | {
27 | if (j % 10 == 0)
28 | {
29 | Console.WriteLine(j);
30 | }
31 | var list = TimeSequence(0, 200, 400, 600)
32 | .ConcatMapEager(v => AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(100)))
33 | .Take(1)
34 | .GetAsyncEnumerator(default);
35 |
36 | try
37 | {
38 | if (!list.MoveNextAsync().Result)
39 | {
40 | Console.WriteLine("Empty?");
41 | }
42 |
43 | if (list.Current != 0)
44 | {
45 | Console.WriteLine(list.Current);
46 | Console.ReadLine();
47 | break;
48 | }
49 | }
50 | finally
51 | {
52 | list.DisposeAsync().AsTask().Wait();
53 | }
54 | }
55 | }
56 |
57 | private static IAsyncEnumerable TimeSequence(params long[] timestamps)
58 | {
59 | return AsyncEnumerable.FromArray(timestamps)
60 | .FlatMap(v => AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(v)).Map(w => v));
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-benchmark/async-enumerable-dotnet-benchmark.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.0
6 | async_enumerable_dotnet_benchmark
7 | latest
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ArrayQueueTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet.impl;
7 |
8 | namespace async_enumerable_dotnet_test
9 | {
10 | public class ArrayQueueTest
11 | {
12 | [Fact]
13 | public void Normal()
14 | {
15 | for (var k = 2; k <= 128; k *= 2)
16 | {
17 | for (var j = 1; j < k * 4; j++) {
18 | var q = new ArrayQueue(k);
19 |
20 | for (var i = 0; i < j; i++)
21 | {
22 | q.Enqueue(i);
23 | Assert.True(q.Dequeue(out var v));
24 | Assert.Equal(i, v);
25 | }
26 |
27 | Assert.False(q.Dequeue(out _));
28 | }
29 | }
30 | }
31 |
32 | [Fact]
33 | public void Grow()
34 | {
35 | for (var k = 2; k <= 128; k *= 2)
36 | {
37 | for (var j = 1; j < k * 4; j++)
38 | {
39 | var q = new ArrayQueue(k);
40 |
41 | for (var i = 0; i < j; i++)
42 | {
43 | q.Enqueue(i);
44 | }
45 |
46 | for (var i = 0; i < j; i++)
47 | {
48 | Assert.True(q.Dequeue(out var v));
49 | Assert.Equal(i, v);
50 | }
51 |
52 | Assert.False(q.Dequeue(out _));
53 | }
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/CancellationHelperTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System.Threading;
6 | using Xunit;
7 | using async_enumerable_dotnet.impl;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class CancellationHelperTest
12 | {
13 | private CancellationTokenSource _cts;
14 |
15 | [Fact]
16 | public void Cancel()
17 | {
18 | Assert.True(CancellationHelper.Cancel(ref _cts));
19 |
20 | Assert.Same(_cts, CancellationHelper.Cancelled);
21 |
22 | Assert.False(CancellationHelper.Cancel(ref _cts));
23 | }
24 |
25 | [Fact]
26 | public void Replace_After_Cancel()
27 | {
28 | Assert.True(CancellationHelper.Cancel(ref _cts));
29 |
30 | var cts = new CancellationTokenSource();
31 |
32 | Assert.False(CancellationHelper.Replace(ref _cts, cts));
33 |
34 | Assert.True(cts.IsCancellationRequested);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/CollectTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Collections.Generic;
9 | using System.Threading.Tasks;
10 |
11 | namespace async_enumerable_dotnet_test
12 | {
13 | public class CollectTest
14 | {
15 | [Fact]
16 | public async Task Normal()
17 | {
18 | await AsyncEnumerable.Range(1, 5)
19 | .Collect(() => new List(), (a, b) => a.Add(b))
20 | .AssertResult(new List(new[] { 1, 2, 3, 4, 5 }));
21 | }
22 |
23 | [Fact]
24 | public async Task Empty()
25 | {
26 | await AsyncEnumerable.Empty()
27 | .Collect(() => new List(), (a, b) => a.Add(b))
28 | .AssertResult(new List());
29 | }
30 |
31 | [Fact]
32 | public async Task Initial_Crash()
33 | {
34 | await AsyncEnumerable.Empty()
35 | .Collect>(() => throw new InvalidOperationException(), (a, b) => a.Add(b))
36 | .AssertFailure(typeof(InvalidOperationException));
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/CombineLatestTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Linq;
8 | using System;
9 | using System.Threading.Tasks;
10 |
11 | namespace async_enumerable_dotnet_test
12 | {
13 | public class CombineLatestTest
14 | {
15 | [Fact]
16 | public async Task Empty()
17 | {
18 | await AsyncEnumerable.CombineLatest(v => v.Sum())
19 | .AssertResult();
20 | }
21 |
22 | [Fact]
23 | public async Task Single()
24 | {
25 | await AsyncEnumerable.CombineLatest(v => v.Sum() + 1,
26 | AsyncEnumerable.Just(1))
27 | .AssertResult(2);
28 | }
29 |
30 | [Fact]
31 | public async Task One_Item_Each()
32 | {
33 | await AsyncEnumerable.CombineLatest(v => v.Sum(), AsyncEnumerable.Just(1), AsyncEnumerable.Just(2))
34 | .AssertResult(3);
35 | }
36 |
37 | [Fact]
38 | public async Task One_Is_Empty()
39 | {
40 | await AsyncEnumerable.CombineLatest(v => v.Sum(), AsyncEnumerable.Empty(), AsyncEnumerable.Just(2))
41 | .AssertResult();
42 | }
43 |
44 | [Fact]
45 | public async Task Two_Is_Empty()
46 | {
47 | await AsyncEnumerable.CombineLatest(v => v.Sum(), AsyncEnumerable.Just(1), AsyncEnumerable.Empty())
48 | .AssertResult();
49 | }
50 |
51 | [Fact]
52 | public async Task ZigZag()
53 | {
54 | var t = 200;
55 | if (Environment.GetEnvironmentVariable("CI") != null)
56 | {
57 | t = 2000;
58 | }
59 | await AsyncEnumerable.CombineLatest(v => v.Sum(),
60 | AsyncEnumerable.Interval(1, 5, TimeSpan.FromMilliseconds(t)),
61 | AsyncEnumerable.Interval(1, 5, TimeSpan.FromMilliseconds(t + t / 2), TimeSpan.FromMilliseconds(t)).Map(v => v * 10)
62 | )
63 | .AssertResult(11, 12, 22, 23, 33, 34, 44, 45, 55);
64 | }
65 |
66 | [Fact]
67 | public async Task Second_Many()
68 | {
69 | var t = 200;
70 | if (Environment.GetEnvironmentVariable("CI") != null)
71 | {
72 | t = 2000;
73 | }
74 | await AsyncEnumerable.CombineLatest(v => v.Sum(),
75 | AsyncEnumerable.Just(10L),
76 | AsyncEnumerable.Interval(1, 5, TimeSpan.FromMilliseconds(t + t / 2), TimeSpan.FromMilliseconds(t))
77 | )
78 | .AssertResult(11, 12, 13, 14, 15);
79 | }
80 |
81 | [Fact]
82 | public async Task Error()
83 | {
84 | await AsyncEnumerable.CombineLatest(v => v.Sum(),
85 | AsyncEnumerable.Just(1),
86 | AsyncEnumerable.Just(2).ConcatWith(
87 | AsyncEnumerable.Error(new InvalidOperationException())
88 | )
89 | )
90 | .AssertFailure(typeof(InvalidOperationException), 3);
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ConcatMapTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class ConcatMapTest
13 | {
14 | [Fact]
15 | public async Task Async_Normal()
16 | {
17 | await AsyncEnumerable.Range(1, 5)
18 | .ConcatMap(v => AsyncEnumerable.Range(v * 10, 5))
19 | .AssertResult(
20 | 10, 11, 12, 13, 14,
21 | 20, 21, 22, 23, 24,
22 | 30, 31, 32, 33, 34,
23 | 40, 41, 42, 43, 44,
24 | 50, 51, 52, 53, 54
25 | );
26 | }
27 |
28 | [Fact]
29 | public async Task Async_Filter()
30 | {
31 | await AsyncEnumerable.Range(1, 10)
32 | .ConcatMap(v => v % 2 == 0 ? AsyncEnumerable.Just(v) : AsyncEnumerable.Empty())
33 | .AssertResult(
34 | 2, 4, 6, 8, 10
35 | );
36 | }
37 |
38 | [Fact]
39 | public async Task Async_Take()
40 | {
41 | await AsyncEnumerable.Range(1, 5)
42 | .ConcatMap(v => AsyncEnumerable.Range(v * 10, 5))
43 | .Take(7)
44 | .AssertResult(
45 | 10, 11, 12, 13, 14,
46 | 20, 21
47 | );
48 | }
49 |
50 | [Fact]
51 | public async Task Enumerable_Normal()
52 | {
53 | await AsyncEnumerable.Range(1, 5)
54 | .ConcatMap(v => Enumerable.Range(v * 10, 5))
55 | .AssertResult(
56 | 10, 11, 12, 13, 14,
57 | 20, 21, 22, 23, 24,
58 | 30, 31, 32, 33, 34,
59 | 40, 41, 42, 43, 44,
60 | 50, 51, 52, 53, 54
61 | );
62 | }
63 |
64 | [Fact]
65 | public async Task Enumerable_Filter()
66 | {
67 | await AsyncEnumerable.Range(1, 10)
68 | .ConcatMap(v => v % 2 == 0 ? new[] { v } : Enumerable.Empty())
69 | .AssertResult(
70 | 2, 4, 6, 8, 10
71 | );
72 | }
73 |
74 | [Fact]
75 | public async Task Enumerable_Take()
76 | {
77 | await AsyncEnumerable.Range(1, 5)
78 | .ConcatMap(v => Enumerable.Range(v * 10, 5))
79 | .Take(7)
80 | .AssertResult(
81 | 10, 11, 12, 13, 14,
82 | 20, 21
83 | );
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ConcatTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System.Collections.Generic;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class ConcatTest
13 | {
14 | [Fact]
15 | public async Task Array_Normal()
16 | {
17 | await AsyncEnumerable.Concat(
18 | AsyncEnumerable.Range(1, 3),
19 | AsyncEnumerable.Empty(),
20 | AsyncEnumerable.FromArray(4, 5, 6, 7),
21 | AsyncEnumerable.Empty(),
22 | AsyncEnumerable.Just(8),
23 | AsyncEnumerable.FromEnumerable(new[] { 9, 10 }),
24 | AsyncEnumerable.Empty()
25 | )
26 | .AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
27 | }
28 |
29 | [Fact]
30 | public async Task Enumerable_Normal()
31 | {
32 | await AsyncEnumerable.Concat((IEnumerable>)new[] {
33 | AsyncEnumerable.Range(1, 3),
34 | AsyncEnumerable.Empty(),
35 | AsyncEnumerable.FromArray(4, 5, 6, 7),
36 | AsyncEnumerable.Empty(),
37 | AsyncEnumerable.Just(8),
38 | AsyncEnumerable.FromEnumerable(new[] { 9, 10 }),
39 | AsyncEnumerable.Empty()
40 | }
41 | )
42 | .AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
43 | }
44 |
45 | [Fact]
46 | public async Task ConcatWith_Normal()
47 | {
48 | await AsyncEnumerable.Range(1, 3)
49 | .ConcatWith(AsyncEnumerable.Range(4, 2))
50 | .AssertResult(1, 2, 3, 4, 5);
51 | }
52 |
53 | [Fact]
54 | public async Task ConcatWith_Take()
55 | {
56 | await AsyncEnumerable.Range(1, 5)
57 | .Take(3)
58 | .ConcatWith(AsyncEnumerable.Range(4, 2))
59 | .AssertResult(1, 2, 3, 4, 5);
60 | }
61 |
62 | [Fact]
63 | public async Task Async_Normal()
64 | {
65 | await
66 | AsyncEnumerable.FromArray(
67 | AsyncEnumerable.Range(1, 3),
68 | AsyncEnumerable.Empty(),
69 | AsyncEnumerable.FromArray(4, 5, 6, 7),
70 | AsyncEnumerable.Empty(),
71 | AsyncEnumerable.Just(8),
72 | AsyncEnumerable.FromEnumerable(new[] { 9, 10 }),
73 | AsyncEnumerable.Empty()
74 | )
75 | .Concat()
76 | .AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ConsumeTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using Xunit;
9 | using async_enumerable_dotnet;
10 |
11 | namespace async_enumerable_dotnet_test
12 | {
13 | public class ConsumeTest
14 | {
15 | [Fact]
16 | public async Task Normal()
17 | {
18 | var push = new MulticastAsyncEnumerable();
19 |
20 | var t1 = push.AssertResult(1, 2, 3, 4, 5);
21 | var t2 = push.AssertResult(1, 2, 3, 4, 5);
22 |
23 | await AsyncEnumerable.Range(1, 5)
24 | .Consume(push);
25 |
26 | await t1;
27 | await t2;
28 | }
29 |
30 | [Fact]
31 | public async Task Error()
32 | {
33 | var push = new MulticastAsyncEnumerable();
34 |
35 | var t1 = push.AssertFailure(typeof(InvalidOperationException));
36 | var t2 = push.AssertFailure(typeof(InvalidOperationException));
37 |
38 | await AsyncEnumerable.Error(new InvalidOperationException())
39 | .Consume(push);
40 |
41 | await t1;
42 | await t2;
43 | }
44 |
45 | [Fact]
46 | public async Task Cancel()
47 | {
48 | var cts = new CancellationTokenSource();
49 |
50 | var push = new UnicastAsyncEnumerable();
51 |
52 | var t = AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(500))
53 | .Consume(push, cts.Token);
54 |
55 | await Task.Delay(100, cts.Token);
56 |
57 | cts.Cancel();
58 |
59 | await t;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/CountTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class CountTest
13 | {
14 | [Fact]
15 | public async Task Empty()
16 | {
17 | await AsyncEnumerable.Empty()
18 | .Count()
19 | .AssertResult(0L);
20 | }
21 |
22 | [Fact]
23 | public async Task Just()
24 | {
25 | await AsyncEnumerable.Just(1)
26 | .Count()
27 | .AssertResult(1L);
28 | }
29 |
30 | [Fact]
31 | public async Task Range()
32 | {
33 | await AsyncEnumerable.Range(1, 100)
34 | .Count()
35 | .AssertResult(100L);
36 | }
37 |
38 |
39 | [Fact]
40 | public async Task Error()
41 | {
42 | await AsyncEnumerable.Range(1, 100).WithError(new InvalidOperationException())
43 | .Count()
44 | .AssertFailure(typeof(InvalidOperationException));
45 | }
46 |
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/CreateTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 | using System;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class CreateTest
13 | {
14 | [Fact]
15 | public async Task Empty()
16 | {
17 | var result = AsyncEnumerable.Create(async e =>
18 | {
19 | await Task.CompletedTask;
20 | });
21 |
22 | await result.AssertResult();
23 | }
24 |
25 | [Fact]
26 | public async Task Range()
27 | {
28 | var result = AsyncEnumerable.Create(async e =>
29 | {
30 | for (var i = 0; i < 10 && !e.DisposeAsyncRequested; i++)
31 | {
32 | await e.Next(i);
33 | }
34 | });
35 |
36 | await result.AssertResult(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
37 | }
38 |
39 | [Fact]
40 | public async Task Range_Loop()
41 | {
42 | for (var j = 0; j < 1000; j++)
43 | {
44 | var result = AsyncEnumerable.Create(async e =>
45 | {
46 | for (var i = 0; i < 10 && !e.DisposeAsyncRequested; i++)
47 | {
48 | await e.Next(i);
49 | }
50 | });
51 |
52 | await result.AssertResult(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
53 | }
54 | }
55 |
56 | [Fact]
57 | public async Task Items_And_Error()
58 | {
59 | var result = AsyncEnumerable.Create(async e =>
60 | {
61 | await e.Next(1);
62 |
63 | await e.Next(2);
64 |
65 | throw new InvalidOperationException();
66 | });
67 |
68 | await result.AssertFailure(typeof(InvalidOperationException), 1, 2);
69 | }
70 |
71 | [Fact]
72 | public async Task Take()
73 | {
74 | await AsyncEnumerable.Create(async e =>
75 | {
76 | for (var i = 0; i < 10 && !e.DisposeAsyncRequested; i++)
77 | {
78 | await e.Next(i);
79 | }
80 | })
81 | .Take(5)
82 | .AssertResult(0, 1, 2, 3, 4);
83 | }
84 |
85 | [Fact]
86 | public async Task Take_Loop()
87 | {
88 | for (var j = 0; j < 1000; j++)
89 | {
90 | await AsyncEnumerable.Create(async e =>
91 | {
92 | for (var i = 0; i < 10 && !e.DisposeAsyncRequested; i++)
93 | {
94 | await e.Next(i);
95 | }
96 | })
97 | .Take(5)
98 | .AssertResult(0, 1, 2, 3, 4);
99 | }
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/DefaultIfEmptyTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class DefaultIfEmptyTest
12 | {
13 | [Fact]
14 | public async Task NonEmpty()
15 | {
16 | await AsyncEnumerable.Range(1, 5)
17 | .DefaultIfEmpty(100)
18 | .AssertResult(1, 2, 3, 4, 5);
19 | }
20 |
21 | [Fact]
22 | public async Task Empty()
23 | {
24 | await AsyncEnumerable.Empty()
25 | .DefaultIfEmpty(100)
26 | .AssertResult(100);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/DeferTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class DeferTest
13 | {
14 | [Fact]
15 | public async Task Normal()
16 | {
17 | var count = 0;
18 | var result = AsyncEnumerable.Defer(() =>
19 | {
20 | count++;
21 | return AsyncEnumerable.FromArray(1, 2, 3, 4, 5);
22 | });
23 |
24 | Assert.Equal(0, count);
25 |
26 | await result.AssertResult(1, 2, 3, 4, 5);
27 |
28 | Assert.Equal(1, count);
29 |
30 | await result.AssertResult(1, 2, 3, 4, 5);
31 |
32 | Assert.Equal(2, count);
33 | }
34 |
35 | [Fact]
36 | public async Task Crash()
37 | {
38 | await AsyncEnumerable.Defer(() => throw new InvalidOperationException())
39 | .AssertFailure(typeof(InvalidOperationException));
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/DistinctTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Collections.Generic;
9 | using System.Threading.Tasks;
10 |
11 | namespace async_enumerable_dotnet_test
12 | {
13 | public class DistinctTest
14 | {
15 | [Fact]
16 | public async Task Empty()
17 | {
18 | await AsyncEnumerable.Empty()
19 | .Distinct()
20 | .AssertResult();
21 | }
22 |
23 | [Fact]
24 | public async Task Normal()
25 | {
26 | await AsyncEnumerable.Range(1, 5)
27 | .Distinct()
28 | .AssertResult(1, 2, 3, 4, 5);
29 | }
30 |
31 | [Fact]
32 | public async Task Redundant()
33 | {
34 | await AsyncEnumerable.FromArray(1, 2, 3, 2, 1, 4, 5, 1, 5)
35 | .Distinct()
36 | .AssertResult(1, 2, 3, 4, 5);
37 | }
38 |
39 | [Fact]
40 | public async Task KeySelector()
41 | {
42 | await AsyncEnumerable.Range(1, 5)
43 | .Distinct(v => v % 3)
44 | .AssertResult(1, 2, 3);
45 | }
46 |
47 | [Fact]
48 | public async Task EqualityComparer()
49 | {
50 | await AsyncEnumerable.Range(1, 5)
51 | .Distinct(EqualityComparer.Default)
52 | .AssertResult(1, 2, 3, 4, 5);
53 | }
54 |
55 | [Fact]
56 | public async Task KeySelector_EqualityComparer()
57 | {
58 | await AsyncEnumerable.Range(1, 5)
59 | .Distinct(v => v % 3, EqualityComparer.Default)
60 | .AssertResult(1, 2, 3);
61 | }
62 |
63 | [Fact]
64 | public async Task Custom_Set()
65 | {
66 | await AsyncEnumerable.Range(1, 5)
67 | .Distinct(v => v % 3, () => new HashSet())
68 | .AssertResult(1, 2, 3);
69 | }
70 |
71 | [Fact]
72 | public async Task Custom_Crash()
73 | {
74 | await AsyncEnumerable.Range(1, 5)
75 | .Distinct(v => v % 3, () => throw new InvalidOperationException())
76 | .AssertFailure(typeof(InvalidOperationException));
77 | }
78 |
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/DistinctUntilChangedTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Collections.Generic;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class DistinctUntilChangedTest
13 | {
14 | [Fact]
15 | public async Task Empty()
16 | {
17 | await AsyncEnumerable.Empty()
18 | .DistinctUntilChanged()
19 | .AssertResult();
20 | }
21 |
22 | [Fact]
23 | public async Task Just()
24 | {
25 | await AsyncEnumerable.Just(1)
26 | .DistinctUntilChanged()
27 | .AssertResult(1);
28 | }
29 |
30 | [Fact]
31 | public async Task Range()
32 | {
33 | await AsyncEnumerable.Range(1, 5)
34 | .DistinctUntilChanged()
35 | .AssertResult(1, 2, 3, 4, 5);
36 | }
37 |
38 | [Fact]
39 | public async Task Redundant()
40 | {
41 | await AsyncEnumerable.FromArray(1, 2, 3, 3, 2, 1, 1, 4, 5, 4, 4)
42 | .DistinctUntilChanged()
43 | .AssertResult(1, 2, 3, 2, 1, 4, 5, 4);
44 | }
45 |
46 | [Fact]
47 | public async Task Redundant_Comparer()
48 | {
49 | await AsyncEnumerable.FromArray(1, 2, 3, 3, 2, 1, 1, 4, 5, 4, 4)
50 | .DistinctUntilChanged(EqualityComparer.Default)
51 | .AssertResult(1, 2, 3, 2, 1, 4, 5, 4);
52 | }
53 |
54 | [Fact]
55 | public async Task KeySelector()
56 | {
57 | await AsyncEnumerable.Range(1, 10)
58 | .DistinctUntilChanged(k => k / 3)
59 | .AssertResult(1, 3, 6, 9);
60 | }
61 |
62 | [Fact]
63 | public async Task KeySelector_KeyComparer()
64 | {
65 | await AsyncEnumerable.Range(1, 10)
66 | .DistinctUntilChanged(k => k / 3, EqualityComparer.Default)
67 | .AssertResult(1, 3, 6, 9);
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/DoOnNextTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 | using System.Collections.Generic;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class DoOnNextTest
13 | {
14 | [Fact]
15 | public async Task Sync_Normal()
16 | {
17 | var list = new List();
18 | await AsyncEnumerable.Range(1, 5)
19 | .DoOnNext(v => list.Add(v))
20 | .AssertResult(1, 2, 3, 4, 5);
21 |
22 | Assert.Equal(new[] { 1, 2, 3, 4, 5 }, list);
23 | }
24 |
25 | [Fact]
26 | public async Task Async_Normal()
27 | {
28 | var list = new List();
29 | await AsyncEnumerable.Range(1, 5)
30 | .DoOnNext(async v =>
31 | {
32 | await Task.Delay(100);
33 | list.Add(v);
34 | })
35 | .AssertResult(1, 2, 3, 4, 5);
36 |
37 | Assert.Equal(new[] { 1, 2, 3, 4, 5 }, list);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ElementAtTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class ElementAtTest
13 | {
14 | [Fact]
15 | public async Task Normal()
16 | {
17 | await AsyncEnumerable.Range(1, 5)
18 | .ElementAt(2)
19 | .AssertResult(3);
20 | }
21 |
22 | [Fact]
23 | public async Task Normal_Default()
24 | {
25 | await AsyncEnumerable.Range(1, 5)
26 | .ElementAt(2, 100)
27 | .AssertResult(3);
28 | }
29 |
30 | [Fact]
31 | public async Task Missing()
32 | {
33 | await AsyncEnumerable.Range(1, 5)
34 | .ElementAt(10)
35 | .AssertFailure(typeof(IndexOutOfRangeException));
36 | }
37 |
38 | [Fact]
39 | public async Task Missing_Default()
40 | {
41 | await AsyncEnumerable.Range(1, 5)
42 | .ElementAt(10, 100)
43 | .AssertResult(100);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/EmptyTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class EmptyTest
12 | {
13 | [Fact]
14 | public async Task Normal()
15 | {
16 | await AsyncEnumerable.Empty()
17 | .AssertResult();
18 | }
19 |
20 | [Fact]
21 | public void Current()
22 | {
23 | Assert.Equal(0, AsyncEnumerable.Empty().GetAsyncEnumerator(default).Current);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ErrorTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class ErrorTest
13 | {
14 | [Fact]
15 | public async Task Calls()
16 | {
17 | var en = AsyncEnumerable.Error(new InvalidOperationException()).GetAsyncEnumerator(default);
18 |
19 | try
20 | {
21 | await en.MoveNextAsync();
22 | Assert.False(true, "Should have thrown");
23 | }
24 | catch (InvalidOperationException)
25 | {
26 | // expected;
27 | }
28 |
29 | Assert.Equal(0, en.Current);
30 | Assert.False(await en.MoveNextAsync());
31 |
32 | await en.DisposeAsync();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ExceptionHelperTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet.impl;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class ExceptionHelperTest
12 | {
13 | private Exception _error;
14 |
15 | [Fact]
16 | public void AddException()
17 | {
18 | var ex = new InvalidOperationException();
19 | Assert.True(ExceptionHelper.AddException(ref _error, ex));
20 |
21 | Assert.Same(ex, _error);
22 | }
23 |
24 | [Fact]
25 | public void AddException_Existing()
26 | {
27 | _error = new IndexOutOfRangeException();
28 | var ex = new InvalidOperationException();
29 | Assert.True(ExceptionHelper.AddException(ref _error, ex));
30 |
31 | Assert.True(_error is AggregateException);
32 |
33 | var g = (AggregateException)_error;
34 |
35 | Assert.Equal(2, g.InnerExceptions.Count);
36 |
37 | Assert.True(g.InnerExceptions[0] is IndexOutOfRangeException);
38 | Assert.True(g.InnerExceptions[1] is InvalidOperationException);
39 | }
40 |
41 | [Fact]
42 | public void AddException_Terminated()
43 | {
44 | var ex = new InvalidOperationException();
45 |
46 | Assert.True(ExceptionHelper.AddException(ref _error, ex));
47 |
48 | Assert.Same(ExceptionHelper.Terminate(ref _error), ex);
49 | }
50 |
51 | [Fact]
52 | public void AddException_Terminated_2()
53 | {
54 | Assert.Same(ExceptionHelper.Terminate(ref _error), null);
55 |
56 | var ex = new InvalidOperationException();
57 |
58 | Assert.False(ExceptionHelper.AddException(ref _error, ex));
59 | }
60 |
61 | [Fact]
62 | public void Terminate()
63 | {
64 | Assert.Same(ExceptionHelper.Terminate(ref _error), null);
65 |
66 | Assert.Same(ExceptionHelper.Terminate(ref _error), ExceptionHelper.Terminated);
67 | }
68 |
69 | [Fact]
70 | public void Extract_Aggregated_Solo()
71 | {
72 | var ex = new InvalidOperationException();
73 |
74 | Assert.Same(ExceptionHelper.Extract(new AggregateException(ex)), ex);
75 | }
76 |
77 | [Fact]
78 | public void Extract_Aggregated_Not_Solo()
79 | {
80 | var ex = new InvalidOperationException();
81 | var ex2 = new IndexOutOfRangeException();
82 |
83 | var g = new AggregateException(ex, ex2);
84 |
85 | Assert.Same(ExceptionHelper.Extract(g), g);
86 | }
87 |
88 | [Fact]
89 | public void Extract_Not_Aggregated()
90 | {
91 | var ex = new InvalidOperationException();
92 |
93 | Assert.Same(ExceptionHelper.Extract(ex), ex);
94 | }
95 |
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/FilterTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class FilterTest
12 | {
13 | [Fact]
14 | public async Task Sync_Normal()
15 | {
16 | var result = AsyncEnumerable.Range(1, 10)
17 | .Filter(v => v % 2 == 0);
18 |
19 | await result.AssertResult(2, 4, 6, 8, 10);
20 | }
21 |
22 | [Fact]
23 | public async Task Async_Normal()
24 | {
25 | var result = AsyncEnumerable.Range(1, 10)
26 | .Filter(async v =>
27 | {
28 | await Task.Delay(100);
29 | return v % 2 == 0;
30 | });
31 |
32 | await result.AssertResult(2, 4, 6, 8, 10);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/FirstLastSingleAsyncTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class FirstLastSingleAsyncTest
13 | {
14 | [Fact]
15 | public async Task First()
16 | {
17 | Assert.Equal(1, await AsyncEnumerable.Range(1, 5).FirstAsync());
18 | }
19 |
20 | [Fact]
21 | public async Task First_Empty()
22 | {
23 | await Assert.ThrowsAsync(() => AsyncEnumerable.Range(1, 0).FirstAsync().AsTask());
24 | }
25 |
26 | [Fact]
27 | public async Task First_Or_Default()
28 | {
29 | Assert.Equal(10, await AsyncEnumerable.Range(1, 0).FirstAsync(10));
30 | }
31 |
32 | [Fact]
33 | public async Task Last()
34 | {
35 | Assert.Equal(5, await AsyncEnumerable.Range(1, 5).LastAsync());
36 | }
37 |
38 | [Fact]
39 | public async Task Last_Empty()
40 | {
41 | await Assert.ThrowsAsync(() => AsyncEnumerable.Range(1, 0).LastAsync().AsTask());
42 | }
43 |
44 | [Fact]
45 | public async Task Last_Or_Default()
46 | {
47 | Assert.Equal(10, await AsyncEnumerable.Range(1, 0).LastAsync(10));
48 | }
49 |
50 | [Fact]
51 | public async Task Single()
52 | {
53 | Assert.Equal(0, await AsyncEnumerable.Just(0).SingleAsync());
54 | }
55 |
56 | [Fact]
57 | public async Task Single_Empty()
58 | {
59 | await Assert.ThrowsAsync(() => AsyncEnumerable.Empty().SingleAsync().AsTask());
60 | }
61 |
62 | [Fact]
63 | public async Task Single_Or_Default()
64 | {
65 | Assert.Equal(10, await AsyncEnumerable.Empty().SingleAsync(10));
66 | }
67 |
68 | [Fact]
69 | public async Task Single_Too_Many()
70 | {
71 | await Assert.ThrowsAsync(() => AsyncEnumerable.Range(1, 5).SingleAsync().AsTask());
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ForEachTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class ForEachTest
13 | {
14 | [Fact]
15 | public async Task Normal()
16 | {
17 | var sum = 0;
18 | await AsyncEnumerable.Range(1, 5)
19 | .ForEach(v => sum += v, onComplete: () => sum += 100);
20 |
21 | Assert.Equal(115, sum);
22 | }
23 |
24 | [Fact]
25 | public async Task Error()
26 | {
27 | var error = default(Exception);
28 | await AsyncEnumerable.Error(new InvalidOperationException())
29 | .ForEach(onError: e => error = e);
30 |
31 | Assert.NotNull(error);
32 | Assert.True(error is InvalidOperationException);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/FromEnumerableTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class FromEnumerableTest
13 | {
14 | [Fact]
15 | public async Task Normal()
16 | {
17 | var result = AsyncEnumerable.FromEnumerable(Enumerable.Range(1, 5))
18 | ;
19 |
20 | await result.AssertResult(1, 2, 3, 4, 5);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/FromTaskFuncTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class FromTaskFuncTest
12 | {
13 | [Fact]
14 | public async Task Func_Normal()
15 | {
16 | var source = AsyncEnumerable.FromTask(async () =>
17 | {
18 | await Task.Delay(100);
19 | return 1;
20 | });
21 |
22 | await source.AssertResult(1);
23 | }
24 |
25 | [Fact]
26 | public async Task Task_Normal()
27 | {
28 | var source = AsyncEnumerable.FromTask(Task.Delay(100).ContinueWith(t => 1));
29 |
30 | await source.AssertResult(1);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/IgnoreElementsTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class IgnoreElementsTest
12 | {
13 | [Fact]
14 | public async Task Normal()
15 | {
16 | await AsyncEnumerable.Range(1, 5)
17 | .IgnoreElements()
18 | .AssertResult();
19 | }
20 |
21 | [Fact]
22 | public async Task Empty()
23 | {
24 | await AsyncEnumerable.Empty()
25 | .IgnoreElements()
26 | .AssertResult();
27 | }
28 |
29 | [Fact]
30 | public void Current()
31 | {
32 | Assert.Equal(0, AsyncEnumerable.Range(1, 5)
33 | .IgnoreElements().GetAsyncEnumerator(default).Current);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/IntervalTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class IntervalTest
13 | {
14 | [Fact]
15 | public async Task Normal()
16 | {
17 | await AsyncEnumerable.Interval(TimeSpan.FromMilliseconds(100))
18 | .Take(5)
19 | .AssertResult(0, 1, 2, 3, 4);
20 | }
21 |
22 | [Fact]
23 | public async Task Normal_initial()
24 | {
25 | await AsyncEnumerable.Interval(TimeSpan.FromMilliseconds(50), TimeSpan.FromMilliseconds(100))
26 | .Take(5)
27 | .AssertResult(0, 1, 2, 3, 4);
28 | }
29 |
30 | [Fact]
31 | public async Task Range()
32 | {
33 | await AsyncEnumerable.Interval(1, 5, TimeSpan.FromMilliseconds(200), TimeSpan.FromMilliseconds(100))
34 | .AssertResult(1, 2, 3, 4, 5);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/IsEmptyTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class IsEmptyTest
13 | {
14 | [Fact]
15 | public async Task NonEmpty()
16 | {
17 | await AsyncEnumerable.Range(1, 5)
18 | .IsEmpty()
19 | .AssertResult(false);
20 | }
21 |
22 | [Fact]
23 | public async Task Empty()
24 | {
25 | await AsyncEnumerable.Empty()
26 | .IsEmpty()
27 | .AssertResult(true);
28 | }
29 |
30 | [Fact]
31 | public async Task Error()
32 | {
33 | await AsyncEnumerable.Error(new InvalidOperationException())
34 | .IsEmpty()
35 | .AssertFailure(typeof(InvalidOperationException));
36 | }
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/JustTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class JustTest
12 | {
13 | [Fact]
14 | public async Task Normal()
15 | {
16 | await AsyncEnumerable.Just(1)
17 | .AssertResult(1);
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/LatestTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class LatestTest
13 | {
14 | [Fact]
15 | public async Task Skip_All()
16 | {
17 | var en = AsyncEnumerable.Range(1, 5).Latest().GetAsyncEnumerator(default);
18 |
19 | try
20 | {
21 | await Task.Delay(200);
22 |
23 | Assert.True(await en.MoveNextAsync());
24 |
25 | Assert.Equal(5, en.Current);
26 |
27 | Assert.False(await en.MoveNextAsync());
28 | }
29 | finally
30 | {
31 | await en.DisposeAsync();
32 | }
33 | }
34 |
35 | [Fact]
36 | public async Task Normal()
37 | {
38 | var push = new MulticastAsyncEnumerable();
39 | var en = push.Latest().GetAsyncEnumerator(default);
40 |
41 | try
42 | {
43 | await push.Next(1);
44 |
45 | Assert.True(await en.MoveNextAsync());
46 |
47 | Assert.Equal(1, en.Current);
48 |
49 | await push.Next(2);
50 | await push.Next(3);
51 |
52 | await Task.Delay(200);
53 |
54 | Assert.True(await en.MoveNextAsync());
55 |
56 | Assert.Equal(3, en.Current);
57 |
58 | await push.Next(4);
59 | await push.Complete();
60 |
61 | Assert.True(await en.MoveNextAsync());
62 |
63 | Assert.Equal(4, en.Current);
64 | Assert.False(await en.MoveNextAsync());
65 | }
66 | finally
67 | {
68 | await en.DisposeAsync();
69 | }
70 | }
71 |
72 | [Fact]
73 | public async Task Error()
74 | {
75 | await AsyncEnumerable.Error(new InvalidOperationException())
76 | .Latest()
77 | .AssertFailure(typeof(InvalidOperationException));
78 | }
79 |
80 | [Fact]
81 | public async Task Take()
82 | {
83 | await AsyncEnumerable.Interval(1, 5, TimeSpan.FromMilliseconds(200))
84 | .Latest()
85 | .Take(1)
86 | .AssertResult(1L);
87 | }
88 |
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/LicenseHeader.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using System.IO;
7 | using System.Text;
8 | using Xunit;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | ///
13 | /// This test class checks all source *.cs files for missing header and
14 | /// adds them. Note that it deliberately fails the first time it finds
15 | /// such files.
16 | ///
17 | public class LicenseHeader
18 | {
19 | private const string HeaderLines = "// Copyright (c) David Karnok & Contributors.\r\n// Licensed under the Apache 2.0 License.\r\n// See LICENSE file in the project root for full license information.\r\n\r\n";
20 |
21 | [Fact]
22 | public void CheckHeaderMainSources()
23 | {
24 | VisitSources(FindPath("async-enumerable-dotnet/") + "async-enumerable-dotnet/");
25 | }
26 |
27 | [Fact]
28 | public void CheckHeaderBenchmarkSources()
29 | {
30 | VisitSources(FindPath("async-enumerable-dotnet/") + "async-enumerable-dotnet-benchmark/");
31 | }
32 |
33 | [Fact]
34 | public void CheckHeaderTestSources()
35 | {
36 | VisitSources(FindPath("async-enumerable-dotnet/") + "async-enumerable-dotnet-test/");
37 | }
38 |
39 | private static string FindPath(string subProject)
40 | {
41 | var dir = Directory.GetCurrentDirectory().Replace("\\", "/");
42 | var idx = dir.LastIndexOf(subProject, StringComparison.InvariantCultureIgnoreCase);
43 | if (idx < 0)
44 | {
45 | throw new ArgumentException("Could not find " + subProject + " in dir");
46 | }
47 | return dir.Substring(0, idx + subProject.Length);
48 | }
49 |
50 | private static void VisitSources(string path)
51 | {
52 | var found = false;
53 |
54 | var ci = Environment.GetEnvironmentVariable("CI") != null;
55 |
56 | var sb = new StringBuilder();
57 |
58 | foreach (var entry in Directory.EnumerateFiles(path, "*.cs", SearchOption.AllDirectories))
59 | {
60 | var entryForward = entry.Replace("\\", "/");
61 | if (entryForward.Contains("AssemblyInfo")
62 | || entryForward.Contains("Temporary")
63 | || entryForward.Contains("/obj/")
64 | || entryForward.Contains("/Debug/")
65 | || entryForward.Contains("/Release/"))
66 | {
67 | continue;
68 | }
69 |
70 | var text = File.ReadAllText(entry, Encoding.UTF8);
71 | if (!text.Contains("\r\n"))
72 | {
73 | text = text.Replace("\n", "\r\n");
74 | }
75 | if (!text.StartsWith(HeaderLines))
76 | {
77 | sb.Append(entry).Append("\r\n");
78 | found = true;
79 | if (!ci)
80 | {
81 | File.WriteAllText(entry, HeaderLines + text, Encoding.UTF8);
82 | }
83 | }
84 | }
85 |
86 | if (found)
87 | {
88 | throw new InvalidOperationException("Missing header found and added. Please rebuild the project of " + path + "\r\n" + sb);
89 | }
90 | }
91 | }
92 | }
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ListComparer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System.Collections.Generic;
6 | using System.Linq;
7 |
8 | namespace async_enumerable_dotnet_test
9 | {
10 | internal sealed class ListComparer : IEqualityComparer>
11 | {
12 | internal static readonly ListComparer Default = new ListComparer();
13 |
14 | public bool Equals(IList x, IList y)
15 | {
16 | return x.SequenceEqual(y);
17 | }
18 |
19 | public int GetHashCode(IList obj)
20 | {
21 | var hash = 19;
22 |
23 | unchecked
24 | {
25 | hash = obj.Aggregate(hash, (current, t) => current * 31 + (t != null ? t.GetHashCode() : 0));
26 | }
27 |
28 | return hash;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/MapTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class MapTest
12 | {
13 | [Fact]
14 | public async Task Sync_Normal()
15 | {
16 | var result = AsyncEnumerable.Range(1, 5)
17 | .Map(v => v * v);
18 |
19 | await result.AssertResult(1, 4, 9, 16, 25);
20 | }
21 |
22 | [Fact]
23 | public async Task Async_Normal()
24 | {
25 | var result = AsyncEnumerable.Range(1, 5)
26 | .Map(async v =>
27 | {
28 | await Task.Delay(100);
29 | return v * v;
30 | });
31 |
32 | await result.AssertResult(1, 4, 9, 16, 25);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/MergeWithTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class MergeWithTest
12 | {
13 | [Fact]
14 | public async Task Normal()
15 | {
16 | await AsyncEnumerable.Range(1, 5)
17 | .MergeWith(AsyncEnumerable.Range(6, 5))
18 | .AssertResultSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/NeverTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 |
8 | namespace async_enumerable_dotnet_test
9 | {
10 | public class NeverTest
11 | {
12 | /*
13 | [Fact(Skip = "The task of MoveNextAsync never completes and thus DisposeAsync won't either")]
14 | public async void Never()
15 | {
16 | await AsyncEnumerable.Never()
17 | .Timeout(TimeSpan.FromMilliseconds(100))
18 | .AssertFailure(typeof(TimeoutException));
19 | }
20 | */
21 |
22 | [Fact]
23 | public void Normal()
24 | {
25 | var en = AsyncEnumerable.Never().GetAsyncEnumerator(default);
26 |
27 | Assert.Equal(0, AsyncEnumerable.Never().GetAsyncEnumerator(default).Current);
28 |
29 | // no await as the test would never end otherwise
30 |
31 | en.MoveNextAsync();
32 | en.DisposeAsync();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/OnErrorResumeNextTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class OnErrorResumeNextTest
13 | {
14 | [Fact]
15 | public async Task Normal()
16 | {
17 | await AsyncEnumerable.Range(1, 5)
18 | .OnErrorResumeNext(e => AsyncEnumerable.Range(6, 5))
19 | .AssertResult(1, 2, 3, 4, 5);
20 | }
21 |
22 | [Fact]
23 | public async Task Error_Switch()
24 | {
25 | await AsyncEnumerable.Error(new Exception())
26 | .OnErrorResumeNext(e => AsyncEnumerable.Range(6, 5))
27 | .AssertResult(6, 7, 8, 9, 10);
28 | }
29 |
30 | [Fact]
31 | public async Task Handler_Crash()
32 | {
33 | await AsyncEnumerable.Error(new InvalidOperationException())
34 | .OnErrorResumeNext(e => throw e)
35 | .AssertFailure(typeof(AggregateException));
36 | }
37 |
38 | [Fact]
39 | public async Task Error_DisposeSource()
40 | {
41 | var disposed = false;
42 | await AsyncEnumerable.Error(new Exception())
43 | .DoOnDispose(() => disposed = true)
44 | .OnErrorResumeNext(e => AsyncEnumerable.Empty())
45 | .AssertResult();
46 | Assert.True(disposed);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/PrefetchTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using Xunit;
9 | using async_enumerable_dotnet;
10 |
11 | namespace async_enumerable_dotnet_test
12 | {
13 | public class PrefetchTest
14 | {
15 | [Fact]
16 | public async Task Normal()
17 | {
18 | await AsyncEnumerable.Range(1, 10)
19 | .Prefetch(2)
20 | .AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
21 | }
22 |
23 | [Fact]
24 | public async Task Normal_1()
25 | {
26 | await AsyncEnumerable.Range(1, 10)
27 | .Prefetch(1)
28 | .AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
29 | }
30 |
31 | [Fact]
32 | public async Task Error()
33 | {
34 | await AsyncEnumerable.Range(1, 10)
35 | .WithError(new InvalidOperationException())
36 | .Prefetch(2)
37 | .AssertFailure(typeof(InvalidOperationException), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
38 | }
39 |
40 | [Fact]
41 | public async Task Fetch_More_Than_The_Length()
42 | {
43 | await AsyncEnumerable.Range(1, 10)
44 | .Prefetch(20)
45 | .AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
46 | }
47 |
48 | [Fact]
49 | public async Task Long_Fetch_1000()
50 | {
51 | await AsyncEnumerable.Range(1, 1_000_000)
52 | .Prefetch(1000)
53 | .Last()
54 | .AssertResult(1_000_000);
55 | }
56 |
57 | [Fact]
58 | public async Task Long_Fetch_1000_Limit_500()
59 | {
60 | await AsyncEnumerable.Range(1, 1_000_000)
61 | .Prefetch(1000, 500)
62 | .Last()
63 | .AssertResult(1_000_000);
64 | }
65 |
66 | [Fact]
67 | public async Task Take()
68 | {
69 | await AsyncEnumerable.Interval(1, 5, TimeSpan.FromMilliseconds(200))
70 | .Prefetch(128)
71 | .Take(1)
72 | .AssertResult(1L);
73 | }
74 |
75 | [Fact]
76 | public async Task Cancel()
77 | {
78 | await AsyncEnumerable.FromTask(Task.FromCanceled(new CancellationToken(true)))
79 | .Prefetch(1)
80 | .AssertFailure(typeof(OperationCanceledException));
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/PublishTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class PublishTest
13 | {
14 | [Fact]
15 | public async Task Simple()
16 | {
17 | await AsyncEnumerable.Range(1, 5)
18 | .Publish(a => a.Map(v => v + 1))
19 | .AssertResult(2, 3, 4, 5, 6);
20 | }
21 |
22 | [Fact]
23 | public async Task Direct()
24 | {
25 | await AsyncEnumerable.Range(1, 5)
26 | .Publish(a => a)
27 | .AssertResult(1, 2, 3, 4, 5);
28 | }
29 |
30 | [Fact]
31 | public async Task Take()
32 | {
33 | await AsyncEnumerable.Range(1, 5)
34 | .Publish(a => a.Map(v => v + 1))
35 | .Take(3)
36 | .AssertResult(2, 3, 4);
37 | }
38 |
39 | [Fact]
40 | public async Task Take_Inner()
41 | {
42 | await AsyncEnumerable.Range(1, 5)
43 | .Publish(a => a.Take(3))
44 | .AssertResult(1, 2, 3);
45 | }
46 |
47 | [Fact]
48 | public async Task Take_Concat_Inner()
49 | {
50 | await AsyncEnumerable.Range(1, 5)
51 | .Publish(a => a.Take(3).ConcatWith(AsyncEnumerable.Range(4, 2)))
52 | .AssertResult(1, 2, 3, 4, 5);
53 | }
54 |
55 | [Fact]
56 | public async Task Multicast_Merge()
57 | {
58 | await AsyncEnumerable.Range(1, 5)
59 | .Publish(a => a.Take(3).MergeWith(a.Skip(3)))
60 | .AssertResultSet(1, 2, 3, 4, 5);
61 | }
62 |
63 | [Fact]
64 | public async Task Multicast_Concat()
65 | {
66 | await AsyncEnumerable.Range(1, 5)
67 | .Publish(a => a.Take(3).ConcatWith(a))
68 | .AssertThen(list => {
69 | // concat may not switch fast enough so publish just runs through
70 | Assert.True(list.Count >= 3, "Items missing: " + list);
71 | });
72 | }
73 |
74 |
75 | [Fact]
76 | public async Task Unrelated()
77 | {
78 | await AsyncEnumerable.Range(1, 5)
79 | .Publish(a => AsyncEnumerable.Range(1, 5)
80 | .Take(3)
81 | .ConcatWith(AsyncEnumerable.Range(4, 2))
82 | )
83 | .AssertResult(1, 2, 3, 4, 5);
84 | }
85 |
86 |
87 | [Fact]
88 | public async Task Handler_Crash()
89 | {
90 | await AsyncEnumerable.Range(1, 5)
91 | .Publish(v => throw new InvalidOperationException())
92 | .AssertFailure(typeof(InvalidOperationException));
93 | }
94 |
95 |
96 | [Fact]
97 | public async Task Error()
98 | {
99 | await AsyncEnumerable.Error(new InvalidOperationException())
100 | .Publish(v => v.Map(w => w + 1))
101 | .AssertFailure(typeof(InvalidOperationException));
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/QueueDrainHelperTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using System.Threading.Tasks;
7 | using Xunit;
8 | using async_enumerable_dotnet.impl;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class QueueDrainHelperTest
13 | {
14 | private int _disposeWip;
15 | private Exception _disposeError;
16 | private readonly TaskCompletionSource _disposeTask = new TaskCompletionSource();
17 |
18 | [Fact]
19 | public void DisposeCrash()
20 | {
21 | var task = Task.FromException(new InvalidOperationException());
22 | _disposeWip = 1;
23 |
24 | QueueDrainHelper.DisposeHandler(task, ref _disposeWip, ref _disposeError, _disposeTask);
25 |
26 | Assert.Equal(0, _disposeWip);
27 | Assert.Null(_disposeError);
28 |
29 | Assert.True(_disposeTask.Task.IsFaulted);
30 |
31 | Assert.True(_disposeTask.Task.Exception.InnerExceptions[0] is InvalidOperationException);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/RangeTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class RangeTest
12 | {
13 | [Fact]
14 | public async Task Normal()
15 | {
16 | var result = AsyncEnumerable.Range(1, 5);
17 |
18 | await result.AssertResult(1, 2, 3, 4, 5);
19 | }
20 |
21 | [Fact]
22 | public async Task Empty()
23 | {
24 | var result = AsyncEnumerable.Range(1, 0);
25 |
26 | await result.AssertResult();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ReduceTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class ReduceTest
13 | {
14 | [Fact]
15 | public async Task NoSeed_Normal()
16 | {
17 | await AsyncEnumerable.Range(1, 5)
18 | .Reduce((a, b) => a + b)
19 | .AssertResult(15);
20 | }
21 |
22 | [Fact]
23 | public async Task NoSeed_Empty()
24 | {
25 | await AsyncEnumerable.Empty()
26 | .Reduce((a, b) => a + b)
27 | .AssertResult();
28 | }
29 |
30 | [Fact]
31 | public async Task WithSeed_Normal()
32 | {
33 | await AsyncEnumerable.Range(1, 5)
34 | .Reduce(() => 10, (a, b) => a + b)
35 | .AssertResult(25);
36 | }
37 |
38 | [Fact]
39 | public async Task WithSeed_Empty()
40 | {
41 | await AsyncEnumerable.Empty()
42 | .Reduce(() => 10, (a, b) => a + b)
43 | .AssertResult(10);
44 | }
45 |
46 | [Fact]
47 | public async Task WithSeed_Crash()
48 | {
49 | await AsyncEnumerable.Empty()
50 | .Reduce(() => throw new InvalidOperationException(), (a, b) => a + b)
51 | .AssertFailure(typeof(InvalidOperationException));
52 | }
53 |
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/RepeatTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class RepeatTest
12 | {
13 | [Fact]
14 | public async Task Unlimited()
15 | {
16 | await AsyncEnumerable.Just(1)
17 | .Repeat()
18 | .Take(5)
19 | .AssertResult(1, 1, 1, 1, 1);
20 | }
21 |
22 | [Fact]
23 | public async Task Limited()
24 | {
25 | await AsyncEnumerable.Range(1, 2)
26 | .Repeat(3)
27 | .AssertResult(1, 2, 1, 2, 1, 2);
28 | }
29 |
30 | [Fact]
31 | public async Task Limited_Condition()
32 | {
33 | await AsyncEnumerable.Range(1, 2)
34 | .Repeat(n => n < 2)
35 | .AssertResult(1, 2, 1, 2, 1, 2);
36 | }
37 |
38 | [Fact]
39 | public async Task Limited_Condition_Task()
40 | {
41 | await AsyncEnumerable.Range(1, 2)
42 | .Repeat(async n => {
43 | await Task.Delay(100);
44 | return n < 2;
45 | })
46 | .AssertResult(1, 2, 1, 2, 1, 2);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ReplayTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class ReplayTest
13 | {
14 | [Fact]
15 | public async Task All_Direct()
16 | {
17 | await AsyncEnumerable.Range(1, 5)
18 | .Replay(v => v)
19 | .AssertResult(1, 2, 3, 4, 5);
20 | }
21 |
22 | [Fact]
23 | public async Task All_Simple()
24 | {
25 | await AsyncEnumerable.Range(1, 5)
26 | .Replay(v => v.Map(w => w + 1))
27 | .AssertResult(2, 3, 4, 5, 6);
28 | }
29 |
30 | [Fact]
31 | public async Task All_Take()
32 | {
33 | await AsyncEnumerable.Range(1, 5)
34 | .Replay(v => v.Take(3))
35 | .AssertResult(1, 2, 3);
36 | }
37 |
38 | [Fact]
39 | public async Task All_Recombine()
40 | {
41 | await AsyncEnumerable.Range(1, 5)
42 | .Replay(v => v.Take(3).ConcatWith(v.Skip(3)))
43 | .AssertResult(1, 2, 3, 4, 5);
44 | }
45 |
46 | [Fact]
47 | public async Task All_Twice()
48 | {
49 | await AsyncEnumerable.Range(1, 5)
50 | .Replay(v => v.ConcatWith(v))
51 | .AssertResult(1, 2, 3, 4, 5, 1, 2, 3, 4, 5);
52 | }
53 |
54 | [Fact]
55 | public async Task All_Handler_Crash()
56 | {
57 | await AsyncEnumerable.Range(1, 5)
58 | .Replay(v => throw new InvalidOperationException())
59 | .AssertFailure(typeof(InvalidOperationException));
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ResumeHelperTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using System.Threading.Tasks;
8 | using async_enumerable_dotnet.impl;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class ResumeHelperTest
13 | {
14 | private TaskCompletionSource _tcs;
15 |
16 | [Fact]
17 | public void Value_Cancelled()
18 | {
19 | var source = new TaskCompletionSource();
20 | source.TrySetCanceled();
21 |
22 | ResumeHelper.Complete(ref _tcs, new ValueTask(source.Task));
23 |
24 | Assert.True(_tcs.Task.IsCanceled);
25 | }
26 |
27 | [Fact]
28 | public void Value_Error()
29 | {
30 | var source = new TaskCompletionSource();
31 | var ex = new InvalidOperationException();
32 | source.TrySetException(ex);
33 |
34 | ResumeHelper.Complete(ref _tcs, new ValueTask(source.Task));
35 |
36 | Assert.True(_tcs.Task.IsFaulted);
37 | Assert.Same(ex, ExceptionHelper.Extract(ExceptionHelper.Extract(_tcs.Task.Exception)));
38 | }
39 |
40 |
41 | [Fact]
42 | public void Value_Success()
43 | {
44 | var source = new TaskCompletionSource();
45 | source.TrySetResult(true);
46 |
47 | ResumeHelper.Complete(ref _tcs, new ValueTask(source.Task));
48 |
49 | Assert.True(_tcs.Task.IsCompleted);
50 | Assert.True(_tcs.Task.Result);
51 | }
52 |
53 | [Fact]
54 | public async Task Async_Cancelled()
55 | {
56 | var source = new TaskCompletionSource();
57 |
58 | ResumeHelper.Complete(ref _tcs, new ValueTask(source.Task));
59 |
60 | source.TrySetCanceled();
61 |
62 | try
63 | {
64 | await _tcs.Task;
65 | }
66 | catch (Exception)
67 | {
68 | // ignored
69 | }
70 |
71 | Assert.True(_tcs.Task.IsCanceled);
72 | }
73 |
74 | [Fact]
75 | public async Task Async_Error()
76 | {
77 | var source = new TaskCompletionSource();
78 |
79 | ResumeHelper.Complete(ref _tcs, new ValueTask(source.Task));
80 |
81 | var ex = new InvalidOperationException();
82 | source.TrySetException(ex);
83 |
84 | try
85 | {
86 | await _tcs.Task;
87 | }
88 | catch (AggregateException g)
89 | {
90 | Assert.Same(ex, ExceptionHelper.Extract(ExceptionHelper.Extract(g)));
91 | }
92 |
93 | Assert.True(_tcs.Task.IsFaulted);
94 | }
95 |
96 |
97 | [Fact]
98 | public async Task Async_Success()
99 | {
100 | var source = new TaskCompletionSource();
101 |
102 | ResumeHelper.Complete(ref _tcs, new ValueTask(source.Task));
103 |
104 | source.TrySetResult(true);
105 |
106 | await _tcs.Task;
107 |
108 | Assert.True(_tcs.Task.IsCompleted);
109 | Assert.True(_tcs.Task.Result);
110 | }
111 |
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/RetryTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class RetryTest
13 | {
14 | [Fact]
15 | public async Task Retry_Unlimited()
16 | {
17 | await AsyncEnumerable.Range(1, 2)
18 | .WithError(new Exception())
19 | .Retry()
20 | .Take(6)
21 | .AssertResult(1, 2, 1, 2, 1, 2);
22 | }
23 |
24 | [Fact]
25 | public async Task Retry_Max()
26 | {
27 | await AsyncEnumerable.Range(1, 2)
28 | .WithError(new InvalidOperationException())
29 | .Retry(3)
30 | .AssertFailure(typeof(InvalidOperationException), 1, 2, 1, 2, 1, 2);
31 | }
32 |
33 | [Fact]
34 | public async Task Retry_Condition()
35 | {
36 | await AsyncEnumerable.Range(1, 2)
37 | .WithError(new InvalidOperationException())
38 | .Retry((idx, ex) => idx < 2)
39 | .AssertFailure(typeof(InvalidOperationException), 1, 2, 1, 2, 1, 2);
40 | }
41 |
42 | [Fact]
43 | public async Task Retry_Condition_False()
44 | {
45 | await AsyncEnumerable.Range(1, 2)
46 | .WithError(new InvalidOperationException())
47 | .Retry((idx, ex) => false)
48 | .AssertFailure(typeof(InvalidOperationException), 1, 2);
49 | }
50 |
51 | [Fact]
52 | public async Task Retry_Condition_Task()
53 | {
54 | await AsyncEnumerable.Range(1, 2)
55 | .WithError(new InvalidOperationException())
56 | .Retry(async (idx, ex) => {
57 | await Task.Delay(100);
58 | return idx < 2;
59 | })
60 | .AssertFailure(typeof(InvalidOperationException), 1, 2, 1, 2, 1, 2);
61 | }
62 |
63 | [Fact]
64 | public async Task Retry_Condition_Task_False()
65 | {
66 | await AsyncEnumerable.Range(1, 2)
67 | .WithError(new InvalidOperationException())
68 | .Retry(async (idx, ex) =>
69 | {
70 | await Task.Delay(100);
71 | return false;
72 | })
73 | .AssertFailure(typeof(InvalidOperationException), 1, 2);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/SampleTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class SampleTest
13 | {
14 | [Fact]
15 | public async Task Normal()
16 | {
17 | var t = 200;
18 | if (Environment.GetEnvironmentVariable("CI") != null)
19 | {
20 | t = 2000;
21 | }
22 |
23 | await AsyncEnumerable.Range(1, 5)
24 | .FlatMap(v =>
25 | AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(t * v - t / 2))
26 | .Map(w => v)
27 | )
28 | .Sample(TimeSpan.FromMilliseconds(t * 2))
29 | .AssertResult(2, 4);
30 | }
31 |
32 | [Fact]
33 | public async Task Last()
34 | {
35 | await AsyncEnumerable.Range(1, 5)
36 | .Sample(TimeSpan.FromMilliseconds(500))
37 | .AssertResult();
38 | }
39 |
40 | [Fact]
41 | public async Task Normal_EmitLast()
42 | {
43 | var t = 200;
44 | if (Environment.GetEnvironmentVariable("CI") != null)
45 | {
46 | t = 2000;
47 | }
48 |
49 | await AsyncEnumerable.Range(1, 5)
50 | .FlatMap(v =>
51 | AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(t * v - t / 2))
52 | .Map(w => v)
53 | )
54 | .Sample(TimeSpan.FromMilliseconds(t * 2), true)
55 | .AssertResult(2, 4, 5);
56 | }
57 |
58 | [Fact]
59 | public async Task Last_EmitLast()
60 | {
61 | await AsyncEnumerable.Range(1, 5)
62 | .Sample(TimeSpan.FromMilliseconds(500), true)
63 | .AssertResult(5);
64 | }
65 |
66 | [Fact]
67 | public async Task Error()
68 | {
69 | await AsyncEnumerable.Error(new InvalidOperationException())
70 | .Sample(TimeSpan.FromMilliseconds(500))
71 | .AssertFailure(typeof(InvalidOperationException));
72 | }
73 |
74 | [Fact]
75 | public async Task Error_EmitLast()
76 | {
77 | await AsyncEnumerable.Error(new InvalidOperationException())
78 | .Sample(TimeSpan.FromMilliseconds(500), true)
79 | .AssertFailure(typeof(InvalidOperationException));
80 | }
81 |
82 | [Fact]
83 | public async Task Take()
84 | {
85 | await TestHelper.TimeSequence(100, 300)
86 | .Sample(TimeSpan.FromMilliseconds(200))
87 | .Take(1)
88 | .AssertResult(100);
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ScanTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class ScanTest
13 | {
14 | [Fact]
15 | public async Task NoSeed_Some()
16 | {
17 | await AsyncEnumerable.Range(1, 5)
18 | .Scan((a, b) => a + b)
19 | .AssertResult(1, 3, 6, 10, 15);
20 | }
21 |
22 | [Fact]
23 | public async Task NoSeed_One()
24 | {
25 | await AsyncEnumerable.Just(1)
26 | .Scan((a, b) => a + b)
27 | .AssertResult(1);
28 | }
29 |
30 | [Fact]
31 | public async Task NoSeed_None()
32 | {
33 | await AsyncEnumerable.Empty()
34 | .Scan((a, b) => a + b)
35 | .AssertResult();
36 | }
37 |
38 | [Fact]
39 | public async Task Seed_Some()
40 | {
41 | await AsyncEnumerable.Range(1, 5)
42 | .Scan(() => 100, (a, b) => a + b)
43 | .AssertResult(100, 101, 103, 106, 110, 115);
44 | }
45 |
46 | [Fact]
47 | public async Task Seed_One()
48 | {
49 | await AsyncEnumerable.Just(1)
50 | .Scan(() => 100, (a, b) => a + b)
51 | .AssertResult(100, 101);
52 | }
53 |
54 | [Fact]
55 | public async Task Seed_None()
56 | {
57 | await AsyncEnumerable.Empty()
58 | .Scan(() => 100, (a, b) => a + b)
59 | .AssertResult(100);
60 | }
61 |
62 | [Fact]
63 | public async Task Seed_Crash()
64 | {
65 | await AsyncEnumerable.Empty()
66 | .Scan(() => throw new InvalidOperationException(), (a, b) => a + b)
67 | .AssertFailure(typeof(InvalidOperationException));
68 | }
69 |
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/SkipLastTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class SkipLastTest
12 | {
13 | [Fact]
14 | public async Task Skip_None()
15 | {
16 | await AsyncEnumerable.Range(1, 5)
17 | .SkipLast(0)
18 | .AssertResult(1, 2, 3, 4, 5);
19 | }
20 |
21 | [Fact]
22 | public async Task Skip_Some()
23 | {
24 | await AsyncEnumerable.Range(1, 5)
25 | .SkipLast(2)
26 | .AssertResult(1, 2, 3);
27 | }
28 |
29 | [Fact]
30 | public async Task Skip_All()
31 | {
32 | await AsyncEnumerable.Range(1, 5)
33 | .SkipLast(5)
34 | .AssertResult();
35 | }
36 |
37 | [Fact]
38 | public async Task Skip_More()
39 | {
40 | await AsyncEnumerable.Range(1, 5)
41 | .SkipLast(10)
42 | .AssertResult();
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/SkipTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class SkipTest
12 | {
13 | [Fact]
14 | public async Task Normal()
15 | {
16 | await AsyncEnumerable.Range(1, 10)
17 | .Skip(5)
18 | .AssertResult(6, 7, 8, 9, 10);
19 | }
20 |
21 | [Fact]
22 | public async Task Zero()
23 | {
24 | await AsyncEnumerable.Range(1, 10)
25 | .Skip(0)
26 | .AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
27 | }
28 |
29 | [Fact]
30 | public async Task All()
31 | {
32 | await AsyncEnumerable.Range(1, 10)
33 | .Skip(10)
34 | .AssertResult();
35 | }
36 |
37 | [Fact]
38 | public async Task More()
39 | {
40 | await AsyncEnumerable.Range(1, 10)
41 | .Skip(11)
42 | .AssertResult();
43 | }
44 |
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/SkipUntilTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class SkipUntilTest
13 | {
14 | [Fact]
15 | public async Task Skip_All()
16 | {
17 | await AsyncEnumerable.Range(1, 5)
18 | .SkipUntil(AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(250)))
19 | .AssertResult();
20 | }
21 |
22 | [Fact]
23 | public async Task Skip_None()
24 | {
25 | await AsyncEnumerable.Range(1, 5)
26 | .ConcatMap(v => AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(100)).Map(w => v))
27 | .SkipUntil(AsyncEnumerable.Empty())
28 | .AssertResult(1, 2, 3, 4, 5);
29 | }
30 |
31 | [Fact]
32 | public async Task Skip_Some()
33 | {
34 | var scale = 200;
35 | if (Environment.GetEnvironmentVariable("CI") != null)
36 | {
37 | scale = 2000;
38 | }
39 | await AsyncEnumerable.Range(1, 5)
40 | .FlatMap(v => AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(v * scale)).Map(w => v))
41 | // ReSharper disable once PossibleLossOfFraction
42 | .SkipUntil(AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(5 * scale / 2)))
43 | .AssertResult(3, 4, 5);
44 | }
45 |
46 | [Fact]
47 | public async Task Error_Main()
48 | {
49 | await AsyncEnumerable.Error(new InvalidOperationException())
50 | .SkipUntil(AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(200)))
51 | .AssertFailure(typeof(InvalidOperationException));
52 | }
53 |
54 | [Fact]
55 | public async Task Error_Other()
56 | {
57 | await AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(200))
58 | .SkipUntil(AsyncEnumerable.Error(new InvalidOperationException()))
59 | .AssertFailure(typeof(InvalidOperationException));
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/SkipWhileTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class SkipWhileTest
12 | {
13 | [Fact]
14 | public async Task Skip_All()
15 | {
16 | await AsyncEnumerable.Range(1, 5)
17 | .SkipWhile(v => v < 6)
18 | .AssertResult();
19 | }
20 |
21 | [Fact]
22 | public async Task Skip_Some()
23 | {
24 | await AsyncEnumerable.Range(1, 5)
25 | .SkipWhile(v => v < 3)
26 | .AssertResult(3, 4, 5);
27 | }
28 |
29 | [Fact]
30 | public async Task Skip_None()
31 | {
32 | await AsyncEnumerable.Range(1, 5)
33 | .SkipWhile(v => v < 1)
34 | .AssertResult(1, 2, 3, 4, 5);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/SlimResumeTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet.impl;
8 | using System.Threading.Tasks;
9 | using System.Threading;
10 |
11 | namespace async_enumerable_dotnet_test
12 | {
13 | public class SlimResumeTest
14 | {
15 | [Fact]
16 | public async Task ReadyUpfront()
17 | {
18 | var rsm = new SlimResume();
19 | rsm.Signal();
20 |
21 | await rsm;
22 | }
23 |
24 | [Fact]
25 | public async Task Completed()
26 | {
27 | var rsm = SlimResume.Completed;
28 |
29 | await rsm;
30 | }
31 |
32 | [Fact]
33 | public async Task SignalLater()
34 | {
35 | var rsm = new SlimResume();
36 |
37 | var t = Task.Delay(100)
38 | .ContinueWith(t0 => rsm.Signal());
39 |
40 | await rsm;
41 |
42 | await t;
43 | }
44 |
45 |
46 | [Fact]
47 | public async Task Race()
48 | {
49 | for (var i = 0; i < 10_000; i++)
50 | {
51 | var rsm = new SlimResume();
52 |
53 | var wip = 2;
54 |
55 | var t1 = Task.Factory.StartNew(() =>
56 | {
57 | if (Interlocked.Decrement(ref wip) != 0)
58 | {
59 | while (Volatile.Read(ref wip) != 0) { }
60 | }
61 |
62 | rsm.Signal();
63 | }, TaskCreationOptions.LongRunning);
64 |
65 | var t2 = Task.Factory.StartNew(async () =>
66 | {
67 | if (Interlocked.Decrement(ref wip) != 0)
68 | {
69 | while (Volatile.Read(ref wip) != 0) { }
70 | }
71 |
72 | await rsm;
73 | }, TaskCreationOptions.LongRunning);
74 |
75 | await t1;
76 |
77 | await t2;
78 | }
79 | }
80 |
81 | [Fact]
82 | public void OneAwaiterMax()
83 | {
84 | var rsm = new SlimResume();
85 |
86 | rsm.OnCompleted(() => { });
87 |
88 | try
89 | {
90 | rsm.OnCompleted(() => { });
91 | Assert.False(true, "Should have thrown");
92 | }
93 | catch (InvalidOperationException)
94 | {
95 | // expected
96 | }
97 | }
98 |
99 | [Fact]
100 | public void DoubleSignal()
101 | {
102 | SlimResume.Completed.Signal();
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/SwitchIfEmptyTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class SwitchIfEmptyTest
12 | {
13 | [Fact]
14 | public async Task NonEmpty()
15 | {
16 | await AsyncEnumerable.Range(1, 5)
17 | .SwitchIfEmpty(AsyncEnumerable.Range(11, 5))
18 | .AssertResult(1, 2, 3, 4, 5);
19 | }
20 |
21 | [Fact]
22 | public async Task Empty()
23 | {
24 | await AsyncEnumerable.Empty()
25 | .SwitchIfEmpty(AsyncEnumerable.Range(11, 5))
26 | .AssertResult(11, 12, 13, 14, 15);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/TakeLastTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class TakeLastTest
12 | {
13 | [Fact]
14 | public async Task More()
15 | {
16 | await AsyncEnumerable.Range(1, 5)
17 | .TakeLast(10)
18 | .AssertResult(1, 2, 3, 4, 5);
19 | }
20 |
21 | [Fact]
22 | public async Task All()
23 | {
24 | await AsyncEnumerable.Range(1, 5)
25 | .TakeLast(5)
26 | .AssertResult(1, 2, 3, 4, 5);
27 | }
28 |
29 | [Fact]
30 | public async Task Some()
31 | {
32 | await AsyncEnumerable.Range(1, 5)
33 | .TakeLast(2)
34 | .AssertResult(4, 5);
35 | }
36 |
37 | [Fact]
38 | public async Task None()
39 | {
40 | await AsyncEnumerable.Range(1, 5)
41 | .TakeLast(0)
42 | .AssertResult();
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/TakeTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class TakeTest
12 | {
13 | [Fact]
14 | public async Task Normal()
15 | {
16 | var result = AsyncEnumerable.FromArray(1, 2, 3, 4, 5)
17 | .Take(3)
18 | ;
19 |
20 | await result.AssertResult(1, 2, 3);
21 | }
22 |
23 | [Fact]
24 | public async Task More()
25 | {
26 | var result = AsyncEnumerable.FromArray(1, 2, 3, 4, 5)
27 | .Take(6)
28 | ;
29 |
30 | await result.AssertResult(1, 2, 3, 4, 5);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/TakeUntilTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class TakeUntilTest
13 | {
14 | [Fact]
15 | public async Task Normal()
16 | {
17 | var t = 500;
18 | if (Environment.GetEnvironmentVariable("CI") != null)
19 | {
20 | t = 3000;
21 | }
22 | var disposedMain = 0;
23 | var disposedOther = 0;
24 |
25 | await AsyncEnumerable.Range(1, 5)
26 | .DoOnDispose(() => disposedMain++)
27 | .TakeUntil(
28 | AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(t))
29 | .DoOnDispose(() => disposedOther += 2)
30 | )
31 | .AssertResult(1, 2, 3, 4, 5);
32 |
33 | Assert.Equal(1, disposedMain);
34 | Assert.Equal(2, disposedOther);
35 | }
36 |
37 | [Fact]
38 | public async Task Until()
39 | {
40 | var disposedMain = 0;
41 | var disposedOther = 0;
42 |
43 | await AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(500))
44 | .DoOnDispose(() => disposedMain++)
45 | .TakeUntil(
46 | AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(100))
47 | .DoOnDispose(() => disposedOther += 2)
48 | )
49 | .AssertResult();
50 |
51 | Assert.Equal(1, disposedMain);
52 | Assert.Equal(2, disposedOther);
53 | }
54 |
55 | [Fact]
56 | public async Task MainError()
57 | {
58 | await AsyncEnumerable.Error(new InvalidOperationException())
59 | .TakeUntil(AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(200)))
60 | .AssertFailure(typeof(InvalidOperationException));
61 |
62 | }
63 |
64 |
65 | [Fact]
66 | public async Task OtherError()
67 | {
68 | await AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(200))
69 | .TakeUntil(AsyncEnumerable.Error(new InvalidOperationException()))
70 | .AssertFailure(typeof(InvalidOperationException));
71 |
72 | }
73 |
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/TakeWhileTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class TakeWhileTest
12 | {
13 | [Fact]
14 | public async Task All_Pass()
15 | {
16 | await AsyncEnumerable.Range(1, 5)
17 | .TakeWhile(v => true)
18 | .AssertResult(1, 2, 3, 4, 5);
19 | }
20 |
21 | [Fact]
22 | public async Task Some_Pass()
23 | {
24 | await AsyncEnumerable.Range(1, 5)
25 | .TakeWhile(v => v < 4)
26 | .AssertResult(1, 2, 3);
27 | }
28 |
29 | [Fact]
30 | public async Task None_Pass()
31 | {
32 | await AsyncEnumerable.Range(1, 5)
33 | .TakeWhile(v => false)
34 | .AssertResult();
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/TestHelperTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Collections.Generic;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class TestHelperTest
13 | {
14 | [Fact]
15 | public async Task AssertResultSet()
16 | {
17 | await AsyncEnumerable.Range(1, 3)
18 | .AssertResultSet(1, 2, 3);
19 | }
20 |
21 | [Fact]
22 | public async Task AssertResultSet_List()
23 | {
24 | await AsyncEnumerable.FromArray(new List(new [] { 1, 2, 3 }))
25 | .AssertResultSet(
26 | ListComparer.Default,
27 | new List(new[] { 1, 2, 3 }));
28 | }
29 |
30 | [Fact]
31 | public void HashSet_Contains()
32 | {
33 | var set = new HashSet>(ListComparer.Default) {new List(new[] {1, 2, 3})};
34 |
35 |
36 | Assert.Contains(new List(new[] { 1, 2, 3 }), set);
37 |
38 | Assert.True(set.Remove(new List(new[] { 1, 2, 3 })));
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/TimeoutTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using async_enumerable_dotnet;
6 | using System;
7 | using Xunit;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class TimeoutTest
13 | {
14 | [Fact]
15 | public async Task NoTimeout()
16 | {
17 | var result = AsyncEnumerable.FromArray(1, 2, 3, 4, 5)
18 | .Timeout(TimeSpan.FromMilliseconds(200))
19 | ;
20 |
21 | await result.AssertResult(1, 2, 3, 4, 5);
22 | }
23 |
24 | [Fact]
25 | public async Task HasTimeout()
26 | {
27 | var disposed = 0;
28 |
29 | var result = AsyncEnumerable.Timer(TimeSpan.FromSeconds(1))
30 | .DoOnDispose(() => disposed++)
31 | .Timeout(TimeSpan.FromMilliseconds(100))
32 | ;
33 |
34 | await result.AssertFailure(typeof(TimeoutException));
35 |
36 | Assert.Equal(1, disposed);
37 | }
38 |
39 | [Fact]
40 | public async Task Error()
41 | {
42 | await AsyncEnumerable.Error(new InvalidOperationException())
43 | .Timeout(TimeSpan.FromMilliseconds(10000))
44 | .AssertFailure(typeof(InvalidOperationException));
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/TimerTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using System.Threading;
7 | using Xunit;
8 | using async_enumerable_dotnet;
9 | using System.Threading.Tasks;
10 |
11 | namespace async_enumerable_dotnet_test
12 | {
13 | public class TimerTest
14 | {
15 | [Fact]
16 | public async Task Token()
17 | {
18 | var value = 0;
19 |
20 | var cts = new CancellationTokenSource();
21 | #pragma warning disable 4014
22 | AsyncEnumerable.Timer(TimeSpan.FromSeconds(200), cts.Token)
23 | .DoOnNext(v => value = 1)
24 | .GetAsyncEnumerator(default)
25 | .MoveNextAsync();
26 | #pragma warning restore 4014
27 |
28 | // ReSharper disable once MethodSupportsCancellation
29 | await Task.Delay(100);
30 |
31 | cts.Cancel();
32 |
33 | // ReSharper disable once MethodSupportsCancellation
34 | await Task.Delay(200);
35 |
36 | Assert.Equal(0, value);
37 | }
38 |
39 | [Fact]
40 | public async Task Normal()
41 | {
42 | var cts = new CancellationTokenSource();
43 | await AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(100), cts.Token)
44 | .AssertResult(0L);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ToCollectionTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System.Collections.Generic;
6 |
7 | using async_enumerable_dotnet;
8 |
9 | using Xunit;
10 | using System.Threading.Tasks;
11 |
12 | namespace async_enumerable_dotnet_test
13 | {
14 | public class ToCollectionTest
15 | {
16 | [Fact]
17 | public async Task ToListAllowsEmptySource()
18 | {
19 | var result = await AsyncEnumerable.FromArray(new int[0]).ToListAsync();
20 | Assert.NotNull(result);
21 | Assert.Empty(result);
22 | }
23 |
24 | [Fact]
25 | public async Task ToListAlwaysReturnsNewInstance()
26 | {
27 | var source = AsyncEnumerable.FromArray(new int[0]);
28 | var result1 = await source.ToListAsync();
29 | var result2 = await source.ToListAsync();
30 | Assert.NotSame(result1, result2);
31 | }
32 |
33 | [Fact]
34 | public async Task ToListReturnsAllItems()
35 | {
36 | var result = await AsyncEnumerable.Range(0, 10).ToListAsync();
37 | var usedNumbers = new HashSet(result);
38 | Assert.Equal(10, result.Count);
39 | for (var i = 0; i != 10; ++i)
40 | {
41 | Assert.Contains(i, usedNumbers);
42 | }
43 | }
44 |
45 | [Fact]
46 | public async Task ToArrayAllowsEmptySource()
47 | {
48 | var result = await AsyncEnumerable.FromArray(new int[0]).ToArrayAsync();
49 | Assert.NotNull(result);
50 | Assert.Empty(result);
51 | }
52 |
53 | [Fact]
54 | public async Task ToArrayAlwaysReturnsNewInstanceForEmptySource()
55 | {
56 | var source = AsyncEnumerable.FromArray(new int[0]);
57 | var result1 = await source.ToArrayAsync();
58 | var result2 = await source.ToArrayAsync();
59 | Assert.Same(result1, result2);
60 | }
61 |
62 | [Fact]
63 | public async Task ToArrayReturnsAllItems()
64 | {
65 | var result = await AsyncEnumerable.Range(0, 10).ToArrayAsync();
66 | var usedNumbers = new HashSet(result);
67 | Assert.Equal(10, result.Length);
68 | for (var i = 0; i != 10; ++i)
69 | {
70 | Assert.Contains(i, usedNumbers);
71 | }
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ToEnumerableTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using System.Collections;
7 | using Xunit;
8 | using async_enumerable_dotnet;
9 | using System.Linq;
10 |
11 | namespace async_enumerable_dotnet_test
12 | {
13 | public class ToEnumerableTest
14 | {
15 | [Fact]
16 | public void Normal()
17 | {
18 | var list = AsyncEnumerable.Range(1, 5).ToEnumerable().ToList();
19 |
20 | Assert.Equal(new[] { 1, 2, 3, 4, 5 }, list);
21 | }
22 |
23 | [Fact]
24 | public void NonGeneric()
25 | {
26 | IEnumerable en = AsyncEnumerable.Range(1, 5).ToEnumerable();
27 |
28 | var enumerator = en.GetEnumerator();
29 |
30 | for (var i = 1; i <= 5; i++)
31 | {
32 | Assert.True(enumerator.MoveNext());
33 | Assert.Equal(i, enumerator.Current);
34 | }
35 | Assert.False(enumerator.MoveNext());
36 |
37 | try
38 | {
39 | enumerator.Reset();
40 | Assert.False(true, "Should have thrown");
41 | }
42 | catch (InvalidOperationException)
43 | {
44 | // expected
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ToListTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Collections.Generic;
9 | using System.Threading.Tasks;
10 |
11 | namespace async_enumerable_dotnet_test
12 | {
13 | public class ToListTest
14 | {
15 | [Fact]
16 | public async Task Normal()
17 | {
18 | await AsyncEnumerable.Range(1, 5)
19 | .ToList()
20 | .AssertResult(new List(new[] { 1, 2, 3, 4, 5 }));
21 | }
22 |
23 | [Fact]
24 | public async Task Empty()
25 | {
26 | await AsyncEnumerable.Empty()
27 | .ToList()
28 | .AssertResult(new List());
29 | }
30 |
31 | [Fact]
32 | public async Task Error()
33 | {
34 | await AsyncEnumerable.Error(new InvalidOperationException())
35 | .ToList()
36 | .AssertFailure(typeof(InvalidOperationException));
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ToObservableTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 | using System.Collections.Generic;
10 |
11 | namespace async_enumerable_dotnet_test
12 | {
13 | public class ToObservableTest
14 | {
15 | [Fact]
16 | public async Task Normal()
17 | {
18 | var result = AsyncEnumerable.Range(1, 5)
19 | .ToObservable();
20 |
21 | var consumer = new BasicObserver();
22 |
23 | using (result.Subscribe(consumer))
24 | {
25 | await consumer.TerminateTask;
26 |
27 | Assert.Equal(new List(new[] {1, 2, 3, 4, 5}), consumer.Values);
28 | Assert.Null(consumer.Error);
29 | Assert.True(consumer.Completed);
30 | }
31 | }
32 |
33 | [Fact]
34 | public async Task Take()
35 | {
36 | var consumer = new BasicObserver();
37 |
38 | using (AsyncEnumerable.Timer(TimeSpan.FromMilliseconds(200))
39 | .ToObservable()
40 | .Subscribe(consumer))
41 | {
42 | await Task.Delay(100);
43 | }
44 |
45 | await Task.Delay(200);
46 |
47 | Assert.Empty(consumer.Values);
48 | Assert.Null(consumer.Error);
49 | Assert.False(consumer.Completed);
50 | }
51 |
52 | [Fact]
53 | public async Task Error()
54 | {
55 | var ex = new InvalidOperationException();
56 | var result = AsyncEnumerable.Error(ex)
57 | .ToObservable();
58 |
59 | var consumer = new BasicObserver();
60 |
61 | using (result.Subscribe(consumer))
62 | {
63 | await consumer.TerminateTask;
64 |
65 | Assert.Empty(consumer.Values);
66 | Assert.Same(ex, consumer.Error);
67 | Assert.False(consumer.Completed);
68 | }
69 | }
70 |
71 | private sealed class BasicObserver : IObserver
72 | {
73 | internal readonly IList Values = new List();
74 | internal bool Completed;
75 | internal Exception Error;
76 |
77 | private readonly TaskCompletionSource _terminate = new TaskCompletionSource();
78 |
79 | public void OnCompleted()
80 | {
81 | Completed = true;
82 | _terminate.TrySetResult(true);
83 | }
84 |
85 | public void OnError(Exception error)
86 | {
87 | Error = error;
88 | _terminate.TrySetResult(true);
89 | }
90 |
91 | public void OnNext(T value)
92 | {
93 | Values.Add(value);
94 | }
95 |
96 | public Task TerminateTask => _terminate.Task;
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/UnitTest1.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet_test
10 | {
11 | public class UnitTest1
12 | {
13 | [Fact]
14 | public async Task Test1()
15 | {
16 | await AsyncEnumerable.Range(1, 5)
17 | .AssertResult(1, 2, 3, 4, 5);
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/UsingTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using Xunit;
7 | using async_enumerable_dotnet;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class UsingTest
13 | {
14 | [Fact]
15 | public async Task Normal()
16 | {
17 | var cleanup = 0;
18 |
19 | var result = AsyncEnumerable.Using(() => 1,
20 | v => AsyncEnumerable.FromArray(v),
21 | v => cleanup = v);
22 |
23 | await result.AssertResult(1);
24 |
25 | Assert.Equal(1, cleanup);
26 | }
27 |
28 | [Fact]
29 | public async Task ResourceSupplier_Crash()
30 | {
31 | await AsyncEnumerable.Using(() => throw new InvalidOperationException(),
32 | v => AsyncEnumerable.Range(v, 5), v => { })
33 | .AssertFailure(typeof(InvalidOperationException));
34 | }
35 |
36 | [Fact]
37 | public async Task SourceSupplier_Crash()
38 | {
39 | await AsyncEnumerable.Using(() => 1,
40 | v => throw new InvalidOperationException(), v => { })
41 | .AssertFailure(typeof(InvalidOperationException));
42 | }
43 |
44 | [Fact]
45 | public async Task SourceSupplier_And_Cleanup_Crash()
46 | {
47 | await AsyncEnumerable.Using(() => 1,
48 | v => throw new InvalidOperationException(), v => throw new IndexOutOfRangeException())
49 | .AssertFailure(typeof(AggregateException));
50 | }
51 |
52 | [Fact]
53 | public async Task Cleanup_Crash()
54 | {
55 | try
56 | {
57 | await AsyncEnumerable.Using(() => 1,
58 | v => AsyncEnumerable.Range(v, 5), v => throw new IndexOutOfRangeException())
59 | .AssertResult(1, 2, 3, 4, 5);
60 | Assert.False(true, "Should have thrown");
61 | }
62 | catch (IndexOutOfRangeException)
63 | {
64 | // expected
65 | }
66 | }
67 |
68 | [Fact]
69 | public async Task Upstream_Dispose_Crash()
70 | {
71 | try
72 | {
73 | await AsyncEnumerable.Using(() => 1,
74 | v => AsyncEnumerable.Range(v, 5).DoOnDispose(() => throw new InvalidOperationException()),
75 | v => { })
76 | .AssertResult(1, 2, 3, 4, 5);
77 | Assert.False(true, "Should have thrown!");
78 | }
79 | catch (InvalidOperationException)
80 | {
81 | // expected
82 | }
83 | }
84 |
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/WithLatestFromTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using Xunit;
6 | using async_enumerable_dotnet;
7 | using System.Threading.Tasks;
8 | using System;
9 |
10 | namespace async_enumerable_dotnet_test
11 | {
12 | public class WithLatestFromTest
13 | {
14 | [Fact]
15 | public async Task Simple()
16 | {
17 | var t = 200;
18 | if (Environment.GetEnvironmentVariable("CI") != null)
19 | {
20 | t = 1000;
21 | }
22 |
23 | await AsyncEnumerable.Range(1, 5)
24 | .DoOnNext(async v =>
25 | {
26 | if (v == 1)
27 | {
28 | // otherwise the first value may come too early.
29 | await Task.Delay(t);
30 | }
31 | })
32 | .WithLatestFrom(AsyncEnumerable.Just(10), (a, b) => a + b)
33 | .AssertResult(11, 12, 13, 14, 15);
34 | }
35 |
36 | [Fact]
37 | public async Task Empty_Main()
38 | {
39 | await AsyncEnumerable.Empty()
40 | .WithLatestFrom(AsyncEnumerable.Just(10), (a, b) => a + b)
41 | .AssertResult();
42 | }
43 |
44 |
45 | [Fact]
46 | public async Task Error_Main()
47 | {
48 | await AsyncEnumerable.Error(new InvalidOperationException())
49 | .WithLatestFrom(AsyncEnumerable.Just(10), (a, b) => a + b)
50 | .AssertFailure(typeof(InvalidOperationException));
51 | }
52 |
53 | [Fact]
54 | public async Task Empty_Other()
55 | {
56 | await AsyncEnumerable.Range(1, 5)
57 | .WithLatestFrom(AsyncEnumerable.Empty(), (a, b) => a + b)
58 | .AssertResult();
59 | }
60 |
61 | [Fact]
62 | public async Task Error_Other()
63 | {
64 | var t = 200;
65 | if (Environment.GetEnvironmentVariable("CI") != null)
66 | {
67 | t = 1000;
68 | }
69 |
70 | await AsyncEnumerable.Just(1)
71 | .DoOnNext(async v =>
72 | {
73 | if (v == 1)
74 | {
75 | // otherwise the first value may come too early.
76 | await Task.Delay(t);
77 | }
78 | })
79 | .WithLatestFrom(AsyncEnumerable.Error(new InvalidOperationException()), (a, b) => a + b)
80 | .AssertFailure(typeof(InvalidOperationException));
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/ZipTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using System.Linq;
7 | using Xunit;
8 | using async_enumerable_dotnet;
9 | using System.Threading.Tasks;
10 |
11 | namespace async_enumerable_dotnet_test
12 | {
13 | public class ZipTest
14 | {
15 | [Fact]
16 | public async Task SameLength()
17 | {
18 | var source = AsyncEnumerable.FromArray(1, 2, 3, 4);
19 |
20 | var result = AsyncEnumerable.Zip(v => v.Sum(), source, source, source);
21 |
22 | await result.AssertResult(3, 6, 9, 12);
23 | }
24 |
25 | [Fact]
26 | public async Task DifferentLengths()
27 | {
28 | var source1 = AsyncEnumerable.FromArray(1, 2, 3, 4);
29 | var source2 = AsyncEnumerable.FromArray(1, 2, 3);
30 | var source3 = AsyncEnumerable.FromArray(1, 2, 3, 4, 5);
31 |
32 | var result = AsyncEnumerable.Zip(v => v.Sum(), source1, source2, source3);
33 |
34 | await result.AssertResult(3, 6, 9);
35 | }
36 |
37 | [Fact]
38 | public async Task Error_One()
39 | {
40 | await AsyncEnumerable.Zip(v => v.Sum(),
41 | AsyncEnumerable.Error(new InvalidOperationException()),
42 | AsyncEnumerable.Range(1, 5)
43 | )
44 | .AssertFailure(typeof(InvalidOperationException));
45 | }
46 |
47 | [Fact]
48 | public async Task Error_Both()
49 | {
50 | await AsyncEnumerable.Zip(v => v.Sum(),
51 | AsyncEnumerable.Error(new InvalidOperationException()),
52 | AsyncEnumerable.Error(new InvalidOperationException())
53 | )
54 | .AssertFailure(typeof(AggregateException));
55 | }
56 |
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet-test/async-enumerable-dotnet-test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0
5 | async_enumerable_dotnet_test
6 |
7 | false
8 |
9 | latest
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28010.2046
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "async-enumerable-dotnet", "async-enumerable-dotnet\async-enumerable-dotnet.csproj", "{12363CF4-3B69-4096-8807-E140D6C5AF72}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "async-enumerable-dotnet-test", "async-enumerable-dotnet-test\async-enumerable-dotnet-test.csproj", "{833B1173-D251-4FA9-A18F-D01F99DF8E2F}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "async-enumerable-dotnet-benchmark", "async-enumerable-dotnet-benchmark\async-enumerable-dotnet-benchmark.csproj", "{81929167-8990-418D-9838-8AFE3F7810D2}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {12363CF4-3B69-4096-8807-E140D6C5AF72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {12363CF4-3B69-4096-8807-E140D6C5AF72}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {12363CF4-3B69-4096-8807-E140D6C5AF72}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {12363CF4-3B69-4096-8807-E140D6C5AF72}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {833B1173-D251-4FA9-A18F-D01F99DF8E2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {833B1173-D251-4FA9-A18F-D01F99DF8E2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {833B1173-D251-4FA9-A18F-D01F99DF8E2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {833B1173-D251-4FA9-A18F-D01F99DF8E2F}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {81929167-8990-418D-9838-8AFE3F7810D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {81929167-8990-418D-9838-8AFE3F7810D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {81929167-8990-418D-9838-8AFE3F7810D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {81929167-8990-418D-9838-8AFE3F7810D2}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {65318B90-70B4-4DF6-9338-95014428192F}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet/IAsyncEmitter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | namespace async_enumerable_dotnet
10 | {
11 | ///
12 | /// Provides API for generating items.
13 | ///
14 | /// The element type.
15 | public interface IAsyncEmitter
16 | {
17 | ///
18 | /// Push an item and wait until the generator can proceed.
19 | ///
20 | /// The element to produce.
21 | /// The task that should be awaited before calling the method again.
22 | ValueTask Next(T value);
23 |
24 | ///
25 | /// Returns true if the consumer requested stopping a sequence.
26 | ///
27 | bool DisposeAsyncRequested { get; }
28 |
29 | ///
30 | /// Returns the CancellationToken instance supplied by the downstream.
31 | ///
32 | CancellationToken Token { get; }
33 | }
34 |
35 | ///
36 | /// The "push-side" of an IAsyncEnumerator.
37 | /// Each method should be awaited and called in a non-overlapping fashion.
38 | ///
39 | /// The element type.
40 | ///
41 | /// The protocol is Next* (Error | Complete)?
42 | ///
43 | public interface IAsyncConsumer
44 | {
45 | ///
46 | /// Push a value. Can be called multiple times.
47 | ///
48 | /// The value to push.
49 | /// The task to await before calling any of the methods again.
50 | ValueTask Next(T value);
51 |
52 | ///
53 | /// Push a final exception. Can be called at most once.
54 | ///
55 | /// The exception to push.
56 | /// The task to await before calling any of the methods again.
57 | ValueTask Error(Exception ex);
58 |
59 | ///
60 | /// Indicate no more items will be pushed. Can be called at most once.
61 | ///
62 | /// The task to await before calling any of the methods again.
63 | ValueTask Complete();
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet/IAsyncGroupedEnumerable.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System.Collections.Generic;
6 |
7 | namespace async_enumerable_dotnet
8 | {
9 | ///
10 | /// An IAsyncEnumerable with a key property to support grouping operations.
11 | ///
12 | /// The key type.
13 | /// The element type of the async sequence.
14 | public interface IAsyncGroupedEnumerable : IAsyncEnumerable
15 | {
16 | ///
17 | /// Returns the group key.
18 | ///
19 | // ReSharper disable once UnusedMemberInSuper.Global
20 | TKey Key
21 | {
22 | // ReSharper disable once UnusedMemberInSuper.Global
23 | get;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet/async-enumerable-dotnet.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0;netstandard2.1
5 | async_enumerable_dotnet
6 | true
7 | latest
8 | akarnokd.async-enumerable-dotnet
9 | 0.0.4.0
10 | David Karnok
11 |
12 | 0.0.4.0
13 | 0.0.4.0
14 | async, concurrency, async-enumerable, operators, async-sequence
15 | https://github.com/akarnokd/async-enumerable-dotnet
16 | https://github.com/akarnokd/async-enumerable-dotnet#getting-started
17 | Experimental operators for the C# 8 IAsyncEnumerables.
18 | (C) David Karnok
19 |
20 | Fix cancellation propagation with many operators
21 | Github
22 | Async Enumerable operators for .NET
23 | Apache-2.0
24 |
25 |
26 |
27 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet/impl/ArrayQueue.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using System.Runtime.CompilerServices;
7 |
8 | [assembly: InternalsVisibleTo("async-enumerable-dotnet-test")]
9 |
10 | namespace async_enumerable_dotnet.impl
11 | {
12 | internal struct ArrayQueue
13 | {
14 | private int _producerIndex;
15 | private int _consumerIndex;
16 |
17 | private T[] _array;
18 |
19 | internal ArrayQueue(int capacity)
20 | {
21 | _producerIndex = 0;
22 | _consumerIndex = 0;
23 | _array = new T[capacity];
24 | }
25 |
26 | internal void Enqueue(T item)
27 | {
28 | var pi = _producerIndex;
29 | var ci = _consumerIndex;
30 | var a = _array;
31 | var len = a.Length;
32 |
33 | a[pi] = item;
34 |
35 | pi = (pi + 1) & (len - 1);
36 | if (pi == ci)
37 | {
38 | var b = new T[len * 2];
39 | Array.Copy(a, ci, b, 0, len - ci);
40 | Array.Copy(a, 0, b, len - ci, ci);
41 | _array = b;
42 | _consumerIndex = 0;
43 | _producerIndex = len;
44 | }
45 | else
46 | {
47 | _producerIndex = pi;
48 | }
49 | }
50 |
51 | internal bool Dequeue(out T item)
52 | {
53 | var pi = _producerIndex;
54 | var ci = _consumerIndex;
55 | var a = _array;
56 | var len = a.Length;
57 |
58 | if (pi == ci)
59 | {
60 | item = default;
61 | return false;
62 | }
63 | item = a[ci];
64 | a[ci] = default;
65 | _consumerIndex = (ci + 1) & (len - 1);
66 | return true;
67 | }
68 |
69 | internal void Release()
70 | {
71 | _array = null;
72 | }
73 |
74 | internal void ForEach(TState state, Action onEach)
75 | {
76 | var ci = _consumerIndex;
77 | var pi = _producerIndex;
78 | var a = _array;
79 | var len = a.Length;
80 |
81 | while (ci != pi)
82 | {
83 | onEach(a[ci], state);
84 | ci = (ci + 1) & (len - 1);
85 | }
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet/impl/CancellationHelper.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System.Threading;
6 |
7 | namespace async_enumerable_dotnet.impl
8 | {
9 | ///
10 | /// Utility class to work with CancellationTokenSources atomically.
11 | ///
12 | internal static class CancellationHelper
13 | {
14 | ///
15 | /// The cancelled indicator, do not leak!
16 | ///
17 | internal static readonly CancellationTokenSource Cancelled = new CancellationTokenSource();
18 |
19 | ///
20 | /// Atomically replace an old CancellationTokenSource within the field
21 | /// or cancel the new token source if the field contains the Cancelled indicator.
22 | ///
23 | /// The target field
24 | /// The new cancellation token source to swap in.
25 | /// True if successful, false if the field contains the Cancelled indicator
26 | internal static bool Replace(ref CancellationTokenSource field, CancellationTokenSource cts)
27 | {
28 | for (; ; )
29 | {
30 | var a = Volatile.Read(ref field);
31 | if (a == Cancelled)
32 | {
33 | cts?.Cancel();
34 | return false;
35 | }
36 | if (Interlocked.CompareExchange(ref field, cts, a) == a)
37 | {
38 | return true;
39 | }
40 | }
41 | }
42 |
43 | ///
44 | /// Atomically swap in the Cancelled indicator and cancel the
45 | /// current token source if any.
46 | ///
47 | /// The target field.
48 | /// True if the cancel happened
49 | internal static bool Cancel(ref CancellationTokenSource field)
50 | {
51 | if (Volatile.Read(ref field) != Cancelled)
52 | {
53 | var old = Interlocked.Exchange(ref field, Cancelled);
54 | if (old != Cancelled)
55 | {
56 | old?.Cancel();
57 | return true;
58 | }
59 | }
60 | return false;
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet/impl/Collect.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using System.Threading.Tasks;
7 | using System.Collections.Generic;
8 | using System.Threading;
9 |
10 | namespace async_enumerable_dotnet.impl
11 | {
12 | internal sealed class Collect : IAsyncEnumerable
13 | {
14 | private readonly IAsyncEnumerable _source;
15 |
16 | private readonly Func _collectionSupplier;
17 |
18 | private readonly Action _collector;
19 |
20 | public Collect(IAsyncEnumerable source, Func collectionSupplier, Action collector)
21 | {
22 | _source = source;
23 | _collectionSupplier = collectionSupplier;
24 | _collector = collector;
25 | }
26 |
27 | public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken)
28 | {
29 | TCollection initial;
30 | try
31 | {
32 | initial = _collectionSupplier();
33 | }
34 | catch (Exception ex)
35 | {
36 | return new Error.ErrorEnumerator(ex);
37 | }
38 | return new CollectEnumerator(_source.GetAsyncEnumerator(cancellationToken), initial, _collector);
39 | }
40 |
41 | private sealed class CollectEnumerator : IAsyncEnumerator
42 | {
43 | private readonly IAsyncEnumerator _source;
44 |
45 | private readonly Action _collector;
46 |
47 | private bool _once;
48 |
49 | public TCollection Current { get; private set; }
50 |
51 | public CollectEnumerator(IAsyncEnumerator source, TCollection collection, Action collector)
52 | {
53 | _source = source;
54 | Current = collection;
55 | _collector = collector;
56 | }
57 |
58 | public ValueTask DisposeAsync()
59 | {
60 | return _source.DisposeAsync();
61 | }
62 |
63 | public async ValueTask MoveNextAsync()
64 | {
65 | if (_once)
66 | {
67 | Current = default;
68 | return false;
69 | }
70 | _once = true;
71 |
72 | while (await _source.MoveNextAsync())
73 | {
74 | _collector(Current, _source.Current);
75 | }
76 |
77 | return true;
78 | }
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet/impl/Count.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System.Threading.Tasks;
6 | using System.Collections.Generic;
7 | using System.Threading;
8 |
9 | namespace async_enumerable_dotnet.impl
10 | {
11 | internal sealed class Count : IAsyncEnumerable
12 | {
13 | private readonly IAsyncEnumerable _source;
14 |
15 | public Count(IAsyncEnumerable source)
16 | {
17 | _source = source;
18 | }
19 |
20 | public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken)
21 | {
22 | return new CountEnumerator(_source.GetAsyncEnumerator(cancellationToken));
23 | }
24 |
25 | private sealed class CountEnumerator : IAsyncEnumerator
26 | {
27 | private readonly IAsyncEnumerator _source;
28 |
29 | public long Current { get; private set; }
30 |
31 | private bool _once;
32 |
33 | public CountEnumerator(IAsyncEnumerator source)
34 | {
35 | _source = source;
36 | }
37 |
38 | public ValueTask DisposeAsync()
39 | {
40 | return _source.DisposeAsync();
41 | }
42 |
43 | public async ValueTask MoveNextAsync()
44 | {
45 | if (_once)
46 | {
47 | return false;
48 | }
49 |
50 | var n = 0L;
51 |
52 | while (await _source.MoveNextAsync())
53 | {
54 | n++;
55 | }
56 |
57 | Current = n;
58 | _once = true;
59 | return true;
60 | }
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/async-enumerable-dotnet/impl/DefaultIfEmpty.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System.Threading.Tasks;
6 | using System.Collections.Generic;
7 | using System.Threading;
8 |
9 | namespace async_enumerable_dotnet.impl
10 | {
11 | internal sealed class DefaultIfEmpty : IAsyncEnumerable
12 | {
13 | private readonly IAsyncEnumerable _source;
14 |
15 | private readonly T _defaultItem;
16 |
17 | public DefaultIfEmpty(IAsyncEnumerable source, T defaultItem)
18 | {
19 | _source = source;
20 | _defaultItem = defaultItem;
21 | }
22 |
23 | public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken)
24 | {
25 | return new DefaultIfEmptyEnumerator(_source.GetAsyncEnumerator(cancellationToken), _defaultItem);
26 | }
27 |
28 | private sealed class DefaultIfEmptyEnumerator : IAsyncEnumerator
29 | {
30 | private IAsyncEnumerator _source;
31 |
32 | private readonly T _defaultItem;
33 |
34 | private bool _hasItems;
35 |
36 | public T Current
37 | {
38 | get
39 | {
40 | if (_source != null)
41 | {
42 | return _source.Current;
43 | }
44 | return _defaultItem;
45 | }
46 | }
47 |
48 | public DefaultIfEmptyEnumerator(IAsyncEnumerator source, T defaultItem)
49 | {
50 | _source = source;
51 | _defaultItem = defaultItem;
52 | }
53 |
54 | public ValueTask DisposeAsync()
55 | {
56 | if (_source != null)
57 | {
58 | return _source.DisposeAsync();
59 | }
60 | return new ValueTask();
61 | }
62 |
63 | public async ValueTask MoveNextAsync()
64 | {
65 | if (_source == null)
66 | {
67 | return false;
68 | }
69 | if (await _source.MoveNextAsync())
70 | {
71 | _hasItems = true;
72 | return true;
73 | }
74 |
75 | if (!_hasItems)
76 | {
77 | await _source.DisposeAsync();
78 | _source = null;
79 | _hasItems = true;
80 | return true;
81 | }
82 | return false;
83 | }
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet/impl/Defer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Threading;
8 |
9 | namespace async_enumerable_dotnet.impl
10 | {
11 | internal sealed class Defer : IAsyncEnumerable
12 | {
13 | private readonly Func> _func;
14 |
15 | public Defer(Func> func)
16 | {
17 | _func = func;
18 | }
19 |
20 | public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken)
21 | {
22 | IAsyncEnumerator en;
23 | try
24 | {
25 | en = _func().GetAsyncEnumerator(cancellationToken);
26 | }
27 | catch (Exception ex)
28 | {
29 | en = new Error.ErrorEnumerator(ex);
30 | }
31 | return en;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet/impl/Distinct.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet.impl
11 | {
12 | internal sealed class Distinct : IAsyncEnumerable
13 | {
14 | private readonly IAsyncEnumerable _source;
15 |
16 | private readonly Func _keySelector;
17 |
18 | private readonly Func> _collectionSupplier;
19 |
20 | public Distinct(IAsyncEnumerable source, Func keySelector, Func> collectionSupplier)
21 | {
22 | _source = source;
23 | _keySelector = keySelector;
24 | _collectionSupplier = collectionSupplier;
25 | }
26 |
27 | public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken)
28 | {
29 | ISet collection;
30 |
31 | try
32 | {
33 | collection = _collectionSupplier();
34 | }
35 | catch (Exception ex)
36 | {
37 | return new Error.ErrorEnumerator(ex);
38 | }
39 | return new DistinctEnumerator(_source.GetAsyncEnumerator(cancellationToken), _keySelector, collection);
40 | }
41 |
42 | private sealed class DistinctEnumerator : IAsyncEnumerator
43 | {
44 | private readonly IAsyncEnumerator _source;
45 |
46 | private readonly Func _keySelector;
47 |
48 | private ISet _collection;
49 |
50 | public TSource Current => _source.Current;
51 |
52 | public DistinctEnumerator(IAsyncEnumerator source, Func keySelector, ISet collection)
53 | {
54 | _source = source;
55 | _keySelector = keySelector;
56 | _collection = collection;
57 | }
58 |
59 | public ValueTask DisposeAsync()
60 | {
61 | _collection = default;
62 | return _source.DisposeAsync();
63 | }
64 |
65 | public async ValueTask MoveNextAsync()
66 | {
67 | for (; ; )
68 | {
69 | if (await _source.MoveNextAsync())
70 | {
71 | if (_collection.Add(_keySelector(_source.Current)))
72 | {
73 | return true;
74 | }
75 | }
76 | else
77 | {
78 | return false;
79 | }
80 | }
81 | }
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet/impl/DistinctUntilChanged.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace async_enumerable_dotnet.impl
11 | {
12 | internal sealed class DistinctUntilChanged : IAsyncEnumerable
13 | {
14 | private readonly IAsyncEnumerable _source;
15 |
16 | private readonly Func _keySelector;
17 |
18 | private readonly IEqualityComparer _keyComparer;
19 |
20 | public DistinctUntilChanged(IAsyncEnumerable source, Func keySelector, IEqualityComparer keyComparer)
21 | {
22 | _source = source;
23 | _keySelector = keySelector;
24 | _keyComparer = keyComparer;
25 | }
26 |
27 | public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken)
28 | {
29 | return new DistinctUntilChangedEnumerator(_source.GetAsyncEnumerator(cancellationToken), _keySelector, _keyComparer);
30 | }
31 |
32 | private sealed class DistinctUntilChangedEnumerator : IAsyncEnumerator
33 | {
34 | private readonly IAsyncEnumerator _source;
35 |
36 | private readonly Func _keySelector;
37 |
38 | private readonly IEqualityComparer _keyComparer;
39 |
40 | private TKey _prevKey;
41 |
42 | public TSource Current => _source.Current;
43 |
44 | private bool _once;
45 |
46 | public DistinctUntilChangedEnumerator(IAsyncEnumerator source, Func keySelector, IEqualityComparer keyComparer)
47 | {
48 | _source = source;
49 | _keySelector = keySelector;
50 | _keyComparer = keyComparer;
51 | }
52 |
53 | public ValueTask DisposeAsync()
54 | {
55 | _prevKey = default;
56 | return _source.DisposeAsync();
57 | }
58 |
59 | public async ValueTask MoveNextAsync()
60 | {
61 | for (; ;)
62 | {
63 | if (await _source.MoveNextAsync())
64 | {
65 | var key = _keySelector(_source.Current);
66 | if (!_once)
67 | {
68 | _once = true;
69 | _prevKey = key;
70 | return true;
71 | }
72 | if (!_keyComparer.Equals(_prevKey, key))
73 | {
74 | _prevKey = key;
75 | return true;
76 | }
77 |
78 | _prevKey = key;
79 | }
80 | else
81 | {
82 | return false;
83 | }
84 | }
85 | }
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet/impl/DoOnNext.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using System.Threading.Tasks;
7 | using System.Collections.Generic;
8 | using System.Threading;
9 |
10 | namespace async_enumerable_dotnet.impl
11 | {
12 | internal sealed class DoOnNext : IAsyncEnumerable
13 | {
14 | private readonly IAsyncEnumerable _source;
15 |
16 | private readonly Action _handler;
17 |
18 | public DoOnNext(IAsyncEnumerable source, Action handler)
19 | {
20 | _source = source;
21 | _handler = handler;
22 | }
23 |
24 | public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken)
25 | {
26 | return new DoOnNextEnumerator(_source.GetAsyncEnumerator(cancellationToken), _handler);
27 | }
28 |
29 | private sealed class DoOnNextEnumerator : IAsyncEnumerator
30 | {
31 | private readonly IAsyncEnumerator _source;
32 |
33 | private readonly Action _handler;
34 |
35 | public DoOnNextEnumerator(IAsyncEnumerator source, Action handler)
36 | {
37 | _source = source;
38 | _handler = handler;
39 | }
40 |
41 | public T Current => _source.Current;
42 |
43 | public ValueTask DisposeAsync()
44 | {
45 | return _source.DisposeAsync();
46 | }
47 |
48 | public async ValueTask MoveNextAsync()
49 | {
50 | if (await _source.MoveNextAsync())
51 | {
52 | _handler(_source.Current);
53 | return true;
54 | }
55 | return false;
56 | }
57 | }
58 | }
59 |
60 | internal sealed class DoOnNextAsync : IAsyncEnumerable
61 | {
62 | private readonly IAsyncEnumerable _source;
63 |
64 | private readonly Func _handler;
65 |
66 | public DoOnNextAsync(IAsyncEnumerable source, Func handler)
67 | {
68 | _source = source;
69 | _handler = handler;
70 | }
71 |
72 | public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken)
73 | {
74 | return new DoOnNextAsyncEnumerator(_source.GetAsyncEnumerator(cancellationToken), _handler);
75 | }
76 |
77 | private sealed class DoOnNextAsyncEnumerator : IAsyncEnumerator
78 | {
79 | private readonly IAsyncEnumerator _source;
80 |
81 | private readonly Func _handler;
82 |
83 | public DoOnNextAsyncEnumerator(IAsyncEnumerator source, Func handler)
84 | {
85 | _source = source;
86 | _handler = handler;
87 | }
88 |
89 | public T Current => _source.Current;
90 |
91 | public ValueTask DisposeAsync()
92 | {
93 | return _source.DisposeAsync();
94 | }
95 |
96 | public async ValueTask MoveNextAsync()
97 | {
98 | if (await _source.MoveNextAsync())
99 | {
100 | await _handler(_source.Current);
101 | return true;
102 | }
103 | return false;
104 | }
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/async-enumerable-dotnet/impl/ElementAt.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) David Karnok & Contributors.
2 | // Licensed under the Apache 2.0 License.
3 | // See LICENSE file in the project root for full license information.
4 |
5 | using System;
6 | using System.Threading.Tasks;
7 | using System.Collections.Generic;
8 | using System.Threading;
9 |
10 | namespace async_enumerable_dotnet.impl
11 | {
12 | internal sealed class ElementAt : IAsyncEnumerable
13 | {
14 | private readonly IAsyncEnumerable