123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
- #if !NO_TPL
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
- using System.Collections;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Diagnostics;
- //using System.Reactive.Linq;
- //using System.Reactive.Concurrency;
- namespace Tests
- {
- public partial class AsyncTests
- {
- [TestInitialize]
- public void InitTests()
- {
- TaskScheduler.UnobservedTaskException += (o, e) =>
- {
- };
- }
- /*
- [TestMethod]
- public void TestPushPopAsync()
- {
- var stack = new Stack<int>();
- var count = 10;
- var observable = Observable.Generate(
- 0,
- i => i < count,
- i => i + 1,
- i => i,
- i => TimeSpan.FromMilliseconds(1), // change this to 0 to avoid the problem [1]
- Scheduler.ThreadPool);
- var task = DoSomethingAsync(observable, stack);
- // we give it a timeout so the test can fail instead of hang
- task.Wait(TimeSpan.FromSeconds(2));
- Assert.AreEqual(10, stack.Count);
- }
- private Task DoSomethingAsync(IObservable<int> observable, Stack<int> stack)
- {
- var ae = observable
- .ToAsyncEnumerable()
- //.Do(i => Debug.WriteLine("Bug-fixing side effect: " + i)) // [2]
- .GetEnumerator();
- var tcs = new TaskCompletionSource<object>();
- var a = default(Action);
- a = new Action(() =>
- {
- ae.MoveNext().ContinueWith(t =>
- {
- if (t.Result)
- {
- var i = ae.Current;
- Debug.WriteLine("Doing something with " + i);
- Thread.Sleep(50);
- stack.Push(i);
- a();
- }
- else
- tcs.TrySetResult(null);
- });
- });
- a();
- return tcs.Task;
- }
- */
- static IEnumerable<int> Xs(Action a)
- {
- try
- {
- var rnd = new Random();
- while (true)
- {
- yield return rnd.Next(0, 43);
- Thread.Sleep(rnd.Next(0, 500));
- }
- }
- finally
- {
- a();
- }
- }
- [TestMethod]
- public void CorrectDispose()
- {
- var disposed = false;
- var xs = new[] { 1, 2, 3 }.WithDispose(() =>
- {
- disposed = true;
- }).ToAsyncEnumerable();
- var ys = xs.Select(x => x + 1);
- var e = ys.GetEnumerator();
- e.Dispose();
- Assert.IsTrue(disposed);
- Assert.IsFalse(e.MoveNext().Result);
- }
- [TestMethod]
- public void DisposesUponError()
- {
- var disposed = false;
- var xs = new[] { 1, 2, 3 }.WithDispose(() =>
- {
- disposed = true;
- }).ToAsyncEnumerable();
- var ex = new Exception("Bang!");
- var ys = xs.Select(x => { if (x == 1) throw ex; return x; });
- var e = ys.GetEnumerator();
- AssertThrows<Exception>(() => e.MoveNext());
- Assert.IsTrue(disposed);
- }
- [TestMethod]
- public void CorrectCancel()
- {
- var disposed = false;
- var xs = new[] { 1, 2, 3 }.WithDispose(() =>
- {
- disposed = true;
- }).ToAsyncEnumerable();
- var ys = xs.Select(x => x + 1).Where(x => true);
- var e = ys.GetEnumerator();
- var cts = new CancellationTokenSource();
- var t = e.MoveNext(cts.Token);
- cts.Cancel();
- try
- {
- t.Wait();
- }
- catch
- {
- // Don't care about the outcome; we could have made it to element 1
- // but we could also have cancelled the MoveNext-calling task. Either
- // way, we want to wait for the task to be completed and check that
- }
- finally
- {
- // the cancellation bubbled all the way up to the source to dispose
- // it. This design is chosen because cancelling a MoveNext call leaves
- // the enumerator in an indeterminate state. Further interactions with
- // it should be forbidden.
- Assert.IsTrue(disposed);
- }
- Assert.IsFalse(e.MoveNext().Result);
- }
- [TestMethod]
- public void CanCancelMoveNext()
- {
- var evt = new ManualResetEvent(false);
- var xs = Blocking(evt).ToAsyncEnumerable().Select(x => x).Where(x => true);
- var e = xs.GetEnumerator();
- var cts = new CancellationTokenSource();
- var t = e.MoveNext(cts.Token);
- cts.Cancel();
- try
- {
- t.Wait();
- Assert.Fail();
- }
- catch
- {
- Assert.IsTrue(t.IsCanceled);
- }
- evt.Set();
- }
- static IEnumerable<int> Blocking(ManualResetEvent evt)
- {
- evt.WaitOne();
- yield return 42;
- }
- }
- static class MyExt
- {
- public static IEnumerable<T> WithDispose<T>(this IEnumerable<T> source, Action a)
- {
- return EnumerableEx.Create(() =>
- {
- var e = source.GetEnumerator();
- return new Enumerator<T>(e.MoveNext, () => e.Current, () => { e.Dispose(); a(); });
- });
- }
- class Enumerator<T> : IEnumerator<T>
- {
- private readonly Func<bool> _moveNext;
- private readonly Func<T> _current;
- private readonly Action _dispose;
- public Enumerator(Func<bool> moveNext, Func<T> current, Action dispose)
- {
- _moveNext = moveNext;
- _current = current;
- _dispose = dispose;
- }
- public T Current
- {
- get { return _current(); }
- }
- public void Dispose()
- {
- _dispose();
- }
- object IEnumerator.Current
- {
- get { return Current; }
- }
- public bool MoveNext()
- {
- return _moveNext();
- }
- public void Reset()
- {
- throw new NotImplementedException();
- }
- }
- }
- }
- #endif
|