using System; using System.IO; using System.Linq; using Chernobyl.Collections.Generic.Event; using Chernobyl.Config; using Chernobyl.Measures.Time; using Chernobyl.Update; using NUnit.Framework; namespace Chernobyl.StateMachine { [TestFixture, Description("Tests for the Countdown type.")] public class CountdownTests : StateTests { //------------------------------------------------------------------ // Constructor Tests //------------------------------------------------------------------ readonly IState _state = new State(); [Test, Description("Ensures that Countdown(IEventCollection, IState, Milliseconds) " + "throws an ArgumentNullException when the first argument is null.")] public void ConstructorExceptionOnNullFirstIServicesArgument() { Assert.Throws(() => CreateCountdown(null, _state, (Milliseconds) 3)); } [Test, Description("Ensures that Countdown(IEventCollection, IState, Milliseconds) " + "throws an ArgumentOutOfRangeException when the third argument is zero.")] public void ConstructorExceptionOnZeroThirdMillisecondArgument() { Assert.Throws(() => CreateCountdown(_core.Services, _state, (Milliseconds)0)); } [Test, Description("Ensures that Countdown(IEventCollection, IState, Milliseconds) " + "throws an ArgumentOutOfRangeException when the third argument is zero.")] public void ConstructorExceptionOnLessThanZeroThirdMillisecondArgument() { Assert.Throws(() => CreateCountdown(_core.Services, _state, new Milliseconds(-1))); } [Test, Description("Ensures that Countdown(IEventCollection, IState, Milliseconds) " + "sets the correct value on Countdown.Next.")] public void ConstructorCorrectSecondIStateArgument() { State expected = new State(); Countdown countdown = CreateCountdown(_core.Services, expected, (Milliseconds)3); Assert.AreEqual(expected, countdown.Next, "The value of Countdown.Next " + "is not what was expected."); } [Test, Description("Ensures that Countdown(IEventCollection, IState, Milliseconds) " + "sets the correct value on Countdown.Count.")] public void ConstructorCorrectThirdMillisecondsArgument() { Milliseconds expected = (Milliseconds)3; Countdown countdown = CreateCountdown(_core.Services, new State(), expected); Assert.AreEqual(expected, countdown.Count, "The value of Countdown.Count " + "is not what was expected."); } [Test, Description("Ensures that the second IState argument passed to " + "Countdown(IEventCollection, IState, Milliseconds) becomes that active IState " + "after the countdown has reached 0.")] public void ConstructorSecondArgumentBecomesActiveStateAfterCountdown() { // Need to use a custom Core for this test since, once this test is // finished, it will have added instances to IRootUpdateable and // causes other tests to fail because of it. Core core = new Core(new SearchPaths(".", "../../../")); State state = new State(); state.Entered += (sender, e) => Assert.Pass(); Countdown countdown = CreateCountdown(core.Services, state, (Milliseconds)3); RootUpdateable updateable = (RootUpdateable)core.Services.OfType().First(); updateable.CalculateDeltaTime = false; State parentState = new State(); parentState.ChildState = countdown; updateable.Update(new TimeSpan(0, 0, 0, 0, 3)); Assert.Fail("Countdown.Next did not become the active IState as was expected."); } [Test, Description("Ensures that the second IState argument passed to " + "Countdown(IEventCollection, IState, Milliseconds) does not become the active IState " + "before the countdown has reached 0.")] public void ConstructorSecondArgumentDoesNotBecomesActiveStateBeforeCountdown() { // Need to use a custom Core for this test since, once this test is // finished, it will have added instances to IRootUpdateable and // causes other tests to fail because of it. Core core = new Core(new SearchPaths(".", "../../../")); State state = new State(); state.Entered += (sender, e) => Assert.Fail("Countdown.Next unexpectedly became the active IState."); Countdown countdown = CreateCountdown(core.Services, state, (Milliseconds)3); RootUpdateable updateable = (RootUpdateable)core.Services.OfType().First(); updateable.CalculateDeltaTime = false; State parentState = new State(); parentState.ChildState = countdown; updateable.Update(new TimeSpan(0, 0, 0, 0, 2)); } //------------------------------------------------------------------ // Countdown.Next Tests //------------------------------------------------------------------ [Test, Description("Ensures that Countdown.Next is the expected value " + "after it has been set.")] public void NextProperValueWhenSet() { Countdown countdown = CreateCountdown(_core.Services, new State(), (Milliseconds)3); IState expected = new State(); countdown.Next = expected; Assert.AreEqual(expected, countdown.Next, "The value of Countdown.Next " + "was not the value that was expected."); } [Test, Description("Ensures that the IState set on Countdown.Next becomes " + "the active IState after the countdown has reached 0.")] public void NextBecomesActiveStateAfterCountdown() { // Need to use a custom Core for this test since, once this test is // finished, it will have added instances to IRootUpdateable and // causes other tests to fail because of it. Core core = new Core(new SearchPaths(".", "../../../")); Countdown countdown = CreateCountdown(core.Services, new State(), (Milliseconds)3); State state = new State(); state.Entered += (sender, e) => Assert.Pass(); countdown.Next = state; RootUpdateable updateable = (RootUpdateable)core.Services.OfType().First(); updateable.CalculateDeltaTime = false; State parentState = new State(); parentState.ChildState = countdown; updateable.Update(new TimeSpan(0, 0, 0, 0, 3)); Assert.Fail("Countdown.Next did not become the active IState as was expected."); } [Test, Description("Ensures that the IState set on Countdown.Next does not " + " become the active IState before the countdown has reached 0.")] public void NextDoesNotBecomesActiveStateBeforeCountdown() { // Need to use a custom Core for this test since, once this test is // finished, it will have added instances to IRootUpdateable and // causes other tests to fail because of it. Core core = new Core(new SearchPaths(".", "../../../")); Countdown countdown = CreateCountdown(core.Services, new State(), (Milliseconds)3); State state = new State(); state.Entered += (sender, e) => Assert.Fail("Countdown.Next unexpectedly became the active IState."); countdown.Next = state; RootUpdateable updateable = (RootUpdateable)core.Services.OfType().First(); updateable.CalculateDeltaTime = false; State parentState = new State(); parentState.ChildState = countdown; updateable.Update(new TimeSpan(0, 0, 0, 0, 2)); } //------------------------------------------------------------------ // Countdown.Count Tests //------------------------------------------------------------------ [Test, Description("Ensures that Countdown.Count throws an " + "ArgumentOutOfRangeException when the value set on it is zero.")] public void CountArgumentOutOfRangeExceptionWhenGivenZeroValue() { Countdown countdown = CreateCountdown(_core.Services, new State(), (Milliseconds)3); Assert.Throws(() => countdown.Count = (Milliseconds)0); } [Test, Description("Ensures that Countdown.Count throws an " + "ArgumentOutOfRangeException when the value set on it is negative.")] public void CountArgumentOutOfRangeExceptionWhenGivenNegativeValue() { Countdown countdown = CreateCountdown(_core.Services, new State(), (Milliseconds)3); Assert.Throws(() => countdown.Count = new Milliseconds(-2)); } [Test, Description("Ensures that Countdown.Count is the expected value " + "after it has been set.")] public void CountProperValueWhenSet() { Countdown countdown = CreateCountdown(_core.Services, new State(), (Milliseconds)3); Milliseconds expected = new Milliseconds(5); countdown.Count = expected; Assert.AreEqual(expected, countdown.Count, "The value of Countdown.Count " + "was not the value that was expected."); } //------------------------------------------------------------------ // Countdown.CurrentCount Tests //------------------------------------------------------------------ [Test, Description("Ensures that the Countdown begins the countdown " + "after it has become an active state, not before.")] public void CountdownStartsAfterStateIsActiveNotBefore() { Milliseconds expected = new Milliseconds(3); Countdown countdown = CreateCountdown(_core.Services, new State(), expected); RootUpdateable updateable = (RootUpdateable)_core.Services.OfType().First(); updateable.CalculateDeltaTime = false; // Try to reduce the countdown (it should fail). updateable.Update(new TimeSpan(0, 0, 0, 0, (int)expected.Value)); Assert.AreEqual(expected, countdown.CurrentCount, "the countdown began before it should have."); // Active the countdown. State parentState = new State(); parentState.ChildState = countdown; // Ensure the count has been reduced. updateable.Update(new TimeSpan(0, 0, 0, 0, (int)expected.Value)); Assert.AreEqual((Milliseconds)0, countdown.CurrentCount, "the countdown did not begin when it should have."); } [Test, Description("Ensures that the Countdown can be paused by deactivating " + "the Countdown IState.")] public void CountdownCanBePausedThroughDeactivation() { Milliseconds expected = new Milliseconds(3); Countdown countdown = CreateCountdown(_core.Services, new State(), expected); RootUpdateable updateable = (RootUpdateable)_core.Services.OfType().First(); updateable.CalculateDeltaTime = false; State parentState = new State(); parentState.ChildState = countdown; // Reduce the Countdown. Milliseconds reduceBy = new Milliseconds(1); updateable.Update(new TimeSpan(0, 0, 0, 0, (int)reduceBy.Value)); Assert.AreEqual(expected -= reduceBy, countdown.CurrentCount, "the countdown did not begin when it should have."); // Deactivate the Countdown. countdown.ParentState = null; // Now check to make sure the countdown has not been reduced. updateable.Update(new TimeSpan(0, 0, 0, 0, (int)reduceBy.Value)); Assert.AreEqual(expected, countdown.CurrentCount, "the countdown did not begin when it should have."); } /// /// Creates the instance to be tested. This /// method should never return the same instance /// more than once. /// /// The instance that takes services and gives /// them out. /// The instance that is to become the active state /// (i.e. set on the property of this /// ) after the countdown timer has reached 0. /// The amount of time, in milliseconds, between this /// becoming active and the /// becoming active. /// Returns the instance that is to be tested. protected virtual Countdown CreateCountdown(IEventCollection services, IState next, Milliseconds count) { return new Countdown(services, next, count); } protected override IState CreateState() { return CreateCountdown(_core.Services, new State(), (Milliseconds)300); } /// /// The needs to be configured to load in the /// plug-ins needed for rendering. /// readonly Core _core = new Core(new SearchPaths(".", "../../../")); } }