// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Reactive; using System.Reactive.Concurrency; 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 System.Collections.Generic; namespace ReactiveTests.Tests { [TestClass] public partial class ObservableExtensionsTest : ReactiveTest { #region Subscribe [TestMethod] public void Subscribe_ArgumentChecking() { var someObservable = Observable.Empty(); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(default(IObservable))); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(default(IObservable), _ => { })); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, default(Action))); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(default(IObservable), _ => { }, () => { })); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, default(Action), () => { })); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, _ => { }, default(Action))); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(default(IObservable), _ => { }, (Exception _) => { })); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, default(Action), (Exception _) => { })); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, _ => { }, default(Action))); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(default(IObservable), _ => { }, (Exception _) => { }, () => { })); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, default(Action), (Exception _) => { }, () => { })); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, _ => { }, default(Action), () => { })); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, _ => { }, (Exception _) => { }, default(Action))); } [TestMethod] public void Subscribe_None_Return() { Observable.Return(1, Scheduler.Immediate).Subscribe(); } [TestMethod] public void Subscribe_None_Throw() { var ex = new Exception(); var xs = Observable.Throw(ex, Scheduler.Immediate); ReactiveAssert.Throws(ex, () => xs.Subscribe()); } [TestMethod] public void Subscribe_None_Empty() { Observable.Empty(Scheduler.Immediate).Subscribe((int _) => { Assert.Fail(); }); } [TestMethod] public void Subscribe_OnNext_Return() { int _x = -1; Observable.Return(42, Scheduler.Immediate).Subscribe((int x) => { _x = x; }); Assert.AreEqual(42, _x); } [TestMethod] public void Subscribe_OnNext_Throw() { var ex = new Exception(); var xs = Observable.Throw(ex, Scheduler.Immediate); ReactiveAssert.Throws(ex, () => xs.Subscribe(_ => { Assert.Fail(); })); } [TestMethod] public void Subscribe_OnNext_Empty() { Observable.Empty(Scheduler.Immediate).Subscribe((int _) => { Assert.Fail(); }); } [TestMethod] public void Subscribe_OnNextOnCompleted_Return() { bool finished = false; int _x = -1; Observable.Return(42, Scheduler.Immediate).Subscribe((int x) => { _x = x; }, () => { finished = true; }); Assert.AreEqual(42, _x); Assert.IsTrue(finished); } [TestMethod] public void Subscribe_OnNextOnCompleted_Throw() { var ex = new Exception(); var xs = Observable.Throw(ex, Scheduler.Immediate); ReactiveAssert.Throws(ex, () => xs.Subscribe(_ => { Assert.Fail(); }, () => { Assert.Fail(); })); } [TestMethod] public void Subscribe_OnNextOnCompleted_Empty() { bool finished = false; Observable.Empty(Scheduler.Immediate).Subscribe((int _) => { Assert.Fail(); }, () => { finished = true; }); Assert.IsTrue(finished); } #endregion #region Subscribe with CancellationToken #if !NO_TPL [TestMethod] public void Subscribe_CT_ArgumentChecking() { var someObservable = Observable.Empty(); var someObserver = Observer.Create(_ => { }); var ct = CancellationToken.None; ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(default(IObservable), someObserver, ct)); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, default(IObserver), ct)); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(default(IObservable), ct)); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(default(IObservable), _ => { }, ct)); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, default(Action), ct)); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(default(IObservable), _ => { }, () => { }, ct)); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, default(Action), () => { }, ct)); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, _ => { }, default(Action), ct)); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(default(IObservable), _ => { }, (Exception _) => { }, ct)); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, default(Action), (Exception _) => { }, ct)); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, _ => { }, default(Action), ct)); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(default(IObservable), _ => { }, (Exception _) => { }, () => { }, ct)); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, default(Action), (Exception _) => { }, () => { }, ct)); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, _ => { }, default(Action), () => { }, ct)); ReactiveAssert.Throws(() => ObservableExtensions.Subscribe(someObservable, _ => { }, (Exception _) => { }, default(Action), ct)); } [TestMethod] public void Subscribe_CT_None() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(220, 2), OnNext(230, 3), OnCompleted(240) ); var obs = scheduler.CreateObserver(); scheduler.ScheduleAbsolute(200, () => xs.Subscribe(obs, CancellationToken.None)); scheduler.Start(); obs.Messages.AssertEqual( OnNext(210, 1), OnNext(220, 2), OnNext(230, 3), OnCompleted(240) ); xs.Subscriptions.AssertEqual( Subscribe(200, Subscription.Infinite /* no auto-dispose when using CreateHotObservable */) ); } [TestMethod] public void Subscribe_CT_CancelBeforeBegin() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(220, 2), OnNext(230, 3), OnCompleted(240) ); var cts = new CancellationTokenSource(); var obs = scheduler.CreateObserver(); scheduler.ScheduleAbsolute(200, () => xs.Subscribe(obs, cts.Token)); scheduler.ScheduleAbsolute(150, cts.Cancel); scheduler.Start(); obs.Messages.AssertEqual( ); xs.Subscriptions.AssertEqual( ); } [TestMethod] public void Subscribe_CT_CancelMiddle() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(220, 2), OnNext(230, 3), OnCompleted(240) ); var cts = new CancellationTokenSource(); var obs = scheduler.CreateObserver(); scheduler.ScheduleAbsolute(200, () => xs.Subscribe(obs, cts.Token)); scheduler.ScheduleAbsolute(225, cts.Cancel); scheduler.Start(); obs.Messages.AssertEqual( OnNext(210, 1), OnNext(220, 2) ); xs.Subscriptions.AssertEqual( Subscribe(200, 225) ); } [TestMethod] public void Subscribe_CT_CancelAfterEnd() { var scheduler = new TestScheduler(); var ex = new Exception(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(220, 2), OnNext(230, 3), OnError(240, ex) ); var cts = new CancellationTokenSource(); var obs = scheduler.CreateObserver(); scheduler.ScheduleAbsolute(200, () => xs.Subscribe(obs, cts.Token)); scheduler.ScheduleAbsolute(250, cts.Cancel); scheduler.Start(); obs.Messages.AssertEqual( OnNext(210, 1), OnNext(220, 2), OnNext(230, 3), OnError(240, ex) ); xs.Subscriptions.AssertEqual( Subscribe(200, Subscription.Infinite /* no auto-dispose when using CreateHotObservable */) ); } [TestMethod] public void Subscribe_CT_NeverCancel() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(220, 2), OnNext(230, 3), OnCompleted(240) ); var cts = new CancellationTokenSource(); var obs = scheduler.CreateObserver(); scheduler.ScheduleAbsolute(200, () => xs.Subscribe(obs, cts.Token)); scheduler.Start(); obs.Messages.AssertEqual( OnNext(210, 1), OnNext(220, 2), OnNext(230, 3), OnCompleted(240) ); xs.Subscriptions.AssertEqual( Subscribe(200, Subscription.Infinite /* no auto-dispose when using CreateHotObservable */) ); } [TestMethod] public void Subscribe_CT_Overloads_AlreadyCancelled() { var xs = Observable.Defer(() => { Assert.Fail(); return Observable.Return(42, Scheduler.Immediate); }); var cts = new CancellationTokenSource(); cts.Cancel(); xs.Subscribe(cts.Token); xs.Subscribe(_ => { }, cts.Token); xs.Subscribe(_ => { }, ex => { }, cts.Token); xs.Subscribe(_ => { }, () => { }, cts.Token); xs.Subscribe(_ => { }, ex => { }, () => { }, cts.Token); xs.Subscribe(Observer.Create(_ => { }, ex => { }, () => { }), cts.Token); } [TestMethod] public void Subscribe_CT_Overloads_None() { var i = 0; var n = 0; var e = 0; var c = 0; var xs = Observable.Defer(() => { i++; return Observable.Return(42, Scheduler.Immediate); }); xs.Subscribe(CancellationToken.None); xs.Subscribe(_ => { n++; }, CancellationToken.None); xs.Subscribe(_ => { n++; }, ex => { e++; }, CancellationToken.None); xs.Subscribe(_ => { n++; }, () => { c++; }, CancellationToken.None); xs.Subscribe(_ => { n++; }, ex => { e++; }, () => { c++; }, CancellationToken.None); xs.Subscribe(Observer.Create(_ => { n++; }, ex => { e++; }, () => { c++; }), CancellationToken.None); Assert.AreEqual(6, i); Assert.AreEqual(5, n); Assert.AreEqual(0, e); Assert.AreEqual(3, c); } [TestMethod] public void Subscribe_CT_CancelDuringCallback() { var scheduler = new TestScheduler(); var xs = scheduler.CreateHotObservable( OnNext(210, 1), OnNext(220, 2), OnNext(230, 3), OnCompleted(240) ); var cts = new CancellationTokenSource(); var n = 0; scheduler.ScheduleAbsolute(200, () => xs.Subscribe(x => { n++; if (x == 2) cts.Cancel(); }, cts.Token)); scheduler.Start(); Assert.AreEqual(2, n); xs.Subscriptions.AssertEqual( Subscribe(200, 220) ); } #endif #endregion } }