Files
acceptance-tests
data
debian
docs
external
Newtonsoft.Json
api-doc-tools
api-snapshot
aspnetwebstack
binary-reference-assemblies
bockbuild
boringssl
cecil
cecil-legacy
corefx
corert
ikdasm
ikvm
linker
nuget-buildtasks
nunit-lite
roslyn-binaries
rx
Ix
Rx
NET
Resources
Samples
Source
.nuget
Microsoft.Reactive.Testing
Playground
References
Rx_Xamarin
System.Reactive.Core
System.Reactive.Debugger
System.Reactive.Experimental
System.Reactive.Interfaces
System.Reactive.Linq
System.Reactive.Observable.Aliases
System.Reactive.PlatformServices
System.Reactive.Providers
System.Reactive.Runtime.Remoting
System.Reactive.Windows.Forms
System.Reactive.Windows.Threading
System.Reactive.WindowsRuntime
Tests.System.Reactive
Dummies
Properties
Stress
Tests
Concurrency
AsyncLockTest.cs
ConcurrencyTest.cs
ControlSchedulerTest.cs
CurrentThreadSchedulerTest.cs
DefaultSchedulerTest.cs
DispatcherSchedulerTest.cs
EventLoopSchedulerTest.cs
HistoricalSchedulerTest.cs
ImmediateSchedulerTest.cs
NewThreadSchedulerTest.cs
ScheduledItemTest.cs
SchedulerTest.cs
StopwatchTest.cs
SynchronizationContextSchedulerTest.cs
SynchronizationTest.cs
TaskPoolSchedulerTest.cs
ThreadPoolSchedulerTest.cs
VirtualSchedulerTest.cs
Disposables
Linq
Aliases.cs
AnonymousTest.cs
ConnectableObservable.cs
ConnectableObservableTest.cs
DefaultConcurrencyAbstractionLayerTest.cs
EventPatternSourceBaseTest.cs
ListObservableTest.cs
MySubject.cs
NotificationTest.cs
ObserverTest.cs
PrivateTypesTest.cs
RegressionTest.cs
RogueEnumerable.cs
SystemClockTest.cs
TaskObservableExtensionsTest.cs
TimeTests.cs
UnitTest.cs
App.cs
DispatcherHelpers.cs
Extensions.cs
MockDisposable.cs
MockEnumerable.cs
NullErrorObservable.cs
Semaphore.cs
TestBase.cs
TestLongRunningScheduler.cs
TestTaskScheduler.cs
Tests.System.Reactive.csproj
Utils.cs
packages
.gitattributes
.gitignore
35MSSharedLib1024.snk
Build.bat
BuildAll.proj
BuildSetup.bat
Clean.bat
Common.targets
Import.targets
Local.testsettings
README.txt
Rx.ruleset
Rx.sln.REMOVED.git-id
Test.ruleset
TraceAndTestImpact.testsettings
license.txt
packages.config
Test
tools
component
xpkg
.gitignore
README-microsoft-original.md
README.md
Rakefile
mono.patch
replacer.sh
xunit-binaries
ikvm-native
libgc
llvm
m4
man
mcs
mono
msvc
po
runtime
samples
scripts
support
tools
COPYING.LIB
LICENSE
Makefile.am
Makefile.in
NEWS
README.md
acinclude.m4
aclocal.m4
autogen.sh
code_of_conduct.md
compile
config.guess
config.h.in
config.rpath
config.sub
configure.REMOVED.git-id
configure.ac.REMOVED.git-id
depcomp
install-sh
ltmain.sh.REMOVED.git-id
missing
mkinstalldirs
mono-uninstalled.pc.in
test-driver
winconfig.h
Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

