using System;
using System.Collections.Generic;
using NUnit.Framework;
namespace Chernobyl.StateMachine
{
///
/// Tests for types that implement the interface.
///
public abstract class StateTests : EnumerationTests
{
public StateTests() : base(true)
{}
[Test, Description("A test to ensure that IState.Entered is raised and " +
"IState.Left is not raised when the IState.ParentState is set")]
public void EnteredRaisedWhenParentSet()
{
IState state = CreateState();
EventChecker enteredEventChecker = new EventChecker();
EventChecker leftEventChecker = new EventChecker();
state.Entered += enteredEventChecker.EventHandler;
state.Left += leftEventChecker.EventHandler;
state.ParentState = new State();
Assert.True(enteredEventChecker.WasEventInvoked,
"IState.Entered should have been invoked but it was not.");
Assert.False(leftEventChecker.WasEventInvoked,
"IState.Left should not have been invoked but it was.");
}
[Test, Description("A test to ensure that IState.Entered is not raised " +
"and IState.Left is not raised when the IState.ParentState is set")]
public void EnteredNotRaisedWhenParentIsSetTwiceWithSameValue()
{
IState state = CreateState();
IState parent = new State();
state.ParentState = parent;
EventChecker enteredEventChecker = new EventChecker();
EventChecker leftEventChecker = new EventChecker();
state.Entered += enteredEventChecker.EventHandler;
state.Left += leftEventChecker.EventHandler;
state.ParentState = parent;
Assert.False(enteredEventChecker.WasEventInvoked,
"IState.Entered should not have been invoked but it was.");
Assert.False(leftEventChecker.WasEventInvoked,
"IState.Left should not have been invoked but it was.");
}
// Left is raised when ParentState is set to null.
// Left is not raised when ParentState is set to null twice.
[Test, Description("A test to ensure that IState.Entered is raised and " +
"IState.Left is not raised when the IState.ParentState is set")]
public void LeftRaisedWhenParentSetToNull()
{
IState state = CreateState();
IState parent = new State();
state.ParentState = parent;
EventChecker enteredEventChecker = new EventChecker();
EventChecker leftEventChecker = new EventChecker();
state.Entered += enteredEventChecker.EventHandler;
state.Left += leftEventChecker.EventHandler;
state.ParentState = null;
Assert.False(enteredEventChecker.WasEventInvoked,
"IState.Entered should have been invoked but it was not.");
Assert.True(leftEventChecker.WasEventInvoked,
"IState.Left should not have been invoked but it was.");
}
[Test, Description("A test to ensure that IState.Entered is not raised " +
"and IState.Left is not raised when the IState.ParentState is set")]
public void LeftNotRaisedWhenParentIsSetTwiceToNullTwice()
{
IState state = CreateState();
IState parent = new State();
state.ParentState = parent;
state.ParentState = null;
EventChecker enteredEventChecker = new EventChecker();
EventChecker leftEventChecker = new EventChecker();
state.Entered += enteredEventChecker.EventHandler;
state.Left += leftEventChecker.EventHandler;
state.ParentState = null;
Assert.False(enteredEventChecker.WasEventInvoked,
"IState.Entered should not have been invoked but it was.");
Assert.False(leftEventChecker.WasEventInvoked,
"IState.Left should not have been invoked but it was.");
}
[Test, Description("A test to ensure that IState.ParentState is set when " +
"IState.ChildState is set.")]
public void ParentSetWhenChildSet()
{
IState parent = CreateState();
IState child = CreateState();
parent.ChildState = child;
Assert.AreEqual(parent, child.ParentState,
"IState.ParentState was not set to the expected value.");
}
[Test, Description("A test to ensure that IState.ChildState is set when " +
"IState.ParentState is set.")]
public void ChildSetWhenParentSet()
{
IState parent = CreateState();
IState child = CreateState();
child.ParentState = parent;
Assert.AreEqual(child, parent.ChildState,
"IState.ParentState was not set to the expected value.");
}
[Test, Description("A test to ensure that IState.ParentState is set to " +
"null when IState.ChildState is set to null.")]
public void ParentUnsetWhenChildSetToNull()
{
IState parent = CreateState();
IState child = CreateState();
parent.ChildState = child;
parent.ChildState = null;
Assert.AreEqual(null, child.ParentState,
"IState.ParentState was not set to the expected value.");
}
[Test, Description("A test to ensure that IState.ChildState is set to " +
"null when IState.ParentState is set to null.")]
public void ChildUnsetWhenParentSetToNull()
{
IState parent = CreateState();
IState child = CreateState();
child.ParentState = parent;
child.ParentState = null;
Assert.AreEqual(null, parent.ChildState,
"IState.ParentState was not set to the expected value.");
}
[Test, Description("A test to ensure that IState.ParentState is set to " +
"null when IState.ChildState is set to another IState.")]
public void ParentUnsetWhenChildSetToAnotherState()
{
IState parent = CreateState();
IState child = CreateState();
IState anotherChild = CreateState();
parent.ChildState = child;
parent.ChildState = anotherChild;
Assert.AreEqual(null, child.ParentState,
"IState.ParentState was not set to the expected value.");
}
[Test, Description("A test to ensure that IState.ChildState is set to " +
"null when IState.ParentState is set to another IState.")]
public void ChildUnsetWhenParentSetToAnotherState()
{
IState parent = CreateState();
IState anotherParent = CreateState();
IState child = CreateState();
child.ParentState = parent;
child.ParentState = anotherParent;
Assert.AreEqual(null, parent.ChildState,
"IState.ParentState was not set to the expected value.");
}
[Test, Description("A test to ensure that deactivating (i.e. leaving) an" +
"IState causes all of its descendant IStates to be deactivated and " +
"in the correct order.")]
public void DeactivatingStateDeactivatesDescendantStates()
{
// IState machine should look like this:
// state1 -> state2 -> state3 -> state4
IState state4 = CreateState();
IState state3 = state4.ParentState = CreateState();
IState state2 = state3.ParentState = CreateState();
IState state1 = state2.ParentState = CreateState();
// We need to ensure the order of deactivation was correct. The order
// of deactivation should be: state3, state2, state1.
List deactivationOrder = new List(3);
state2.Left += (sender, e) => deactivationOrder.Add((IState)sender);
state3.Left += (sender, e) => deactivationOrder.Add((IState)sender);
state4.Left += (sender, e) => deactivationOrder.Add((IState)sender);
// Deactivate state2 and the sub-states below it.
state2.ParentState = null;
// Ensure all the states are deactivated.
Assert.AreEqual(null, state2.ParentState,
"Second sub-state was not deactivated.");
Assert.AreEqual(null, state3.ParentState,
"Third sub-state was not deactivated.");
Assert.AreEqual(null, state4.ParentState,
"Fourth sub-state was not deactivated.");
// Check the order of deactivation.
Assert.AreEqual(state4, deactivationOrder[0],
"The third sub-state was not deactivated first; it should have been.");
Assert.AreEqual(state3, deactivationOrder[1],
"The second sub-state was not deactivated second; it should have been.");
Assert.AreEqual(state2, deactivationOrder[2],
"The first sub-state was not deactivated third; it should have been.");
}
///
/// A helper class that is used to check whether an event was invoked or
/// not.
///
public class EventChecker
{
///
/// An event handler that can be assigned to an event. When this
/// method is raised, will be set to
/// true.
///
/// The instance that generated the event.
/// The instance
/// containing the event data.
public void EventHandler(object sender, EventArgs e)
{
WasEventInvoked = true;
}
///
/// True if was
/// invoked, false if otherwise.
///
public bool WasEventInvoked { get; set; }
}
///
/// Creates the instance that is to be tested. This
/// method should always create a new and never
/// return the same instance twice.
///
/// The instance to be tested.
protected abstract IState CreateState();
protected override IEnumerable CreateSingleItemEnumerable()
{
return CreateState();
}
protected override IEnumerable CreateManyItemEnumerable()
{
IState item6 = new State();
IState item5 = new State { ChildState = item6 };
IState item4 = new State { ChildState = item5 };
IState item3 = new State { ChildState = item4 };
IState item2 = new State { ChildState = item3 };
IState item1 = new State { ChildState = item2 };
IState item0 = CreateState();
item0.ChildState = item1;
_orderedItems = new[] { item0, item1, item2, item3, item4, item5, item6 };
return item0;
}
protected override IEnumerable OrderedItems
{
get { return _orderedItems; }
}
///
/// The backing field to .
///
IEnumerable _orderedItems;
}
}