863 lines
25 KiB
C#
863 lines
25 KiB
C#
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Reactive;
|
|||
|
using System.Reactive.Concurrency;
|
|||
|
using System.Reactive.Linq;
|
|||
|
using System.Reactive.Subjects;
|
|||
|
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;
|
|||
|
|
|||
|
namespace ReactiveTests.Tests
|
|||
|
{
|
|||
|
[TestClass]
|
|||
|
public class ObservableConversionTests : ReactiveTest
|
|||
|
{
|
|||
|
#region + Subscribe +
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void SubscribeToEnumerable_ArgumentChecking()
|
|||
|
{
|
|||
|
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Subscribe<int>((IEnumerable<int>)null, DummyObserver<int>.Instance));
|
|||
|
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Subscribe<int>(DummyEnumerable<int>.Instance, (IObserver<int>)null));
|
|||
|
|
|||
|
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Subscribe<int>((IEnumerable<int>)null, DummyObserver<int>.Instance, DummyScheduler.Instance));
|
|||
|
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Subscribe<int>(DummyEnumerable<int>.Instance, DummyObserver<int>.Instance, null));
|
|||
|
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Subscribe<int>(DummyEnumerable<int>.Instance, (IObserver<int>)null, DummyScheduler.Instance));
|
|||
|
ReactiveAssert.Throws<NullReferenceException>(() => NullEnumeratorEnumerable<int>.Instance.Subscribe(Observer.Create<int>(x => { }), Scheduler.CurrentThread));
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void SubscribeToEnumerable_Finite()
|
|||
|
{
|
|||
|
var scheduler = new TestScheduler();
|
|||
|
|
|||
|
var results = scheduler.CreateObserver<int>();
|
|||
|
var d = default(IDisposable);
|
|||
|
var xs = default(MockEnumerable<int>);
|
|||
|
|
|||
|
scheduler.ScheduleAbsolute(Created, () => xs = new MockEnumerable<int>(scheduler, Enumerable_Finite()));
|
|||
|
scheduler.ScheduleAbsolute(Subscribed, () => d = xs.Subscribe(results, scheduler));
|
|||
|
scheduler.ScheduleAbsolute(Disposed, () => d.Dispose());
|
|||
|
|
|||
|
scheduler.Start();
|
|||
|
|
|||
|
results.Messages.AssertEqual(
|
|||
|
OnNext(201, 1),
|
|||
|
OnNext(202, 2),
|
|||
|
OnNext(203, 3),
|
|||
|
OnNext(204, 4),
|
|||
|
OnNext(205, 5),
|
|||
|
OnCompleted<int>(206)
|
|||
|
);
|
|||
|
|
|||
|
xs.Subscriptions.AssertEqual(
|
|||
|
Subscribe(200, 206)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void SubscribeToEnumerable_Infinite()
|
|||
|
{
|
|||
|
var scheduler = new TestScheduler();
|
|||
|
|
|||
|
var results = scheduler.CreateObserver<int>();
|
|||
|
var d = default(IDisposable);
|
|||
|
var xs = default(MockEnumerable<int>);
|
|||
|
|
|||
|
scheduler.ScheduleAbsolute(Created, () => xs = new MockEnumerable<int>(scheduler, Enumerable_Infinite()));
|
|||
|
scheduler.ScheduleAbsolute(Subscribed, () => d = xs.Subscribe(results, scheduler));
|
|||
|
scheduler.ScheduleAbsolute(210, () => d.Dispose());
|
|||
|
|
|||
|
scheduler.Start();
|
|||
|
|
|||
|
results.Messages.AssertEqual(
|
|||
|
OnNext(201, 1),
|
|||
|
OnNext(202, 1),
|
|||
|
OnNext(203, 1),
|
|||
|
OnNext(204, 1),
|
|||
|
OnNext(205, 1),
|
|||
|
OnNext(206, 1),
|
|||
|
OnNext(207, 1),
|
|||
|
OnNext(208, 1),
|
|||
|
OnNext(209, 1)
|
|||
|
);
|
|||
|
|
|||
|
xs.Subscriptions.AssertEqual(
|
|||
|
Subscribe(200, 210)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void SubscribeToEnumerable_Error()
|
|||
|
{
|
|||
|
var scheduler = new TestScheduler();
|
|||
|
|
|||
|
var results = scheduler.CreateObserver<int>();
|
|||
|
var d = default(IDisposable);
|
|||
|
var xs = default(MockEnumerable<int>);
|
|||
|
var ex = new Exception();
|
|||
|
|
|||
|
scheduler.ScheduleAbsolute(Created, () => xs = new MockEnumerable<int>(scheduler, Enumerable_Error(ex)));
|
|||
|
scheduler.ScheduleAbsolute(Subscribed, () => d = xs.Subscribe(results, scheduler));
|
|||
|
scheduler.ScheduleAbsolute(Disposed, () => d.Dispose());
|
|||
|
|
|||
|
scheduler.Start();
|
|||
|
|
|||
|
results.Messages.AssertEqual(
|
|||
|
OnNext(201, 1),
|
|||
|
OnNext(202, 2),
|
|||
|
OnNext(203, 3),
|
|||
|
OnError<int>(204, ex)
|
|||
|
);
|
|||
|
|
|||
|
xs.Subscriptions.AssertEqual(
|
|||
|
Subscribe(200, 204)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
#if !SILVERLIGHTM7
|
|||
|
[TestMethod]
|
|||
|
public void SubscribeToEnumerable_DefaultScheduler()
|
|||
|
{
|
|||
|
for (int i = 0; i < 100; i++)
|
|||
|
{
|
|||
|
var scheduler = new TestScheduler();
|
|||
|
|
|||
|
var results1 = new List<int>();
|
|||
|
var results2 = new List<int>();
|
|||
|
|
|||
|
var s1 = new Semaphore(0, 1);
|
|||
|
var s2 = new Semaphore(0, 1);
|
|||
|
|
|||
|
Observable.Subscribe(Enumerable_Finite(),
|
|||
|
Observer.Create<int>(x => results1.Add(x), ex => { throw ex; }, () => s1.Release()));
|
|||
|
Observable.Subscribe(Enumerable_Finite(),
|
|||
|
Observer.Create<int>(x => results2.Add(x), ex => { throw ex; }, () => s2.Release()),
|
|||
|
DefaultScheduler.Instance);
|
|||
|
|
|||
|
s1.WaitOne();
|
|||
|
s2.WaitOne();
|
|||
|
|
|||
|
results1.AssertEqual(results2);
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region ToEnumerable
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEnumerable_ArgumentChecking()
|
|||
|
{
|
|||
|
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.ToEnumerable(default(IObservable<int>)));
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEnumerable_Generic()
|
|||
|
{
|
|||
|
Assert.IsTrue(Observable.Range(0, 10).ToEnumerable().SequenceEqual(Enumerable.Range(0, 10)));
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEnumerable_NonGeneric()
|
|||
|
{
|
|||
|
Assert.IsTrue(((IEnumerable)Observable.Range(0, 10).ToEnumerable()).Cast<int>().SequenceEqual(Enumerable.Range(0, 10)));
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEnumerable_ManualGeneric()
|
|||
|
{
|
|||
|
var res = Observable.Range(0, 10).ToEnumerable();
|
|||
|
var ieg = res.GetEnumerator();
|
|||
|
for (int i = 0; i < 10; i++)
|
|||
|
{
|
|||
|
Assert.IsTrue(ieg.MoveNext());
|
|||
|
Assert.AreEqual(i, ieg.Current);
|
|||
|
}
|
|||
|
Assert.IsFalse(ieg.MoveNext());
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEnumerable_ManualNonGeneric()
|
|||
|
{
|
|||
|
var res = (IEnumerable)Observable.Range(0, 10).ToEnumerable();
|
|||
|
var ien = res.GetEnumerator();
|
|||
|
for (int i = 0; i < 10; i++)
|
|||
|
{
|
|||
|
Assert.IsTrue(ien.MoveNext());
|
|||
|
Assert.AreEqual(i, ien.Current);
|
|||
|
}
|
|||
|
Assert.IsFalse(ien.MoveNext());
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEnumerable_ResetNotSupported()
|
|||
|
{
|
|||
|
ReactiveAssert.Throws<NotSupportedException>(() => Observable.Range(0, 10).ToEnumerable().GetEnumerator().Reset());
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region ToEvent
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEvent_ArgumentChecks()
|
|||
|
{
|
|||
|
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.ToEvent(default(IObservable<Unit>)));
|
|||
|
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.ToEvent(default(IObservable<int>)));
|
|||
|
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.ToEvent(default(IObservable<EventPattern<EventArgs>>)));
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEvent_Unit()
|
|||
|
{
|
|||
|
var src = new Subject<Unit>();
|
|||
|
var evt = src.ToEvent();
|
|||
|
|
|||
|
var num = 0;
|
|||
|
var hnd = new Action<Unit>(_ =>
|
|||
|
{
|
|||
|
num++;
|
|||
|
});
|
|||
|
|
|||
|
evt.OnNext += hnd;
|
|||
|
|
|||
|
Assert.AreEqual(0, num);
|
|||
|
|
|||
|
src.OnNext(new Unit());
|
|||
|
Assert.AreEqual(1, num);
|
|||
|
|
|||
|
src.OnNext(new Unit());
|
|||
|
Assert.AreEqual(2, num);
|
|||
|
|
|||
|
evt.OnNext -= hnd;
|
|||
|
|
|||
|
src.OnNext(new Unit());
|
|||
|
Assert.AreEqual(2, num);
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEvent_NonUnit()
|
|||
|
{
|
|||
|
var src = new Subject<int>();
|
|||
|
var evt = src.ToEvent();
|
|||
|
|
|||
|
var lst = new List<int>();
|
|||
|
var hnd = new Action<int>(e =>
|
|||
|
{
|
|||
|
lst.Add(e);
|
|||
|
});
|
|||
|
|
|||
|
evt.OnNext += hnd;
|
|||
|
|
|||
|
src.OnNext(1);
|
|||
|
src.OnNext(2);
|
|||
|
|
|||
|
evt.OnNext -= hnd;
|
|||
|
|
|||
|
src.OnNext(3);
|
|||
|
|
|||
|
Assert.IsTrue(lst.SequenceEqual(new[] { 1, 2 }));
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEvent_FromEvent()
|
|||
|
{
|
|||
|
var src = new Subject<int>();
|
|||
|
var evt = src.ToEvent();
|
|||
|
|
|||
|
var res = Observable.FromEvent<int>(h => evt.OnNext += h, h => evt.OnNext -= h);
|
|||
|
|
|||
|
var lst = new List<int>();
|
|||
|
using (res.Subscribe(e => lst.Add(e), () => Assert.Fail()))
|
|||
|
{
|
|||
|
src.OnNext(1);
|
|||
|
src.OnNext(2);
|
|||
|
}
|
|||
|
|
|||
|
src.OnNext(3);
|
|||
|
|
|||
|
Assert.IsTrue(lst.SequenceEqual(new[] { 1, 2 }));
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region ToEventPattern
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEventPattern_ArgumentChecking()
|
|||
|
{
|
|||
|
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.ToEventPattern<EventArgs>(null));
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEventPattern_IEvent()
|
|||
|
{
|
|||
|
var src = new Subject<EventPattern<EventArgs<int>>>();
|
|||
|
var evt = src.ToEventPattern();
|
|||
|
|
|||
|
var snd = new object();
|
|||
|
|
|||
|
var lst = new List<int>();
|
|||
|
var hnd = new EventHandler<EventArgs<int>>((s, e) =>
|
|||
|
{
|
|||
|
Assert.AreSame(snd, s);
|
|||
|
lst.Add(e.Value);
|
|||
|
});
|
|||
|
|
|||
|
evt.OnNext += hnd;
|
|||
|
|
|||
|
src.OnNext(new EventPattern<EventArgs<int>>(snd, new EventArgs<int>(42)));
|
|||
|
src.OnNext(new EventPattern<EventArgs<int>>(snd, new EventArgs<int>(43)));
|
|||
|
|
|||
|
evt.OnNext -= hnd;
|
|||
|
|
|||
|
src.OnNext(new EventPattern<EventArgs<int>>(snd, new EventArgs<int>(44)));
|
|||
|
|
|||
|
Assert.IsTrue(lst.SequenceEqual(new[] { 42, 43 }));
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEventPattern_IEvent_Fails()
|
|||
|
{
|
|||
|
var src = new Subject<EventPattern<EventArgs<int>>>();
|
|||
|
var evt = src.ToEventPattern();
|
|||
|
|
|||
|
var snd = new object();
|
|||
|
|
|||
|
var lst = new List<int>();
|
|||
|
var hnd = new EventHandler<EventArgs<int>>((s, e) =>
|
|||
|
{
|
|||
|
Assert.AreSame(snd, s);
|
|||
|
lst.Add(e.Value);
|
|||
|
});
|
|||
|
|
|||
|
evt.OnNext += hnd;
|
|||
|
|
|||
|
src.OnNext(new EventPattern<EventArgs<int>>(snd, new EventArgs<int>(42)));
|
|||
|
src.OnNext(new EventPattern<EventArgs<int>>(snd, new EventArgs<int>(43)));
|
|||
|
|
|||
|
var ex = new Exception();
|
|||
|
|
|||
|
ReactiveAssert.Throws(ex, () => src.OnError(ex));
|
|||
|
|
|||
|
Assert.IsTrue(lst.SequenceEqual(new[] { 42, 43 }));
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEventPattern_IEvent_Completes()
|
|||
|
{
|
|||
|
var src = new Subject<EventPattern<EventArgs<int>>>();
|
|||
|
var evt = src.ToEventPattern();
|
|||
|
|
|||
|
var snd = new object();
|
|||
|
|
|||
|
var lst = new List<int>();
|
|||
|
var hnd = new EventHandler<EventArgs<int>>((s, e) =>
|
|||
|
{
|
|||
|
Assert.AreSame(snd, s);
|
|||
|
lst.Add(e.Value);
|
|||
|
});
|
|||
|
|
|||
|
evt.OnNext += hnd;
|
|||
|
|
|||
|
src.OnNext(new EventPattern<EventArgs<int>>(snd, new EventArgs<int>(42)));
|
|||
|
src.OnNext(new EventPattern<EventArgs<int>>(snd, new EventArgs<int>(43)));
|
|||
|
|
|||
|
src.OnCompleted();
|
|||
|
|
|||
|
Assert.IsTrue(lst.SequenceEqual(new[] { 42, 43 }));
|
|||
|
}
|
|||
|
|
|||
|
class EventSrc
|
|||
|
{
|
|||
|
public event EventHandler<EventArgs<string>> E;
|
|||
|
|
|||
|
public void On(string s)
|
|||
|
{
|
|||
|
var e = E;
|
|||
|
if (e != null)
|
|||
|
e(this, new EventArgs<string>(s));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class EventArgs<T> : EventArgs
|
|||
|
{
|
|||
|
public T Value { get; private set; }
|
|||
|
|
|||
|
public EventArgs(T value)
|
|||
|
{
|
|||
|
Value = value;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void FromEventPattern_ToEventPattern()
|
|||
|
{
|
|||
|
var src = new EventSrc();
|
|||
|
var evt = Observable.FromEventPattern<EventHandler<EventArgs<string>>, EventArgs<string>>(h => new EventHandler<EventArgs<string>>(h), h => src.E += h, h => src.E -= h);
|
|||
|
|
|||
|
var res = evt.ToEventPattern();
|
|||
|
|
|||
|
var lst = new List<string>();
|
|||
|
var hnd = new EventHandler<EventArgs<string>>((s, e) =>
|
|||
|
{
|
|||
|
Assert.AreSame(src, s);
|
|||
|
lst.Add(e.Value);
|
|||
|
});
|
|||
|
|
|||
|
src.On("bar");
|
|||
|
|
|||
|
res.OnNext += hnd;
|
|||
|
|
|||
|
src.On("foo");
|
|||
|
src.On("baz");
|
|||
|
|
|||
|
res.OnNext -= hnd;
|
|||
|
|
|||
|
src.On("qux");
|
|||
|
|
|||
|
Assert.IsTrue(lst.SequenceEqual(new[] { "foo", "baz" }));
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEvent_DuplicateHandlers()
|
|||
|
{
|
|||
|
var src = new Subject<Unit>();
|
|||
|
var evt = src.ToEvent();
|
|||
|
|
|||
|
var num = 0;
|
|||
|
var hnd = new Action<Unit>(e => num++);
|
|||
|
|
|||
|
evt.OnNext += hnd;
|
|||
|
|
|||
|
Assert.AreEqual(0, num);
|
|||
|
|
|||
|
src.OnNext(new Unit());
|
|||
|
Assert.AreEqual(1, num);
|
|||
|
|
|||
|
evt.OnNext += hnd;
|
|||
|
|
|||
|
src.OnNext(new Unit());
|
|||
|
Assert.AreEqual(3, num);
|
|||
|
|
|||
|
evt.OnNext -= hnd;
|
|||
|
|
|||
|
src.OnNext(new Unit());
|
|||
|
Assert.AreEqual(4, num);
|
|||
|
|
|||
|
evt.OnNext -= hnd;
|
|||
|
|
|||
|
src.OnNext(new Unit());
|
|||
|
Assert.AreEqual(4, num);
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEvent_SourceCompletes()
|
|||
|
{
|
|||
|
var src = new Subject<Unit>();
|
|||
|
var evt = src.ToEvent();
|
|||
|
|
|||
|
var num = 0;
|
|||
|
var hnd = new Action<Unit>(e => num++);
|
|||
|
|
|||
|
evt.OnNext += hnd;
|
|||
|
|
|||
|
Assert.AreEqual(0, num);
|
|||
|
|
|||
|
src.OnNext(new Unit());
|
|||
|
Assert.AreEqual(1, num);
|
|||
|
|
|||
|
src.OnNext(new Unit());
|
|||
|
Assert.AreEqual(2, num);
|
|||
|
|
|||
|
src.OnCompleted();
|
|||
|
Assert.AreEqual(2, num);
|
|||
|
|
|||
|
#if !SILVERLIGHT // FieldAccessException
|
|||
|
var tbl = GetSubscriptionTable(evt);
|
|||
|
Assert.IsTrue(tbl.Count == 0);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEvent_SourceFails()
|
|||
|
{
|
|||
|
var src = new Subject<Unit>();
|
|||
|
var evt = src.ToEvent();
|
|||
|
|
|||
|
var num = 0;
|
|||
|
var hnd = new Action<Unit>(e => num++);
|
|||
|
|
|||
|
evt.OnNext += hnd;
|
|||
|
|
|||
|
Assert.AreEqual(0, num);
|
|||
|
|
|||
|
src.OnNext(new Unit());
|
|||
|
Assert.AreEqual(1, num);
|
|||
|
|
|||
|
src.OnNext(new Unit());
|
|||
|
Assert.AreEqual(2, num);
|
|||
|
|
|||
|
var ex = new Exception();
|
|||
|
|
|||
|
ReactiveAssert.Throws(ex, () => src.OnError(ex));
|
|||
|
|
|||
|
#if !SILVERLIGHT // FieldAccessException
|
|||
|
var tbl = GetSubscriptionTable(evt);
|
|||
|
Assert.IsTrue(tbl.Count == 0);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEvent_DoneImmediately()
|
|||
|
{
|
|||
|
var src = Observable.Empty<Unit>();
|
|||
|
var evt = src.ToEvent();
|
|||
|
|
|||
|
var num = 0;
|
|||
|
var hnd = new Action<Unit>(e => num++);
|
|||
|
|
|||
|
for (int i = 0; i < 2; i++)
|
|||
|
{
|
|||
|
evt.OnNext += hnd;
|
|||
|
|
|||
|
Assert.AreEqual(0, num);
|
|||
|
|
|||
|
#if !SILVERLIGHT // FieldAccessException
|
|||
|
var tbl = GetSubscriptionTable(evt);
|
|||
|
Assert.IsTrue(tbl.Count == 0);
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void ToEvent_UnbalancedHandlers()
|
|||
|
{
|
|||
|
var src = new Subject<Unit>();
|
|||
|
var evt = src.ToEvent();
|
|||
|
|
|||
|
var num = 0;
|
|||
|
var hnd = new Action<Unit>(e => num++);
|
|||
|
|
|||
|
evt.OnNext += hnd;
|
|||
|
Assert.AreEqual(0, num);
|
|||
|
|
|||
|
evt.OnNext -= hnd;
|
|||
|
Assert.AreEqual(0, num);
|
|||
|
|
|||
|
evt.OnNext -= hnd;
|
|||
|
Assert.AreEqual(0, num);
|
|||
|
|
|||
|
evt.OnNext += hnd;
|
|||
|
Assert.AreEqual(0, num);
|
|||
|
|
|||
|
src.OnNext(new Unit());
|
|||
|
Assert.AreEqual(1, num);
|
|||
|
|
|||
|
src.OnNext(new Unit());
|
|||
|
Assert.AreEqual(2, num);
|
|||
|
|
|||
|
evt.OnNext -= hnd;
|
|||
|
Assert.AreEqual(2, num);
|
|||
|
|
|||
|
src.OnNext(new Unit());
|
|||
|
Assert.AreEqual(2, num);
|
|||
|
}
|
|||
|
|
|||
|
private static Dictionary<Delegate, Stack<IDisposable>> GetSubscriptionTable(object evt)
|
|||
|
{
|
|||
|
return (Dictionary<Delegate, Stack<IDisposable>>)evt.GetType().GetField("_subscriptions", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(evt);
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void EventPattern_Equality()
|
|||
|
{
|
|||
|
var e1 = new EventPattern<string, EventArgs>("Bart", EventArgs.Empty);
|
|||
|
var e2 = new EventPattern<string, EventArgs>("Bart", EventArgs.Empty);
|
|||
|
|
|||
|
Assert.IsTrue(e1.Equals(e1));
|
|||
|
Assert.IsTrue(e1.Equals(e2));
|
|||
|
Assert.IsTrue(e2.Equals(e1));
|
|||
|
Assert.IsTrue(e1 == e2);
|
|||
|
Assert.IsTrue(!(e1 != e2));
|
|||
|
Assert.IsTrue(e1.GetHashCode() == e2.GetHashCode());
|
|||
|
|
|||
|
Assert.IsFalse(e1.Equals(null));
|
|||
|
Assert.IsFalse(e1.Equals("xy"));
|
|||
|
Assert.IsFalse(e1 == null);
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void EventPattern_Inequality()
|
|||
|
{
|
|||
|
var a1 = new MyEventArgs();
|
|||
|
var a2 = new MyEventArgs();
|
|||
|
|
|||
|
var e1 = new EventPattern<string, MyEventArgs>("Bart", a1);
|
|||
|
var e2 = new EventPattern<string, MyEventArgs>("John", a1);
|
|||
|
var e3 = new EventPattern<string, MyEventArgs>("Bart", a2);
|
|||
|
|
|||
|
Assert.IsTrue(!e1.Equals(e2));
|
|||
|
Assert.IsTrue(!e2.Equals(e1));
|
|||
|
Assert.IsTrue(!(e1 == e2));
|
|||
|
Assert.IsTrue(e1 != e2);
|
|||
|
Assert.IsTrue(e1.GetHashCode() != e2.GetHashCode());
|
|||
|
|
|||
|
Assert.IsTrue(!e1.Equals(e3));
|
|||
|
Assert.IsTrue(!e3.Equals(e1));
|
|||
|
Assert.IsTrue(!(e1 == e3));
|
|||
|
Assert.IsTrue(e1 != e3);
|
|||
|
Assert.IsTrue(e1.GetHashCode() != e3.GetHashCode());
|
|||
|
}
|
|||
|
|
|||
|
class MyEventArgs : EventArgs
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region + ToObservable +
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void EnumerableToObservable_ArgumentChecking()
|
|||
|
{
|
|||
|
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.ToObservable((IEnumerable<int>)null, DummyScheduler.Instance));
|
|||
|
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.ToObservable(DummyEnumerable<int>.Instance, (IScheduler)null));
|
|||
|
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.ToObservable(DummyEnumerable<int>.Instance, DummyScheduler.Instance).Subscribe(null));
|
|||
|
ReactiveAssert.Throws<NullReferenceException>(() => Observable.ToObservable(NullEnumeratorEnumerable<int>.Instance, Scheduler.CurrentThread).Subscribe());
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void EnumerableToObservable_Complete()
|
|||
|
{
|
|||
|
var scheduler = new TestScheduler();
|
|||
|
|
|||
|
var e = new MockEnumerable<int>(scheduler,
|
|||
|
new[] { 3, 1, 2, 4 }
|
|||
|
);
|
|||
|
|
|||
|
var results = scheduler.Start(() =>
|
|||
|
e.ToObservable(scheduler)
|
|||
|
);
|
|||
|
|
|||
|
results.Messages.AssertEqual(
|
|||
|
OnNext(201, 3),
|
|||
|
OnNext(202, 1),
|
|||
|
OnNext(203, 2),
|
|||
|
OnNext(204, 4),
|
|||
|
OnCompleted<int>(205)
|
|||
|
);
|
|||
|
|
|||
|
e.Subscriptions.AssertEqual(
|
|||
|
Subscribe(200, 205)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void EnumerableToObservable_Dispose()
|
|||
|
{
|
|||
|
var scheduler = new TestScheduler();
|
|||
|
|
|||
|
var e = new MockEnumerable<int>(scheduler,
|
|||
|
new[] { 3, 1, 2, 4 }
|
|||
|
);
|
|||
|
|
|||
|
var results = scheduler.Start(() =>
|
|||
|
e.ToObservable(scheduler),
|
|||
|
203
|
|||
|
);
|
|||
|
|
|||
|
results.Messages.AssertEqual(
|
|||
|
OnNext(201, 3),
|
|||
|
OnNext(202, 1)
|
|||
|
);
|
|||
|
|
|||
|
e.Subscriptions.AssertEqual(
|
|||
|
Subscribe(200, 203)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void EnumerableToObservable_Error()
|
|||
|
{
|
|||
|
var scheduler = new TestScheduler();
|
|||
|
|
|||
|
var ex = new Exception();
|
|||
|
|
|||
|
var e = new MockEnumerable<int>(scheduler,
|
|||
|
EnumerableToObservable_Error_Core(ex)
|
|||
|
);
|
|||
|
|
|||
|
var results = scheduler.Start(() =>
|
|||
|
e.ToObservable(scheduler)
|
|||
|
);
|
|||
|
|
|||
|
results.Messages.AssertEqual(
|
|||
|
OnNext(201, 1),
|
|||
|
OnNext(202, 2),
|
|||
|
OnError<int>(203, ex)
|
|||
|
);
|
|||
|
|
|||
|
e.Subscriptions.AssertEqual(
|
|||
|
Subscribe(200, 203)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void EnumerableToObservable_Default_ArgumentChecking()
|
|||
|
{
|
|||
|
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.ToObservable((IEnumerable<int>)null));
|
|||
|
ReactiveAssert.Throws<ArgumentNullException>(() => Observable.ToObservable(DummyEnumerable<int>.Instance).Subscribe(null));
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void EnumerableToObservable_Default()
|
|||
|
{
|
|||
|
var xs = new[] { 4, 3, 1, 5, 9, 2 };
|
|||
|
|
|||
|
xs.ToObservable().AssertEqual(xs.ToObservable(DefaultScheduler.Instance));
|
|||
|
}
|
|||
|
|
|||
|
#if !NO_PERF
|
|||
|
[TestMethod]
|
|||
|
public void EnumerableToObservable_LongRunning_Complete()
|
|||
|
{
|
|||
|
var start = default(ManualResetEvent);
|
|||
|
var end = default(ManualResetEvent);
|
|||
|
var scheduler = new TestLongRunningScheduler(x => start = x, x => end = x);
|
|||
|
|
|||
|
var e = new[] { 3, 1, 2, 4 };
|
|||
|
|
|||
|
var results = e.ToObservable(scheduler);
|
|||
|
|
|||
|
var lst = new List<int>();
|
|||
|
results.Subscribe(lst.Add);
|
|||
|
|
|||
|
start.WaitOne();
|
|||
|
end.WaitOne();
|
|||
|
|
|||
|
Assert.IsTrue(e.SequenceEqual(lst));
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void EnumerableToObservable_LongRunning_Dispose()
|
|||
|
{
|
|||
|
var start = default(ManualResetEvent);
|
|||
|
var end = default(ManualResetEvent);
|
|||
|
var scheduler = new TestLongRunningScheduler(x => start = x, x => end = x);
|
|||
|
|
|||
|
var e = Enumerable.Range(0, int.MaxValue);
|
|||
|
|
|||
|
var results = e.ToObservable(scheduler);
|
|||
|
|
|||
|
var lst = new List<int>();
|
|||
|
var d = results.Subscribe(lst.Add);
|
|||
|
|
|||
|
start.WaitOne();
|
|||
|
|
|||
|
while (lst.Count < 100)
|
|||
|
;
|
|||
|
|
|||
|
d.Dispose();
|
|||
|
end.WaitOne();
|
|||
|
|
|||
|
Assert.IsTrue(e.Take(100).SequenceEqual(lst.Take(100)));
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void EnumerableToObservable_LongRunning_Error()
|
|||
|
{
|
|||
|
var start = default(ManualResetEvent);
|
|||
|
var end = default(ManualResetEvent);
|
|||
|
var scheduler = new TestLongRunningScheduler(x => start = x, x => end = x);
|
|||
|
|
|||
|
var ex = new Exception();
|
|||
|
var e = EnumerableToObservable_Error_Core(ex);
|
|||
|
|
|||
|
var results = e.ToObservable(scheduler);
|
|||
|
|
|||
|
var lst = new List<int>();
|
|||
|
var err = default(Exception);
|
|||
|
results.Subscribe(lst.Add, ex_ => err = ex_);
|
|||
|
|
|||
|
start.WaitOne();
|
|||
|
end.WaitOne();
|
|||
|
|
|||
|
Assert.IsTrue(new[] { 1, 2 }.SequenceEqual(lst));
|
|||
|
Assert.AreSame(ex, err);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
static IEnumerable<int> EnumerableToObservable_Error_Core(Exception ex)
|
|||
|
{
|
|||
|
yield return 1;
|
|||
|
yield return 2;
|
|||
|
throw ex;
|
|||
|
}
|
|||
|
|
|||
|
[TestMethod]
|
|||
|
public void EnumerableToObservable_GetEnumeratorThrows()
|
|||
|
{
|
|||
|
var ex = new Exception();
|
|||
|
|
|||
|
var scheduler = new TestScheduler();
|
|||
|
|
|||
|
var xs = new RogueEnumerable<int>(ex);
|
|||
|
|
|||
|
var res = scheduler.Start(() =>
|
|||
|
xs.ToObservable(scheduler)
|
|||
|
);
|
|||
|
|
|||
|
res.Messages.AssertEqual(
|
|||
|
OnError<int>(200, ex)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region |> Helpers <|
|
|||
|
|
|||
|
IEnumerable<int> Enumerable_Finite()
|
|||
|
{
|
|||
|
yield return 1;
|
|||
|
yield return 2;
|
|||
|
yield return 3;
|
|||
|
yield return 4;
|
|||
|
yield return 5;
|
|||
|
yield break;
|
|||
|
}
|
|||
|
|
|||
|
IEnumerable<int> Enumerable_Infinite()
|
|||
|
{
|
|||
|
while (true)
|
|||
|
yield return 1;
|
|||
|
}
|
|||
|
|
|||
|
IEnumerable<int> Enumerable_Error(Exception exception)
|
|||
|
{
|
|||
|
yield return 1;
|
|||
|
yield return 2;
|
|||
|
yield return 3;
|
|||
|
throw exception;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
}
|
|||
|
}
|