Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

1102 lines
33 KiB
C#

// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
#if !NO_REMOTING
using System;
using System.Collections.Generic;
using System.Reactive;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Reactive.PlatformServices;
#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
namespace ReactiveTests.Tests
{
static class Exts
{
public static T Deq<T>(this List<T> l)
{
var t = l[0];
l.RemoveAt(0);
return t;
}
}
[TestClass]
public class SystemClockTest
{
private void Run(CrossAppDomainDelegate a)
{
var domain = AppDomain.CreateDomain(Guid.NewGuid().ToString(), null, new AppDomainSetup { ApplicationBase = Utils.GetTestBaseDirectory() });
domain.DoCallBack(a);
AppDomain.Unload(domain);
}
[TestMethod]
public void PastWork()
{
Run(() =>
{
var provider = new MyPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var cal = provider._cal;
var now = new DateTimeOffset(2012, 4, 25, 12, 0, 0, TimeSpan.Zero);
var due = now - TimeSpan.FromMinutes(1);
var s = new MyScheduler();
s.SetTime(now);
var done = false;
s.Schedule(due, () => { done = true; });
Assert.AreEqual(1, s._queue.Count);
var next = s._queue.Deq();
Assert.IsTrue(s.Now + next.DueTime == now);
s.SetTime(due);
next.Invoke();
Assert.IsTrue(done);
});
}
[TestMethod]
public void ImmediateWork()
{
Run(() =>
{
var provider = new MyPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var cal = provider._cal;
var now = new DateTimeOffset(2012, 4, 25, 12, 0, 0, TimeSpan.Zero);
var due = now;
var s = new MyScheduler();
s.SetTime(now);
var done = false;
s.Schedule(due, () => { done = true; });
Assert.AreEqual(1, s._queue.Count);
var next = s._queue.Deq();
Assert.IsTrue(s.Now + next.DueTime == due);
s.SetTime(due);
next.Invoke();
Assert.IsTrue(done);
});
}
[TestMethod]
public void ShortTermWork()
{
Run(() =>
{
var provider = new MyPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var cal = provider._cal;
var now = new DateTimeOffset(2012, 4, 25, 12, 0, 0, TimeSpan.Zero);
var rel = TimeSpan.FromSeconds(1) /* rel <= SHORTTERM */;
var due = now + rel;
var s = new MyScheduler();
s.SetTime(now);
var done = false;
s.Schedule(due, () => { done = true; });
Assert.AreEqual(1, s._queue.Count);
var next = s._queue.Deq();
Assert.IsTrue(s.Now + next.DueTime == due);
s.SetTime(due);
next.Invoke();
Assert.IsTrue(done);
});
}
[TestMethod]
public void ShortTermWork_Dispose()
{
Run(() =>
{
var provider = new MyPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var cal = provider._cal;
var now = new DateTimeOffset(2012, 4, 25, 12, 0, 0, TimeSpan.Zero);
var rel = TimeSpan.FromSeconds(1) /* rel <= SHORTTERM */;
var due = now + rel;
var s = new MyScheduler();
s.SetTime(now);
var done = false;
var d = s.Schedule(due, () => { done = true; });
Assert.AreEqual(1, s._queue.Count);
var next = s._queue.Deq();
Assert.IsTrue(s.Now + next.DueTime == due);
d.Dispose();
s.SetTime(due);
next.Invoke();
Assert.IsFalse(done);
});
}
[TestMethod]
public void ShortTermWork_InaccurateClock()
{
Run(() =>
{
var provider = new MyPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var cal = provider._cal;
var now = new DateTimeOffset(2012, 4, 25, 12, 0, 0, TimeSpan.Zero);
var rel = TimeSpan.FromSeconds(1);
var due = now + rel;
var s = new MyScheduler();
s.SetTime(now);
var done = false;
s.Schedule(due, () => { done = true; });
Assert.AreEqual(1, s._queue.Count);
var nxt1 = s._queue.Deq();
Assert.IsTrue(s.Now + nxt1.DueTime == due);
s.SetTime(due - TimeSpan.FromMilliseconds(500) /* > RETRYSHORT */);
nxt1.Invoke();
Assert.AreEqual(1, s._queue.Count);
var nxt2 = s._queue.Deq();
Assert.IsTrue(s.Now + nxt2.DueTime == due);
s.SetTime(due);
nxt2.Invoke();
Assert.IsTrue(done);
});
}
[TestMethod]
public void LongTermWork1()
{
Run(() =>
{
var provider = new MyPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var cal = provider._cal;
var now = new DateTimeOffset(2012, 4, 25, 12, 0, 0, TimeSpan.Zero);
var rel = TimeSpan.FromMinutes(1) /* rel > SHORTTERM */;
var due = now + rel;
var s = new MyScheduler();
s.SetTime(now);
var done = false;
s.Schedule(due, () => { done = true; });
Assert.AreEqual(1, cal._queue.Count);
var work = cal._queue.Deq();
Assert.IsTrue(work.Interval < rel);
s.SetTime(s.Now + work.Interval);
work.Value._action(work.Value._state);
Assert.AreEqual(1, s._queue.Count);
var next = s._queue.Deq();
Assert.IsTrue(s.Now + next.DueTime == due);
s.SetTime(due);
next.Invoke();
Assert.IsTrue(done);
});
}
[TestMethod]
public void LongTermWork2()
{
Run(() =>
{
var provider = new MyPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var cal = provider._cal;
var now = new DateTimeOffset(2012, 4, 25, 12, 0, 0, TimeSpan.Zero);
var rel = TimeSpan.FromDays(1) /* rel > SHORTTERM and rel * MAXERRORRATIO > SHORTTERM */;
var due = now + rel;
var s = new MyScheduler();
s.SetTime(now);
var done = false;
s.Schedule(due, () => { done = true; });
Assert.AreEqual(1, cal._queue.Count);
var wrk1 = cal._queue.Deq();
Assert.IsTrue(wrk1.Interval < rel);
s.SetTime(s.Now + wrk1.Interval);
wrk1.Value._action(wrk1.Value._state);
// Begin of second long term scheduling
Assert.AreEqual(1, cal._queue.Count);
var wrk2 = cal._queue.Deq();
Assert.IsTrue(wrk2.Interval < rel);
s.SetTime(s.Now + wrk2.Interval);
wrk2.Value._action(wrk2.Value._state);
// End of second long term scheduling
Assert.AreEqual(1, s._queue.Count);
var next = s._queue.Deq();
Assert.IsTrue(s.Now + next.DueTime == due);
s.SetTime(due);
next.Invoke();
Assert.IsTrue(done);
});
}
[TestMethod]
public void LongTerm_Multiple()
{
Run(() =>
{
var provider = new MyPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var cal = provider._cal;
var now = new DateTimeOffset(2012, 4, 25, 12, 0, 0, TimeSpan.Zero);
var s = new MyScheduler();
s.SetTime(now);
var due1 = now + TimeSpan.FromMinutes(10);
var due2 = now + TimeSpan.FromMinutes(30);
var due3 = now + TimeSpan.FromMinutes(60);
var done1 = false;
var done2 = false;
var done3 = false;
s.Schedule(due2, () => { done2 = true; });
s.Schedule(due1, () => { done1 = true; });
s.Schedule(due3, () => { done3 = true; });
// First CHK
Assert.AreEqual(1, cal._queue.Count);
var wrk1 = cal._queue.Deq();
var fst = s.Now + wrk1.Interval;
Assert.IsTrue(fst < due1);
// First TRN
s.SetTime(fst);
wrk1.Value._action(wrk1.Value._state);
// First SHT
Assert.AreEqual(1, s._queue.Count);
var sh1 = s._queue.Deq();
// Second CHK
Assert.AreEqual(1, cal._queue.Count);
var wrk2 = cal._queue.Deq();
var snd = s.Now + wrk2.Interval;
Assert.IsTrue(snd < due2);
// First RUN
s.SetTime(due1);
sh1.Invoke();
Assert.IsTrue(done1);
// Second TRN
s.SetTime(snd);
wrk2.Value._action(wrk2.Value._state);
// Second SHT
Assert.AreEqual(1, s._queue.Count);
var sh2 = s._queue.Deq();
// Third CHK
Assert.AreEqual(1, cal._queue.Count);
var wrk3 = cal._queue.Deq();
var trd = s.Now + wrk3.Interval;
Assert.IsTrue(trd < due3);
// Second RUN
s.SetTime(due2);
sh2.Invoke();
Assert.IsTrue(done2);
// Third TRN
s.SetTime(trd);
wrk3.Value._action(wrk3.Value._state);
// Third SHT
Assert.AreEqual(1, s._queue.Count);
var sh3 = s._queue.Deq();
// Third RUN
s.SetTime(due3);
sh3.Invoke();
Assert.IsTrue(done3);
});
}
[TestMethod]
public void LongTerm_Multiple_Dispose()
{
Run(() =>
{
var provider = new MyPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var cal = provider._cal;
var now = new DateTimeOffset(2012, 4, 25, 12, 0, 0, TimeSpan.Zero);
var s = new MyScheduler();
s.SetTime(now);
var due1 = now + TimeSpan.FromMinutes(10);
var due2 = now + TimeSpan.FromMinutes(30);
var due3 = now + TimeSpan.FromMinutes(60);
var done1 = false;
var done2 = false;
var done3 = false;
var d2 = s.Schedule(due2, () => { done2 = true; });
var d1 = s.Schedule(due1, () => { done1 = true; });
var d3 = s.Schedule(due3, () => { done3 = true; });
// First CHK
Assert.AreEqual(1, cal._queue.Count);
var wrk1 = cal._queue.Deq();
var fst = s.Now + wrk1.Interval;
Assert.IsTrue(fst < due1);
// First TRN
s.SetTime(fst);
wrk1.Value._action(wrk1.Value._state);
// First DIS
d1.Dispose();
// First SHT
Assert.AreEqual(1, s._queue.Count);
var sh1 = s._queue.Deq();
// Second CHK
Assert.AreEqual(1, cal._queue.Count);
var wrk2 = cal._queue.Deq();
var snd = s.Now + wrk2.Interval;
Assert.IsTrue(snd < due2);
// First RUN
s.SetTime(due1);
sh1.Invoke();
Assert.IsFalse(done1);
// Second DIS
// Third DIS
d2.Dispose();
d3.Dispose();
// Second TRN
s.SetTime(snd);
wrk2.Value._action(wrk2.Value._state);
// Second SHT
Assert.AreEqual(1, s._queue.Count);
var sh2 = s._queue.Deq();
// Third CHK
Assert.AreEqual(1, cal._queue.Count);
var wrk3 = cal._queue.Deq();
var trd = s.Now + wrk3.Interval;
Assert.IsTrue(trd < due3);
// Second RUN
s.SetTime(due2);
sh2.Invoke();
Assert.IsFalse(done2);
// Third TRN
s.SetTime(trd);
wrk3.Value._action(wrk3.Value._state);
// Third SHT
Assert.AreEqual(1, s._queue.Count);
var sh3 = s._queue.Deq();
// Third RUN
s.SetTime(due3);
sh3.Invoke();
Assert.IsFalse(done3);
});
}
[TestMethod]
public void ClockChanged_FalsePositive()
{
Run(() =>
{
var provider = new MyPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var scm = (ClockChanged)provider.GetService<INotifySystemClockChanged>();
var cal = provider._cal;
var now = new DateTimeOffset(2012, 4, 25, 12, 0, 0, TimeSpan.Zero);
var rel = TimeSpan.FromMinutes(1);
var due = now + rel;
var s = new MyScheduler();
s.SetTime(now);
var done = false;
s.Schedule(due, () => { done = true; });
Assert.AreEqual(1, cal._queue.Count);
s.SetTime(now);
scm.OnSystemClockChanged();
var work = cal._queue.Deq();
Assert.IsTrue(work.Interval < rel);
s.SetTime(s.Now + work.Interval);
work.Value._action(work.Value._state);
Assert.AreEqual(1, s._queue.Count);
var next = s._queue.Deq();
Assert.IsTrue(s.Now + next.DueTime == due);
s.SetTime(due);
next.Invoke();
Assert.IsTrue(done);
});
}
[TestMethod]
public void ClockChanged_Forward1()
{
Run(() =>
{
var provider = new MyPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var scm = (ClockChanged)provider.GetService<INotifySystemClockChanged>();
var cal = provider._cal;
var now = new DateTimeOffset(2012, 4, 25, 12, 0, 0, TimeSpan.Zero);
var rel = TimeSpan.FromMinutes(1);
var due = now + rel;
var err = TimeSpan.FromMinutes(1);
var s = new MyScheduler();
s.SetTime(now);
var done = false;
s.Schedule(due, () => { done = true; });
Assert.AreEqual(1, cal._queue.Count);
Assert.AreEqual(0, s._queue.Count);
s.SetTime(due + err);
scm.OnSystemClockChanged();
Assert.AreEqual(1, s._queue.Count);
var next = s._queue.Deq();
Assert.IsTrue(next.DueTime == TimeSpan.Zero);
next.Invoke();
Assert.IsTrue(done);
var tmr = cal._queue.Deq();
tmr.Value._action(tmr.Value._state);
Assert.AreEqual(0, cal._queue.Count);
Assert.AreEqual(0, s._queue.Count);
});
}
[TestMethod]
public void ClockChanged_Forward2()
{
Run(() =>
{
var provider = new MyPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var scm = (ClockChanged)provider.GetService<INotifySystemClockChanged>();
var cal = provider._cal;
var now = new DateTimeOffset(2012, 4, 25, 12, 0, 0, TimeSpan.Zero);
var rel = TimeSpan.FromSeconds(1);
var due = now + rel;
var err = TimeSpan.FromMinutes(1);
var s = new MyScheduler();
s.SetTime(now);
var n = 0;
s.Schedule(due, () => { n++; });
Assert.AreEqual(1, s._queue.Count);
var wrk = s._queue.Deq();
Assert.IsTrue(wrk.DueTime == rel);
s.SetTime(due + err);
scm.OnSystemClockChanged();
Assert.AreEqual(1, s._queue.Count);
var next = s._queue.Deq();
Assert.IsTrue(next.DueTime == TimeSpan.Zero);
next.Invoke();
Assert.AreEqual(1, n);
wrk.Invoke(); // Bad schedulers may not grant cancellation immediately.
Assert.AreEqual(1, n); // Invoke shouldn't cause double execution of the work.
});
}
[TestMethod]
public void ClockChanged_Backward1()
{
Run(() =>
{
var provider = new MyPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var scm = (ClockChanged)provider.GetService<INotifySystemClockChanged>();
var cal = provider._cal;
var now = new DateTimeOffset(2012, 4, 25, 12, 0, 0, TimeSpan.Zero);
var rel = TimeSpan.FromMinutes(1);
var due = now + rel;
var err = TimeSpan.FromMinutes(-2);
var s = new MyScheduler();
s.SetTime(now);
var done = false;
s.Schedule(due, () => { done = true; });
Assert.AreEqual(1, cal._queue.Count);
Assert.IsTrue(cal._queue[0].Interval < rel);
Assert.AreEqual(0, s._queue.Count);
s.SetTime(due + err);
scm.OnSystemClockChanged();
Assert.AreEqual(1, cal._queue.Count);
var tmr = cal._queue.Deq();
Assert.IsTrue(tmr.Interval > rel);
Assert.IsTrue(tmr.Interval < -err);
s.SetTime(s.Now + tmr.Interval);
tmr.Value._action(tmr.Value._state);
Assert.IsFalse(done);
Assert.AreEqual(0, cal._queue.Count);
Assert.AreEqual(1, s._queue.Count);
s.SetTime(due);
s._queue.Deq().Invoke();
Assert.IsTrue(done);
});
}
[TestMethod]
public void ClockChanged_Backward2()
{
Run(() =>
{
var provider = new MyPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var scm = (ClockChanged)provider.GetService<INotifySystemClockChanged>();
var cal = provider._cal;
var now = new DateTimeOffset(2012, 4, 25, 12, 0, 0, TimeSpan.Zero);
var rel = TimeSpan.FromSeconds(1);
var due = now + rel;
var err = TimeSpan.FromMinutes(-1);
var s = new MyScheduler();
s.SetTime(now);
var n = 0;
s.Schedule(due, () => { n++; });
Assert.AreEqual(0, cal._queue.Count);
Assert.AreEqual(1, s._queue.Count);
var wrk = s._queue[0];
Assert.IsTrue(wrk.DueTime == rel);
s.SetTime(due + err);
scm.OnSystemClockChanged();
Assert.AreEqual(1, cal._queue.Count);
var tmr = cal._queue.Deq();
Assert.IsTrue(tmr.Interval > rel);
Assert.IsTrue(tmr.Interval < -err);
s.SetTime(s.Now + tmr.Interval);
tmr.Value._action(tmr.Value._state);
Assert.AreEqual(0, n);
Assert.AreEqual(0, cal._queue.Count);
Assert.AreEqual(1, s._queue.Count);
s.SetTime(due);
s._queue.Deq().Invoke();
Assert.AreEqual(1, n);
wrk.Invoke(); // Bad schedulers may not grant cancellation immediately.
Assert.AreEqual(1, n); // Invoke shouldn't cause double execution of the work.
});
}
[TestMethod]
public void PeriodicSystemClockChangeMonitor()
{
Run(() =>
{
var provider = new FakeClockPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var clock = (FakeClock)provider.GetService<ISystemClock>();
clock._now = new DateTimeOffset(2012, 4, 26, 12, 0, 0, TimeSpan.Zero);
var cal = (FakeClockCAL)provider.GetService<IConcurrencyAbstractionLayer>();
var period = TimeSpan.FromSeconds(1);
var ptscm = new PeriodicTimerSystemClockMonitor(period);
var delta = TimeSpan.Zero;
var n = 0;
var h = new EventHandler<SystemClockChangedEventArgs>((o, e) =>
{
delta = e.NewTime - e.OldTime;
n++;
});
ptscm.SystemClockChanged += h;
Assert.IsNotNull(cal._action);
Assert.IsTrue(cal._period == period);
Assert.AreEqual(0, n);
clock._now += period;
cal._action();
Assert.AreEqual(0, n);
clock._now += period;
cal._action();
Assert.AreEqual(0, n);
var diff1 = TimeSpan.FromSeconds(3);
clock._now += period + diff1;
cal._action();
Assert.AreEqual(1, n);
Assert.IsTrue(delta == diff1);
clock._now += period;
cal._action();
Assert.AreEqual(1, n);
clock._now += period;
cal._action();
Assert.AreEqual(1, n);
var diff2 = TimeSpan.FromSeconds(-5);
clock._now += period + diff2;
cal._action();
Assert.AreEqual(2, n);
Assert.IsTrue(delta == diff2);
clock._now += period;
cal._action();
Assert.AreEqual(2, n);
ptscm.SystemClockChanged -= h;
Assert.IsNull(cal._action);
});
}
[TestMethod]
public void ClockChanged_RefCounting()
{
Run(() =>
{
var provider = new MyPlatformEnlightenmentProvider();
PlatformEnlightenmentProvider.Current = provider;
var scm = (ClockChanged)provider.GetService<INotifySystemClockChanged>();
var cal = provider._cal;
var now = new DateTimeOffset(2012, 4, 25, 12, 0, 0, TimeSpan.Zero);
var s = new MyScheduler();
s.SetTime(now);
var due1 = now + TimeSpan.FromSeconds(5);
var due2 = now + TimeSpan.FromSeconds(8);
var due3 = now + TimeSpan.FromMinutes(1);
var due4 = now + TimeSpan.FromMinutes(2);
var due5 = now + TimeSpan.FromMinutes(3);
var due6 = now + TimeSpan.FromMinutes(3) + TimeSpan.FromSeconds(2);
var done1 = false;
var done2 = false;
var done3 = false;
var done4 = false;
var done5 = false;
var done6 = false;
var d1 = s.Schedule(due1, () => { done1 = true; });
var d5 = s.Schedule(due5, () => { done5 = true; });
var d3 = s.Schedule(due3, () => { done3 = true; throw new Exception(); });
var d2 = s.Schedule(due2, () => { done2 = true; });
var d4 = s.Schedule(due4, () => { done4 = true; });
d2.Dispose();
d4.Dispose();
Assert.AreEqual(1, scm.n);
s.SetTime(due1);
var i1 = s._queue.Deq();
i1.Invoke();
Assert.IsTrue(done1);
Assert.AreEqual(1, scm.n);
s.SetTime(due2);
var i2 = s._queue.Deq();
i2.Invoke();
Assert.IsFalse(done2);
Assert.AreEqual(1, scm.n);
var l1 = cal._queue.Deq();
var l1d = now + l1.Interval;
s.SetTime(l1d);
l1.Value._action(l1.Value._state);
s.SetTime(due3);
var i3 = s._queue.Deq();
try
{
i3.Invoke();
Assert.Fail();
}
catch { }
Assert.IsTrue(done3);
Assert.AreEqual(1, scm.n);
var l2 = cal._queue.Deq();
var l2d = l1d + l2.Interval;
s.SetTime(l2d);
l2.Value._action(l2.Value._state);
s.SetTime(due4);
var i4 = s._queue.Deq();
i4.Invoke();
Assert.IsFalse(done4);
Assert.AreEqual(1, scm.n);
var l3 = cal._queue.Deq();
var l3d = l2d + l3.Interval;
s.SetTime(l3d);
l3.Value._action(l3.Value._state);
s.SetTime(due5);
var i5 = s._queue.Deq();
i5.Invoke();
Assert.IsTrue(done5);
Assert.AreEqual(0, scm.n);
var d6 = s.Schedule(due6, () => { done6 = true; });
Assert.AreEqual(1, scm.n);
s.SetTime(due6);
var i6 = s._queue.Deq();
i6.Invoke();
Assert.IsTrue(done6);
Assert.AreEqual(0, scm.n);
});
}
class MyScheduler : LocalScheduler
{
internal List<ScheduledItem<TimeSpan>> _queue = new List<ScheduledItem<TimeSpan>>();
private DateTimeOffset _now;
public void SetTime(DateTimeOffset now)
{
_now = now;
}
public override DateTimeOffset Now
{
get { return _now; }
}
public override IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
{
var s = new ScheduledItem<TimeSpan, TState>(this, state, action, dueTime);
_queue.Add(s);
return Disposable.Create(() => _queue.Remove(s));
}
}
class MyPlatformEnlightenmentProvider : IPlatformEnlightenmentProvider
{
internal MyCAL _cal;
public MyPlatformEnlightenmentProvider()
{
_cal = new MyCAL();
}
public T GetService<T>(params object[] args) where T : class
{
if (typeof(T) == typeof(IConcurrencyAbstractionLayer))
{
return (T)(object)_cal;
}
else if (typeof(T) == typeof(INotifySystemClockChanged))
{
return (T)(object)ClockChanged.Instance;
}
return null;
}
}
class FakeClockPlatformEnlightenmentProvider : IPlatformEnlightenmentProvider
{
internal FakeClockCAL _cal;
internal FakeClock _clock;
public FakeClockPlatformEnlightenmentProvider()
{
_cal = new FakeClockCAL();
_clock = new FakeClock();
}
public T GetService<T>(params object[] args) where T : class
{
if (typeof(T) == typeof(IConcurrencyAbstractionLayer))
{
return (T)(object)_cal;
}
else if (typeof(T) == typeof(ISystemClock))
{
return (T)(object)_clock;
}
return null;
}
}
class Work
{
internal readonly Action<object> _action;
internal readonly object _state;
public Work(Action<object> action, object state)
{
_action = action;
_state = state;
}
}
class MyCAL : IConcurrencyAbstractionLayer
{
internal List<TimeInterval<Work>> _queue = new List<TimeInterval<Work>>();
public IDisposable StartTimer(Action<object> action, object state, TimeSpan dueTime)
{
var t = new TimeInterval<Work>(new Work(action, state), dueTime);
_queue.Add(t);
return Disposable.Create(() => _queue.Remove(t));
}
public IDisposable StartPeriodicTimer(Action action, TimeSpan period)
{
throw new NotImplementedException();
}
public IDisposable QueueUserWorkItem(Action<object> action, object state)
{
throw new NotImplementedException();
}
public void Sleep(TimeSpan timeout)
{
throw new NotImplementedException();
}
public IStopwatch StartStopwatch()
{
throw new NotImplementedException();
}
public bool SupportsLongRunning
{
get { throw new NotImplementedException(); }
}
public void StartThread(Action<object> action, object state)
{
throw new NotImplementedException();
}
}
class FakeClockCAL : IConcurrencyAbstractionLayer
{
internal Action _action;
internal TimeSpan _period;
public IDisposable StartTimer(Action<object> action, object state, TimeSpan dueTime)
{
throw new NotImplementedException();
}
public IDisposable StartPeriodicTimer(Action action, TimeSpan period)
{
_action = action;
_period = period;
return Disposable.Create(() => _action = null);
}
public IDisposable QueueUserWorkItem(Action<object> action, object state)
{
throw new NotImplementedException();
}
public void Sleep(TimeSpan timeout)
{
throw new NotImplementedException();
}
public IStopwatch StartStopwatch()
{
throw new NotImplementedException();
}
public bool SupportsLongRunning
{
get { throw new NotImplementedException(); }
}
public void StartThread(Action<object> action, object state)
{
throw new NotImplementedException();
}
}
class FakeClock : ISystemClock
{
internal DateTimeOffset _now;
public DateTimeOffset UtcNow
{
get { return _now; }
}
}
class ClockChanged : INotifySystemClockChanged
{
private static ClockChanged s_instance = new ClockChanged();
private EventHandler<SystemClockChangedEventArgs> _systemClockChanged;
internal int n = 0;
public event EventHandler<SystemClockChangedEventArgs> SystemClockChanged
{
add
{
_systemClockChanged += value;
n++;
}
remove
{
_systemClockChanged -= value;
n--;
}
}
public static ClockChanged Instance
{
get
{
return s_instance;
}
}
public void OnSystemClockChanged()
{
var scc = _systemClockChanged;
if (scc != null)
scc(this, new SystemClockChangedEventArgs());
}
}
}
}
#endif