Represents an invalid trigger attempt, for various reasons.
Inheritance: System.ArgumentException
 public void InvalidTriggerException_MessageEx_VerifyMessageEx()
 {
     var inner = new Exception();
     var ex = new InvalidTriggerException("message", inner);
     Assert.Equal("message", ex.Message);
     Assert.Same(inner, ex.InnerException);
 }
 public void InvalidTriggerException_Message_VerifyMessage()
 {
     var ex = new InvalidTriggerException("message");
     Assert.Equal("message", ex.Message);
 }
Example #3
0
        public void Trigger(Trigger trigger, TStateModel model)
        {
            if (trigger == null)
            {
                throw new ArgumentNullException("trigger");
            }
            if (model == null)
            {
                throw new ArgumentNullException("model");
            }
            if (model.CurrentState == null || !(model.CurrentState is State <TStateModel>))
            {
                throw new InvalidStateModelException(
                          "State model's CurrentState object property must be of type State<TStateModel>");
            }

            // get current state
            var currentState = (State <TStateModel>)model.CurrentState;


            // find all possible transitions (state+global) from current state with given trigger
            // doesn't yet take into account the passing of those transitions' guards lambdas
            var possibleTransitions = currentState
                                      .TransitionsOn(trigger)
                                      .Concat(GlobalTransitionsOn(trigger));

            // if no possible transistions, throw exception about it
            if (Configuration.RaiseExceptionOnTriggerMatchingNoTransition && possibleTransitions.Count() == 0)
            {
                var availableTriggers = AvailableTriggers(model).ToList();
                var ex = new InvalidTriggerException(string.Format(
                                                         "State Model's CurrentState '{0}' does not define a Transition for trigger '{1}', nor does the state machine provide any global transitions on this trigger.  Available Triggers from this state: {2}.  This exception can be suppressed via the state machine's Configuration.RaiseExceptionOnTriggerMatchingNoTransitions property",
                                                         model.CurrentState,
                                                         trigger,
                                                         string.Join(", ", availableTriggers.ConvertAll(t => t.Name).ToArray())));
                ex.AvailableTriggers = availableTriggers;
                throw ex;
            }


            // out of the possible transitions, find the first whose guard passes
            var firstTransitionWithPassingGuard = possibleTransitions
                                                  .FirstOrDefault(t => t.Guard(model));

            // if no possible transition had a passign guard, throw exception about it.
            if (Configuration.RaiseExceptionOnTriggerMatchingNoPassingTransition &&
                (firstTransitionWithPassingGuard == null || firstTransitionWithPassingGuard.Target == null))
            {
                throw new InvalidTriggerException(string.Format(
                                                      "State Model's CurrentState '{0}' and the state machine's global transitions define at least {1} transition(s) for the trigger '{2}', but none of their guard lambdas returned true.  This exception can be suppressed via the state machine's Configuration.RaiseExceptionOnTriggerMatchingNoPassingTransitions property",
                                                      model.CurrentState,
                                                      possibleTransitions.Count().ToString(),
                                                      trigger.Name));
            }


            if (firstTransitionWithPassingGuard != null && firstTransitionWithPassingGuard.Target != null)
            {
                var nextState = firstTransitionWithPassingGuard.Target;

                // No transitions should happen if not effectively changing states, even if there's a matching transition
                if (nextState != currentState)
                {
                    // run transition callbacks and set the new state on model
                    if (Transitioning != null)
                    {
                        Transitioning(this,
                                      new TransitionEventArgs <TStateModel>(model, currentState, nextState, trigger));
                    }

                    // raise events that occur before actual state change
                    currentState.RaiseExiting(model, nextState, trigger);
                    nextState.RaiseEntering(model, currentState, trigger);

                    // change state
                    model.CurrentState = nextState;

                    // raise events that occur after actual state change
                    currentState.RaiseExited(model, nextState, trigger);
                    nextState.RaiseEntered(model, currentState, trigger);

                    // run transition callbacks and set the new state on model
                    if (Transitioned != null)
                    {
                        Transitioned(this,
                                     new TransitionEventArgs <TStateModel>(model, currentState, nextState, trigger));
                    }
                }
                // else if the next state is same as current, and machine is configured to
                // raise exception when that happens, go ahead and raise it
                else if (Configuration.RaiseExceptionBeforeTransitionToSameState)
                {
                    throw new InvalidTriggerException(string.Format(
                                                          "Trigger '{0}' would effectively transition State Model from its current state of '{1}' to the same state of '{2}', and the machine is currently configured to raise an exception when this happens.  This exception can be suppressed via the state machine's Configuration.RaiseExceptionBeforeTransitionToSameState property.",
                                                          trigger.Name,
                                                          model.CurrentState,
                                                          nextState));
                }
            }
        }