public static Task Run <T>( this CoroutineProxy <T> @this, IAsyncApartment apartment, Func <CancellationToken, IAsyncEnumerable <T> > routine, CancellationToken token) { return(apartment.Run( () => @this.Run(routine, token), token)); }
public async Task test_two_coroutines_execution_flow() { // Here we execute two cotoutines, CoroutineA and CoroutineB, // which asynchronously yield to each other //TODO: test cancellation scenarios var token = CancellationToken.None; // use ThreadPoolApartment to impose asynchronous continuations for all awaits, // regardless if the task has completed synchronously // the reasoning behind this is essentially the same as for // the TaskContinuationOptions.RunContinuationsAsynchronously option: // https://tinyurl.com/RunContinuationsAsynchronously await using var apartment = new Tests.ThreadPoolApartment(); await apartment.Run(async() => { var proxyA = new CoroutineProxy <string>(); var proxyB = new CoroutineProxy <string>(); var listener = new Tests.CategoryTraceListener(TRACE_CATEGORY); Trace.Listeners.Add(listener); try { // start both coroutines await Task.WhenAll( proxyA.Run(token => CoroutineA(proxyB, token), token), proxyB.Run(token => CoroutineB(proxyA, token), token)) .WithAggregatedExceptions(); } finally { Trace.Listeners.Remove(listener); } var traces = listener.ToArray(); Assert.AreEqual(traces[0], "A about to yeild: 1"); Assert.AreEqual(traces[1], "B received: 1 from A"); Assert.AreEqual(traces[2], "B about to yeild: 1"); Assert.AreEqual(traces[3], "A received: 1 from B"); Assert.AreEqual(traces[4], "A about to yeild: 2"); Assert.AreEqual(traces[5], "B received: 2 from A"); Assert.AreEqual(traces[6], "B about to yeild: 2"); Assert.AreEqual(traces[7], "A received: 2 from B"); Assert.AreEqual(traces[8], "A about to yeild: 3"); Assert.AreEqual(traces[9], "B received: 3 from A"); }); }