2561 lines
75 KiB
C#
Raw Normal View History

// 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.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reactive;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reflection;
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 ObservableTest : ReactiveTest
{
#region - Create -
[TestMethod]
public void Create_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Create<int>(default(Func<IObserver<int>, Action>)));
//
// BREAKING CHANGE v2.0 > v1.x - Returning null from Subscribe means "nothing to do upon unsubscription"
// all null-coalesces to Disposable.Empty.
//
//ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Create<int>(o => default(Action)).Subscribe(DummyObserver<int>.Instance));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Create<int>(o => () => { }).Subscribe(null));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Create<int>(o =>
{
o.OnError(null);
return () => { };
}).Subscribe(null));
}
[TestMethod]
public void Create_NullCoalescingAction()
{
var xs = Observable.Create<int>(o =>
{
o.OnNext(42);
return default(Action);
});
var lst = new List<int>();
var d = xs.Subscribe(lst.Add);
d.Dispose();
Assert.IsTrue(lst.SequenceEqual(new[] {42}));
}
[TestMethod]
public void Create_Next()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Create<int>(o =>
{
o.OnNext(1);
o.OnNext(2);
return () => { };
})
);
res.Messages.AssertEqual(
OnNext(200, 1),
OnNext(200, 2)
);
}
[TestMethod]
public void Create_Completed()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Create<int>(o =>
{
o.OnCompleted();
o.OnNext(100);
o.OnError(new Exception());
o.OnCompleted();
return () => { };
})
);
res.Messages.AssertEqual(
OnCompleted<int>(200)
);
}
[TestMethod]
public void Create_Error()
{
var scheduler = new TestScheduler();
var ex = new Exception();
var res = scheduler.Start(() =>
Observable.Create<int>(o =>
{
o.OnError(ex);
o.OnNext(100);
o.OnError(new Exception());
o.OnCompleted();
return () => { };
})
);
res.Messages.AssertEqual(
OnError<int>(200, ex)
);
}
[TestMethod]
public void Create_Exception()
{
ReactiveAssert.Throws<InvalidOperationException>(() =>
Observable.Create<int>(new Func<IObserver<int>, Action>(o => { throw new InvalidOperationException(); })).Subscribe());
}
[TestMethod]
public void Create_Dispose()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Create<int>(o =>
{
var stopped = false;
o.OnNext(1);
o.OnNext(2);
scheduler.Schedule(TimeSpan.FromTicks(600), () =>
{
if (!stopped)
o.OnNext(3);
});
scheduler.Schedule(TimeSpan.FromTicks(700), () =>
{
if (!stopped)
o.OnNext(4);
});
scheduler.Schedule(TimeSpan.FromTicks(900), () =>
{
if (!stopped)
o.OnNext(5);
});
scheduler.Schedule(TimeSpan.FromTicks(1100), () =>
{
if (!stopped)
o.OnNext(6);
});
return () => { stopped = true; };
})
);
res.Messages.AssertEqual(
OnNext(200, 1),
OnNext(200, 2),
OnNext(800, 3),
OnNext(900, 4)
);
}
[TestMethod]
public void Create_ObserverThrows()
{
ReactiveAssert.Throws<InvalidOperationException>(() =>
Observable.Create<int>(o =>
{
o.OnNext(1);
return () => { };
}).Subscribe(x => { throw new InvalidOperationException(); }));
ReactiveAssert.Throws<InvalidOperationException>(() =>
Observable.Create<int>(o =>
{
o.OnError(new Exception());
return () => { };
}).Subscribe(x => { }, ex => { throw new InvalidOperationException(); }));
ReactiveAssert.Throws<InvalidOperationException>(() =>
Observable.Create<int>(o =>
{
o.OnCompleted();
return () => { };
}).Subscribe(x => { }, ex => { }, () => { throw new InvalidOperationException(); }));
}
[TestMethod]
public void CreateWithDisposable_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Create<int>(default(Func<IObserver<int>, IDisposable>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Create<int>(o => DummyDisposable.Instance).Subscribe(null));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Create<int>(o =>
{
o.OnError(null);
return DummyDisposable.Instance;
}).Subscribe(null));
}
[TestMethod]
public void CreateWithDisposable_NullCoalescingAction()
{
var xs = Observable.Create<int>(o =>
{
o.OnNext(42);
return default(IDisposable);
});
var lst = new List<int>();
var d = xs.Subscribe(lst.Add);
d.Dispose();
Assert.IsTrue(lst.SequenceEqual(new[] { 42 }));
}
[TestMethod]
public void CreateWithDisposable_Next()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Create<int>(o =>
{
o.OnNext(1);
o.OnNext(2);
return Disposable.Empty;
})
);
res.Messages.AssertEqual(
OnNext(200, 1),
OnNext(200, 2)
);
}
[TestMethod]
public void CreateWithDisposable_Completed()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Create<int>(o =>
{
o.OnCompleted();
o.OnNext(100);
o.OnError(new Exception());
o.OnCompleted();
return Disposable.Empty;
})
);
res.Messages.AssertEqual(
OnCompleted<int>(200)
);
}
[TestMethod]
public void CreateWithDisposable_Error()
{
var scheduler = new TestScheduler();
var ex = new Exception();
var res = scheduler.Start(() =>
Observable.Create<int>(o =>
{
o.OnError(ex);
o.OnNext(100);
o.OnError(new Exception());
o.OnCompleted();
return Disposable.Empty;
})
);
res.Messages.AssertEqual(
OnError<int>(200, ex)
);
}
[TestMethod]
public void CreateWithDisposable_Exception()
{
ReactiveAssert.Throws<InvalidOperationException>(() =>
Observable.Create<int>(new Func<IObserver<int>, IDisposable>(o => { throw new InvalidOperationException(); })).Subscribe());
}
[TestMethod]
public void CreateWithDisposable_Dispose()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Create<int>(o =>
{
var d = new BooleanDisposable();
o.OnNext(1);
o.OnNext(2);
scheduler.Schedule(TimeSpan.FromTicks(600), () =>
{
if (!d.IsDisposed)
o.OnNext(3);
});
scheduler.Schedule(TimeSpan.FromTicks(700), () =>
{
if (!d.IsDisposed)
o.OnNext(4);
});
scheduler.Schedule(TimeSpan.FromTicks(900), () =>
{
if (!d.IsDisposed)
o.OnNext(5);
});
scheduler.Schedule(TimeSpan.FromTicks(1100), () =>
{
if (!d.IsDisposed)
o.OnNext(6);
});
return d;
})
);
res.Messages.AssertEqual(
OnNext(200, 1),
OnNext(200, 2),
OnNext(800, 3),
OnNext(900, 4)
);
}
[TestMethod]
public void CreateWithDisposable_ObserverThrows()
{
ReactiveAssert.Throws<InvalidOperationException>(() =>
Observable.Create<int>(o =>
{
o.OnNext(1);
return Disposable.Empty;
}).Subscribe(x => { throw new InvalidOperationException(); }));
ReactiveAssert.Throws<InvalidOperationException>(() =>
Observable.Create<int>(o =>
{
o.OnError(new Exception());
return Disposable.Empty;
}).Subscribe(x => { }, ex => { throw new InvalidOperationException(); }));
ReactiveAssert.Throws<InvalidOperationException>(() =>
Observable.Create<int>(o =>
{
o.OnCompleted();
return Disposable.Empty;
}).Subscribe(x => { }, ex => { }, () => { throw new InvalidOperationException(); }));
}
#endregion
#region - CreateAsync -
#if !NO_TPL
[TestMethod]
public void CreateAsync_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Create<int>(default(Func<IObserver<int>, Task>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Create<int>(default(Func<IObserver<int>, CancellationToken, Task>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Create<int>(default(Func<IObserver<int>, Task<IDisposable>>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Create<int>(default(Func<IObserver<int>, CancellationToken, Task<IDisposable>>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Create<int>(default(Func<IObserver<int>, Task<Action>>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Create<int>(default(Func<IObserver<int>, CancellationToken, Task<Action>>)));
}
[TestMethod]
public void CreateAsync_NullCoalescingAction1()
{
var xs = Observable.Create<int>(o =>
{
o.OnNext(42);
return Task.Factory.StartNew(() => default(Action));
});
var lst = new List<int>();
var d = xs.Subscribe(lst.Add);
d.Dispose();
Assert.IsTrue(lst.SequenceEqual(new[] { 42 }));
}
[TestMethod]
public void CreateAsync_NullCoalescingAction2()
{
var xs = Observable.Create<int>((o, ct) =>
{
o.OnNext(42);
return Task.Factory.StartNew(() => default(Action));
});
var lst = new List<int>();
var d = xs.Subscribe(lst.Add);
d.Dispose();
Assert.IsTrue(lst.SequenceEqual(new[] { 42 }));
}
[TestMethod]
public void CreateAsync_NullCoalescingDisposable1()
{
var xs = Observable.Create<int>(o =>
{
o.OnNext(42);
return Task.Factory.StartNew(() => default(IDisposable));
});
var lst = new List<int>();
var d = xs.Subscribe(lst.Add);
d.Dispose();
Assert.IsTrue(lst.SequenceEqual(new[] { 42 }));
}
[TestMethod]
public void CreateAsync_NullCoalescingDisposable2()
{
var xs = Observable.Create<int>((o, ct) =>
{
o.OnNext(42);
return Task.Factory.StartNew(() => default(IDisposable));
});
var lst = new List<int>();
var d = xs.Subscribe(lst.Add);
d.Dispose();
Assert.IsTrue(lst.SequenceEqual(new[] { 42 }));
}
Task Producer1(IObserver<int> results, CancellationToken token, IScheduler scheduler)
{
var tcs = new TaskCompletionSource<object>();
var x = 0;
var d = scheduler.Schedule(TimeSpan.FromTicks(100), self =>
{
results.OnNext(++x);
self(TimeSpan.FromTicks(100));
});
token.Register(d.Dispose);
return tcs.Task;
}
[TestMethod]
public void CreateAsync_Never()
{
RunSynchronously(() =>
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Create<int>((observer, token) => Producer1(observer, token, scheduler))
);
res.Messages.AssertEqual(
OnNext(300, 1),
OnNext(400, 2),
OnNext(500, 3),
OnNext(600, 4),
OnNext(700, 5),
OnNext(800, 6),
OnNext(900, 7)
);
});
}
Task Producer2(IObserver<int> results, CancellationToken token, IScheduler scheduler)
{
var tcs = new TaskCompletionSource<object>();
var x = 0;
var d = scheduler.Schedule(TimeSpan.FromTicks(100), self =>
{
if (x == 4)
{
tcs.SetResult(null);
}
results.OnNext(++x);
self(TimeSpan.FromTicks(100));
});
token.Register(d.Dispose);
return tcs.Task;
}
[TestMethod]
public void CreateAsync_Completed1()
{
RunSynchronously(() =>
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Create<int>((observer, token) => Producer2(observer, token, scheduler))
);
res.Messages.AssertEqual(
OnNext(300, 1),
OnNext(400, 2),
OnNext(500, 3),
OnNext(600, 4),
OnCompleted<int>(700)
);
});
}
Task Producer3(IObserver<int> results, CancellationToken token, IScheduler scheduler)
{
var tcs = new TaskCompletionSource<object>();
var x = 0;
var d = scheduler.Schedule(TimeSpan.FromTicks(100), self =>
{
if (x == 4)
{
results.OnCompleted();
}
results.OnNext(++x);
self(TimeSpan.FromTicks(100));
});
token.Register(d.Dispose);
return tcs.Task;
}
[TestMethod]
public void CreateAsync_Completed2()
{
RunSynchronously(() =>
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Create<int>((observer, token) => Producer3(observer, token, scheduler))
);
res.Messages.AssertEqual(
OnNext(300, 1),
OnNext(400, 2),
OnNext(500, 3),
OnNext(600, 4),
OnCompleted<int>(700)
);
});
}
Task Producer4(IObserver<int> results, CancellationToken token, IScheduler scheduler, Exception exception)
{
var tcs = new TaskCompletionSource<object>();
var x = 0;
var d = scheduler.Schedule(TimeSpan.FromTicks(100), self =>
{
if (x == 4)
{
results.OnError(exception);
}
results.OnNext(++x);
self(TimeSpan.FromTicks(100));
});
token.Register(d.Dispose);
return tcs.Task;
}
[TestMethod]
public void CreateAsync_Error1()
{
RunSynchronously(() =>
{
var scheduler = new TestScheduler();
var exception = new Exception();
var res = scheduler.Start(() =>
Observable.Create<int>((observer, token) => Producer4(observer, token, scheduler, exception))
);
res.Messages.AssertEqual(
OnNext(300, 1),
OnNext(400, 2),
OnNext(500, 3),
OnNext(600, 4),
OnError<int>(700, exception)
);
});
}
Task Producer5(IObserver<int> results, CancellationToken token, IScheduler scheduler, Exception exception)
{
var tcs = new TaskCompletionSource<object>();
var x = 0;
var d = scheduler.Schedule(TimeSpan.FromTicks(100), self =>
{
if (x == 4)
{
tcs.SetException(exception);
}
results.OnNext(++x);
self(TimeSpan.FromTicks(100));
});
token.Register(d.Dispose);
return tcs.Task;
}
[TestMethod]
public void CreateAsync_Error2()
{
RunSynchronously(() =>
{
var scheduler = new TestScheduler();
var exception = new Exception();
var res = scheduler.Start(() =>
Observable.Create<int>((observer, token) => Producer5(observer, token, scheduler, exception))
);
res.Messages.AssertEqual(
OnNext(300, 1),
OnNext(400, 2),
OnNext(500, 3),
OnNext(600, 4),
OnError<int>(700, exception)
);
});
}
Task Producer6(IObserver<int> results, CancellationToken token, Exception exception)
{
throw exception;
}
[TestMethod]
public void CreateAsync_Error3()
{
RunSynchronously(() =>
{
var scheduler = new TestScheduler();
var exception = new InvalidOperationException();
var res = scheduler.Start(() =>
Observable.Create<int>((observer, token) => Producer6(observer, token, exception))
);
res.Messages.AssertEqual(
OnError<int>(200, exception)
);
});
}
Task Producer7(IObserver<int> results, CancellationToken token, IScheduler scheduler)
{
var tcs = new TaskCompletionSource<object>();
var x = 0;
var d = scheduler.Schedule(TimeSpan.FromTicks(100), self =>
{
if (x == 4)
{
tcs.SetResult(null);
}
results.OnNext(++x);
self(TimeSpan.FromTicks(100));
});
token.Register(d.Dispose);
return tcs.Task;
}
[TestMethod]
public void CreateAsync_Cancel1()
{
RunSynchronously(() =>
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Create<int>((observer, token) => Producer7(observer, token, scheduler)),
650
);
res.Messages.AssertEqual(
OnNext(300, 1),
OnNext(400, 2),
OnNext(500, 3),
OnNext(600, 4)
);
});
}
Task Producer8(IObserver<int> results, CancellationToken token, IScheduler scheduler)
{
var tcs = new TaskCompletionSource<object>();
var x = 0;
var d = scheduler.Schedule(TimeSpan.FromTicks(100), self =>
{
if (x == 4)
{
results.OnCompleted();
}
results.OnNext(++x);
self(TimeSpan.FromTicks(100));
});
token.Register(d.Dispose);
return tcs.Task;
}
[TestMethod]
public void CreateAsync_Cancel2()
{
RunSynchronously(() =>
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Create<int>((observer, token) => Producer8(observer, token, scheduler)),
650
);
res.Messages.AssertEqual(
OnNext(300, 1),
OnNext(400, 2),
OnNext(500, 3),
OnNext(600, 4)
);
});
}
Task Producer9(IObserver<int> results, CancellationToken token, IScheduler scheduler)
{
var tcs = new TaskCompletionSource<object>();
var x = 0;
var d = scheduler.Schedule(TimeSpan.FromTicks(100), self =>
{
if (x == 4)
{
results.OnCompleted();
}
results.OnNext(++x);
self(TimeSpan.FromTicks(100));
});
token.Register(d.Dispose);
return tcs.Task;
}
[TestMethod]
public void CreateAsync_Cancel3()
{
RunSynchronously(() =>
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Create<int>((observer, token) => Producer9(observer, token, scheduler)),
750
);
res.Messages.AssertEqual(
OnNext(300, 1),
OnNext(400, 2),
OnNext(500, 3),
OnNext(600, 4),
OnCompleted<int>(700)
);
});
}
Task Producer10(IObserver<int> results, CancellationToken token, IScheduler scheduler)
{
var tcs = new TaskCompletionSource<object>();
var x = 0;
var d = scheduler.Schedule(TimeSpan.FromTicks(100), self =>
{
if (x == 4)
{
tcs.SetCanceled();
}
results.OnNext(++x);
self(TimeSpan.FromTicks(100));
});
token.Register(d.Dispose);
return tcs.Task;
}
[TestMethod]
public void CreateAsync_Cancel4()
{
RunSynchronously(() =>
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Create<int>((observer, token) => Producer10(observer, token, scheduler))
);
res.Messages.Take(4).AssertEqual(
OnNext(300, 1),
OnNext(400, 2),
OnNext(500, 3),
OnNext(600, 4)
);
Assert.AreEqual(5, res.Messages.Count);
Assert.AreEqual(700, res.Messages[4].Time);
Assert.AreEqual(NotificationKind.OnError, res.Messages[4].Value.Kind);
Assert.IsTrue(res.Messages[4].Value.Exception is OperationCanceledException);
});
}
void RunSynchronously(Action action)
{
var t = new Task(action);
t.RunSynchronously(new SynchronousScheduler());
t.Wait();
}
class SynchronousScheduler : TaskScheduler
{
protected override IEnumerable<Task> GetScheduledTasks()
{
throw new NotImplementedException();
}
protected override void QueueTask(Task task)
{
TryExecuteTask(task);
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return TryExecuteTask(task);
}
}
[TestMethod]
public void CreateAsync_Task_Simple()
{
var xs = Observable.Create<int>(observer =>
{
return Task.Factory.StartNew(() =>
{
observer.OnNext(42);
observer.OnCompleted();
});
});
var lst = new List<int>();
xs.ForEach(lst.Add);
Assert.IsTrue(new[] { 42 }.SequenceEqual(lst));
}
[TestMethod]
public void CreateAsync_Task_Token()
{
var e = new ManualResetEvent(false);
var xs = Observable.Create<int>((observer, ct) =>
{
return Task.Factory.StartNew(() =>
{
var i = 0;
while (!ct.IsCancellationRequested)
{
if (i++ == 10)
e.Set();
observer.OnNext(42);
}
});
});
var lst = new List<int>();
var d = xs.Subscribe(lst.Add);
e.WaitOne();
d.Dispose();
Assert.IsTrue(lst.Take(10).SequenceEqual(Enumerable.Repeat(42, 10)));
}
[TestMethod]
public void CreateAsync_IDisposable_Simple()
{
var stopped = new ManualResetEvent(false);
var s = Disposable.Create(() => stopped.Set());
var xs = Observable.Create<int>(observer =>
{
return Task.Factory.StartNew(() =>
{
observer.OnNext(42);
observer.OnCompleted();
return s;
});
});
var lst = new List<int>();
xs.ForEach(lst.Add);
stopped.WaitOne();
Assert.IsTrue(new[] { 42 }.SequenceEqual(lst));
}
[TestMethod]
public void CreateAsync_IDisposable_Token()
{
var stopped = new ManualResetEvent(false);
var s = Disposable.Create(() => stopped.Set());
var e = new ManualResetEvent(false);
var xs = Observable.Create<int>((observer, ct) =>
{
return Task.Factory.StartNew(() =>
{
var i = 0;
while (!ct.IsCancellationRequested)
{
if (i++ == 10)
e.Set();
observer.OnNext(42);
}
return s;
});
});
var lst = new List<int>();
var d = xs.Subscribe(lst.Add);
e.WaitOne();
d.Dispose();
stopped.WaitOne();
Assert.IsTrue(lst.Take(10).SequenceEqual(Enumerable.Repeat(42, 10)));
}
[TestMethod]
public void CreateAsync_Action_Simple()
{
var stopped = new ManualResetEvent(false);
var s = new Action(() => stopped.Set());
var xs = Observable.Create<int>(observer =>
{
return Task.Factory.StartNew(() =>
{
observer.OnNext(42);
observer.OnCompleted();
return s;
});
});
var lst = new List<int>();
xs.ForEach(lst.Add);
stopped.WaitOne();
Assert.IsTrue(new[] { 42 }.SequenceEqual(lst));
}
[TestMethod]
public void CreateAsync_Action_Token()
{
var stopped = new ManualResetEvent(false);
var s = new Action(() => stopped.Set());
var e = new ManualResetEvent(false);
var xs = Observable.Create<int>((observer, ct) =>
{
return Task.Factory.StartNew(() =>
{
var i = 0;
while (!ct.IsCancellationRequested)
{
if (i++ == 10)
e.Set();
observer.OnNext(42);
}
return s;
});
});
var lst = new List<int>();
var d = xs.Subscribe(lst.Add);
e.WaitOne();
d.Dispose();
stopped.WaitOne();
Assert.IsTrue(lst.Take(10).SequenceEqual(Enumerable.Repeat(42, 10)));
}
#endif
#endregion
#region + Defer +
[TestMethod]
public void Defer_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Defer<int>(default(Func<IObservable<int>>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Defer(() => DummyObservable<int>.Instance).Subscribe(null));
ReactiveAssert.Throws</*some*/Exception>(() => Observable.Defer<int>(() => default(IObservable<int>)).Subscribe());
}
[TestMethod]
public void Defer_Complete()
{
var scheduler = new TestScheduler();
var invoked = 0;
var xs = default(ITestableObservable<long>);
var res = scheduler.Start(() =>
Observable.Defer(() =>
{
invoked++;
xs = scheduler.CreateColdObservable(
OnNext<long>(100, scheduler.Clock),
OnCompleted<long>(200));
return xs;
})
);
res.Messages.AssertEqual(
OnNext(300, 200L),
OnCompleted<long>(400)
);
Assert.AreEqual(1, invoked);
xs.Subscriptions.AssertEqual(
Subscribe(200, 400)
);
}
[TestMethod]
public void Defer_Error()
{
var scheduler = new TestScheduler();
var invoked = 0;
var xs = default(ITestableObservable<long>);
var ex = new Exception();
var res = scheduler.Start(() =>
Observable.Defer(() =>
{
invoked++;
xs = scheduler.CreateColdObservable(
OnNext<long>(100, scheduler.Clock),
OnError<long>(200, ex));
return xs;
})
);
res.Messages.AssertEqual(
OnNext(300, 200L),
OnError<long>(400, ex)
);
Assert.AreEqual(1, invoked);
xs.Subscriptions.AssertEqual(
Subscribe(200, 400)
);
}
[TestMethod]
public void Defer_Dispose()
{
var scheduler = new TestScheduler();
var invoked = 0;
var xs = default(ITestableObservable<long>);
var res = scheduler.Start(() =>
Observable.Defer(() =>
{
invoked++;
xs = scheduler.CreateColdObservable(
OnNext<long>(100, scheduler.Clock),
OnNext<long>(200, invoked),
OnNext<long>(1100, 1000));
return xs;
})
);
res.Messages.AssertEqual(
OnNext(300, 200L),
OnNext(400, 1L)
);
Assert.AreEqual(1, invoked);
xs.Subscriptions.AssertEqual(
Subscribe(200, 1000)
);
}
[TestMethod]
public void Defer_Throw()
{
var scheduler = new TestScheduler();
var invoked = 0;
var ex = new Exception();
var res = scheduler.Start(() =>
Observable.Defer<int>(new Func<IObservable<int>>(() =>
{
invoked++;
throw ex;
}))
);
res.Messages.AssertEqual(
OnError<int>(200, ex)
);
Assert.AreEqual(1, invoked);
}
#endregion
#region - DeferAsync -
#if !NO_TPL
[TestMethod]
public void DeferAsync_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Defer(default(Func<Task<IObservable<int>>>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.DeferAsync(default(Func<CancellationToken, Task<IObservable<int>>>)));
}
[TestMethod]
public void DeferAsync_Simple()
{
var xs = Observable.Defer<int>(() => Task.Factory.StartNew(() => Observable.Return(42)));
var res = xs.ToEnumerable().ToList();
Assert.IsTrue(new[] { 42 }.SequenceEqual(res));
}
[TestMethod]
public void DeferAsync_WithCancel_Simple()
{
var xs = Observable.DeferAsync<int>(ct => Task.Factory.StartNew(() => Observable.Return(42)));
var res = xs.ToEnumerable().ToList();
Assert.IsTrue(new[] { 42 }.SequenceEqual(res));
}
[TestMethod]
public void DeferAsync_WithCancel_Cancel()
{
var N = 10;// 0000;
for (int i = 0; i < N; i++)
{
var e = new ManualResetEvent(false);
var called = false;
var xs = Observable.DeferAsync<int>(ct => Task.Factory.StartNew(() =>
{
e.Set();
while (!ct.IsCancellationRequested)
;
return Observable.Defer(() => { called = true; return Observable.Return(42); });
}));
var d = xs.Subscribe(_ => { });
e.WaitOne();
d.Dispose();
Assert.IsFalse(called);
}
}
#endif
#endregion
#region + Empty +
[TestMethod]
public void Empty_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Empty<int>(null));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Empty<int>(null, 42));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Empty<int>(DummyScheduler.Instance).Subscribe(null));
}
[TestMethod]
public void Empty_Basic()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Empty<int>(scheduler)
);
res.Messages.AssertEqual(
OnCompleted<int>(201)
);
}
[TestMethod]
public void Empty_Disposed()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Empty<int>(scheduler),
200
);
res.Messages.AssertEqual(
);
}
[TestMethod]
public void Empty_ObserverThrows()
{
var scheduler1 = new TestScheduler();
var xs = Observable.Empty<int>(scheduler1);
xs.Subscribe(x => { }, exception => { }, () => { throw new InvalidOperationException(); });
ReactiveAssert.Throws<InvalidOperationException>(() => scheduler1.Start());
}
[TestMethod]
public void Empty_DefaultScheduler()
{
Observable.Empty<int>().AssertEqual(Observable.Empty<int>(DefaultScheduler.Instance));
}
[TestMethod]
public void Empty_Basic_Witness()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Empty<int>(scheduler, 42)
);
res.Messages.AssertEqual(
OnCompleted<int>(201)
);
}
#endregion
#region + Generate +
[TestMethod]
public void Generate_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Generate(0, DummyFunc<int, bool>.Instance, DummyFunc<int, int>.Instance, DummyFunc<int, int>.Instance, (IScheduler)null));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Generate(0, (Func<int, bool>)null, DummyFunc<int, int>.Instance, DummyFunc<int, int>.Instance, DummyScheduler.Instance));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Generate(0, DummyFunc<int, bool>.Instance, DummyFunc<int, int>.Instance, (Func<int, int>)null, DummyScheduler.Instance));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Generate(0, DummyFunc<int, bool>.Instance, (Func<int, int>)null, DummyFunc<int, int>.Instance, DummyScheduler.Instance));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Generate(0, DummyFunc<int, bool>.Instance, DummyFunc<int, int>.Instance, DummyFunc<int, int>.Instance, DummyScheduler.Instance).Subscribe(null));
}
[TestMethod]
public void Generate_Finite()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Generate(0, x => x <= 3, x => x + 1, x => x, scheduler)
);
res.Messages.AssertEqual(
OnNext(201, 0),
OnNext(202, 1),
OnNext(203, 2),
OnNext(204, 3),
OnCompleted<int>(205)
);
}
[TestMethod]
public void Generate_Throw_Condition()
{
var scheduler = new TestScheduler();
var ex = new Exception();
var res = scheduler.Start(() =>
Observable.Generate(0, new Func<int, bool>(x => { throw ex; }), x => x + 1, x => x, scheduler)
);
res.Messages.AssertEqual(
OnError<int>(201, ex)
);
}
[TestMethod]
public void Generate_Throw_ResultSelector()
{
var scheduler = new TestScheduler();
var ex = new Exception();
var res = scheduler.Start(() =>
Observable.Generate(0, x => true, x => x + 1, new Func<int, int>(x => { throw ex; }), scheduler)
);
res.Messages.AssertEqual(
OnError<int>(201, ex)
);
}
[TestMethod]
public void Generate_Throw_Iterate()
{
var scheduler = new TestScheduler();
var ex = new Exception();
var res = scheduler.Start(() =>
Observable.Generate(0, x => true, new Func<int, int>(x => { throw ex; }), x => x, scheduler)
);
res.Messages.AssertEqual(
OnNext(201, 0),
OnError<int>(202, ex)
);
}
[TestMethod]
public void Generate_Dispose()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Generate(0, x => true, x => x + 1, x => x, scheduler),
203
);
res.Messages.AssertEqual(
OnNext(201, 0),
OnNext(202, 1)
);
}
[TestMethod]
public void Generate_DefaultScheduler_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Generate(0, (Func<int, bool>)null, DummyFunc<int, int>.Instance, DummyFunc<int, int>.Instance));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Generate(0, DummyFunc<int, bool>.Instance, DummyFunc<int, int>.Instance, (Func<int, int>)null));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Generate(0, DummyFunc<int, bool>.Instance, (Func<int, int>)null, DummyFunc<int, int>.Instance));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Generate(0, DummyFunc<int, bool>.Instance, DummyFunc<int, int>.Instance, DummyFunc<int, int>.Instance).Subscribe(null));
}
[TestMethod]
public void Generate_DefaultScheduler()
{
Observable.Generate(0, x => x < 10, x => x + 1, x => x).AssertEqual(Observable.Generate(0, x => x < 10, x => x + 1, x => x, DefaultScheduler.Instance));
}
#if !NO_PERF
[TestMethod]
public void Generate_LongRunning1()
{
var start = default(ManualResetEvent);
var end = default(ManualResetEvent);
var s = new TestLongRunningScheduler(x => start = x, x => end = x);
var xs = Observable.Generate(0, x => x < 100, x => x + 1, x => x, s);
var lst = new List<int>();
var done = false;
xs.Subscribe(x => { lst.Add(x); }, () => done = true);
end.WaitOne();
Assert.IsTrue(lst.SequenceEqual(Enumerable.Range(0, 100)));
Assert.IsTrue(done);
}
[TestMethod]
public void Generate_LongRunning2()
{
var start = default(ManualResetEvent);
var end = default(ManualResetEvent);
var s = new TestLongRunningScheduler(x => start = x, x => end = x);
var xs = Observable.Generate(0, _ => true, x => x + 1, x => x, s);
var lst = new List<int>();
var d = xs.Subscribe(x => { lst.Add(x); });
start.WaitOne();
while (lst.Count < 100)
;
d.Dispose();
end.WaitOne();
Assert.IsTrue(lst.Take(100).SequenceEqual(Enumerable.Range(0, 100)));
}
[TestMethod]
public void Generate_LongRunning_Throw()
{
var start = default(ManualResetEvent);
var end = default(ManualResetEvent);
var s = new TestLongRunningScheduler(x => start = x, x => end = x);
var ex = new Exception();
var xs = Observable.Generate(0, x => { if (x < 100) return true; throw ex; }, x => x + 1, x => x, s);
var lst = new List<int>();
var e = default(Exception);
var done = false;
xs.Subscribe(x => { lst.Add(x); }, e_ => e = e_, () => done = true);
end.WaitOne();
Assert.IsTrue(lst.SequenceEqual(Enumerable.Range(0, 100)));
Assert.AreSame(ex, e);
Assert.IsFalse(done);
}
#endif
#endregion
#region + Never +
[TestMethod]
public void Never_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Never<int>().Subscribe(null));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Never<int>(42).Subscribe(null));
}
[TestMethod]
public void Never_Basic()
{
var scheduler = new TestScheduler();
var xs = Observable.Never<int>();
var res = scheduler.CreateObserver<int>();
xs.Subscribe(res);
scheduler.Start();
res.Messages.AssertEqual(
);
}
[TestMethod]
public void Never_Basic_Witness()
{
var scheduler = new TestScheduler();
var xs = Observable.Never<int>(42);
var res = scheduler.CreateObserver<int>();
xs.Subscribe(res);
scheduler.Start();
res.Messages.AssertEqual(
);
}
#endregion
#region + Range +
[TestMethod]
public void Range_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Range(0, 0, null));
ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => Observable.Range(0, -1, DummyScheduler.Instance));
ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => Observable.Range(int.MaxValue, 2, DummyScheduler.Instance));
}
[TestMethod]
public void Range_Zero()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Range(0, 0, scheduler)
);
res.Messages.AssertEqual(
OnCompleted<int>(201)
);
}
[TestMethod]
public void Range_One()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Range(0, 1, scheduler)
);
res.Messages.AssertEqual(
OnNext(201, 0),
OnCompleted<int>(202)
);
}
[TestMethod]
public void Range_Five()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Range(10, 5, scheduler)
);
res.Messages.AssertEqual(
OnNext(201, 10),
OnNext(202, 11),
OnNext(203, 12),
OnNext(204, 13),
OnNext(205, 14),
OnCompleted<int>(206)
);
}
[TestMethod]
public void Range_Boundaries()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Range(int.MaxValue, 1, scheduler)
);
res.Messages.AssertEqual(
OnNext(201, int.MaxValue),
OnCompleted<int>(202)
);
}
[TestMethod]
public void Range_Dispose()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Range(-10, 5, scheduler),
204
);
res.Messages.AssertEqual(
OnNext(201, -10),
OnNext(202, -9),
OnNext(203, -8)
);
}
[TestMethod]
public void Range_Default_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => Observable.Range(0, -1));
ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => Observable.Range(int.MaxValue, 2));
}
[TestMethod]
public void Range_Default()
{
for (int i = 0; i < 100; i++)
Observable.Range(100, 100).AssertEqual(Observable.Range(100, 100, DefaultScheduler.Instance));
}
#if !NO_PERF
[TestMethod]
public void Range_LongRunning1()
{
var start = default(ManualResetEvent);
var end = default(ManualResetEvent);
var s = new TestLongRunningScheduler(x => start = x, x => end = x);
var xs = Observable.Range(0, 100, s);
var lst = new List<int>();
var done = false;
xs.Subscribe(x => { lst.Add(x); }, () => done = true);
end.WaitOne();
Assert.IsTrue(lst.SequenceEqual(Enumerable.Range(0, 100)));
Assert.IsTrue(done);
}
[TestMethod]
public void Range_LongRunning2()
{
var start = default(ManualResetEvent);
var end = default(ManualResetEvent);
var s = new TestLongRunningScheduler(x => start = x, x => end = x);
var xs = Observable.Range(0, int.MaxValue, s);
var lst = new List<int>();
var d = xs.Subscribe(x => { lst.Add(x); });
start.WaitOne();
while (lst.Count < 100)
;
d.Dispose();
end.WaitOne();
Assert.IsTrue(true);
}
[TestMethod]
public void Range_LongRunning_Empty()
{
var start = default(ManualResetEvent);
var end = default(ManualResetEvent);
var scheduler = new TestLongRunningScheduler(x => start = x, x => end = x);
var xs = Observable.Range(5, 0, scheduler);
var lst = new List<int>();
xs.ForEach(lst.Add);
Assert.IsTrue(lst.SequenceEqual(Enumerable.Range(5, 0)));
}
[TestMethod]
public void Range_LongRunning_Regular()
{
var start = default(ManualResetEvent);
var end = default(ManualResetEvent);
var scheduler = new TestLongRunningScheduler(x => start = x, x => end = x);
var xs = Observable.Range(5, 17, scheduler);
var lst = new List<int>();
xs.ForEach(lst.Add);
Assert.IsTrue(lst.SequenceEqual(Enumerable.Range(5, 17)));
}
[TestMethod]
public void Range_LongRunning_Boundaries()
{
var start = default(ManualResetEvent);
var end = default(ManualResetEvent);
var scheduler = new TestLongRunningScheduler(x => start = x, x => end = x);
var xs = Observable.Range(int.MaxValue, 1, scheduler);
var lst = new List<int>();
xs.ForEach(lst.Add);
Assert.IsTrue(lst.SequenceEqual(Enumerable.Range(int.MaxValue, 1)));
}
#endif
#endregion
#region + Repeat +
[TestMethod]
public void Repeat_Value_Count_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Repeat(1, 0, default(IScheduler)));
ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => Observable.Repeat(1, -1, DummyScheduler.Instance));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Repeat(1, 1, DummyScheduler.Instance).Subscribe(null));
}
[TestMethod]
public void Repeat_Value_Count_Zero()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Repeat(42, 0, scheduler)
);
#if !NO_PERF
res.Messages.AssertEqual(
OnCompleted<int>(201)
);
#else
res.Messages.AssertEqual(
OnCompleted<int>(200)
);
#endif
}
[TestMethod]
public void Repeat_Value_Count_One()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Repeat(42, 1, scheduler)
);
res.Messages.AssertEqual(
OnNext(201, 42),
OnCompleted<int>(201)
);
}
[TestMethod]
public void Repeat_Value_Count_Ten()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Repeat(42, 10, scheduler)
);
res.Messages.AssertEqual(
OnNext(201, 42),
OnNext(202, 42),
OnNext(203, 42),
OnNext(204, 42),
OnNext(205, 42),
OnNext(206, 42),
OnNext(207, 42),
OnNext(208, 42),
OnNext(209, 42),
OnNext(210, 42),
OnCompleted<int>(210)
);
}
[TestMethod]
public void Repeat_Value_Count_Dispose()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Repeat(42, 10, scheduler),
207
);
res.Messages.AssertEqual(
OnNext(201, 42),
OnNext(202, 42),
OnNext(203, 42),
OnNext(204, 42),
OnNext(205, 42),
OnNext(206, 42)
);
}
[TestMethod]
public void Repeat_Value_Count_Default_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => Observable.Repeat(1, -1));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Repeat(1, 1).Subscribe(null));
}
[TestMethod]
public void Repeat_Value_Count_Default()
{
Observable.Repeat(42, 10).AssertEqual(Observable.Repeat(42, 10, DefaultScheduler.Instance));
}
[TestMethod]
public void Repeat_Value_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Repeat(1, (IScheduler)null));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Repeat(DummyScheduler.Instance, 1).Subscribe(null));
}
[TestMethod]
public void Repeat_Value()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Repeat(42, scheduler),
207
);
res.Messages.AssertEqual(
OnNext(201, 42),
OnNext(202, 42),
OnNext(203, 42),
OnNext(204, 42),
OnNext(205, 42),
OnNext(206, 42)
);
}
[TestMethod]
public void Repeat_Value_Default_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Repeat(1).Subscribe(null));
}
[TestMethod]
public void Repeat_Value_Default()
{
Observable.Repeat(42).Take(100).AssertEqual(Observable.Repeat(42, DefaultScheduler.Instance).Take(100));
}
#if !NO_PERF
[TestMethod]
public void Repeat_Count_LongRunning1()
{
var start = default(ManualResetEvent);
var end = default(ManualResetEvent);
var s = new TestLongRunningScheduler(x => start = x, x => end = x);
var xs = Observable.Repeat(42, 100, s);
var lst = new List<int>();
var done = false;
xs.Subscribe(x => { lst.Add(x); }, () => done = true);
end.WaitOne();
Assert.IsTrue(lst.SequenceEqual(Enumerable.Repeat(42, 100)));
Assert.IsTrue(done);
}
[TestMethod]
public void Repeat_Count_LongRunning2()
{
var start = default(ManualResetEvent);
var end = default(ManualResetEvent);
var s = new TestLongRunningScheduler(x => start = x, x => end = x);
var xs = Observable.Repeat(42, int.MaxValue, s);
var lst = new List<int>();
var d = xs.Subscribe(x => { lst.Add(x); });
start.WaitOne();
while (lst.Count < 100)
;
d.Dispose();
end.WaitOne();
Assert.IsTrue(true);
}
[TestMethod]
public void Repeat_Inf_LongRunning()
{
var start = default(ManualResetEvent);
var end = default(ManualResetEvent);
var s = new TestLongRunningScheduler(x => start = x, x => end = x);
var xs = Observable.Repeat(42, s);
var lst = new List<int>();
var d = xs.Subscribe(x => { lst.Add(x); });
start.WaitOne();
while (lst.Count < 100)
;
d.Dispose();
end.WaitOne();
Assert.IsTrue(true);
}
#endif
#endregion
#region + Return +
[TestMethod]
public void Return_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Return(0, null));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Return(0, DummyScheduler.Instance).Subscribe(null));
}
[TestMethod]
public void Return_Basic()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Return(42, scheduler)
);
res.Messages.AssertEqual(
OnNext(201, 42),
OnCompleted<int>(201)
);
}
[TestMethod]
public void Return_Disposed()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Return(42, scheduler),
200
);
res.Messages.AssertEqual(
);
}
[TestMethod]
public void Return_DisposedAfterNext()
{
var scheduler = new TestScheduler();
var d = new SerialDisposable();
var xs = Observable.Return(42, scheduler);
var res = scheduler.CreateObserver<int>();
scheduler.ScheduleAbsolute(100, () =>
d.Disposable = xs.Subscribe(
x =>
{
d.Dispose();
res.OnNext(x);
},
res.OnError,
res.OnCompleted
)
);
scheduler.Start();
res.Messages.AssertEqual(
OnNext(101, 42)
);
}
[TestMethod]
public void Return_ObserverThrows()
{
var scheduler1 = new TestScheduler();
var xs = Observable.Return(1, scheduler1);
xs.Subscribe(x => { throw new InvalidOperationException(); });
ReactiveAssert.Throws<InvalidOperationException>(() => scheduler1.Start());
var scheduler2 = new TestScheduler();
var ys = Observable.Return(1, scheduler2);
ys.Subscribe(x => { }, ex => { }, () => { throw new InvalidOperationException(); });
ReactiveAssert.Throws<InvalidOperationException>(() => scheduler2.Start());
}
[TestMethod]
public void Return_DefaultScheduler()
{
Observable.Return(42).AssertEqual(Observable.Return(42, DefaultScheduler.Instance));
}
#endregion
#region + Throw +
[TestMethod]
public void Throw_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Throw<int>(null));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Throw<int>(null, 42));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Throw<int>(new Exception(), null));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Throw<int>(new Exception(), null, 42));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Throw<int>(null, DummyScheduler.Instance));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Throw<int>(null, DummyScheduler.Instance, 42));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Throw<int>(new Exception(), DummyScheduler.Instance).Subscribe(null));
}
[TestMethod]
public void Throw_Basic()
{
var scheduler = new TestScheduler();
var ex = new Exception();
var res = scheduler.Start(() =>
Observable.Throw<int>(ex, scheduler)
);
res.Messages.AssertEqual(
OnError<int>(201, ex)
);
}
[TestMethod]
public void Throw_Disposed()
{
var scheduler = new TestScheduler();
var res = scheduler.Start(() =>
Observable.Throw<int>(new Exception(), scheduler),
200
);
res.Messages.AssertEqual(
);
}
[TestMethod]
public void Throw_ObserverThrows()
{
var scheduler1 = new TestScheduler();
var xs = Observable.Throw<int>(new Exception(), scheduler1);
xs.Subscribe(x => { }, ex => { throw new InvalidOperationException(); }, () => { });
ReactiveAssert.Throws<InvalidOperationException>(() => scheduler1.Start());
}
[TestMethod]
public void Throw_DefaultScheduler()
{
var ex = new Exception();
Observable.Throw<int>(ex).AssertEqual(Observable.Throw<int>(ex, DefaultScheduler.Instance));
}
[TestMethod]
public void Throw_Witness_Basic()
{
var scheduler = new TestScheduler();
var ex = new Exception();
var res = scheduler.Start(() =>
Observable.Throw<int>(ex, scheduler, 42)
);
res.Messages.AssertEqual(
OnError<int>(201, ex)
);
}
#endregion
#region + Using +
[TestMethod]
public void Using_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Using((Func<IDisposable>)null, DummyFunc<IDisposable, IObservable<int>>.Instance));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Using(DummyFunc<IDisposable>.Instance, (Func<IDisposable, IObservable<int>>)null));
ReactiveAssert.Throws</*some*/Exception>(() => Observable.Using(() => DummyDisposable.Instance, d => default(IObservable<int>)).Subscribe());
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Using(() => DummyDisposable.Instance, d => DummyObservable<int>.Instance).Subscribe(null));
}
[TestMethod]
public void Using_Null()
{
var scheduler = new TestScheduler();
var disposeInvoked = 0L;
var createInvoked = 0L;
var xs = default(ITestableObservable<long>);
var disposable = default(MockDisposable);
var _d = default(MockDisposable);
var res = scheduler.Start(() =>
Observable.Using(
() =>
{
disposeInvoked++;
disposable = default(MockDisposable);
return disposable;
},
d =>
{
_d = d;
createInvoked++;
xs = scheduler.CreateColdObservable(
OnNext<long>(100, scheduler.Clock),
OnCompleted<long>(200));
return xs;
}
)
);
Assert.AreSame(disposable, _d);
res.Messages.AssertEqual(
OnNext(300, 200L),
OnCompleted<long>(400)
);
Assert.AreEqual(1, createInvoked);
Assert.AreEqual(1, disposeInvoked);
xs.Subscriptions.AssertEqual(
Subscribe(200, 400)
);
Assert.IsNull(disposable);
}
[TestMethod]
public void Using_Complete()
{
var scheduler = new TestScheduler();
var disposeInvoked = 0;
var createInvoked = 0;
var xs = default(ITestableObservable<long>);
var disposable = default(MockDisposable);
var _d = default(MockDisposable);
var res = scheduler.Start(() =>
Observable.Using(
() =>
{
disposeInvoked++;
disposable = new MockDisposable(scheduler);
return disposable;
},
d =>
{
_d = d;
createInvoked++;
xs = scheduler.CreateColdObservable(
OnNext<long>(100, scheduler.Clock),
OnCompleted<long>(200));
return xs;
}
)
);
Assert.AreSame(disposable, _d);
res.Messages.AssertEqual(
OnNext(300, 200L),
OnCompleted<long>(400)
);
Assert.AreEqual(1, createInvoked);
Assert.AreEqual(1, disposeInvoked);
xs.Subscriptions.AssertEqual(
Subscribe(200, 400)
);
disposable.AssertEqual(
200,
400
);
}
[TestMethod]
public void Using_Error()
{
var scheduler = new TestScheduler();
var disposeInvoked = 0;
var createInvoked = 0;
var xs = default(ITestableObservable<long>);
var disposable = default(MockDisposable);
var _d = default(MockDisposable);
var ex = new Exception();
var res = scheduler.Start(() =>
Observable.Using(
() =>
{
disposeInvoked++;
disposable = new MockDisposable(scheduler);
return disposable;
},
d =>
{
_d = d;
createInvoked++;
xs = scheduler.CreateColdObservable(
OnNext<long>(100, scheduler.Clock),
OnError<long>(200, ex));
return xs;
}
)
);
Assert.AreSame(disposable, _d);
res.Messages.AssertEqual(
OnNext(300, 200L),
OnError<long>(400, ex)
);
Assert.AreEqual(1, createInvoked);
Assert.AreEqual(1, disposeInvoked);
xs.Subscriptions.AssertEqual(
Subscribe(200, 400)
);
disposable.AssertEqual(
200,
400
);
}
[TestMethod]
public void Using_Dispose()
{
var scheduler = new TestScheduler();
var disposeInvoked = 0;
var createInvoked = 0;
var xs = default(ITestableObservable<long>);
var disposable = default(MockDisposable);
var _d = default(MockDisposable);
var res = scheduler.Start(() =>
Observable.Using(
() =>
{
disposeInvoked++;
disposable = new MockDisposable(scheduler);
return disposable;
},
d =>
{
_d = d;
createInvoked++;
xs = scheduler.CreateColdObservable(
OnNext<long>(100, scheduler.Clock),
OnNext<long>(1000, scheduler.Clock + 1));
return xs;
}
)
);
Assert.AreSame(disposable, _d);
res.Messages.AssertEqual(
OnNext(300, 200L)
);
Assert.AreEqual(1, createInvoked);
Assert.AreEqual(1, disposeInvoked);
xs.Subscriptions.AssertEqual(
Subscribe(200, 1000)
);
disposable.AssertEqual(
200,
1000
);
}
[TestMethod]
public void Using_ThrowResourceSelector()
{
var scheduler = new TestScheduler();
var disposeInvoked = 0;
var createInvoked = 0;
var ex = new Exception();
var res = scheduler.Start(() =>
Observable.Using<int, IDisposable>(
() =>
{
disposeInvoked++;
throw ex;
},
d =>
{
createInvoked++;
return Observable.Never<int>();
}
)
);
res.Messages.AssertEqual(
OnError<int>(200, ex)
);
Assert.AreEqual(0, createInvoked);
Assert.AreEqual(1, disposeInvoked);
}
[TestMethod]
public void Using_ThrowResourceUsage()
{
var scheduler = new TestScheduler();
var ex = new Exception();
var disposeInvoked = 0;
var createInvoked = 0;
var disposable = default(MockDisposable);
var res = scheduler.Start(() =>
Observable.Using<int, IDisposable>(
() =>
{
disposeInvoked++;
disposable = new MockDisposable(scheduler);
return disposable;
},
d =>
{
createInvoked++;
throw ex;
}
)
);
res.Messages.AssertEqual(
OnError<int>(200, ex)
);
Assert.AreEqual(1, createInvoked);
Assert.AreEqual(1, disposeInvoked);
disposable.AssertEqual(
200,
200
);
}
#endregion
#region - UsingAsync -
#if !NO_TPL
[TestMethod]
public void UsingAsync_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Using<int, IDisposable>(null, (res, ct) => null));
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Using<int, IDisposable>(ct => null, null));
}
[TestMethod]
public void UsingAsync_Simple()
{
var done = false;
var xs = Observable.Using<int, IDisposable>(
ct => Task.Factory.StartNew<IDisposable>(() => Disposable.Create(() => done = true)),
(_, ct) => Task.Factory.StartNew<IObservable<int>>(() => Observable.Return(42))
);
var res = xs.ToEnumerable().ToList();
Assert.IsTrue(new[] { 42 }.SequenceEqual(res));
Assert.IsTrue(done);
}
[TestMethod]
public void UsingAsync_CancelResource()
{
var N = 10;// 0000;
for (int i = 0; i < N; i++)
{
var called = false;
var s = new ManualResetEvent(false);
var e = new ManualResetEvent(false);
var x = new ManualResetEvent(false);
var xs = Observable.Using<int, IDisposable>(
ct => Task.Factory.StartNew<IDisposable>(() =>
{
s.Set();
e.WaitOne();
while (!ct.IsCancellationRequested)
;
x.Set();
return Disposable.Empty;
}),
(_, ct) =>
{
called = true;
return Task.Factory.StartNew<IObservable<int>>(() =>
Observable.Return(42)
);
}
);
var d = xs.Subscribe(_ => { });
s.WaitOne();
d.Dispose();
e.Set();
x.WaitOne();
Assert.IsFalse(called);
}
}
[TestMethod]
public void UsingAsync_CancelFactory()
{
var N = 10;// 0000;
for (int i = 0; i < N; i++)
{
var gate = new object();
var disposed = false;
var called = false;
var s = new ManualResetEvent(false);
var e = new ManualResetEvent(false);
var x = new ManualResetEvent(false);
var xs = Observable.Using<int, IDisposable>(
ct => Task.Factory.StartNew<IDisposable>(() =>
Disposable.Create(() =>
{
lock (gate)
disposed = true;
})
),
(_, ct) => Task.Factory.StartNew<IObservable<int>>(() =>
{
s.Set();
e.WaitOne();
while (!ct.IsCancellationRequested)
;
x.Set();
return Observable.Defer<int>(() =>
{
called = true;
return Observable.Return(42);
});
})
);
var d = xs.Subscribe(_ => { });
s.WaitOne();
//
// This will *eventually* set the CancellationToken. There's a fundamental race between observing the CancellationToken
// and returning the IDisposable that will set the CancellationTokenSource. Notice this is reflected in the code above,
// by looping until the CancellationToken is set.
//
d.Dispose();
e.Set();
x.WaitOne();
while (true)
{
lock (gate)
if (disposed)
break;
}
Assert.IsFalse(called, i.ToString());
}
}
#endif
#endregion
}
}