protected SolidMachine<TelephoneTrigger> BuildTelephoneStateMachine() { var sm = new SolidMachine<TelephoneTrigger>(); sm.State<IdleState>() .IsInitialState() .On(TelephoneTrigger.PickingUpPhone).GoesTo<DiallingState>() .On(TelephoneTrigger.IncomingCall).GoesTo<RingingState>(); sm.State<RingingState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo<ConversationState>() .On(TelephoneTrigger.NotAnswering).GoesTo<IdleState>(); sm.State<DiallingState>() .On(TelephoneTrigger.DialedNumber).GoesTo<WaitForAnswerState>() .On(TelephoneTrigger.HangingUp).GoesTo<IdleState>(); sm.State<WaitForAnswerState>() .On(TelephoneTrigger.Answered).GoesTo<ConversationState>() .On(TelephoneTrigger.NotAnswering).GoesTo<IdleState>() .On(TelephoneTrigger.HangingUp).GoesTo<IdleState>(); sm.State<ConversationState>() .On(TelephoneTrigger.HangingUp).GoesTo<IdleState>(); sm.Start(); return sm; }
public void CorrectOrderOnTransitions() { var states = new List <string>(); var sm = new SolidMachine <int>(); sm.Transitioned += (sender, args) => { var stateName = args.TargetState.Name; Console.WriteLine("Transitioned to " + stateName); states.Add(stateName); if (states.Count == 5) { var stateOrder = string.Join("_", states); Assert.IsTrue(stateOrder == "IdleState_StepState1_StepState2_StepState3_StepState4", string.Format("Wrong state order: {0}", stateOrder)); } }; sm.State <IdleState>() .On(0).GoesTo <StepState1>(); sm.State <StepState1>() .On(1).GoesTo <StepState2>(); sm.State <StepState2>() .On(2).GoesTo <StepState3>(); sm.State <StepState3>() .On(3).GoesTo <StepState4>(); sm.Start(); sm.Trigger(0); }
protected SolidMachine <TelephoneTrigger> BuildTelephoneStateMachine() { var sm = new SolidMachine <TelephoneTrigger>(); sm.State <IdleState>() .IsInitialState() .On(TelephoneTrigger.PickingUpPhone).GoesTo <DiallingState>() .On(TelephoneTrigger.IncomingCall).GoesTo <RingingState>(); sm.State <RingingState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo <ConversationState>() .On(TelephoneTrigger.NotAnswering).GoesTo <IdleState>(); sm.State <DiallingState>() .On(TelephoneTrigger.DialedNumber).GoesTo <WaitForAnswerState>() .On(TelephoneTrigger.HangingUp).GoesTo <IdleState>(); sm.State <WaitForAnswerState>() .On(TelephoneTrigger.Answered).GoesTo <ConversationState>() .On(TelephoneTrigger.NotAnswering).GoesTo <IdleState>() .On(TelephoneTrigger.HangingUp).GoesTo <IdleState>(); sm.State <ConversationState>() .On(TelephoneTrigger.HangingUp).GoesTo <IdleState>(); sm.Start(); return(sm); }
public void GoBack() { var sm = new SolidMachine <TelephoneTrigger>(); var isGoingToDialling = false; sm.State <IdleState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo <DiallingState>(); sm.State <DiallingState>() .On(TelephoneTrigger.Answered, () => isGoingToDialling).GoesTo <ConversationState>() .On(TelephoneTrigger.Answered, () => !isGoingToDialling).GoesTo <WaitForAnswerState>(); sm.Start(); sm.Trigger(TelephoneTrigger.PickingUpPhone); sm.Trigger(TelephoneTrigger.Answered); Assert.IsTrue(sm.CurrentState is WaitForAnswerState, "Expected state WaitForAnswerState"); sm.GoBack(); Assert.IsTrue(sm.CurrentState is DiallingState, string.Format("Expected state DiallingState, was {0}", sm.CurrentState.GetType().Name)); // Shift the track isGoingToDialling = true; sm.Trigger(TelephoneTrigger.Answered); Assert.IsTrue(sm.CurrentState is ConversationState, "Expected state ConversationState"); sm.GoBack(); Assert.IsTrue(sm.CurrentState is DiallingState, "Expected state DiallingState... again"); }
public void UsingStateResolver() { // Lets this test class act as the state resolver... var sm = new SolidMachine <TelephoneTrigger>(null, this); sm.State <IdleState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo <StateWithoutParameterlessConstructor>(); sm.Start(); sm.Trigger(TelephoneTrigger.PickingUpPhone); Assert.IsTrue(sm.CurrentState is StateWithoutParameterlessConstructor); }
public void UsingExplicitContext() { var dateTime = new DateHolder(); var sm = new SolidMachine <TelephoneTrigger>(dateTime); sm.State <IdleState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo <DateReportingState>(); sm.Start(); sm.Trigger(TelephoneTrigger.PickingUpPhone); // The state should be able to use the specified context (dateTime variable) to report the date. Assert.IsTrue(dateTime.CurrentDate.Equals(DateTime.Now.Date), "Wrong date in context!"); }
public void CorrectImplicitInitialState() { var sm = new SolidMachine<TelephoneTrigger>(); sm.State<IdleState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo<DiallingState>() .On(TelephoneTrigger.IncomingCall).GoesTo<RingingState>(); sm.State<RingingState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo<ConversationState>() .On(TelephoneTrigger.HangingUp).GoesTo<IdleState>(); sm.Start(); Assert.IsTrue(sm.CurrentState is IdleState); }
public void StartWithoutStates() { try { var sm = new SolidMachine <TelephoneTrigger>(); sm.Start(); Assert.Fail("Start without configured states permitted!"); } catch (Exception ex) { Console.WriteLine(ex.Message); Assert.IsTrue(ex is SolidStateException); Assert.IsTrue((ex as SolidStateException).ErrorId == SolidStateConstants.ErrorNoStatesHaveBeenConfigured); } }
public void CorrectImplicitInitialState() { var sm = new SolidMachine <TelephoneTrigger>(); sm.State <IdleState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo <DiallingState>() .On(TelephoneTrigger.IncomingCall).GoesTo <RingingState>(); sm.State <RingingState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo <ConversationState>() .On(TelephoneTrigger.HangingUp).GoesTo <IdleState>(); sm.Start(); Assert.IsTrue(sm.CurrentState is IdleState); }
public void StartWithParameterizedState() { try { var sm = new SolidMachine <TelephoneTrigger>(); sm.State <IdleState>() .On(TelephoneTrigger.IncomingCall).GoesTo <StateWithoutParameterlessConstructor>(); sm.Start(); Assert.Fail("Startup without state resolver was permitted!"); } catch (Exception ex) { Console.WriteLine(ex.Message); Assert.IsTrue(ex is SolidStateException); Assert.IsTrue((ex as SolidStateException).ErrorId == SolidStateConstants.ErrorStatesNeedParameterlessConstructor); } }
/// <summary> /// Configures and starts the telephone state machine. /// </summary> private void ConfigureTelephone() { _sm = new SolidMachine <TelephoneTrigger>(null, this); // Uncomment this row if you want a new state instance to be created on each transition // _sm.InstantiateStatePerTransition = true; _sm.Transitioned += StateMachineOnTransitioned; _sm.State <IdleState>() .IsInitialState() .On(TelephoneTrigger.PickingUpPhone).GoesTo <DiallingState>() .On(TelephoneTrigger.IncomingCall).GoesTo <RingingState>(); _sm.State <RingingState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo <ConversationState>() .On(TelephoneTrigger.IgnoreIncomingCall).GoesTo <IdleState>(); _sm.State <DiallingState>() .On(TelephoneTrigger.FinishedDialling, () => !IsLineBusy).GoesTo <WaitForAnswerState>() .On(TelephoneTrigger.FinishedDialling, () => IsLineBusy).GoesTo <LineBusyState>() .On(TelephoneTrigger.MeHangingUp).GoesTo <IdleState>(); _sm.State <LineBusyState>() .On(TelephoneTrigger.MeHangingUp).GoesTo <IdleState>(); _sm.State <WaitForAnswerState>() .On(TelephoneTrigger.AnswerInOtherEnd).GoesTo <ConversationState>() .On(TelephoneTrigger.MeHangingUp).GoesTo <IdleState>(); _sm.State <ConversationState>() .On(TelephoneTrigger.MeHangingUp).GoesTo <IdleState>() .On(TelephoneTrigger.OtherEndHangingUp).GoesTo <LineDisconnectedState>(); _sm.State <LineDisconnectedState>() .On(TelephoneTrigger.MeHangingUp).GoesTo <IdleState>(); _sm.Start(); }
// Private methods private void ConfigureWizard() { _wizardContext = new WizardContext(); // Create the state machine with the correct context _sm = new SolidMachine<WizardTrigger>(_wizardContext); _sm.Transitioned += StateMachineOnTransitioned; // Assign the state machine to the context so it's accessible _wizardContext.StateMachine = _sm; _sm.State<WelcomePage>() .On(WizardTrigger.Cancel).GoesTo<ShutdownApplicationState>() .On(WizardTrigger.Next).GoesTo<InfoSelectionPage>(); _sm.State<InfoSelectionPage>() .On(WizardTrigger.Cancel).GoesTo<ShutdownApplicationState>() .On(WizardTrigger.Next, () => _wizardContext.InfoSelection == InfoSelectionMode.Family).GoesTo<FamilyInfoPage1>() .On(WizardTrigger.Next, () => _wizardContext.InfoSelection == InfoSelectionMode.Work).GoesTo<WorkInfoPage>(); _sm.State<FamilyInfoPage1>() .On(WizardTrigger.Cancel).GoesTo<ShutdownApplicationState>() .On(WizardTrigger.Next).GoesTo<FamilyInfoPage2>(); _sm.State<FamilyInfoPage2>() .On(WizardTrigger.Cancel).GoesTo<ShutdownApplicationState>() .On(WizardTrigger.Next).GoesTo<FinishPage>(); _sm.State<WorkInfoPage>() .On(WizardTrigger.Cancel).GoesTo<ShutdownApplicationState>() .On(WizardTrigger.Next).GoesTo<FinishPage>(); _sm.State<FinishPage>() .On(WizardTrigger.Finish).GoesTo<ShutdownApplicationState>(); _sm.Start(); }
public void OneStepGuardedTransition() { var isPhoneWorking = false; var sm = new SolidMachine <TelephoneTrigger>(); sm.State <IdleState>() .On(TelephoneTrigger.PickingUpPhone, () => isPhoneWorking).GoesTo <DiallingState>() .On(TelephoneTrigger.PickingUpPhone, () => !isPhoneWorking).GoesTo <TelephoneBrokenState>() .On(TelephoneTrigger.IncomingCall).GoesTo <RingingState>(); sm.State <RingingState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo <ConversationState>() .On(TelephoneTrigger.NotAnswering).GoesTo <IdleState>(); sm.State <TelephoneBrokenState>() .On(TelephoneTrigger.HangingUp).GoesTo <IdleState>(); sm.Start(); sm.Trigger(TelephoneTrigger.PickingUpPhone); Assert.IsTrue(sm.CurrentState is TelephoneBrokenState, string.Format("Telephone state is {0}, expected {1}", sm.CurrentState.GetType().Name, typeof(TelephoneBrokenState).Name)); // Reset the machine to IdleState sm.Trigger(TelephoneTrigger.HangingUp); isPhoneWorking = true; sm.Trigger(TelephoneTrigger.PickingUpPhone); Assert.IsTrue(sm.CurrentState is DiallingState, string.Format("Telephone state is {0}, expected {1}", sm.CurrentState.GetType().Name, typeof(DiallingState).Name)); }
// Private methods private void ConfigureWizard() { _wizardContext = new WizardContext(); // Create the state machine with the correct context _sm = new SolidMachine <WizardTrigger>(_wizardContext); _sm.Transitioned += StateMachineOnTransitioned; // Assign the state machine to the context so it's accessible _wizardContext.StateMachine = _sm; _sm.State <WelcomePage>() .On(WizardTrigger.Cancel).GoesTo <ShutdownApplicationState>() .On(WizardTrigger.Next).GoesTo <InfoSelectionPage>(); _sm.State <InfoSelectionPage>() .On(WizardTrigger.Cancel).GoesTo <ShutdownApplicationState>() .On(WizardTrigger.Next, () => _wizardContext.InfoSelection == InfoSelectionMode.Family).GoesTo <FamilyInfoPage1>() .On(WizardTrigger.Next, () => _wizardContext.InfoSelection == InfoSelectionMode.Work).GoesTo <WorkInfoPage>(); _sm.State <FamilyInfoPage1>() .On(WizardTrigger.Cancel).GoesTo <ShutdownApplicationState>() .On(WizardTrigger.Next).GoesTo <FamilyInfoPage2>(); _sm.State <FamilyInfoPage2>() .On(WizardTrigger.Cancel).GoesTo <ShutdownApplicationState>() .On(WizardTrigger.Next).GoesTo <FinishPage>(); _sm.State <WorkInfoPage>() .On(WizardTrigger.Cancel).GoesTo <ShutdownApplicationState>() .On(WizardTrigger.Next).GoesTo <FinishPage>(); _sm.State <FinishPage>() .On(WizardTrigger.Finish).GoesTo <ShutdownApplicationState>(); _sm.Start(); }
public void MultipleGuardsEvaluateToTrue() { try { var sm = new SolidMachine<TelephoneTrigger>(); sm.State<IdleState>() .IsInitialState() .On(TelephoneTrigger.PickingUpPhone, () => ((1 + 1) == 2)).GoesTo<DiallingState>() .On(TelephoneTrigger.PickingUpPhone, () => ((6 / 2) == 3)).GoesTo<RingingState>(); sm.Start(); sm.Trigger(TelephoneTrigger.PickingUpPhone); Assert.Fail("Multiple guard clauses that return True as permitted!"); } catch (Exception ex) { Console.WriteLine(ex.Message); Assert.IsTrue(ex is SolidStateException); Assert.IsTrue((ex as SolidStateException).ErrorId == SolidStateConstants.ErrorMultipleGuardClausesAreTrue); } }
public void MultipleGuardsEvaluateToTrue() { try { var sm = new SolidMachine <TelephoneTrigger>(); sm.State <IdleState>() .IsInitialState() .On(TelephoneTrigger.PickingUpPhone, () => ((1 + 1) == 2)).GoesTo <DiallingState>() .On(TelephoneTrigger.PickingUpPhone, () => ((6 / 2) == 3)).GoesTo <RingingState>(); sm.Start(); sm.Trigger(TelephoneTrigger.PickingUpPhone); Assert.Fail("Multiple guard clauses that return True as permitted!"); } catch (Exception ex) { Console.WriteLine(ex.Message); Assert.IsTrue(ex is SolidStateException); Assert.IsTrue((ex as SolidStateException).ErrorId == SolidStateConstants.ErrorMultipleGuardClausesAreTrue); } }
public void InvalidTriggerWithHandler() { var _handlerCalledMessage = ""; var sm = new SolidMachine <TelephoneTrigger>(); sm.OnInvalidTrigger((state, trigger) => { _handlerCalledMessage = string.Format("{0}_{1}", state.Name, trigger); }); sm.State <IdleState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo <DiallingState>(); sm.State <DiallingState>() .On(TelephoneTrigger.HangingUp).GoesTo <IdleState>(); sm.Start(); sm.Trigger(TelephoneTrigger.PickingUpPhone); sm.Trigger(TelephoneTrigger.PickingUpPhone); Assert.IsTrue(_handlerCalledMessage == string.Format("{0}_{1}", typeof(DiallingState).Name, TelephoneTrigger.PickingUpPhone), string.Format("HandlerCalledMessage not what expected : {0}", _handlerCalledMessage)); }
public void StartWithoutStates() { try { var sm = new SolidMachine<TelephoneTrigger>(); sm.Start(); Assert.Fail("Start without configured states permitted!"); } catch (Exception ex) { Console.WriteLine(ex.Message); Assert.IsTrue(ex is SolidStateException); Assert.IsTrue((ex as SolidStateException).ErrorId == SolidStateConstants.ErrorNoStatesHaveBeenConfigured); } }
public void StartWithParameterizedState() { try { var sm = new SolidMachine<TelephoneTrigger>(); sm.State<IdleState>() .On(TelephoneTrigger.IncomingCall).GoesTo<StateWithoutParameterlessConstructor>(); sm.Start(); Assert.Fail("Startup without state resolver was permitted!"); } catch (Exception ex) { Console.WriteLine(ex.Message); Assert.IsTrue(ex is SolidStateException); Assert.IsTrue((ex as SolidStateException).ErrorId == SolidStateConstants.ErrorStatesNeedParameterlessConstructor); } }
public void OneStepGuardedTransition() { var isPhoneWorking = false; var sm = new SolidMachine<TelephoneTrigger>(); sm.State<IdleState>() .On(TelephoneTrigger.PickingUpPhone, () => isPhoneWorking).GoesTo<DiallingState>() .On(TelephoneTrigger.PickingUpPhone, () => !isPhoneWorking).GoesTo<TelephoneBrokenState>() .On(TelephoneTrigger.IncomingCall).GoesTo<RingingState>(); sm.State<RingingState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo<ConversationState>() .On(TelephoneTrigger.NotAnswering).GoesTo<IdleState>(); sm.State<TelephoneBrokenState>() .On(TelephoneTrigger.HangingUp).GoesTo<IdleState>(); sm.Start(); sm.Trigger(TelephoneTrigger.PickingUpPhone); Assert.IsTrue(sm.CurrentState is TelephoneBrokenState, string.Format("Telephone state is {0}, expected {1}", sm.CurrentState.GetType().Name, typeof (TelephoneBrokenState).Name)); // Reset the machine to IdleState sm.Trigger(TelephoneTrigger.HangingUp); isPhoneWorking = true; sm.Trigger(TelephoneTrigger.PickingUpPhone); Assert.IsTrue(sm.CurrentState is DiallingState, string.Format("Telephone state is {0}, expected {1}", sm.CurrentState.GetType().Name, typeof (DiallingState).Name)); }
public void GoBack() { var sm = new SolidMachine<TelephoneTrigger>(); var isGoingToDialling = false; sm.State<IdleState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo<DiallingState>(); sm.State<DiallingState>() .On(TelephoneTrigger.Answered, () => isGoingToDialling).GoesTo<ConversationState>() .On(TelephoneTrigger.Answered, () => !isGoingToDialling).GoesTo<WaitForAnswerState>(); sm.Start(); sm.Trigger(TelephoneTrigger.PickingUpPhone); sm.Trigger(TelephoneTrigger.Answered); Assert.IsTrue(sm.CurrentState is WaitForAnswerState, "Expected state WaitForAnswerState"); sm.GoBack(); Assert.IsTrue(sm.CurrentState is DiallingState, string.Format("Expected state DiallingState, was {0}", sm.CurrentState.GetType().Name)); // Shift the track isGoingToDialling = true; sm.Trigger(TelephoneTrigger.Answered); Assert.IsTrue(sm.CurrentState is ConversationState, "Expected state ConversationState"); sm.GoBack(); Assert.IsTrue(sm.CurrentState is DiallingState, "Expected state DiallingState... again"); }
public void InvalidTriggerWithHandler() { var _handlerCalledMessage = ""; var sm = new SolidMachine<TelephoneTrigger>(); sm.OnInvalidTrigger((state, trigger) => { _handlerCalledMessage = string.Format("{0}_{1}", state.Name, trigger); }); sm.State<IdleState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo<DiallingState>(); sm.State<DiallingState>() .On(TelephoneTrigger.HangingUp).GoesTo<IdleState>(); sm.Start(); sm.Trigger(TelephoneTrigger.PickingUpPhone); sm.Trigger(TelephoneTrigger.PickingUpPhone); Assert.IsTrue(_handlerCalledMessage == string.Format("{0}_{1}", typeof (DiallingState).Name, TelephoneTrigger.PickingUpPhone), string.Format("HandlerCalledMessage not what expected : {0}", _handlerCalledMessage)); }
public void CorrectOrderOnTransitions() { var states = new List<string>(); var sm = new SolidMachine<int>(); sm.Transitioned += (sender, args) => { var stateName = args.TargetState.Name; Console.WriteLine("Transitioned to " + stateName); states.Add(stateName); if (states.Count == 5) { var stateOrder = string.Join("_", states); Assert.IsTrue(stateOrder == "IdleState_StepState1_StepState2_StepState3_StepState4", string.Format("Wrong state order: {0}", stateOrder)); } }; sm.State<IdleState>() .On(0).GoesTo<StepState1>(); sm.State<StepState1>() .On(1).GoesTo<StepState2>(); sm.State<StepState2>() .On(2).GoesTo<StepState3>(); sm.State<StepState3>() .On(3).GoesTo<StepState4>(); sm.Start(); sm.Trigger(0); }
public void UsingExplicitContext() { var dateTime = new DateHolder(); var sm = new SolidMachine<TelephoneTrigger>(dateTime); sm.State<IdleState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo<DateReportingState>(); sm.Start(); sm.Trigger(TelephoneTrigger.PickingUpPhone); // The state should be able to use the specified context (dateTime variable) to report the date. Assert.IsTrue(dateTime.CurrentDate.Equals(DateTime.Now.Date), "Wrong date in context!"); }
public void UsingStateResolver() { // Lets this test class act as the state resolver... var sm = new SolidMachine<TelephoneTrigger>(null, this); sm.State<IdleState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo<StateWithoutParameterlessConstructor>(); sm.Start(); sm.Trigger(TelephoneTrigger.PickingUpPhone); Assert.IsTrue(sm.CurrentState is StateWithoutParameterlessConstructor); }
/// <summary> /// Configures and starts the telephone state machine. /// </summary> private void ConfigureTelephone() { _sm = new SolidMachine<TelephoneTrigger>(null, this); // Uncomment this row if you want a new state instance to be created on each transition // _sm.InstantiateStatePerTransition = true; _sm.Transitioned += StateMachineOnTransitioned; _sm.State<IdleState>() .IsInitialState() .On(TelephoneTrigger.PickingUpPhone).GoesTo<DiallingState>() .On(TelephoneTrigger.IncomingCall).GoesTo<RingingState>(); _sm.State<RingingState>() .On(TelephoneTrigger.PickingUpPhone).GoesTo<ConversationState>() .On(TelephoneTrigger.IgnoreIncomingCall).GoesTo<IdleState>(); _sm.State<DiallingState>() .On(TelephoneTrigger.FinishedDialling, () => !IsLineBusy).GoesTo<WaitForAnswerState>() .On(TelephoneTrigger.FinishedDialling, () => IsLineBusy).GoesTo<LineBusyState>() .On(TelephoneTrigger.MeHangingUp).GoesTo<IdleState>(); _sm.State<LineBusyState>() .On(TelephoneTrigger.MeHangingUp).GoesTo<IdleState>(); _sm.State<WaitForAnswerState>() .On(TelephoneTrigger.AnswerInOtherEnd).GoesTo<ConversationState>() .On(TelephoneTrigger.MeHangingUp).GoesTo<IdleState>(); _sm.State<ConversationState>() .On(TelephoneTrigger.MeHangingUp).GoesTo<IdleState>() .On(TelephoneTrigger.OtherEndHangingUp).GoesTo<LineDisconnectedState>(); _sm.State<LineDisconnectedState>() .On(TelephoneTrigger.MeHangingUp).GoesTo<IdleState>(); _sm.Start(); }