// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Linq; using System.Reactive.Concurrency; using System.Reactive.Disposables; using System.Reactive.Linq; using System.Threading; using Microsoft.Reactive.Testing; #if NUNIT using NUnit.Framework; using TestClassAttribute = NUnit.Framework.TestFixtureAttribute; using TestMethodAttribute = NUnit.Framework.TestAttribute; using TestInitializeAttribute = NUnit.Framework.SetUpAttribute; #else using Microsoft.VisualStudio.TestTools.UnitTesting; #endif using ReactiveTests.Dummies; #if !NO_TPL using System.Threading.Tasks; #endif namespace ReactiveTests.Tests { [TestClass] public partial class ObservableImperativeTest : ReactiveTest { #region ForEachAsync #if !NO_TPL [TestMethod] public void ForEachAsync_ArgumentChecking() { ReactiveAssert.Throws(() => Observable.ForEachAsync(default(IObservable), x => { })); ReactiveAssert.Throws(() => Observable.ForEachAsync(Observable.Never(), default(Action))); ReactiveAssert.Throws(() => Observable.ForEachAsync(default(IObservable), x => { }, CancellationToken.None)); ReactiveAssert.Throws(() => Observable.ForEachAsync(Observable.Never(), default(Action), CancellationToken.None)); ReactiveAssert.Throws(() => Observable.ForEachAsync(default(IObservable), (x, i) => { })); ReactiveAssert.Throws(() => Observable.ForEachAsync(Observable.Never(), default(Action))); ReactiveAssert.Throws(() => Observable.ForEachAsync(default(IObservable), (x, i) => { }, CancellationToken.None)); ReactiveAssert.Throws(() => Observable.ForEachAsync(Observable.Never(), default(Action), CancellationToken.None)); } [TestMethod] public void ForEachAsync_Never() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(100, 1), OnNext(200, 2), OnNext(300, 3), OnNext(400, 4), OnNext(500, 5) ); var task = default(Task); var cts = new CancellationTokenSource(); var list = new List>(); scheduler.ScheduleAbsolute(150, () => task = xs.ForEachAsync(x => list.Add(new Recorded(scheduler.Clock, x)), cts.Token)); scheduler.Start(); xs.Subscriptions.AssertEqual( Subscribe(150) ); list.AssertEqual( new Recorded(200, 2), new Recorded(300, 3), new Recorded(400, 4), new Recorded(500, 5) ); Assert.AreEqual(TaskStatus.WaitingForActivation, task.Status); } [TestMethod] public void ForEachAsync_Completed() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(100, 1), OnNext(200, 2), OnNext(300, 3), OnNext(400, 4), OnNext(500, 5), OnCompleted(600) ); var task = default(Task); var cts = new CancellationTokenSource(); var list = new List>(); scheduler.ScheduleAbsolute(150, () => task = xs.ForEachAsync(x => list.Add(new Recorded(scheduler.Clock, x)), cts.Token)); scheduler.Start(); xs.Subscriptions.AssertEqual( Subscribe(150, 600) ); list.AssertEqual( new Recorded(200, 2), new Recorded(300, 3), new Recorded(400, 4), new Recorded(500, 5) ); Assert.AreEqual(TaskStatus.RanToCompletion, task.Status); } [TestMethod] public void ForEachAsync_Error() { var scheduler = new TestScheduler(); var exception = new Exception(); var xs = scheduler.CreateHotObservable( OnNext(100, 1), OnNext(200, 2), OnNext(300, 3), OnNext(400, 4), OnNext(500, 5), OnError(600, exception) ); var task = default(Task); var cts = new CancellationTokenSource(); var list = new List>(); scheduler.ScheduleAbsolute(150, () => task = xs.ForEachAsync(x => list.Add(new Recorded(scheduler.Clock, x)), cts.Token)); scheduler.Start(); xs.Subscriptions.AssertEqual( Subscribe(150, 600) ); list.AssertEqual( new Recorded(200, 2), new Recorded(300, 3), new Recorded(400, 4), new Recorded(500, 5) ); Assert.AreEqual(TaskStatus.Faulted, task.Status); Assert.AreSame(exception, task.Exception.InnerException); } [TestMethod] public void ForEachAsync_Throw() { var scheduler = new TestScheduler(); var exception = new Exception(); var xs = scheduler.CreateHotObservable( OnNext(100, 1), OnNext(200, 2), OnNext(300, 3), OnNext(400, 4), OnNext(500, 5), OnCompleted(600) ); var task = default(Task); var cts = new CancellationTokenSource(); var list = new List>(); scheduler.ScheduleAbsolute(150, () => task = xs.ForEachAsync(x => { if (scheduler.Clock > 400) throw exception; list.Add(new Recorded(scheduler.Clock, x)); }, cts.Token)); scheduler.Start(); xs.Subscriptions.AssertEqual( Subscribe(150, 500) ); list.AssertEqual( new Recorded(200, 2), new Recorded(300, 3), new Recorded(400, 4) ); Assert.AreEqual(TaskStatus.Faulted, task.Status); Assert.AreSame(exception, task.Exception.InnerException); } [TestMethod] public void ForEachAsync_CancelDuring() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(100, 1), OnNext(200, 2), OnNext(300, 3), OnNext(400, 4), OnNext(500, 5), OnCompleted(600) ); var task = default(Task); var cts = new CancellationTokenSource(); var list = new List>(); scheduler.ScheduleAbsolute(150, () => task = xs.ForEachAsync(x => list.Add(new Recorded(scheduler.Clock, x)), cts.Token)); scheduler.ScheduleAbsolute(350, () => cts.Cancel()); scheduler.Start(); xs.Subscriptions.AssertEqual( Subscribe(150, 350) ); list.AssertEqual( new Recorded(200, 2), new Recorded(300, 3) ); Assert.AreEqual(TaskStatus.Canceled, task.Status); } [TestMethod] public void ForEachAsync_CancelBefore() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(100, 1), OnNext(200, 2), OnNext(300, 3), OnNext(400, 4), OnNext(500, 5), OnCompleted(600) ); var task = default(Task); var cts = new CancellationTokenSource(); var list = new List>(); cts.Cancel(); scheduler.ScheduleAbsolute(150, () => task = xs.ForEachAsync(x => list.Add(new Recorded(scheduler.Clock, x)), cts.Token)); scheduler.Start(); xs.Subscriptions.AssertEqual( ); list.AssertEqual( ); Assert.AreEqual(TaskStatus.Canceled, task.Status); } [TestMethod] public void ForEachAsync_CancelAfter() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(100, 1), OnNext(200, 2), OnNext(300, 3), OnNext(400, 4), OnNext(500, 5), OnCompleted(600) ); var task = default(Task); var cts = new CancellationTokenSource(); var list = new List>(); scheduler.ScheduleAbsolute(150, () => task = xs.ForEachAsync(x => list.Add(new Recorded(scheduler.Clock, x)), cts.Token)); scheduler.ScheduleAbsolute(700, () => cts.Cancel()); scheduler.Start(); xs.Subscriptions.AssertEqual( Subscribe(150, 600) ); list.AssertEqual( new Recorded(200, 2), new Recorded(300, 3), new Recorded(400, 4), new Recorded(500, 5) ); Assert.AreEqual(TaskStatus.RanToCompletion, task.Status); } [TestMethod] public void ForEachAsync_Default() { var list = new List(); Observable.Range(1, 10).ForEachAsync(list.Add).Wait(); list.AssertEqual(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); } [TestMethod] public void ForEachAsync_Index() { var list = new List(); Observable.Range(3, 5).ForEachAsync((x, i) => list.Add(x * i)).Wait(); list.AssertEqual(3 * 0, 4 * 1, 5 * 2, 6 * 3, 7 * 4); } [TestMethod] public void ForEachAsync_Default_Cancel() { var N = 10; for (int n = 0; n < N; n++) { var cts = new CancellationTokenSource(); var done = false; var xs = Observable.Create(observer => { return new CompositeDisposable( Observable.Repeat(42, Scheduler.Default).Subscribe(observer), Disposable.Create(() => done = true) ); }); var lst = new List(); var t = xs.ForEachAsync( x => { lock (lst) lst.Add(x); }, cts.Token ); while (true) { lock (lst) if (lst.Count >= 10) break; } cts.Cancel(); while (!t.IsCompleted) ; for (int i = 0; i < 10; i++) Assert.AreEqual(42, lst[i]); Assert.IsTrue(done); Assert.IsTrue(t.IsCanceled); } } [TestMethod] public void ForEachAsync_Index_Cancel() { var N = 10; for (int n = 0; n < N; n++) { var cts = new CancellationTokenSource(); var done = false; var xs = Observable.Create(observer => { return new CompositeDisposable( Observable.Repeat(42, Scheduler.Default).Subscribe(observer), Disposable.Create(() => done = true) ); }); var lst = new List(); var t = xs.ForEachAsync( (x, i) => { lock (lst) lst.Add(x * i); }, cts.Token ); while (true) { lock (lst) if (lst.Count >= 10) break; } cts.Cancel(); while (!t.IsCompleted) ; for (int i = 0; i < 10; i++) Assert.AreEqual(i * 42, lst[i]); Assert.IsTrue(done); Assert.IsTrue(t.IsCanceled); } } [TestMethod] [Ignore] public void ForEachAsync_DisposeThrows() { var cts = new CancellationTokenSource(); var ex = new Exception(); var xs = Observable.Create(observer => { return new CompositeDisposable( Observable.Range(0, 10, Scheduler.Default).Subscribe(observer), Disposable.Create(() => { throw ex; }) ); }); var lst = new List(); var t = xs.ForEachAsync(lst.Add, cts.Token); try { t.Wait(); Assert.Fail(); } catch (AggregateException err) { Assert.AreEqual(1, err.InnerExceptions.Count); Assert.AreSame(ex, err.InnerExceptions[0]); } } [TestMethod] public void ForEachAsync_SubscribeThrows() { var ex = new Exception(); var x = 42; var xs = Observable.Create(observer => { if (x == 42) throw ex; return Disposable.Empty; }); var t = xs.ForEachAsync(_ => { }); try { t.Wait(); Assert.Fail(); } catch (AggregateException err) { Assert.AreEqual(1, err.InnerExceptions.Count); Assert.AreSame(ex, err.InnerExceptions[0]); } } #endif #endregion #region + Case + [TestMethod] public void Case_ArgumentChecking() { ReactiveAssert.Throws(() => Observable.Case(null, new Dictionary>(), DummyObservable.Instance)); ReactiveAssert.Throws(() => Observable.Case(DummyFunc.Instance, null, DummyObservable.Instance)); ReactiveAssert.Throws(() => Observable.Case(DummyFunc.Instance, new Dictionary>(), default(IObservable))); ReactiveAssert.Throws(() => Observable.Case(null, new Dictionary>(), DummyScheduler.Instance)); ReactiveAssert.Throws(() => Observable.Case(DummyFunc.Instance, null, DummyScheduler.Instance)); ReactiveAssert.Throws(() => Observable.Case(DummyFunc.Instance, new Dictionary>(), default(IScheduler))); ReactiveAssert.Throws(() => Observable.Case(null, new Dictionary>())); ReactiveAssert.Throws(() => Observable.Case(DummyFunc.Instance, null)); } [TestMethod] public void Case_One() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(240, 2), OnNext(270, 3), OnCompleted(300) ); var ys = scheduler.CreateHotObservable( OnNext(220, 11), OnNext(250, 12), OnNext(280, 13), OnCompleted(310) ); var zs = scheduler.CreateHotObservable( OnNext(230, 21), OnNext(240, 22), OnNext(290, 23), OnCompleted(320) ); var map = new Dictionary> { { 1, xs }, { 2, ys } }; var results = scheduler.Start(() => Observable.Case(() => 1, map, zs)); results.Messages.AssertEqual( OnNext(210, 1), OnNext(240, 2), OnNext(270, 3), OnCompleted(300) ); xs.Subscriptions.AssertEqual( Subscribe(200, 300) ); ys.Subscriptions.AssertEqual( ); zs.Subscriptions.AssertEqual( ); } [TestMethod] public void Case_Two() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(240, 2), OnNext(270, 3), OnCompleted(300) ); var ys = scheduler.CreateHotObservable( OnNext(220, 11), OnNext(250, 12), OnNext(280, 13), OnCompleted(310) ); var zs = scheduler.CreateHotObservable( OnNext(230, 21), OnNext(240, 22), OnNext(290, 23), OnCompleted(320) ); var map = new Dictionary> { { 1, xs }, { 2, ys } }; var results = scheduler.Start(() => Observable.Case(() => 2, map, zs)); results.Messages.AssertEqual( OnNext(220, 11), OnNext(250, 12), OnNext(280, 13), OnCompleted(310) ); xs.Subscriptions.AssertEqual( ); ys.Subscriptions.AssertEqual( Subscribe(200, 310) ); zs.Subscriptions.AssertEqual( ); } [TestMethod] public void Case_Three() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(240, 2), OnNext(270, 3), OnCompleted(300) ); var ys = scheduler.CreateHotObservable( OnNext(220, 11), OnNext(250, 12), OnNext(280, 13), OnCompleted(310) ); var zs = scheduler.CreateHotObservable( OnNext(230, 21), OnNext(240, 22), OnNext(290, 23), OnCompleted(320) ); var map = new Dictionary> { { 1, xs }, { 2, ys } }; var results = scheduler.Start(() => Observable.Case(() => 3, map, zs)); results.Messages.AssertEqual( OnNext(230, 21), OnNext(240, 22), OnNext(290, 23), OnCompleted(320) ); xs.Subscriptions.AssertEqual( ); ys.Subscriptions.AssertEqual( ); zs.Subscriptions.AssertEqual( Subscribe(200, 320) ); } [TestMethod] public void Case_Throw() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(240, 2), OnNext(270, 3), OnCompleted(300) ); var ys = scheduler.CreateHotObservable( OnNext(220, 11), OnNext(250, 12), OnNext(280, 13), OnCompleted(310) ); var zs = scheduler.CreateHotObservable( OnNext(230, 21), OnNext(240, 22), OnNext(290, 23), OnCompleted(320) ); var map = new Dictionary> { { 1, xs }, { 2, ys } }; var ex = new Exception(); var results = scheduler.Start(() => Observable.Case(() => Throw(ex), map, zs)); results.Messages.AssertEqual( OnError(200, ex) ); xs.Subscriptions.AssertEqual( ); ys.Subscriptions.AssertEqual( ); zs.Subscriptions.AssertEqual( ); } [TestMethod] public void CaseWithDefault_One() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(240, 2), OnNext(270, 3), OnCompleted(300) ); var ys = scheduler.CreateHotObservable( OnNext(220, 11), OnNext(250, 12), OnNext(280, 13), OnCompleted(310) ); var map = new Dictionary> { { 1, xs }, { 2, ys } }; var results = scheduler.Start(() => Observable.Case(() => 1, map, scheduler)); results.Messages.AssertEqual( OnNext(210, 1), OnNext(240, 2), OnNext(270, 3), OnCompleted(300) ); xs.Subscriptions.AssertEqual( Subscribe(200, 300) ); ys.Subscriptions.AssertEqual( ); } [TestMethod] public void CaseWithDefault_Two() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(240, 2), OnNext(270, 3), OnCompleted(300) ); var ys = scheduler.CreateHotObservable( OnNext(220, 11), OnNext(250, 12), OnNext(280, 13), OnCompleted(310) ); var map = new Dictionary> { { 1, xs }, { 2, ys } }; var results = scheduler.Start(() => Observable.Case(() => 2, map, scheduler)); results.Messages.AssertEqual( OnNext(220, 11), OnNext(250, 12), OnNext(280, 13), OnCompleted(310) ); xs.Subscriptions.AssertEqual( ); ys.Subscriptions.AssertEqual( Subscribe(200, 310) ); } [TestMethod] public void CaseWithDefault_Three() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(240, 2), OnNext(270, 3), OnCompleted(300) ); var ys = scheduler.CreateHotObservable( OnNext(220, 11), OnNext(250, 12), OnNext(280, 13), OnCompleted(310) ); var map = new Dictionary> { { 1, xs }, { 2, ys } }; var results = scheduler.Start(() => Observable.Case(() => 3, map, scheduler)); results.Messages.AssertEqual( OnCompleted(201) ); xs.Subscriptions.AssertEqual( ); ys.Subscriptions.AssertEqual( ); } [TestMethod] public void CaseWithDefault_Throw() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(240, 2), OnNext(270, 3), OnCompleted(300) ); var ys = scheduler.CreateHotObservable( OnNext(220, 11), OnNext(250, 12), OnNext(280, 13), OnCompleted(310) ); var map = new Dictionary> { { 1, xs }, { 2, ys } }; var ex = new Exception(); var results = scheduler.Start(() => Observable.Case(() => Throw(ex), map, scheduler)); results.Messages.AssertEqual( OnError(200, ex) ); xs.Subscriptions.AssertEqual( ); ys.Subscriptions.AssertEqual( ); } [TestMethod] public void CaseWithDefault_CheckDefault() { Observable.Case(() => 1, new Dictionary>(), DefaultScheduler.Instance) .AssertEqual(Observable.Case(() => 1, new Dictionary>())); } [TestMethod] public void Case_Error() { var scheduler = new TestScheduler(); var ex = new Exception(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(240, 2), OnNext(270, 3), OnError(300, ex) ); var ys = scheduler.CreateHotObservable( OnNext(220, 11), OnNext(250, 12), OnNext(280, 13), OnCompleted(310) ); var map = new Dictionary> { { 1, xs }, { 2, ys } }; var results = scheduler.Start(() => Observable.Case(() => 1, map, scheduler)); results.Messages.AssertEqual( OnNext(210, 1), OnNext(240, 2), OnNext(270, 3), OnError(300, ex) ); xs.Subscriptions.AssertEqual( Subscribe(200, 300) ); ys.Subscriptions.AssertEqual( ); } #endregion #region + DoWhile + [TestMethod] public void DoWhile_ArgumentChecking() { ReactiveAssert.Throws(() => Observable.DoWhile(DummyObservable.Instance, null)); ReactiveAssert.Throws(() => Observable.DoWhile(default(IObservable), DummyFunc.Instance)); } [TestMethod] public void DoWhile_AlwaysFalse() { var scheduler = new TestScheduler(); var xs = scheduler.CreateColdObservable( OnNext(50, 1), OnNext(100, 2), OnNext(150, 3), OnNext(200, 4), OnCompleted(250) ); var results = scheduler.Start(() => Observable.DoWhile(xs, () => false)); results.Messages.AssertEqual( OnNext(250, 1), OnNext(300, 2), OnNext(350, 3), OnNext(400, 4), OnCompleted(450) ); xs.Subscriptions.AssertEqual( Subscribe(200, 450) ); } [TestMethod] public void DoWhile_AlwaysTrue() { var scheduler = new TestScheduler(); var xs = scheduler.CreateColdObservable( OnNext(50, 1), OnNext(100, 2), OnNext(150, 3), OnNext(200, 4), OnCompleted(250) ); var results = scheduler.Start(() => Observable.DoWhile(xs, () => true)); results.Messages.AssertEqual( OnNext(250, 1), OnNext(300, 2), OnNext(350, 3), OnNext(400, 4), OnNext(500, 1), OnNext(550, 2), OnNext(600, 3), OnNext(650, 4), OnNext(750, 1), OnNext(800, 2), OnNext(850, 3), OnNext(900, 4) ); xs.Subscriptions.AssertEqual( Subscribe(200, 450), Subscribe(450, 700), Subscribe(700, 950), Subscribe(950, 1000) ); } [TestMethod] public void DoWhile_AlwaysTrue_Throw() { var scheduler = new TestScheduler(); var ex = new Exception(); var xs = scheduler.CreateColdObservable( OnError(50, ex) ); var results = scheduler.Start(() => Observable.DoWhile(xs, () => true)); results.Messages.AssertEqual( OnError(250, ex) ); xs.Subscriptions.AssertEqual( Subscribe(200, 250) ); } [TestMethod] public void DoWhile_AlwaysTrue_Infinite() { var scheduler = new TestScheduler(); var xs = scheduler.CreateColdObservable( OnNext(50, 1) ); var results = scheduler.Start(() => Observable.DoWhile(xs, () => true)); results.Messages.AssertEqual( OnNext(250, 1) ); xs.Subscriptions.AssertEqual( Subscribe(200, 1000) ); } [TestMethod] public void DoWhile_SometimesTrue() { var scheduler = new TestScheduler(); var xs = scheduler.CreateColdObservable( OnNext(50, 1), OnNext(100, 2), OnNext(150, 3), OnNext(200, 4), OnCompleted(250) ); int n = 0; var results = scheduler.Start(() => Observable.DoWhile(xs, () => ++n < 3)); results.Messages.AssertEqual( OnNext(250, 1), OnNext(300, 2), OnNext(350, 3), OnNext(400, 4), OnNext(500, 1), OnNext(550, 2), OnNext(600, 3), OnNext(650, 4), OnNext(750, 1), OnNext(800, 2), OnNext(850, 3), OnNext(900, 4), OnCompleted(950) ); xs.Subscriptions.AssertEqual( Subscribe(200, 450), Subscribe(450, 700), Subscribe(700, 950) ); } [TestMethod] public void DoWhile_SometimesThrows() { var scheduler = new TestScheduler(); var xs = scheduler.CreateColdObservable( OnNext(50, 1), OnNext(100, 2), OnNext(150, 3), OnNext(200, 4), OnCompleted(250) ); int n = 0; var ex = new Exception(); var results = scheduler.Start(() => Observable.DoWhile(xs, () => ++n < 3 ? true : Throw(ex))); results.Messages.AssertEqual( OnNext(250, 1), OnNext(300, 2), OnNext(350, 3), OnNext(400, 4), OnNext(500, 1), OnNext(550, 2), OnNext(600, 3), OnNext(650, 4), OnNext(750, 1), OnNext(800, 2), OnNext(850, 3), OnNext(900, 4), OnError(950, ex) ); xs.Subscriptions.AssertEqual( Subscribe(200, 450), Subscribe(450, 700), Subscribe(700, 950) ); } #endregion #region + For + [TestMethod] public void For_ArgumentChecking() { ReactiveAssert.Throws(() => Observable.For(DummyEnumerable.Instance, default(Func>))); ReactiveAssert.Throws(() => Observable.For(null, DummyFunc>.Instance)); } [TestMethod] public void For_Basic() { var scheduler = new TestScheduler(); var results = scheduler.Start(() => Observable.For(new[] { 1, 2, 3 }, x => scheduler.CreateColdObservable( OnNext((ushort)(x * 100 + 10), x * 10 + 1), OnNext((ushort)(x * 100 + 20), x * 10 + 2), OnNext((ushort)(x * 100 + 30), x * 10 + 3), OnCompleted((ushort)(x * 100 + 40))))); results.Messages.AssertEqual( OnNext(310, 11), OnNext(320, 12), OnNext(330, 13), OnNext(550, 21), OnNext(560, 22), OnNext(570, 23), OnNext(890, 31), OnNext(900, 32), OnNext(910, 33), OnCompleted(920) ); } IEnumerable For_Error_Core(Exception ex) { yield return 1; yield return 2; yield return 3; throw ex; } [TestMethod] public void For_Error_Iterator() { var scheduler = new TestScheduler(); var ex = new Exception(); var results = scheduler.Start(() => Observable.For(For_Error_Core(ex), x => scheduler.CreateColdObservable( OnNext((ushort)(x * 100 + 10), x * 10 + 1), OnNext((ushort)(x * 100 + 20), x * 10 + 2), OnNext((ushort)(x * 100 + 30), x * 10 + 3), OnCompleted((ushort)(x * 100 + 40))))); results.Messages.AssertEqual( OnNext(310, 11), OnNext(320, 12), OnNext(330, 13), OnNext(550, 21), OnNext(560, 22), OnNext(570, 23), OnNext(890, 31), OnNext(900, 32), OnNext(910, 33), OnError(920, ex) ); } [TestMethod] public void For_Error_Source() { var scheduler = new TestScheduler(); var ex = new Exception(); var results = scheduler.Start(() => Observable.For(new[] { 1, 2, 3 }, x => Observable.Throw(ex))); results.Messages.AssertEqual( OnError(200, ex) ); } [TestMethod] public void For_SelectorThrows() { var scheduler = new TestScheduler(); var ex = new Exception(); var results = scheduler.Start(() => Observable.For(new[] { 1, 2, 3 }, x => Throw>(ex))); results.Messages.AssertEqual( OnError(200, ex) ); } #endregion #region + If + [TestMethod] public void If_ArgumentChecking() { ReactiveAssert.Throws(() => Observable.If(null, DummyObservable.Instance, DummyObservable.Instance)); ReactiveAssert.Throws(() => Observable.If(DummyFunc.Instance, null, DummyObservable.Instance)); ReactiveAssert.Throws(() => Observable.If(DummyFunc.Instance, DummyObservable.Instance, default(IObservable))); ReactiveAssert.Throws(() => Observable.If(null, DummyObservable.Instance, Scheduler.Default)); ReactiveAssert.Throws(() => Observable.If(DummyFunc.Instance, default(IObservable), Scheduler.Default)); ReactiveAssert.Throws(() => Observable.If(DummyFunc.Instance, DummyObservable.Instance, default(IScheduler))); } [TestMethod] public void If_True() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(250, 2), OnCompleted(300) ); var ys = scheduler.CreateHotObservable( OnNext(310, 3), OnNext(350, 4), OnCompleted(400) ); var results = scheduler.Start(() => Observable.If(() => true, xs, ys)); results.Messages.AssertEqual( OnNext(210, 1), OnNext(250, 2), OnCompleted(300) ); xs.Subscriptions.AssertEqual( Subscribe(200, 300) ); ys.Subscriptions.AssertEqual( ); } [TestMethod] public void If_False() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(250, 2), OnCompleted(300) ); var ys = scheduler.CreateHotObservable( OnNext(310, 3), OnNext(350, 4), OnCompleted(400) ); var results = scheduler.Start(() => Observable.If(() => false, xs, ys)); results.Messages.AssertEqual( OnNext(310, 3), OnNext(350, 4), OnCompleted(400) ); xs.Subscriptions.AssertEqual( ); ys.Subscriptions.AssertEqual( Subscribe(200, 400) ); } [TestMethod] public void If_Throw() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(250, 2), OnCompleted(300) ); var ys = scheduler.CreateHotObservable( OnNext(310, 3), OnNext(350, 4), OnCompleted(400) ); var ex = new Exception(); var results = scheduler.Start(() => Observable.If(() => Throw(ex), xs, ys)); results.Messages.AssertEqual( OnError(200, ex) ); xs.Subscriptions.AssertEqual( ); ys.Subscriptions.AssertEqual( ); } [TestMethod] public void If_Dispose() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(250, 2) ); var ys = scheduler.CreateHotObservable( OnNext(310, 3), OnNext(350, 4), OnCompleted(400) ); var results = scheduler.Start(() => Observable.If(() => true, xs, ys)); results.Messages.AssertEqual( OnNext(210, 1), OnNext(250, 2) ); xs.Subscriptions.AssertEqual( Subscribe(200, 1000) ); ys.Subscriptions.AssertEqual( ); } [TestMethod] public void If_Default_ArgumentChecking() { ReactiveAssert.Throws(() => Observable.If(null, DummyObservable.Instance)); ReactiveAssert.Throws(() => Observable.If(DummyFunc.Instance, null)); } [TestMethod] public void If_Default_Completed() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(110, 1), OnNext(220, 2), OnNext(330, 3), OnCompleted(440) ); var b = false; scheduler.ScheduleAbsolute(150, () => b = true); var results = scheduler.Start(() => Observable.If(() => b, xs)); results.Messages.AssertEqual( OnNext(220, 2), OnNext(330, 3), OnCompleted(440) ); xs.Subscriptions.AssertEqual( Subscribe(200, 440) ); } [TestMethod] public void If_Default_Error() { var scheduler = new TestScheduler(); var ex = new Exception(); var xs = scheduler.CreateHotObservable( OnNext(110, 1), OnNext(220, 2), OnNext(330, 3), OnError(440, ex) ); var b = false; scheduler.ScheduleAbsolute(150, () => b = true); var results = scheduler.Start(() => Observable.If(() => b, xs)); results.Messages.AssertEqual( OnNext(220, 2), OnNext(330, 3), OnError(440, ex) ); xs.Subscriptions.AssertEqual( Subscribe(200, 440) ); } [TestMethod] public void If_Default_Never() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(110, 1), OnNext(220, 2), OnNext(330, 3) ); var b = false; scheduler.ScheduleAbsolute(150, () => b = true); var results = scheduler.Start(() => Observable.If(() => b, xs)); results.Messages.AssertEqual( OnNext(220, 2), OnNext(330, 3) ); xs.Subscriptions.AssertEqual( Subscribe(200, 1000) ); } [TestMethod] public void If_Default_Other() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(110, 1), OnNext(220, 2), OnNext(330, 3), OnError(440, new Exception()) ); var b = true; scheduler.ScheduleAbsolute(150, () => b = false); var results = scheduler.Start(() => Observable.If(() => b, xs)); results.Messages.AssertEqual( OnCompleted(200) ); xs.Subscriptions.AssertEqual( ); } [TestMethod] public void If_Default_Scheduler() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(110, 1), OnNext(220, 2), OnNext(330, 3), OnError(440, new Exception()) ); var results = scheduler.Start(() => Observable.If(() => false, xs, scheduler)); results.Messages.AssertEqual( OnCompleted(201) ); xs.Subscriptions.AssertEqual( ); } #endregion #region + While + [TestMethod] public void While_ArgumentChecking() { ReactiveAssert.Throws(() => Observable.While(default(Func), DummyObservable.Instance)); ReactiveAssert.Throws(() => Observable.While(DummyFunc.Instance, default(IObservable))); } [TestMethod] public void While_AlwaysFalse() { var scheduler = new TestScheduler(); var xs = scheduler.CreateColdObservable( OnNext(50, 1), OnNext(100, 2), OnNext(150, 3), OnNext(200, 4), OnCompleted(250) ); var results = scheduler.Start(() => Observable.While(() => false, xs)); results.Messages.AssertEqual( OnCompleted(200) ); xs.Subscriptions.AssertEqual( ); } [TestMethod] public void While_AlwaysTrue() { var scheduler = new TestScheduler(); var xs = scheduler.CreateColdObservable( OnNext(50, 1), OnNext(100, 2), OnNext(150, 3), OnNext(200, 4), OnCompleted(250) ); var results = scheduler.Start(() => Observable.While(() => true, xs)); results.Messages.AssertEqual( OnNext(250, 1), OnNext(300, 2), OnNext(350, 3), OnNext(400, 4), OnNext(500, 1), OnNext(550, 2), OnNext(600, 3), OnNext(650, 4), OnNext(750, 1), OnNext(800, 2), OnNext(850, 3), OnNext(900, 4) ); xs.Subscriptions.AssertEqual( Subscribe(200, 450), Subscribe(450, 700), Subscribe(700, 950), Subscribe(950, 1000) ); } [TestMethod] public void While_AlwaysTrue_Throw() { var scheduler = new TestScheduler(); var ex = new Exception(); var xs = scheduler.CreateColdObservable( OnError(50, ex) ); var results = scheduler.Start(() => Observable.While(() => true, xs)); results.Messages.AssertEqual( OnError(250, ex) ); xs.Subscriptions.AssertEqual( Subscribe(200, 250) ); } [TestMethod] public void While_AlwaysTrue_Infinite() { var scheduler = new TestScheduler(); var xs = scheduler.CreateColdObservable( OnNext(50, 1) ); var results = scheduler.Start(() => Observable.While(() => true, xs)); results.Messages.AssertEqual( OnNext(250, 1) ); xs.Subscriptions.AssertEqual( Subscribe(200, 1000) ); } [TestMethod] public void While_SometimesTrue() { var scheduler = new TestScheduler(); var xs = scheduler.CreateColdObservable( OnNext(50, 1), OnNext(100, 2), OnNext(150, 3), OnNext(200, 4), OnCompleted(250) ); int n = 0; var results = scheduler.Start(() => Observable.While(() => ++n < 3, xs)); results.Messages.AssertEqual( OnNext(250, 1), OnNext(300, 2), OnNext(350, 3), OnNext(400, 4), OnNext(500, 1), OnNext(550, 2), OnNext(600, 3), OnNext(650, 4), OnCompleted(700) ); xs.Subscriptions.AssertEqual( Subscribe(200, 450), Subscribe(450, 700) ); } static T Throw(Exception ex) { throw ex; } [TestMethod] public void While_SometimesThrows() { var scheduler = new TestScheduler(); var xs = scheduler.CreateColdObservable( OnNext(50, 1), OnNext(100, 2), OnNext(150, 3), OnNext(200, 4), OnCompleted(250) ); int n = 0; var ex = new Exception(); var results = scheduler.Start(() => Observable.While(() => ++n < 3 ? true : Throw(ex), xs)); results.Messages.AssertEqual( OnNext(250, 1), OnNext(300, 2), OnNext(350, 3), OnNext(400, 4), OnNext(500, 1), OnNext(550, 2), OnNext(600, 3), OnNext(650, 4), OnError(700, ex) ); xs.Subscriptions.AssertEqual( Subscribe(200, 450), Subscribe(450, 700) ); } #endregion #region General tests for loops [TestMethod] public void LoopTest1() { var loop = Observable.Defer(() => { var n = 0; return Observable.While( () => n++ < 5, Observable.Defer(() => { return Observable.For( Enumerable.Range(0, n), x => Observable.Return(x) ); }) ); }); var res = new List(); var std = new List(); loop.ForEach(x => { res.Add(x); std.Add(new System.Diagnostics.StackTrace().FrameCount); }); Assert.IsTrue(res.SequenceEqual(new[] { 0, 0, 1, 0, 1, 2, 0, 1, 2, 3, 0, 1, 2, 3, 4 })); Assert.IsTrue(std.Distinct().Count() == 1); } [TestMethod] public void LoopTest2() { var n = 0; var loop = default(IObservable); loop = Observable.While( () => n++ < 10, Observable.Concat( Observable.Return(42), Observable.Defer(() => loop) ) ); var res = new List(); var std = new List(); loop.ForEach(x => { res.Add(x); std.Add(new System.Diagnostics.StackTrace().FrameCount); }); Assert.IsTrue(res.SequenceEqual(Enumerable.Repeat(42, 10))); Assert.IsTrue(std.Distinct().Count() == 1); } #endregion } }