public async Task DisposeAfterPartialEnumeration()
        {
            // ARRANGE

            var testDisposable = new TestDisposable();
            var enumerator     = new AsyncEnumerator <int>(async yield =>
            {
                using (testDisposable)
                {
                    await yield.ReturnAsync(1);
                    await yield.ReturnAsync(2);
                    await yield.ReturnAsync(3);
                }
            });

            // ACT

            await enumerator.MoveNextAsync();

            enumerator.Dispose();

            // ASSERT

            Assert.IsTrue(testDisposable.HasDisposed);
        }
        public async Task DisposeByGCAfterPartialEnumeration()
        {
            // ARRANGE

            var testDisposable = new TestDisposable();

            var enumerator = new AsyncEnumerator <int>(async yield =>
            {
                using (testDisposable)
                {
                    await yield.ReturnAsync(1);
                    await yield.ReturnAsync(2);
                    await yield.ReturnAsync(3);
                }
            });

            // ACT

            // Do partial enumeration.
            await enumerator.MoveNextAsync();

            // Instead of calling enumerator.Dispose(), do garbage collection.
            enumerator = null;
            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true);

            // Give some time to other thread that does the disposal of the enumerator.
            // (see finalizer of the AsyncEnumerator for details)
            await Task.Delay(16);

            // ASSERT

            Assert.IsTrue(testDisposable.HasDisposed);
        }
        public async Task YieldBreak()
        {
            // ARRANGE

            var asyncEnumerationCanceledExceptionRaised = false;

            var enumerator = new AsyncEnumerator <int>(async yield =>
            {
                try
                {
                    yield.Break();
                }
                catch (AsyncEnumerationCanceledException)
                {
                    asyncEnumerationCanceledExceptionRaised = true;
                }

                await yield.ReturnAsync(1);
            });

            // ACT

            var result = await enumerator.MoveNextAsync();

            await Task.Yield();

            // ASSERT

            Assert.IsFalse(result, "MoveNextAsync must return False due to Yield.Break");
            Assert.IsTrue(asyncEnumerationCanceledExceptionRaised, "Yield.Break must throw AsyncEnumerationCanceledException so the enumerator body can perform finalization");
        }
Esempio n. 4
0
        public void OnDisposeMustBeCalledOnGcWhenEnumerationHasNotBeenStarted()
        {
            // ARRANGE

            var testDisposable = new TestDisposable();

            void CreateEnumerator()
            {
                var enumerator = new AsyncEnumerator <int>(async yield =>
                {
                    await yield.ReturnAsync(1);
                },
                                                           onDispose: () => testDisposable.Dispose());
            }

            // ACT

            CreateEnumerator();
            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true);
            Thread.Sleep(16);

            // ASSERT

            Assert.IsTrue(testDisposable.HasDisposed);
        }
Esempio n. 5
0
        public void ToObservable_DisposesEnumeratorOnCompletion()
        {
            var fail = false;
            var evt  = new ManualResetEvent(false);

            var ae = AsyncEnumerable.Create(
                _ => AsyncEnumerator.Create <int>(
                    () => new ValueTask <bool>(false),
                    () => { throw new InvalidOperationException(); },
                    () => { evt.Set(); return(default); }));
        public void CancelEnumeration()
        {
            var cts = new CancellationTokenSource();

            var enumerator = new AsyncEnumerator <int>(yield =>
            {
                cts.Cancel();
                yield.CancellationToken.ThrowIfCancellationRequested();
                return(Task.FromResult(0));
            });

            Assert.ThrowsAsync <OperationCanceledException>(() => enumerator.MoveNextAsync(cts.Token));
        }
        public async Task RaceConditionOnEndOfEnumeration()
        {
            var enumerator = new AsyncEnumerator <int>(async yield =>
            {
                await Task.Run(async() =>
                {
                    await yield.ReturnAsync(1);
                });
            });

            var moveResult1 = await enumerator.MoveNextAsync();

            var moveResult2 = await enumerator.MoveNextAsync();

            var moveResult3 = await enumerator.MoveNextAsync();

            Assert.IsTrue(moveResult1);
            Assert.IsFalse(moveResult2);
            Assert.IsFalse(moveResult3);
        }
        public void OnDisposeActionIsCalled()
        {
            // ARRANGE

            var testDisposable = new TestDisposable();

            var enumerator = new AsyncEnumerator <int>(async yield =>
            {
                await yield.ReturnAsync(1);
            },
                                                       onDispose: () => testDisposable.Dispose());

            // ACT

            enumerator.Dispose();

            // ASSERT

            Assert.IsTrue(testDisposable.HasDisposed);
        }
Esempio n. 9
0
        protected static IAsyncEnumerable <TValue> Throw <TValue>(Exception exception)
        {
            if (exception == null)
            {
                throw new ArgumentNullException(nameof(exception));
            }

#if NO_TASK_FROMEXCEPTION
            var tcs = new TaskCompletionSource <bool>();
            tcs.TrySetException(exception);
            var moveNextThrows = new ValueTask <bool>(tcs.Task);
#else
            var moveNextThrows = new ValueTask <bool>(Task.FromException <bool>(exception));
#endif

            return(AsyncEnumerable.Create(
                       _ => AsyncEnumerator.Create <TValue>(
                           () => moveNextThrows,
                           getCurrent: null,
                           disposeAsync: null)
                       ));
        }
        public async Task EnumerationMustEndAfterDispose()
        {
            // ARRANGE

            var enumerator = new AsyncEnumerator <int>(async yield =>
            {
                await yield.ReturnAsync(1);
                await yield.ReturnAsync(2);
            });

            await enumerator.MoveNextAsync();

            // ACT

            enumerator.Dispose();
            bool moveNextResult = await enumerator.MoveNextAsync();

            int currentElement = enumerator.Current;

            // ASSERT

            Assert.IsFalse(moveNextResult, "MoveNextAsync must return False after Dispose");
            Assert.AreEqual(1, currentElement, "Current must not change after Dispose");
        }
        public async Task MeasureEnumerationTime()
        {
            var iterations = 1000000;
            var enumerator = new AsyncEnumerator <int>(async yield =>
            {
                for (int i = 0; i < iterations; i++)
                {
                    await yield.ReturnAsync(1);
                }
            });

            var sw  = Stopwatch.StartNew();
            int sum = 0;

            while (await enumerator.MoveNextAsync())
            {
                sum += enumerator.Current;
            }

            var time = sw.Elapsed;

            Console.WriteLine($"Time taken: {time},   Sum: {sum}");



            sw  = Stopwatch.StartNew();
            sum = 0;

            foreach (var number in EnumerateNumbers())
            {
                sum += number;
            }

            time = sw.Elapsed;
            Console.WriteLine($"Time taken: {time},   Sum: {sum}");



            sw  = Stopwatch.StartNew();
            sum = 0;

            int _lock = 0;

            for (int i = 0; i < iterations; i++)
            {
                Interlocked.CompareExchange(ref _lock, 1, 0);
                var tcs = new TaskCompletionSource <int>();
                tcs.TrySetResult(1);
                sum += await tcs.Task;
                //await Task.Yield();
                //await Task.Yield();
                Interlocked.Exchange(ref _lock, 0);
            }

            time = sw.Elapsed;
            Console.WriteLine($"Time taken: {time},   Sum: {sum}");



            sw  = Stopwatch.StartNew();
            sum = 0;

            var t = Task.FromResult(1);

            for (int i = 0; i < iterations; i++)
            {
                sum += await t;
            }

            time = sw.Elapsed;
            Console.WriteLine($"Time taken: {time},   Sum: {sum}");
        }