public void CanCancelMoveNext() { var xs = new CancellationTestAsyncEnumerable().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(WaitTimeoutMs); Assert.True(false); } catch { Assert.True(t.IsCanceled); } }
public async Task CorrectCancel() { var disposed = new TaskCompletionSource <bool>(); var xs = new CancellationTestAsyncEnumerable().WithDispose(() => { disposed.TrySetResult(true); }); 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(WaitTimeoutMs); } 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. var result = await disposed.Task; Assert.True(result); } Assert.False(await e.MoveNext()); }