1090 lines
39 KiB
C#
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
|
|||
|
}
|
|||
|
}
|