public void SimpleStartToEndScenarioTest()
        {

            // Setup Fakes

            var fakeRtEvents = new FakeRTEvents();
            var fakeDecalEvents = new FakeDecalEventsProxy();

            Queue<Location> locationResults = new Queue<Location>();
            locationResults.Enqueue(new Location(0, 0, 1, 0, 0));
            locationResults.Enqueue(new Location(0, 0, 2, 0, 0));
            locationResults.Enqueue(new Location(0, 0, 3, 0, 0));
            locationResults.Enqueue(new Location(0, 0, 4, 0, 0));

            for (int i = 0; i < JumpRecorder.NumberOfConsecutiveZCoordsSameToSingleLand; i++)
            {
                locationResults.Enqueue(new Location(0, 0, 5, 0, 0));
            }

            List<SelfJumpCompleteEventArgs> cachedCompleteCallValues = new List<SelfJumpCompleteEventArgs>();

            // Workflow to Test

            JumpRecorder recorder = new JumpRecorder(fakeRtEvents, fakeDecalEvents, e => cachedCompleteCallValues.Add(e), () => locationResults.Dequeue());

            var initialJumpData = new JumpData(new Location(0, 0, 0, 0, 0), 0.0, 0.0);

            Assert.IsFalse(recorder.IsRecording);

            fakeRtEvents.FireSelfJump(new JumpEventArgs(0, initialJumpData, 0, 0));

            Assert.IsTrue(recorder.IsRecording);

            fakeDecalEvents.FireRenderFrame(new EventArgs());
            fakeDecalEvents.FireRenderFrame(new EventArgs());
            fakeDecalEvents.FireRenderFrame(new EventArgs());

            // We should not have landed yet
            Assert.IsTrue(recorder.IsRecording);
            Assert.AreEqual(0, cachedCompleteCallValues.Count);

            fakeDecalEvents.FireRenderFrame(new EventArgs());

            for (int i = 0; i < JumpRecorder.NumberOfConsecutiveZCoordsSameToSingleLand; i++)
            {
                fakeDecalEvents.FireRenderFrame(new EventArgs());
            }

            // Now we should have landed
            Assert.IsFalse(recorder.IsRecording);
            Assert.AreEqual(1, cachedCompleteCallValues.Count);

            Assert.AreEqual(initialJumpData, cachedCompleteCallValues[0].JumpData);

            Assert.AreEqual(4 + JumpRecorder.NumberOfConsecutiveZCoordsSameToSingleLand, cachedCompleteCallValues[0].Trajectory);
            Assert.AreEqual(1, cachedCompleteCallValues[0].Trajectory[0].Z);
            Assert.AreEqual(5, cachedCompleteCallValues[0].Trajectory.Last().Z);

            Assert.AreEqual(5, cachedCompleteCallValues[0].LandingLocation.Z);
        }
        public void VerifyQueueActionWillQueueAndRunOnceRenderFrameFired()
        {
            var fakeDecalEventsProxy = new Fakes.FakeDecalEventsProxy();

            bool actionCalled = false;

            using (var dispatcher = new GameThreadDispatcher(fakeDecalEventsProxy))
            {
                dispatcher.QueueAction(() =>
                {
                    actionCalled = true;
                });

                Assert.AreEqual(1, dispatcher.QueueCount);

                // Fire the render event to simulate what decal would do
                fakeDecalEventsProxy.FireRenderFrame(new EventArgs());

                Assert.IsTrue(actionCalled);
                Assert.AreEqual(0, dispatcher.QueueCount);
            }
        }
        public void VerifyQueueActionWillQueueAndRunOnceRenderFrameFired()
        {
            var fakeDecalEventsProxy = new Fakes.FakeDecalEventsProxy();
            using (var fakePipelineAction = new Fakes.FakePipelineAction())
            {
                using (var dispatcher = new PipelineDispatcher(fakeDecalEventsProxy))
                {
                    dispatcher.EnqueueAction(fakePipelineAction);

                    Assert.AreEqual(1, dispatcher.QueueCount);
                    Assert.IsFalse(dispatcher.HasPendingAction);

                    // Nothing should be called as a result of queueing
                    Assert.AreEqual(0, fakePipelineAction.InitCallCount);
                    Assert.AreEqual(0, fakePipelineAction.BeginInvokeCallCount);
                    Assert.AreEqual(0, fakePipelineAction.EndInvokeCallCount);
                    Assert.IsFalse(fakePipelineAction.IsComplete);

                    // Fire the render event
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());

                    // Step 1 is to Init.  Verify that happened.
                    Assert.IsTrue(dispatcher.HasPendingAction);

                    Assert.AreEqual(1, fakePipelineAction.InitCallCount);
                    Assert.AreEqual(0, fakePipelineAction.BeginInvokeCallCount);
                    Assert.AreEqual(0, fakePipelineAction.EndInvokeCallCount);
                    Assert.IsFalse(fakePipelineAction.IsComplete);

                    // Fire the render event
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());

                    // Step 2 is to BeginInvoke & Wait in the Background
                    Assert.IsTrue(dispatcher.HasPendingAction);

                    Assert.AreEqual(1, fakePipelineAction.InitCallCount);
                    Assert.AreEqual(1, fakePipelineAction.BeginInvokeCallCount);
                    Assert.AreEqual(0, fakePipelineAction.EndInvokeCallCount);
                    Assert.IsFalse(fakePipelineAction.IsComplete);

                    // Now tell the background wait to release.
                    fakePipelineAction.ForTesting_SetComplete(false);

                    // The action should report complete, but the dispatcher shouldn't have processed it yet
                    // since we haven't fired render frame yet.
                    Assert.AreEqual(1, fakePipelineAction.InitCallCount);
                    Assert.AreEqual(1, fakePipelineAction.BeginInvokeCallCount);
                    Assert.AreEqual(0, fakePipelineAction.EndInvokeCallCount);
                    Assert.IsTrue(fakePipelineAction.IsComplete);

                    // Fire the render event
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());
                    Assert.IsFalse(dispatcher.HasPendingAction);

                    // Now the action should have been fully processed
                    Assert.AreEqual(1, fakePipelineAction.InitCallCount);
                    Assert.AreEqual(1, fakePipelineAction.BeginInvokeCallCount);
                    Assert.AreEqual(1, fakePipelineAction.EndInvokeCallCount);
                    Assert.IsTrue(fakePipelineAction.IsComplete);

                    Assert.AreEqual(0, dispatcher.QueueCount);

                    // Check the thread id's that everything was invoked on to verify they were correct.
                    // Doing this at the end to simplying timing of caching this info
                    Assert.AreEqual(Thread.CurrentThread.ManagedThreadId, fakePipelineAction.InitThreadId);
                    Assert.AreEqual(Thread.CurrentThread.ManagedThreadId, fakePipelineAction.BeginInvokeThreadId);
                    Assert.AreEqual(Thread.CurrentThread.ManagedThreadId, fakePipelineAction.EndInvokeThreadId);

                    Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, fakePipelineAction.WaitForCompleteThreadId);
                }
            }
        }
        public void VerifyReadyBehavior_WhenNotReady_ThenBecomesReady()
        {
            var fakeDecalEventsProxy = new Fakes.FakeDecalEventsProxy();
            using (var fakePipelineAction = new Fakes.FakePipelineAction(false))
            {
                using (var dispatcher = new PipelineDispatcher(fakeDecalEventsProxy))
                {
                    dispatcher.EnqueueAction(fakePipelineAction);

                    Assert.AreEqual(0, fakePipelineAction.ReadyCallCount);

                    // Fire the render event
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());

                    // Step 1 is to Init.  Ready should not have been called yet
                    Assert.AreEqual(0, fakePipelineAction.ReadyCallCount);

                    // Fire the render event
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());

                    // Step 2 is to Call Ready, Perform if so, and Wait in the Background
                    Assert.IsTrue(dispatcher.HasPendingAction);

                    Assert.AreEqual(1, fakePipelineAction.ReadyCallCount);
                    Assert.AreEqual(0, fakePipelineAction.BeginInvokeCallCount);
                    Assert.AreEqual(0, fakePipelineAction.EndInvokeCallCount);
                    Assert.IsFalse(fakePipelineAction.IsComplete);

                    // So set it as ready so the next time around we can perform it
                    fakePipelineAction.ForTesting_Ready = true;

                    // Fire the render event
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());

                    Assert.AreEqual(2, fakePipelineAction.ReadyCallCount);
                    Assert.AreEqual(1, fakePipelineAction.BeginInvokeCallCount);
                    Assert.AreEqual(0, fakePipelineAction.EndInvokeCallCount);
                    Assert.IsFalse(fakePipelineAction.IsComplete);

                    // Now tell the background wait to release.
                    fakePipelineAction.ForTesting_SetComplete(false);

                    // The action should report complete, but the dispatcher shouldn't have processed it yet
                    // since we haven't fired render frame yet.
                    Assert.AreEqual(1, fakePipelineAction.InitCallCount);
                    Assert.AreEqual(2, fakePipelineAction.ReadyCallCount);
                    Assert.AreEqual(1, fakePipelineAction.BeginInvokeCallCount);
                    Assert.AreEqual(0, fakePipelineAction.EndInvokeCallCount);
                    Assert.IsTrue(fakePipelineAction.IsComplete);

                    // Fire the render event
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());
                    Assert.IsFalse(dispatcher.HasPendingAction);

                    // Now the action should have been fully processed
                    Assert.AreEqual(1, fakePipelineAction.InitCallCount);
                    Assert.AreEqual(2, fakePipelineAction.ReadyCallCount);
                    Assert.AreEqual(1, fakePipelineAction.BeginInvokeCallCount);
                    Assert.AreEqual(1, fakePipelineAction.EndInvokeCallCount);
                    Assert.IsTrue(fakePipelineAction.IsComplete);

                    Assert.AreEqual(0, dispatcher.QueueCount);
                }
            }
        }
        public void VerifyReadyBehavior_WhenNotReady()
        {
            var fakeDecalEventsProxy = new Fakes.FakeDecalEventsProxy();
            using (var fakePipelineAction = new Fakes.FakePipelineAction(false))
            {
                using (var dispatcher = new PipelineDispatcher(fakeDecalEventsProxy))
                {
                    dispatcher.EnqueueAction(fakePipelineAction);

                    // Fire the render event
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());

                    // Step 1 is to Init.   Ready should not have been called yet
                    Assert.AreEqual(0, fakePipelineAction.ReadyCallCount);

                    // Fire the render event
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());

                    // Step 2 is to Call Ready, Perform if so, and Wait in the Background
                    Assert.IsTrue(dispatcher.HasPendingAction);

                    Assert.AreEqual(1, fakePipelineAction.ReadyCallCount);
                    Assert.AreEqual(0, fakePipelineAction.BeginInvokeCallCount);
                    Assert.AreEqual(0, fakePipelineAction.EndInvokeCallCount);
                    Assert.IsFalse(fakePipelineAction.IsComplete);
                }
            }
        }
        public void VerifyReadyBehaviorWhenReadyInitially()
        {
            var fakeDecalEventsProxy = new Fakes.FakeDecalEventsProxy();
            using (var fakePipelineAction = new Fakes.FakePipelineAction())
            {
                using (var dispatcher = new PipelineDispatcher(fakeDecalEventsProxy))
                {
                    dispatcher.EnqueueAction(fakePipelineAction);

                    // Nothing should be called as a result of queueing
                    Assert.AreEqual(0, fakePipelineAction.ReadyCallCount);

                    // Fire the render event
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());

                    // Step 1 is to Init.  Ready should not have been called yet
                    Assert.AreEqual(0, fakePipelineAction.ReadyCallCount);

                    // Fire the render event
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());

                    // Step 2 is to BeginInvoke & Wait in the Background
                    Assert.IsTrue(dispatcher.HasPendingAction);

                    Assert.AreEqual(1, fakePipelineAction.ReadyCallCount);
                    Assert.AreEqual(1, fakePipelineAction.BeginInvokeCallCount);

                    // Now tell the background wait to release.
                    fakePipelineAction.ForTesting_SetComplete(false);

                    // Fire the render event
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());
                    Assert.IsFalse(dispatcher.HasPendingAction);

                    // Now the action should have been fully processed
                    Assert.AreEqual(1, fakePipelineAction.InitCallCount);
                    Assert.AreEqual(1, fakePipelineAction.BeginInvokeCallCount);
                    Assert.AreEqual(1, fakePipelineAction.EndInvokeCallCount);
                    Assert.IsTrue(fakePipelineAction.IsComplete);

                    Assert.AreEqual(0, dispatcher.QueueCount);
                }
            }
        }
        public void VerifyQueueActionCanRetry()
        {
            var fakeDecalEventsProxy = new Fakes.FakeDecalEventsProxy();
            using (var fakePipelineAction = new Fakes.FakePipelineAction())
            {
                using (var dispatcher = new PipelineDispatcher(fakeDecalEventsProxy))
                {
                    dispatcher.EnqueueAction(fakePipelineAction);

                    // Fire the render event - Gets us init'ed
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());

                    // Fire the render event again - bets us begin invoked
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());

                    // Now tell the background wait to release and request a retry
                    fakePipelineAction.ForTesting_SetComplete(true);

                    // Now we are into the situation this unit test is focused on.  Start making assertions.
                    Assert.IsTrue(dispatcher.HasPendingAction);

                    // Fire the render event - This should trip the Retry check and Reset
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());

                    // Init should not be called again, so make sure that count is still 1.
                    Assert.AreEqual(1, fakePipelineAction.InitCallCount);
                    // Begin invoke shouldn't have been called again yet.  So the count should still be 1.
                    Assert.AreEqual(1, fakePipelineAction.BeginInvokeCallCount);
                    // We are retrying, not completing, so no EndInvoke.
                    Assert.AreEqual(0, fakePipelineAction.EndInvokeCallCount);
                    
                    // Now, what should have changed due to the lastest firing.
                    Assert.AreEqual(1, fakePipelineAction.RetryCallCount);
                    Assert.AreEqual(1, fakePipelineAction.ResetForRetryCallCount);

                    Assert.IsTrue(dispatcher.HasPendingAction);

                    // Fire the render event - Now begin invoke will be called again.
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());

                    // Init should never be called again, so make sure that count is still 1.
                    Assert.AreEqual(1, fakePipelineAction.InitCallCount);
                    // Begin invoke will have been called again
                    Assert.AreEqual(2, fakePipelineAction.BeginInvokeCallCount);
                    // We are retrying, not completing, so no EndInvoke.
                    Assert.AreEqual(0, fakePipelineAction.EndInvokeCallCount);

                    // These are unchanged
                    Assert.AreEqual(1, fakePipelineAction.RetryCallCount);
                    Assert.AreEqual(1, fakePipelineAction.ResetForRetryCallCount);

                    // Now complete the action for real
                    fakePipelineAction.ForTesting_SetComplete(false);

                    // Fire the render event - This should cause everything to complete.
                    fakeDecalEventsProxy.FireRenderFrame(new EventArgs());


                    // Now the action should have been fully processed
                    Assert.AreEqual(1, fakePipelineAction.InitCallCount);
                    Assert.AreEqual(2, fakePipelineAction.BeginInvokeCallCount);
                    Assert.AreEqual(1, fakePipelineAction.EndInvokeCallCount);
                    Assert.IsTrue(fakePipelineAction.IsComplete);
                    Assert.AreEqual(2, fakePipelineAction.RetryCallCount);
                    Assert.AreEqual(1, fakePipelineAction.ResetForRetryCallCount);

                    Assert.AreEqual(0, dispatcher.QueueCount);

                    // Check the thread id's that everything was invoked on to verify they were correct.
                    // Doing this at the end to simplying timing of caching this info
                    Assert.AreEqual(Thread.CurrentThread.ManagedThreadId, fakePipelineAction.InitThreadId);
                    Assert.AreEqual(Thread.CurrentThread.ManagedThreadId, fakePipelineAction.BeginInvokeThreadId);
                    Assert.AreEqual(Thread.CurrentThread.ManagedThreadId, fakePipelineAction.EndInvokeThreadId);
                    Assert.AreEqual(Thread.CurrentThread.ManagedThreadId, fakePipelineAction.ResetForRetryThreadId);

                    Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, fakePipelineAction.WaitForCompleteThreadId);
                }
            }
        }