1090 lines
39 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.Generic;
using System.Linq;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.PlatformServices;
using System.Runtime.CompilerServices;
using System.Threading;
#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 Microsoft.Reactive.Testing;
#if HAS_WINFORMS
using System.Windows.Forms;
#endif
namespace ReactiveTests.Tests
{
[TestClass]
public class SchedulerTest
{
#region IScheduler
[TestMethod]
public void Scheduler_ArgumentChecks()
{
var ms = new MyScheduler();
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default(IScheduler), a => { }));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default(IScheduler), () => { }));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default(IScheduler), 1, (a, s) => { }));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(ms, default(Action<Action>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(ms, 1, default(Action<int, Action<int>>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default(IScheduler), DateTimeOffset.Now, a => { }));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default(IScheduler), DateTimeOffset.Now, () => { }));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default(IScheduler), 1, DateTimeOffset.Now, (a, s) => { }));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(ms, DateTimeOffset.Now, default(Action<Action<DateTimeOffset>>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(ms, 1, DateTimeOffset.Now, default(Action<int, Action<int, DateTimeOffset>>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default(IScheduler), TimeSpan.Zero, a => { }));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default(IScheduler), TimeSpan.Zero, () => { }));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default(IScheduler), 1, TimeSpan.Zero, (a, s) => { }));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(ms, TimeSpan.Zero, default(Action<Action<TimeSpan>>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(ms, 1, TimeSpan.Zero, default(Action<int, Action<int, TimeSpan>>)));
}
[TestMethod]
public void Schedulers_ArgumentChecks()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.CurrentThread.Schedule(default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.CurrentThread.Schedule(TimeSpan.Zero, default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.CurrentThread.Schedule(DateTimeOffset.MaxValue, default(Action)));
#if !NO_WINDOWS_THREADING
ReactiveAssert.Throws<ArgumentNullException>(() => DispatcherScheduler.Instance.Schedule(default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => DispatcherScheduler.Instance.Schedule(TimeSpan.Zero, default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => DispatcherScheduler.Instance.Schedule(DateTimeOffset.MaxValue, default(Action)));
#endif
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Immediate.Schedule(default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Immediate.Schedule(TimeSpan.Zero, default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Immediate.Schedule(DateTimeOffset.MaxValue, default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => NewThreadScheduler.Default.Schedule(default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => NewThreadScheduler.Default.Schedule(TimeSpan.Zero, default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => NewThreadScheduler.Default.Schedule(DateTimeOffset.MaxValue, default(Action)));
#if !NO_TPL
ReactiveAssert.Throws<ArgumentNullException>(() => TaskPoolScheduler.Default.Schedule(default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => TaskPoolScheduler.Default.Schedule(TimeSpan.Zero, default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => TaskPoolScheduler.Default.Schedule(DateTimeOffset.MaxValue, default(Action)));
#endif
ReactiveAssert.Throws<ArgumentNullException>(() => DefaultScheduler.Instance.Schedule(default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => DefaultScheduler.Instance.Schedule(TimeSpan.Zero, default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => DefaultScheduler.Instance.Schedule(DateTimeOffset.MaxValue, default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => DefaultScheduler.Instance.SchedulePeriodic(42, TimeSpan.FromSeconds(1), default(Func<int, int>)));
ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => DefaultScheduler.Instance.SchedulePeriodic(42, TimeSpan.FromSeconds(-1), _ => _));
#if HAS_WINFORMS
var lbl = new Label();
ReactiveAssert.Throws<ArgumentNullException>(() => new ControlScheduler(lbl).Schedule(default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => new ControlScheduler(lbl).Schedule(TimeSpan.Zero, default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => new ControlScheduler(lbl).Schedule(DateTimeOffset.MaxValue, default(Action)));
#endif
var ctx = new SynchronizationContext();
ReactiveAssert.Throws<ArgumentNullException>(() => new SynchronizationContextScheduler(ctx).Schedule(default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => new SynchronizationContextScheduler(ctx).Schedule(TimeSpan.Zero, default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => new SynchronizationContextScheduler(ctx).Schedule(DateTimeOffset.MaxValue, default(Action)));
}
[TestMethod]
public void Scheduler_ScheduleNonRecursive()
{
var ms = new MyScheduler();
var res = false;
Scheduler.Schedule(ms, a => { res = true; });
Assert.IsTrue(res);
}
[TestMethod]
public void Scheduler_ScheduleRecursive()
{
var ms = new MyScheduler();
var i = 0;
Scheduler.Schedule(ms, a => { if (++i < 10) a(); });
Assert.AreEqual(10, i);
}
[TestMethod]
public void Scheduler_ScheduleWithTimeNonRecursive()
{
var now = DateTimeOffset.Now;
var ms = new MyScheduler(now) { Check = (a, s, t) => { Assert.IsTrue(t == TimeSpan.Zero); } };
var res = false;
Scheduler.Schedule(ms, now, a => { res = true; });
Assert.IsTrue(res);
Assert.IsTrue(ms.WaitCycles == 0);
}
[TestMethod]
public void Scheduler_ScheduleWithTimeRecursive()
{
var now = DateTimeOffset.Now;
var i = 0;
var ms = new MyScheduler(now) { Check = (a, s, t) => { Assert.IsTrue(t == TimeSpan.Zero); } };
Scheduler.Schedule(ms, now, a => { if (++i < 10) a(now); });
Assert.IsTrue(ms.WaitCycles == 0);
Assert.AreEqual(10, i);
}
[TestMethod]
public void Scheduler_ScheduleWithTimeSpanNonRecursive()
{
var now = DateTimeOffset.Now;
var ms = new MyScheduler(now) { Check = (a, s, t) => { Assert.IsTrue(t == TimeSpan.Zero); } };
var res = false;
Scheduler.Schedule(ms, TimeSpan.Zero, a => { res = true; });
Assert.IsTrue(res);
Assert.IsTrue(ms.WaitCycles == 0);
}
[TestMethod]
public void Scheduler_ScheduleWithTimeSpanRecursive()
{
var now = DateTimeOffset.Now;
var ms = new MyScheduler(now) { Check = (a, s, t) => { Assert.IsTrue(t < TimeSpan.FromTicks(10)); } };
var i = 0;
Scheduler.Schedule(ms, TimeSpan.Zero, a => { if (++i < 10) a(TimeSpan.FromTicks(i)); });
Assert.IsTrue(ms.WaitCycles == Enumerable.Range(1, 9).Sum());
Assert.AreEqual(10, i);
}
[TestMethod]
public void Scheduler_StateThreading()
{
var lst = new List<int>();
Scheduler.Immediate.Schedule(0, (i, a) =>
{
lst.Add(i);
if (i < 9)
a(i + 1);
});
Assert.IsTrue(lst.SequenceEqual(Enumerable.Range(0, 10)));
}
[TestMethod]
public void Scheduler_Builtins()
{
// Default
{
var e = new ManualResetEvent(false);
Scheduler.Default.Schedule(() => e.Set());
e.WaitOne();
}
if (!Utils.IsRunningWithPortableLibraryBinaries())
{
Scheduler_Builtins_NoPlib();
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void Scheduler_Builtins_NoPlib()
{
#if !PLIB
// ThreadPool
{
var e = new ManualResetEvent(false);
Scheduler.ThreadPool.Schedule(() => e.Set());
e.WaitOne();
}
#endif
#if !NO_THREAD
// NewThread
{
var e = new ManualResetEvent(false);
Scheduler.NewThread.Schedule(() => e.Set());
e.WaitOne();
}
#endif
#if !NO_TPL
// TaskPool
{
var e = new ManualResetEvent(false);
Scheduler.TaskPool.Schedule(() => e.Set());
e.WaitOne();
}
#endif
}
#endregion
#region ISchedulerLongRunning
#if !NO_PERF
[TestMethod]
public void Scheduler_LongRunning_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleLongRunning(null, c => { }));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleLongRunning(ThreadPoolScheduler.Instance, default(Action<ICancelable>)));
}
[TestMethod]
public void Scheduler_Periodic_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.SchedulePeriodic(null, TimeSpan.FromSeconds(1), () => { }));
ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => Scheduler.SchedulePeriodic(ThreadPoolScheduler.Instance, TimeSpan.FromSeconds(-1), () => { }));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.SchedulePeriodic(ThreadPoolScheduler.Instance, TimeSpan.FromSeconds(1), default(Action)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.SchedulePeriodic<int>(null, 42, TimeSpan.FromSeconds(1), _ => { }));
ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => Scheduler.SchedulePeriodic<int>(ThreadPoolScheduler.Instance, 42, TimeSpan.FromSeconds(-1), _ => { }));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.SchedulePeriodic<int>(ThreadPoolScheduler.Instance, 42, TimeSpan.FromSeconds(1), default(Action<int>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.SchedulePeriodic<int>(null, 42, TimeSpan.FromSeconds(1), _ => _));
ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => Scheduler.SchedulePeriodic<int>(ThreadPoolScheduler.Instance, 42, TimeSpan.FromSeconds(-1), _ => _));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.SchedulePeriodic<int>(ThreadPoolScheduler.Instance, 42, TimeSpan.FromSeconds(1), default(Func<int, int>)));
}
[TestMethod]
public void Scheduler_Stopwatch_Emulation()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.StartStopwatch(null));
}
#if !NO_TPL
[TestMethod]
public void Scheduler_LongRunning1()
{
var s = TaskPoolScheduler.Default;
var x = new ManualResetEvent(false);
var e = new ManualResetEvent(false);
var d = s.ScheduleLongRunning(42, (state, cancel) =>
{
while (!cancel.IsDisposed)
x.Set();
e.Set();
});
x.WaitOne();
d.Dispose();
e.WaitOne();
}
[TestMethod]
public void Scheduler_LongRunning2()
{
var s = TaskPoolScheduler.Default;
var x = new ManualResetEvent(false);
var e = new ManualResetEvent(false);
var d = s.ScheduleLongRunning(cancel =>
{
while (!cancel.IsDisposed)
x.Set();
e.Set();
});
x.WaitOne();
d.Dispose();
e.WaitOne();
}
#endif
#endif
#endregion
#region ISchedulerPeriodic
#if !NO_PERF
[TestMethod]
public void Scheduler_Periodic1()
{
var n = 0;
var e = new ManualResetEvent(false);
var d = ThreadPoolScheduler.Instance.SchedulePeriodic(TimeSpan.FromMilliseconds(50), () =>
{
if (n++ == 10)
e.Set();
});
e.WaitOne();
d.Dispose();
}
[TestMethod]
public void Scheduler_Periodic2()
{
var n = 0;
var e = new ManualResetEvent(false);
var d = ThreadPoolScheduler.Instance.SchedulePeriodic(42, TimeSpan.FromMilliseconds(50), x =>
{
Assert.AreEqual(42, x);
if (n++ == 10)
e.Set();
});
e.WaitOne();
d.Dispose();
}
#if DESKTOPCLR
[TestMethod]
public void Scheduler_Periodic_HostLifecycleManagement()
{
var cur = Utils.GetTestBaseDirectory();
var domain = AppDomain.CreateDomain("HLN", null, new AppDomainSetup { ApplicationBase = cur });
domain.DoCallBack(() =>
{
var pep = PlatformEnlightenmentProvider.Current;
try
{
var hln = new HLN();
PlatformEnlightenmentProvider.Current = new PEP(hln);
var s = ThreadPoolScheduler.Instance.DisableOptimizations(typeof(ISchedulerPeriodic));
var n = 0;
var e = new ManualResetEvent(false);
var d = Observable.Interval(TimeSpan.FromMilliseconds(100), s).Subscribe(_ =>
{
if (n++ == 10)
e.Set();
});
hln.OnSuspending();
hln.OnResuming();
Thread.Sleep(250);
hln.OnSuspending();
Thread.Sleep(150);
hln.OnResuming();
Thread.Sleep(50);
hln.OnSuspending();
hln.OnResuming();
e.WaitOne();
d.Dispose();
}
finally
{
PlatformEnlightenmentProvider.Current = pep;
}
});
}
class PEP : IPlatformEnlightenmentProvider
{
private readonly IPlatformEnlightenmentProvider _old;
private readonly IHostLifecycleNotifications _hln;
public PEP(HLN hln)
{
_old = PlatformEnlightenmentProvider.Current;
_hln = hln;
}
public T GetService<T>(params object[] args) where T : class
{
if (typeof(T) == typeof(IHostLifecycleNotifications))
{
return (T)(object)_hln;
}
return _old.GetService<T>(args);
}
}
class HLN : IHostLifecycleNotifications
{
public event EventHandler<HostSuspendingEventArgs> Suspending;
public event EventHandler<HostResumingEventArgs> Resuming;
public void OnSuspending()
{
var s = Suspending;
if (s != null)
s(this, null);
}
public void OnResuming()
{
var s = Resuming;
if (s != null)
s(this, null);
}
}
#endif
#endif
#endregion
#region DisableOptimizations
#if !NO_PERF
[TestMethod]
public void DisableOptimizations_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.DisableOptimizations(default(IScheduler)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.DisableOptimizations(default(IScheduler), new Type[0]));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.DisableOptimizations(ThreadPoolScheduler.Instance, default(Type[])));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.DisableOptimizations(Scheduler.Default).Schedule(42, default(Func<IScheduler, int, IDisposable>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.DisableOptimizations(Scheduler.Default).Schedule(42, TimeSpan.FromSeconds(1), default(Func<IScheduler, int, IDisposable>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.DisableOptimizations(Scheduler.Default).Schedule(42, DateTimeOffset.Now, default(Func<IScheduler, int, IDisposable>)));
}
#if !NO_TPL
[TestMethod]
public void DisableOptimizations1()
{
var s = TaskPoolScheduler.Default;
Assert.IsTrue(s is IServiceProvider);
var t = s.DisableOptimizations();
var d = t.Now - s.Now;
Assert.IsTrue(d.TotalSeconds < 1);
var e1 = new ManualResetEvent(false);
t.Schedule(42, (self, state) =>
{
e1.Set();
return Disposable.Empty;
});
e1.WaitOne();
var e2 = new ManualResetEvent(false);
t.Schedule(42, TimeSpan.FromMilliseconds(1), (self, state) =>
{
e2.Set();
return Disposable.Empty;
});
e2.WaitOne();
var e3 = new ManualResetEvent(false);
t.Schedule(42, DateTimeOffset.Now.AddMilliseconds(10), (self, state) =>
{
e3.Set();
return Disposable.Empty;
});
e3.WaitOne();
}
[TestMethod]
public void DisableOptimizations2()
{
var s = TaskPoolScheduler.Default;
Assert.IsTrue(s is IServiceProvider);
var lr1 = ((IServiceProvider)s).GetService(typeof(ISchedulerLongRunning));
Assert.IsNotNull(lr1);
var e1 = new ManualResetEvent(false);
s.Schedule(42, (self, state) =>
{
Assert.IsTrue(self is IServiceProvider);
var lrr1 = ((IServiceProvider)self).GetService(typeof(ISchedulerLongRunning));
Assert.IsNotNull(lrr1);
e1.Set();
return Disposable.Empty;
});
e1.WaitOne();
var t = s.DisableOptimizations();
Assert.IsTrue(t is IServiceProvider);
var lr2 = ((IServiceProvider)t).GetService(typeof(ISchedulerLongRunning));
Assert.IsNull(lr2);
var e2 = new ManualResetEvent(false);
t.Schedule(42, (self, state) =>
{
Assert.IsTrue(self is IServiceProvider);
var lrr2 = ((IServiceProvider)self).GetService(typeof(ISchedulerLongRunning));
Assert.IsNull(lrr2);
e2.Set();
return Disposable.Empty;
});
e2.WaitOne();
}
[TestMethod]
public void DisableOptimizations3()
{
var s = TaskPoolScheduler.Default;
Assert.IsTrue(s is IServiceProvider);
var lr1 = ((IServiceProvider)s).GetService(typeof(ISchedulerLongRunning));
Assert.IsNotNull(lr1);
var p1 = ((IServiceProvider)s).GetService(typeof(ISchedulerPeriodic));
Assert.IsNotNull(p1);
var e1 = new ManualResetEvent(false);
s.Schedule(42, (self, state) =>
{
Assert.IsTrue(self is IServiceProvider);
var lrr1 = ((IServiceProvider)self).GetService(typeof(ISchedulerLongRunning));
Assert.IsNotNull(lrr1);
var pr1 = ((IServiceProvider)self).GetService(typeof(ISchedulerPeriodic));
Assert.IsNotNull(pr1);
e1.Set();
return Disposable.Empty;
});
e1.WaitOne();
var t = s.DisableOptimizations(typeof(ISchedulerLongRunning));
Assert.IsTrue(t is IServiceProvider);
var lr2 = ((IServiceProvider)t).GetService(typeof(ISchedulerLongRunning));
Assert.IsNull(lr2);
var p2 = ((IServiceProvider)t).GetService(typeof(ISchedulerPeriodic));
Assert.IsNotNull(p2);
var e2 = new ManualResetEvent(false);
t.Schedule(42, (self, state) =>
{
Assert.IsTrue(self is IServiceProvider);
var lrr2 = ((IServiceProvider)self).GetService(typeof(ISchedulerLongRunning));
Assert.IsNull(lrr2);
var pr2 = ((IServiceProvider)self).GetService(typeof(ISchedulerPeriodic));
Assert.IsNotNull(pr2);
e2.Set();
return Disposable.Empty;
});
e2.WaitOne();
}
#endif
#endif
[TestMethod]
public void DisableOptimizations_UnknownService()
{
var s = new MyScheduler();
Assert.IsFalse(s is IServiceProvider);
var d = s.DisableOptimizations();
Assert.IsTrue(d is IServiceProvider);
Assert.IsNull(((IServiceProvider)d).GetService(typeof(bool)));
}
class MyScheduler : IScheduler
{
public MyScheduler()
: this(DateTimeOffset.Now)
{
}
public MyScheduler(DateTimeOffset now)
{
Now = now;
}
public DateTimeOffset Now
{
get;
private set;
}
public IDisposable Schedule<T>(T state, Func<IScheduler, T, IDisposable> action)
{
return action(this, state);
}
public Action<Action<object>, object, TimeSpan> Check { get; set; }
public long WaitCycles { get; set; }
public IDisposable Schedule<T>(T state, TimeSpan dueTime, Func<IScheduler, T, IDisposable> action)
{
Check(o => action(this, (T)o), state, dueTime);
WaitCycles += dueTime.Ticks;
return action(this, state);
}
public IDisposable Schedule<T>(T state, DateTimeOffset dueTime, Func<IScheduler, T, IDisposable> action)
{
return Schedule(state, dueTime - Now, action);
}
}
#endregion
#region Catch
[TestMethod]
public void Catch_ArgumentChecking()
{
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Catch<Exception>(default(IScheduler), _ => true));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Catch<Exception>(Scheduler.Default, default(Func<Exception, bool>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Catch<Exception>(Scheduler.Default, _ => true).Schedule(42, default(Func<IScheduler, int, IDisposable>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Catch<Exception>(Scheduler.Default, _ => true).Schedule(42, TimeSpan.FromSeconds(1), default(Func<IScheduler, int, IDisposable>)));
ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Catch<Exception>(Scheduler.Default, _ => true).Schedule(42, DateTimeOffset.Now, default(Func<IScheduler, int, IDisposable>)));
}
[TestMethod]
public void Catch_Builtin_Swallow_Shallow()
{
var done = new ManualResetEvent(false);
var swallow = Scheduler.Default.Catch<InvalidOperationException>(_ => { done.Set(); return true; });
swallow.Schedule(() =>
{
throw new InvalidOperationException();
});
done.WaitOne();
}
[TestMethod]
public void Catch_Builtin_Swallow_Recursive()
{
var done = new ManualResetEvent(false);
var swallow = Scheduler.Default.Catch<InvalidOperationException>(_ => { done.Set(); return true; });
swallow.Schedule(42, (self, state) =>
{
return self.Schedule(() =>
{
throw new InvalidOperationException();
});
});
done.WaitOne();
}
[TestMethod]
public void Catch_Custom_Unhandled()
{
var err = default(Exception);
var scheduler = new MyExceptionScheduler(ex_ => err = ex_);
scheduler.Catch<InvalidOperationException>(_ => true).Schedule(() =>
{
throw new InvalidOperationException();
});
Assert.IsNull(err);
var ex = new ArgumentException();
scheduler.Catch<InvalidOperationException>(_ => true).Schedule(() =>
{
throw ex;
});
Assert.AreSame(ex, err);
}
[TestMethod]
public void Catch_Custom_Rethrow()
{
var err = default(Exception);
var scheduler = new MyExceptionScheduler(ex_ => err = ex_);
var ex = new InvalidOperationException();
scheduler.Catch<InvalidOperationException>(_ => false).Schedule(() =>
{
throw ex;
});
Assert.AreSame(ex, err);
}
[TestMethod]
public void Catch_Custom_LongRunning_Caught()
{
var err = default(Exception);
var scheduler = new MyExceptionScheduler(ex_ => err = ex_);
var caught = false;
var @catch = scheduler.Catch<InvalidOperationException>(_ => caught = true);
var slr = (ISchedulerLongRunning)((IServiceProvider)@catch).GetService(typeof(ISchedulerLongRunning));
slr.ScheduleLongRunning(cancel =>
{
throw new InvalidOperationException();
});
Assert.IsTrue(caught);
Assert.IsNull(err);
var ex = new ArgumentException();
slr.ScheduleLongRunning(cancel =>
{
throw ex;
});
Assert.AreSame(ex, err);
}
[TestMethod]
public void Catch_Custom_LongRunning_Rethrow()
{
var err = default(Exception);
var scheduler = new MyExceptionScheduler(ex_ => err = ex_);
var @catch = scheduler.Catch<InvalidOperationException>(_ => false);
var slr = (ISchedulerLongRunning)((IServiceProvider)@catch).GetService(typeof(ISchedulerLongRunning));
var done = false;
slr.ScheduleLongRunning(cancel =>
{
done = true;
});
Assert.IsTrue(done);
var ex = new InvalidOperationException();
slr.ScheduleLongRunning(cancel =>
{
throw ex;
});
Assert.AreSame(ex, err);
}
[TestMethod]
public void Catch_Custom_Periodic_Regular()
{
var scheduler = new MyExceptionScheduler(_ => { });
scheduler.PeriodicStopped = new ManualResetEvent(false);
var @catch = scheduler.Catch<InvalidOperationException>(_ => true);
var per = (ISchedulerPeriodic)((IServiceProvider)@catch).GetService(typeof(ISchedulerPeriodic));
var madeProgress = new ManualResetEvent(false);
var d = per.SchedulePeriodic(0, TimeSpan.Zero, x =>
{
if (x > 10)
madeProgress.Set();
return x + 1;
});
madeProgress.WaitOne();
d.Dispose();
scheduler.PeriodicStopped.WaitOne();
}
[TestMethod]
public void Catch_Custom_Periodic_Uncaught1()
{
var err = default(Exception);
var done = new ManualResetEvent(false);
var scheduler = new MyExceptionScheduler(ex_ => { err = ex_; done.Set(); });
scheduler.PeriodicStopped = new ManualResetEvent(false);
var @catch = scheduler.Catch<InvalidOperationException>(_ => true);
var per = (ISchedulerPeriodic)((IServiceProvider)@catch).GetService(typeof(ISchedulerPeriodic));
var ex = new ArgumentException();
per.SchedulePeriodic(42, TimeSpan.Zero, x =>
{
throw ex;
});
scheduler.PeriodicStopped.WaitOne();
done.WaitOne();
Assert.AreSame(ex, err);
}
[TestMethod]
public void Catch_Custom_Periodic_Uncaught2()
{
var err = default(Exception);
var done = new ManualResetEvent(false);
var scheduler = new MyExceptionScheduler(ex_ => { err = ex_; done.Set(); });
scheduler.PeriodicStopped = new ManualResetEvent(false);
var @catch = scheduler.Catch<InvalidOperationException>(_ => false);
var per = (ISchedulerPeriodic)((IServiceProvider)@catch).GetService(typeof(ISchedulerPeriodic));
var ex = new InvalidOperationException();
per.SchedulePeriodic(42, TimeSpan.Zero, x =>
{
throw ex;
});
scheduler.PeriodicStopped.WaitOne();
done.WaitOne();
Assert.AreSame(ex, err);
}
[TestMethod]
public void Catch_Custom_Periodic_Caught()
{
var err = default(Exception);
var scheduler = new MyExceptionScheduler(ex_ => err = ex_);
scheduler.PeriodicStopped = new ManualResetEvent(false);
var caught = new ManualResetEvent(false);
var @catch = scheduler.Catch<InvalidOperationException>(_ => { caught.Set(); return true; });
var per = (ISchedulerPeriodic)((IServiceProvider)@catch).GetService(typeof(ISchedulerPeriodic));
per.SchedulePeriodic(42, TimeSpan.Zero, x =>
{
throw new InvalidOperationException();
});
scheduler.PeriodicStopped.WaitOne();
caught.WaitOne();
Assert.IsNull(err);
}
class MyExceptionScheduler : LocalScheduler, ISchedulerLongRunning, ISchedulerPeriodic
{
private readonly Action<Exception> _onError;
public MyExceptionScheduler(Action<Exception> onError)
{
_onError = onError;
}
public override IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
{
try
{
return action(this, state);
}
catch (Exception exception)
{
_onError(exception);
return Disposable.Empty;
}
}
public override IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
{
throw new NotImplementedException();
}
public IDisposable ScheduleLongRunning<TState>(TState state, Action<TState, ICancelable> action)
{
var b = new BooleanDisposable();
try
{
action(state, b);
}
catch (Exception exception)
{
_onError(exception);
return Disposable.Empty;
}
return b;
}
public ManualResetEvent PeriodicStopped { get; set; }
public IDisposable SchedulePeriodic<TState>(TState state, TimeSpan period, Func<TState, TState> action)
{
var b = new BooleanDisposable();
Scheduler.Default.Schedule(() =>
{
try
{
var s = state;
for (int i = 0; true; i++)
{
if (i > 100 /* mimic delayed cancellation */ && b.IsDisposed)
break;
s = action(s);
}
}
catch (Exception exception)
{
_onError(exception);
}
finally
{
PeriodicStopped.Set();
}
});
return b;
}
}
#endregion
#region Services
[TestMethod]
public void InvalidService_Null()
{
var s = new MySchedulerWithoutServices();
Assert.IsNull(((IServiceProvider)s).GetService(typeof(IAsyncResult)));
}
class MySchedulerWithoutServices : LocalScheduler
{
public override IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
{
throw new NotImplementedException();
}
}
[TestMethod]
public void DetectServices_Null_1()
{
var s = new MyDumbScheduler1();
Assert.IsNull(Scheduler.AsLongRunning(s));
Assert.IsNull(Scheduler.AsPeriodic(s));
Assert.IsNull(Scheduler.AsStopwatchProvider(s));
}
class MyDumbScheduler1 : IScheduler
{
public DateTimeOffset Now
{
get { throw new NotImplementedException(); }
}
public IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
{
throw new NotImplementedException();
}
public IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
{
throw new NotImplementedException();
}
public IDisposable Schedule<TState>(TState state, DateTimeOffset dueTime, Func<IScheduler, TState, IDisposable> action)
{
throw new NotImplementedException();
}
}
[TestMethod]
public void DetectServices_Null_2()
{
var s = new MyDumbScheduler2(new Dictionary<Type, object>());
Assert.IsNull(Scheduler.AsLongRunning(s));
Assert.IsNull(Scheduler.AsPeriodic(s));
Assert.IsNull(Scheduler.AsStopwatchProvider(s));
}
[TestMethod]
public void DetectServices_Found()
{
{
var x = new MyLongRunning();
var s = new MyDumbScheduler2(new Dictionary<Type, object>
{
{ typeof(ISchedulerLongRunning), x }
});
Assert.AreEqual(x, Scheduler.AsLongRunning(s));
}
{
var x = new MyStopwatchProvider();
var s = new MyDumbScheduler2(new Dictionary<Type, object>
{
{ typeof(IStopwatchProvider), x }
});
Assert.AreEqual(x, Scheduler.AsStopwatchProvider(s));
}
{
var x = new MyPeriodic();
var s = new MyDumbScheduler2(new Dictionary<Type, object>
{
{ typeof(ISchedulerPeriodic), x }
});
Assert.AreEqual(x, Scheduler.AsPeriodic(s));
}
}
class MyDumbScheduler2 : IScheduler, IServiceProvider
{
private readonly Dictionary<Type, object> _services;
public MyDumbScheduler2(Dictionary<Type, object> services)
{
_services = services;
}
public DateTimeOffset Now
{
get { throw new NotImplementedException(); }
}
public IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
{
throw new NotImplementedException();
}
public IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
{
throw new NotImplementedException();
}
public IDisposable Schedule<TState>(TState state, DateTimeOffset dueTime, Func<IScheduler, TState, IDisposable> action)
{
throw new NotImplementedException();
}
public object GetService(Type serviceType)
{
var res = default(object);
if (_services.TryGetValue(serviceType, out res))
return res;
return null;
}
}
class MyLongRunning : ISchedulerLongRunning
{
public IDisposable ScheduleLongRunning<TState>(TState state, Action<TState, ICancelable> action)
{
throw new NotImplementedException();
}
}
class MyStopwatchProvider : IStopwatchProvider
{
public IStopwatch StartStopwatch()
{
throw new NotImplementedException();
}
}
class MyPeriodic : ISchedulerPeriodic
{
public IDisposable SchedulePeriodic<TState>(TState state, TimeSpan period, Func<TState, TState> action)
{
throw new NotImplementedException();
}
}
#endregion
}
}