public void ShouldUpdateExecutedTimeAfterBlocking()
        {
            var indicator        = false;
            var firstTime        = true;
            var threadToSinkSync = new ManualResetEvent(false);
            var sinkToThreadSync = new ManualResetEvent(false);

            using (var master = new MasterTimeSource {
                Quantum = TimeInterval.FromTicks(10), AdvanceImmediately = true
            })
                using (var timeSlave = new SlaveTimeSource()
                {
                    Quantum = TimeInterval.FromTicks(10), AdvanceImmediately = true
                })
                {
                    var timeSink = new SimpleTimeSink(1.0, (sts, th, ti) =>
                    {
                        if (firstTime)
                        {
                            Assert.AreEqual(10, ti.Ticks);
                            firstTime    = false;
                            var timeUsed = TimeInterval.FromTicks(ti.Ticks / 2);
                            var timeLeft = ti - timeUsed;

                            sts.ElapsedVirtualTime += timeUsed;

                            th.ReportBackAndBreak(timeLeft);
                            sinkToThreadSync.Set();
                            threadToSinkSync.WaitOne();
                        }
                        else
                        {
                            Assert.AreEqual(5, ti.Ticks);
                            sts.ElapsedVirtualTime += ti;
                            th.ReportBackAndContinue(TimeInterval.Empty);
                        }

                        return(false);
                    });

                    // tester thread
                    new Thread(() =>
                    {
                        // wait for the pause
                        sinkToThreadSync.WaitOne();

                        // here we sleep to make sure that master won't go further
                        Thread.Sleep(5000);

                        Assert.AreEqual(5, master.ElapsedVirtualTime.Ticks);
                        Assert.AreEqual(5, timeSlave.ElapsedVirtualTime.Ticks);
                        indicator = true;

                        threadToSinkSync.Set();
                    }).Start();

                    master.RegisterSink(timeSlave);
                    timeSlave.RegisterSink(timeSink);

                    // just to pass the first syncpoint
                    master.Run(1);

                    master.Run(1);
                    Assert.IsTrue(indicator);

                    Assert.AreEqual(10, master.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(10, timeSlave.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(10, timeSink.ElapsedVirtualTime.Ticks);
                }
        }
        public void ShouldHandleTwoBlockingSinks()
        {
            var indicator = false;

            using (var master = new MasterTimeSource {
                Quantum = TimeInterval.FromTicks(10), AdvanceImmediately = true
            })
                using (var timeSlave = new SlaveTimeSource()
                {
                    Quantum = TimeInterval.FromTicks(10), AdvanceImmediately = true
                })
                    using (var timeSinkA2 = new MoreComplicatedTimeSink("A"))
                        using (var timeSinkB2 = new MoreComplicatedTimeSink("B"))
                        {
                            var ttt = new Thread(() =>
                            {
                                Parallel(
                                    () =>
                                {
                                    timeSinkA2.ExecuteOnDispatcherThread((sts, ti) =>
                                    {
                                        this.Trace();
                                        Assert.AreEqual(10, ti.Ticks);
                                        var timeUsed = TimeInterval.FromTicks(4);
                                        var timeLeft = ti - timeUsed;
                                        sts.TimeHandle.ReportBackAndBreak(timeLeft);
                                    });
                                },

                                    () =>
                                {
                                    timeSinkB2.ExecuteOnDispatcherThread((sts, ti) =>
                                    {
                                        this.Trace();
                                        Assert.AreEqual(10, ti.Ticks);
                                        var timeUsed = TimeInterval.FromTicks(6);
                                        var timeLeft = ti - timeUsed;
                                        sts.TimeHandle.ReportBackAndBreak(timeLeft);
                                    });
                                }
                                    );

                                // here we sleep to make sure that master won't go further
                                this.Trace();
                                Thread.Sleep(5000);

                                this.Trace();
                                Assert.AreEqual(4, master.ElapsedVirtualTime.Ticks);
                                Assert.AreEqual(4, timeSlave.ElapsedVirtualTime.Ticks);

                                Parallel(
                                    () =>
                                {
                                    timeSinkA2.ExecuteOnDispatcherThread((sts, ti) =>
                                    {
                                        this.Trace();
                                        Assert.AreEqual(6, ti.Ticks);
                                        var timeUsed = TimeInterval.FromTicks(4);
                                        var timeLeft = ti - timeUsed;
                                        sts.TimeHandle.ReportBackAndBreak(timeLeft);
                                    });
                                },

                                    () =>
                                {
                                    timeSinkB2.ExecuteOnDispatcherThread((sts, ti) =>
                                    {
                                        this.Trace();
                                        Assert.AreEqual(4, ti.Ticks);
                                        sts.TimeHandle.ReportBackAndBreak(ti);
                                    });
                                }
                                    );

                                // here we sleep to make sure that master won't go further
                                this.Trace();
                                Thread.Sleep(5000);

                                this.Trace();
                                Assert.AreEqual(6, master.ElapsedVirtualTime.Ticks);
                                Assert.AreEqual(6, timeSlave.ElapsedVirtualTime.Ticks);

                                Parallel(
                                    () =>
                                {
                                    timeSinkA2.ExecuteOnDispatcherThread((sts, ti) =>
                                    {
                                        this.Trace();
                                        Assert.AreEqual(2, ti.Ticks);
                                        sts.TimeHandle.ReportBackAndBreak(ti);
                                    });
                                },

                                    () =>
                                {
                                    timeSinkB2.ExecuteOnDispatcherThread((sts, ti) =>
                                    {
                                        this.Trace();
                                        Assert.AreEqual(4, ti.Ticks);
                                        sts.TimeHandle.ReportBackAndContinue(TimeInterval.Empty);
                                    });
                                }
                                    );

                                // here we sleep to make sure that master won't go further
                                this.Trace();
                                Thread.Sleep(5000);

                                this.Trace();
                                Assert.AreEqual(8, master.ElapsedVirtualTime.Ticks);
                                Assert.AreEqual(8, timeSlave.ElapsedVirtualTime.Ticks);

                                Parallel(
                                    () =>
                                {
                                    timeSinkA2.ExecuteOnDispatcherThread((sts, ti) =>
                                    {
                                        this.Trace();
                                        Assert.AreEqual(2, ti.Ticks);
                                        indicator = true;
                                        sts.TimeHandle.ReportBackAndContinue(TimeInterval.Empty);
                                    });
                                },

                                    () =>
                                {
                                    timeSinkB2.ExecuteOnDispatcherThread((sts, ti) =>
                                    {
                                        this.Trace();
                                        Assert.Fail();
                                    }, false);           // do not wait for finish
                                    Thread.Sleep(10000); // wait for 10s and check if Fail() is called
                                }
                                    );
                            })
                            {
                                Name = "tester thread"
                            };
                            ttt.Start();

                            master.RegisterSink(timeSlave);
                            timeSlave.RegisterSink(timeSinkA2);
                            timeSlave.RegisterSink(timeSinkB2);

                            // just to pass the first syncpoint
                            master.Run(1);

                            master.Run(1);
                            Assert.IsTrue(indicator);

                            this.Trace();
                            Assert.AreEqual(10, master.ElapsedVirtualTime.Ticks);
                            Assert.AreEqual(10, timeSlave.ElapsedVirtualTime.Ticks);

                            ttt.Join();
                        }
        }
        public void ShouldHandleBlockingAtTheEndOfGrantedInterval()
        {
            var indicator = false;

            using (var master = new MasterTimeSource {
                Quantum = TimeInterval.FromTicks(10), AdvanceImmediately = true
            })
                using (var timeSlave = new SlaveTimeSource()
                {
                    Quantum = TimeInterval.FromTicks(10), AdvanceImmediately = true
                })
                    using (var timeSink = new MoreComplicatedTimeSink("A"))
                    {
                        // tester thread
                        new Thread(() =>
                        {
                            this.Trace();
                            timeSink.ExecuteOnDispatcherThread((ts, ti) =>
                            {
                                this.Trace();
                                Assert.AreEqual(10, ti.Ticks);

                                ts.TimeHandle.ReportBackAndBreak(TimeInterval.Empty);
                            });

                            this.Trace();
                            // here we sleep to make sure that master won't go further
                            Thread.Sleep(5000);

                            this.Trace();
                            Assert.AreEqual(10, master.ElapsedVirtualTime.Ticks);
                            Assert.AreEqual(10, timeSlave.ElapsedVirtualTime.Ticks);
                            indicator = true;

                            this.Trace();
                            timeSink.ExecuteOnDispatcherThread((ts, ti) =>
                            {
                                this.Trace();
                                Assert.AreEqual(0, ti.Ticks);
                                ts.TimeHandle.ReportBackAndContinue(TimeInterval.Empty);
                            });

                            timeSink.ExecuteOnDispatcherThread((ts, ti) =>
                            {
                                this.Trace();
                                Assert.AreEqual(10, ti.Ticks);
                                ts.TimeHandle.ReportBackAndContinue(TimeInterval.Empty);
                            });
                        })
                        {
                            Name = "tester thread"
                        }.Start();

                        master.RegisterSink(timeSlave);
                        timeSlave.RegisterSink(timeSink);

                        // just to pass the first syncpoint
                        master.Run(1);

                        this.Trace();
                        master.Run(1);
                        this.Trace();
                        Assert.IsTrue(indicator);
                        Assert.AreEqual(10, master.ElapsedVirtualTime.Ticks);
                        Assert.AreEqual(10, timeSlave.ElapsedVirtualTime.Ticks);

                        master.Run(1);
                        Assert.AreEqual(20, master.ElapsedVirtualTime.Ticks);
                        Assert.AreEqual(20, timeSlave.ElapsedVirtualTime.Ticks);
                    }
        }
        public void ShouldHandleSlaveTimeSourceWithNotAlignedQuantum()
        {
            using (var timeSource = new MasterTimeSource {
                Quantum = TimeInterval.FromTicks(10), AdvanceImmediately = true
            })
                using (var timeSlave = new SlaveTimeSource()
                {
                    Quantum = TimeInterval.FromTicks(3), AdvanceImmediately = true
                })
                {
                    var timeSink = new SimpleTimeSink(1.0);

                    timeSource.RegisterSink(timeSlave);
                    timeSlave.RegisterSink(timeSink);

                    // the first round does not increment the time - it just triggers a sync point
                    timeSource.Run(1);

                    Assert.AreEqual(1, timeSource.NumberOfSyncPoints);
                    Assert.AreEqual(0, timeSlave.NumberOfSyncPoints);
                    Assert.AreEqual(0, timeSink.NumberOfRounds);

                    Assert.AreEqual(0, timeSource.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(0, timeSlave.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(0, timeSink.ElapsedVirtualTime.Ticks);

                    timeSource.Run(1);

                    Assert.AreEqual(2, timeSource.NumberOfSyncPoints);
                    Assert.AreEqual(4, timeSlave.NumberOfSyncPoints);
                    Assert.AreEqual(3, timeSink.NumberOfRounds);

                    Assert.AreEqual(10, timeSource.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(9, timeSlave.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(9, timeSink.ElapsedVirtualTime.Ticks);

                    timeSource.Run(1);

                    Assert.AreEqual(3, timeSource.NumberOfSyncPoints);
                    Assert.AreEqual(7, timeSlave.NumberOfSyncPoints);
                    Assert.AreEqual(6, timeSink.NumberOfRounds);

                    Assert.AreEqual(20, timeSource.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(18, timeSlave.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(18, timeSink.ElapsedVirtualTime.Ticks);

                    timeSource.Run(1);

                    Assert.AreEqual(4, timeSource.NumberOfSyncPoints);
                    Assert.AreEqual(11, timeSlave.NumberOfSyncPoints);
                    Assert.AreEqual(10, timeSink.NumberOfRounds);

                    Assert.AreEqual(30, timeSource.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(30, timeSlave.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(30, timeSink.ElapsedVirtualTime.Ticks);

                    timeSource.Run(1);

                    Assert.AreEqual(5, timeSource.NumberOfSyncPoints);
                    Assert.AreEqual(14, timeSlave.NumberOfSyncPoints);
                    Assert.AreEqual(13, timeSink.NumberOfRounds);

                    Assert.AreEqual(40, timeSource.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(39, timeSlave.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(39, timeSink.ElapsedVirtualTime.Ticks);

                    timeSource.Run(1);

                    Assert.AreEqual(6, timeSource.NumberOfSyncPoints);
                    Assert.AreEqual(17, timeSlave.NumberOfSyncPoints);
                    Assert.AreEqual(16, timeSink.NumberOfRounds);

                    Assert.AreEqual(50, timeSource.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(48, timeSlave.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(48, timeSink.ElapsedVirtualTime.Ticks);

                    timeSource.Run(1);

                    Assert.AreEqual(7, timeSource.NumberOfSyncPoints);
                    Assert.AreEqual(21, timeSlave.NumberOfSyncPoints);
                    Assert.AreEqual(20, timeSink.NumberOfRounds);

                    Assert.AreEqual(60, timeSource.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(60, timeSlave.ElapsedVirtualTime.Ticks);
                    Assert.AreEqual(60, timeSink.ElapsedVirtualTime.Ticks);
                }
        }