Source code for examples.TestHFSM.symplehfsm_demo

#!/usr/bin/python
# -*- coding: utf-8 -*-

"""

It's all about:
::

    making a statemachine testable based on: http://accu.org/index.php/journals/1548


    ------------------------------------------------------------------------------

    Statechart used to test the SympleHFSM
    based on 
    [Samek] Miro Samek, Practical Statecharts in C/C++, CMP Books 2002. 
    There's a companion website with additional information: http://www.quantum-leaps.com
    taken from: http://accu.org/index.php/journals/252

    see also: http://en.wikipedia.org/wiki/UML_state_machine#Local_versus_external_transitions
    making a statemachine testable based on: http://accu.org/index.php/journals/1548

              +-------------------------------------------------------------------------------------+
    *--init-->|                                         s0                                          |
              +-------------------------------------------------------------------------------------+
              | entry/                                                                              |
              | exit/                                                                               |
              |       +-------------------------+    +------------------------------------------+   |
              |   *-->|        s1               |    |               s2                         |   |
              |       +-------------------------+    +------------------------------------------+   |
              |       | entry/                  |-c->| entry/              +-----------------+  |   |
              |<--d---| exit/                   |    | exit/               | h[!foo]/ foo=1; |  |   |
              |       |     +---------------+   |<-c-|      +----------------------------+   |  |   |
              |       | *-->|      s11      |   |    |  *-->|             s21            |<--+  |   |
              |       |     +---------------+   |    |      +----------------------------+      |   |
              |    +--|     | entry/        |   |    |      | entry/                     |      |   |
              |   a|  |     | exit/         |<---f---|      | exit/                      |      |   |
              |    +->|     | h[foo]/ foo=0;|   |    |      |       +--------------+     |      |   |
              |       |     |               |   |    |      |   *-->|     s211     |     |      |   |
              |       |--b->|               |   |    |      |       +--------------+     |      |   |
              |       |     |               |   |--------f--------->| entry/       |     |      |   |
              |       |     |               |   |    |      |       | exit/        |--------g------>|
              |       |     |               |----------g----------->|              |     |      |   |
              |       |     |               |   |    |      |--b--->|              |<-------e-------|
              |       |     |               |   |    |      |<---d--|              |     |      |   |
              |       |     |               |   |    |      |       +--------------+     |      |   |
              |       |     +---------------+   |    |      +----------------------------+      |   |--exit-->O
              |       |                         |    |                                          |   |
              |       +-------------------------+    +------------------------------------------+   |
              |                                                                                     |
              +-------------------------------------------------------------------------------------+


      As far as I understand it, current_state always points to either s11 or s211 (one of the leaf states).
      Also for the transitions triggered by an event I assume it works as follows:

      event| from -> to | transition actions
       init:  s0 ->  s11:   s0.entry, s1.entry, s11.entry
       exit:s211 ->   s0: s211.exit, s21.exit, s2.exit, s0.exit
             s11 ->   s0:  s11.exit, s1.exit, s0.exit
          a:  s1 ->   s1:  s11.exit,  s1.exit,  s1.entry, s11.entry
          b:  s1 ->  s11:  s11.exit, s11.entry
             s21 -> s211: s211.exit, s211.entry
          c:  s1 ->   s2:  s11.exit,  s1.exit,  s2.entry, s21.entry, s211.entry
              s2 ->   s1: s211.exit, s21.exit,  s2.exit, s1.entry, s11.entry
          d:  s1 ->   s0:  s11.exit,  s1.exit,  s1.entry, s11.entry
            s211 ->  s21: s211.exit, s211.entry
          e:  s0 -> s211:  s11.exit,  s1.exit, s2.entry, s21.entry, s211.entry
                          s211.exit, s21.exit,  s2.exit, s2.entry, s21.entry, s211.entry
          f:  s2 ->  s11: s211.exit, s21.exit,  s2.exit, s1.entry, s11.entry
              s1 -> s211:  s11.exit,  s1.exit,  s2.entry, s21.entry, s211.entry
          g: s11 -> s211:  s11.exit,  s1.exit,  s2.entry, s21.entry, s211.entry
            s211 ->   s0: s211.exit, s21.exit,  s2.exit,  s1.entry, s11.entry
          h: s11 foo==True: actions.unset_foo
             s11 foo==False: do nothing
             s21 foo==False: s211.exit, s21.exit, actions.set_foo, s21.entry, s211.entry
             s21 foo==True: do nothing
          
      Actions:
          set_foo() => foo = 1
          unset_foo() => foo = 0

    The action specifications shown are:

       *

         The transition from s21 to itself (a self-transition). This is an example of a transition 
         that has a guard (in brackets []) and an associated action (after the slash /). The guard 
         is a condition that must evaluate to true to enable the transition. If it evaluates to false, 
         the transition is not taken and none of the actions are executed. A self-transition exits and 
         reenters the state, hence the associated exit and entry actions are executed.
       *

         The internal transition inside s11 is not drawn with an arrow. It merely specifies an action 
         that is to be taken when a certain event occurs, but no transition to another state occurs, 
         and no exit or entry actions are performed. In our case the internal transition has a guard, 
         so the associated action (foo = 0) is only executed when the h key is pressed while foo 
         evaluates to true.


..todo: loop action back to event -> queue?

"""

__version__ = "1.0.3.0"
__author__ = "dr0iddr0id {at} gmail [dot] com (C) 2012"

import operator

import symplehfsm
from symplehfsm import SympleDictHFSM
from symplehfsm import Structure
from symplehfsm import BaseHFSMTests


# ------------------------------------------------------------------------------

[docs]class Actions(object): """ The Actions the statemachine can execute. """
[docs] def set_foo(self): raise NotImplementedException()
[docs] def unset_foo(self): raise NotImplementedException()
[docs] def check_foo(self): raise NotImplementedError("check_foo needs to be overridden to return bool")
[docs] def check_foo_inverted(self): raise NotImplementedError("check_foo_inverted needs to be overridden to return !check_foo") # following are just to prove it works correctly
[docs] def enter_s0(self): raise NotImplementedException()
[docs] def exit_s0(self): raise NotImplementedException()
[docs] def enter_s1(self): raise NotImplementedException()
[docs] def exit_s1(self): raise NotImplementedException()
[docs] def enter_s11(self): raise NotImplementedException()
[docs] def exit_s11(self): raise NotImplementedException()
[docs] def enter_s2(self): raise NotImplementedException()
[docs] def exit_s2(self): raise NotImplementedException()
[docs] def enter_s21(self): raise NotImplementedException()
[docs] def exit_s21(self): raise NotImplementedException()
[docs] def enter_s211(self): raise NotImplementedException()
[docs] def exit_s211(self): raise NotImplementedException()
[docs] def trans_s1_to_s1_a(self): raise NotImplementedException()
[docs] def trans_s1_to_s11_b(self): raise NotImplementedException()
[docs] def trans_s21_to_s211_b(self): raise NotImplementedException()
[docs] def trans_s1_to_s2_c(self): raise NotImplementedException()
[docs] def trans_s2_to_s1_c(self): raise NotImplementedException()
[docs] def trans_s1_to_s0_d(self): raise NotImplementedException()
[docs] def trans_s211_to_s21_d(self): raise NotImplementedException()
[docs] def trans_s0_to_s211_e(self): raise NotImplementedException()
[docs] def trans_s1_to_s211_f(self): raise NotImplementedException()
[docs] def trans_s2_to_s11_f(self): raise NotImplementedException()
[docs] def trans_s11_to_s211_g(self): raise NotImplementedException()
[docs] def trans_s211_to_s0_g(self): raise NotImplementedException()
[docs] def trans_s11_to_s11_h(self): raise NotImplementedException()
[docs] def trans_s21_to_s21_h(self): raise NotImplementedException() # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
[docs]class EventEnum(object): """ Event identifiers of the statemachine (the events it can handle). """ # just make sure that the values are unique! a = 0 b = 1 c = 2 d = 3 e = 4 f = 5 g = 6 h = 7 # make it read only
EventEnum.__setattr__ = None # ------------------------------------------------------------------------------ # REQUIREMENTS: # - events interface # - actions interface (usage using different action interface implementations for test purposes) # - one state declaration/instanciation for each sm-type (sharing states as static datastructure since state itself are stateless) # - hierarchical states # - automatic calling entry/exits in a transition # - testable # PROS: # - simpler to setup # - less error prone # - less line of code to write # CONS: # - identifiers are strings (not necesairly), maybe 'enums' # - events are identifiers ('enums') # - typesafety from operator import methodcaller
[docs]class MyStateMachine(object): sm_structure = Structure() # state, parent, initial, entry, exit sm_structure.add_state("s0", None, False, methodcaller(Actions.enter_s0.__name__), methodcaller(Actions.exit_s0.__name__)) sm_structure.add_state( "s1", "s0", True, methodcaller("enter_s1"), methodcaller("exit_s1")) sm_structure.add_state( "s11", "s1", True, methodcaller("enter_s11"), methodcaller("exit_s11")) sm_structure.add_state( "s2", "s0", False, methodcaller("enter_s2"), methodcaller("exit_s2")) sm_structure.add_state( "s21", "s2", True, methodcaller("enter_s21"), methodcaller("exit_s21")) sm_structure.add_state( "s211", "s21", True, methodcaller("enter_s211"), methodcaller("exit_s211")) # handling state, event, next state, action, guard sm_structure.add_trans("s0", "e", "s211", methodcaller(Actions.trans_s0_to_s211_e.__name__), None) sm_structure.add_trans( "s1", "a", "s1", methodcaller("trans_s1_to_s1_a"), None) sm_structure.add_trans( "s1", "b", "s11", methodcaller("trans_s1_to_s11_b"), None) sm_structure.add_trans( "s1", "c", "s2", methodcaller("trans_s1_to_s2_c"), None) sm_structure.add_trans( "s1", "d", "s0", methodcaller("trans_s1_to_s0_d"), None) sm_structure.add_trans( "s1", "f", "s211", methodcaller("trans_s1_to_s211_f"), None) sm_structure.add_trans( "s11", "g", "s211", methodcaller("trans_s11_to_s211_g"), None) sm_structure.add_trans( "s11", "h", None, methodcaller("trans_s11_to_s11_h"), methodcaller("check_foo")) sm_structure.add_trans( "s2", "c", "s1", methodcaller("trans_s2_to_s1_c"), None) sm_structure.add_trans( "s2", "f", "s11", methodcaller("trans_s2_to_s11_f"), None) sm_structure.add_trans( "s21", "b", "s211", methodcaller("trans_s21_to_s211_b"), None) sm_structure.add_trans( "s21", "h", "s21", methodcaller("trans_s21_to_s21_h"), methodcaller("check_foo_inverted"), "s211-h") sm_structure.add_trans( "s211", "d", "s21", methodcaller("trans_s211_to_s21_d"), None) sm_structure.add_trans( "s211", "g", "s0", methodcaller("trans_s211_to_s0_g"), None) def __init__(self, actions): self.sm = SympleDictHFSM(self.sm_structure, actions)
[docs] def init(self): self.sm.init()
[docs] def exit(self): self.sm.exit()
[docs] def set_state(self, new_state): self.sm.set_state(new_state)
def _get_current_state(self): return self.sm.current_state current_state = property(_get_current_state)
[docs] def a(self): self.sm.handle_event("a")
[docs] def b(self): self.sm.handle_event("b")
[docs] def c(self): self.sm.handle_event("c")
[docs] def d(self): self.sm.handle_event("d")
[docs] def e(self): self.sm.handle_event("e")
[docs] def f(self): self.sm.handle_event("f")
[docs] def g(self): self.sm.handle_event("g")
[docs] def h(self): self.sm.handle_event("h") # ------------------------------------------------------------------------------
[docs]class SympleHFSMTests(BaseHFSMTests): """ Testcases for MyStateMachine using the BaseHFSMTests as base. """ # -- inner classes ---#
[docs] class TActions(Actions): """Test Actions for testing, captures all actions for comparison"""
[docs] class AEnum(object): """Define an 'enum' to have comparable values for each action""" # make sure each variable has a unique value! SETFOO = "SETFOO" UNSETFOO = "UNSETFOO" CHECKFOO = "CHECKFOO" ENTERS0 = "ENTERS0" EXITS0 = "EXITS0" ENTERS1 = "ENTERS1" EXITS1 = "EXITS1" ENTERS11 = "ENTERS11" EXITS11 = "EXITS11" ENTERS2 = "ENTERS2" EXITS2 = "EXITS2" ENTERS21 = "ENTERS21" EXITS21 = "EXITS21" ENTERS211 = "ENTERS211" EXITS211 = "EXITS211" TRANS_S1_TO_S1_A = "TRANS_S1_TO_S1_A" TRANS_S1_TO_S11_B = "TRANS_S1_TO_S11_B" TRANS_S21_TO_S211_B = "TRANS_S21_TO_S211_B" TRANS_S1_TO_S2_C = "TRANS_S1_TO_S2_C" TRANS_S2_TO_S1_C = "TRANS_S2_TO_S1_C" TRANS_S1_TO_S0_D = "TRANS_S1_TO_S0_D" TRANS_S211_TO_S21_D = "TRANS_S211_TO_S21_D" TRANS_S0_TO_S211_E = "TRANS_S0_TO_S211_E" TRANS_S1_TO_S211_F = "TRANS_S1_TO_S211_F" TRANS_S2_TO_S11_F = "TRANS_S2_TO_S11_F" TRANS_S11_TO_S211_G = "TRANS_S11_TO_S211_G" TRANS_S211_TO_S0_G = "TRANS_S211_TO_S0_G" TRANS_S11_TO_S11_H = "TRANS_S11_TO_S11_H" TRANS_S21_TO_S21_H = "TRANS_S21_TO_S21_H" # make it read only
AEnum.__setattr__ = None def __init__(self): self.captured_actions = [] self.foo = False # actions for guarded event/transition
[docs] def set_foo(self): self.captured_actions.append(self.AEnum.SETFOO)
[docs] def unset_foo(self): self.captured_actions.append(self.AEnum.UNSETFOO)
[docs] def check_foo(self): self.captured_actions.append(self.AEnum.CHECKFOO) return self.foo
[docs] def check_foo_inverted(self): return not self.check_foo() # following are just to prove it works correctly
[docs] def enter_s0(self): self.captured_actions.append(self.AEnum.ENTERS0)
[docs] def exit_s0(self): self.captured_actions.append(self.AEnum.EXITS0)
[docs] def enter_s1(self): self.captured_actions.append(self.AEnum.ENTERS1)
[docs] def exit_s1(self): self.captured_actions.append(self.AEnum.EXITS1)
[docs] def enter_s11(self): self.captured_actions.append(self.AEnum.ENTERS11)
[docs] def exit_s11(self): self.captured_actions.append(self.AEnum.EXITS11)
[docs] def enter_s2(self): self.captured_actions.append(self.AEnum.ENTERS2)
[docs] def exit_s2(self): self.captured_actions.append(self.AEnum.EXITS2)
[docs] def enter_s21(self): self.captured_actions.append(self.AEnum.ENTERS21)
[docs] def exit_s21(self): self.captured_actions.append(self.AEnum.EXITS21)
[docs] def enter_s211(self): self.captured_actions.append(self.AEnum.ENTERS211)
[docs] def exit_s211(self): self.captured_actions.append(self.AEnum.EXITS211)
[docs] def separator(self): self.captured_actions.append(self.AEnum._I) # transition acctions
[docs] def trans_s1_to_s1_a(self): self.captured_actions.append(self.AEnum.TRANS_S1_TO_S1_A)
[docs] def trans_s1_to_s11_b(self): self.captured_actions.append(self.AEnum.TRANS_S1_TO_S11_B)
[docs] def trans_s21_to_s211_b(self): self.captured_actions.append(self.AEnum.TRANS_S21_TO_S211_B)
[docs] def trans_s1_to_s2_c(self): self.captured_actions.append(self.AEnum.TRANS_S1_TO_S2_C)
[docs] def trans_s2_to_s1_c(self): self.captured_actions.append(self.AEnum.TRANS_S2_TO_S1_C)
[docs] def trans_s1_to_s0_d(self): self.captured_actions.append(self.AEnum.TRANS_S1_TO_S0_D)
[docs] def trans_s211_to_s21_d(self): self.captured_actions.append(self.AEnum.TRANS_S211_TO_S21_D)
[docs] def trans_s0_to_s211_e(self): self.captured_actions.append(self.AEnum.TRANS_S0_TO_S211_E)
[docs] def trans_s1_to_s211_f(self): self.captured_actions.append(self.AEnum.TRANS_S1_TO_S211_F)
[docs] def trans_s2_to_s11_f(self): self.captured_actions.append(self.AEnum.TRANS_S2_TO_S11_F)
[docs] def trans_s11_to_s211_g(self): self.captured_actions.append(self.AEnum.TRANS_S11_TO_S211_G)
[docs] def trans_s211_to_s0_g(self): self.captured_actions.append(self.AEnum.TRANS_S211_TO_S0_G)
[docs] def trans_s11_to_s11_h(self): self.captured_actions.append(self.AEnum.TRANS_S11_TO_S11_H) self.unset_foo()
[docs] def trans_s21_to_s21_h(self): self.captured_actions.append(self.AEnum.TRANS_S21_TO_S21_H) self.set_foo() # -- transition tests ---#
[docs] def setUp(self): self.actions = self.TActions() # self.state_machine = MyStateMachine(self.actions) self.state_machine = MyStateMachine(self.actions) print('======') self.state_machine.init() self.states = MyStateMachine.sm_structure.states
[docs] def tearDown(self): self.state_machine.exit()
[docs] def test_initial_transition_state(self): # init: s0 -> s11: s0.entry, s1.entry, s11.entry v = self.TestVector("init", self.states["s0"], self.state_machine.init, self.states["s11"], [self.TActions.AEnum.ENTERS0, self.TActions.AEnum.ENTERS1, self.TActions.AEnum.ENTERS11]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_exit_transition_from_s211(self): # exit:s211 -> s0: s211.exit, s21.exit, s2.exit, s0.exit v = self.TestVector("exit from s211", self.states["s211"], self.state_machine.exit, None, \ [self.TActions.AEnum.EXITS211, self.TActions.AEnum.EXITS21, self.TActions.AEnum.EXITS2, self.TActions.AEnum.EXITS0]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_exit_transition_from_s11(self): # s11 -> s0: s11.exit, s1.exit, s0.exit v = self.TestVector("exit from s11", self.states["s11"], self.state_machine.exit, None, \ [self.TActions.AEnum.EXITS11, self.TActions.AEnum.EXITS1, self.TActions.AEnum.EXITS0]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s1_to_s1_event_a(self): # a: s1 -> s1: s11.exit, s1.exit, s1.entry, s11.entry v = self.TestVector("s1 to s1 event a", self.states["s11"], self.state_machine.a, self.states["s11"], \ [self.TActions.AEnum.EXITS11, self.TActions.AEnum.EXITS1, self.TActions.AEnum.TRANS_S1_TO_S1_A ,self.TActions.AEnum.ENTERS1, self.TActions.AEnum.ENTERS11]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s1_to_s11_event_b(self): # b: s1 -> s11: s11.exit, s1.exit, s1.entry, s11.entry v = self.TestVector("s1 to s11 event b", self.states["s11"], self.state_machine.b, self.states["s11"], \ [self.TActions.AEnum.EXITS11, self.TActions.AEnum.TRANS_S1_TO_S11_B , self.TActions.AEnum.ENTERS11]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s21_to_s211_event_b(self): # s21 -> s211: s211.exit, s21.exit, s21.entry, s211.entry v = self.TestVector("s21 to s211 event b", self.states["s211"], self.state_machine.b, self.states["s211"], \ [self.TActions.AEnum.EXITS211, self.TActions.AEnum.TRANS_S21_TO_S211_B, self.TActions.AEnum.ENTERS211]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s1_to_s2_event_c(self): # c: s1 -> s2: s11.exit, s1.exit, s2.entry, s21.entry, s211.entry v = self.TestVector("s1 to s2 event c", self.states["s11"], self.state_machine.c, self.states["s211"], \ [self.TActions.AEnum.EXITS11, self.TActions.AEnum.EXITS1, self.TActions.AEnum.TRANS_S1_TO_S2_C, self.TActions.AEnum.ENTERS2, self.TActions.AEnum.ENTERS21, self.TActions.AEnum.ENTERS211]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s2_to_s1_event_c(self): # s2 -> s1: s211.exit, s21.exit, s2.exit, s1.entry, s11.entry v = self.TestVector("s2 to s1 event c", self.states["s211"], self.state_machine.c, self.states["s11"], \ [self.TActions.AEnum.EXITS211, self.TActions.AEnum.EXITS21, self.TActions.AEnum.EXITS2, self.TActions.AEnum.TRANS_S2_TO_S1_C, self.TActions.AEnum.ENTERS1, self.TActions.AEnum.ENTERS11]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s1_to_s0_event_d(self): # d: s1 -> s0: s11.exit, s1.exit, s1.entry, s11.entry v = self.TestVector("s1 to s0 event d", self.states["s11"], self.state_machine.d, self.states["s11"], \ [self.TActions.AEnum.EXITS11, self.TActions.AEnum.EXITS1, self.TActions.AEnum.TRANS_S1_TO_S0_D, self.TActions.AEnum.ENTERS1, self.TActions.AEnum.ENTERS11]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s211_to_s21_event_d(self): # s211 -> s21: s211.exit, s21.exit, s21.entry, s211.entry v = self.TestVector("s211 to s21 event d", self.states["s211"], self.state_machine.d, self.states["s211"], \ [self.TActions.AEnum.EXITS211, self.TActions.AEnum.TRANS_S211_TO_S21_D, self.TActions.AEnum.ENTERS211]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s0_to_s211_event_e_case_s11(self): # e: s0 -> s211: s11.exit, s1.exit, s2.entry, s21.entry, s211.entry v = self.TestVector("s0 to s211 event e case s11", self.states["s11"], self.state_machine.e, self.states["s211"], \ [self.TActions.AEnum.EXITS11, self.TActions.AEnum.EXITS1, self.TActions.AEnum.TRANS_S0_TO_S211_E, self.TActions.AEnum.ENTERS2, self.TActions.AEnum.ENTERS21, self.TActions.AEnum.ENTERS211]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s0_t0_s211_event_e_case_s211(self): # s211.exit, s21.exit, s2.exit, s2.entry, s21.entry, s211.entry v = self.TestVector("s0 to s211 event e case s211", self.states["s211"], self.state_machine.e, self.states["s211"], \ [self.TActions.AEnum.EXITS211, self.TActions.AEnum.EXITS21, self.TActions.AEnum.EXITS2, self.TActions.AEnum.TRANS_S0_TO_S211_E, self.TActions.AEnum.ENTERS2, self.TActions.AEnum.ENTERS21, self.TActions.AEnum.ENTERS211]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s2_to_s11_event_f(self): # f: s2 -> s11: s211.exit, s21.exit, s2.exit, s1.entry, s11.entry v = self.TestVector("s2 to s11 event f", self.states["s211"], self.state_machine.f, self.states["s11"], \ [self.TActions.AEnum.EXITS211, self.TActions.AEnum.EXITS21, self.TActions.AEnum.EXITS2, self.TActions.AEnum.TRANS_S2_TO_S11_F, self.TActions.AEnum.ENTERS1, self.TActions.AEnum.ENTERS11]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s1_to_s211_event_f(self): # s1 -> s211: s11.exit, s1.exit, s2.entry, s21.entry, s211.entry v = self.TestVector("s1 to s211 event f", self.states["s11"], self.state_machine.f, self.states["s211"], \ [self.TActions.AEnum.EXITS11, self.TActions.AEnum.EXITS1, self.TActions.AEnum.TRANS_S1_TO_S211_F, self.TActions.AEnum.ENTERS2, self.TActions.AEnum.ENTERS21, self.TActions.AEnum.ENTERS211]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s11_to_s211_event_g(self): # g: s11 -> s211: s11.exit, s1.exit, s2.entry, s21.entry, s211.entry v = self.TestVector("s11 to s211 event g", self.states["s11"], self.state_machine.g, self.states["s211"], \ [self.TActions.AEnum.EXITS11, self.TActions.AEnum.EXITS1, self.TActions.AEnum.TRANS_S11_TO_S211_G, self.TActions.AEnum.ENTERS2, self.TActions.AEnum.ENTERS21, self.TActions.AEnum.ENTERS211]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s211_to_s0_event_g(self): # s211 -> s0: s211.exit, s21.exit, s2.exit, s1.entry, s11.entry v = self.TestVector("s211 to s0 event g", self.states["s211"], self.state_machine.g, self.states["s11"], \ [self.TActions.AEnum.EXITS211, self.TActions.AEnum.EXITS21, self.TActions.AEnum.EXITS2, self.TActions.AEnum.TRANS_S211_TO_S0_G, self.TActions.AEnum.ENTERS1, self.TActions.AEnum.ENTERS11]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s11_to_s11_event_h_guard_true(self): # h: s11 foo==True: actions.check_foo, actions.unset_foo self.actions.foo = True v = self.TestVector("test_s11_to_s11_event_h_guard_true", self.states["s11"], self.state_machine.h, self.states["s11"], \ [self.TActions.AEnum.CHECKFOO, self.TActions.AEnum.TRANS_S11_TO_S11_H, self.TActions.AEnum.UNSETFOO]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s11_to_s11_event_h_guard_false(self): # h: s11 foo==False: actions.check_foo self.actions.unset_foo = False v = self.TestVector("test_s11_to_s11_event_h_guard_false", self.states["s11"], self.state_machine.h, self.states["s11"], \ [self.TActions.AEnum.CHECKFOO]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s211_to_s211_event_h_guard_false(self): # s21 foo==False: s211.exit, s21.exit, actions.set_foo, s21.entry, s211.entry self.actions.foo = False v = self.TestVector("test_s211_to_s211_event_h_guard_false", self.states["s211"], self.state_machine.h, self.states["s211"], \ [self.TActions.AEnum.CHECKFOO, self.TActions.AEnum.EXITS211, self.TActions.AEnum.EXITS21, self.TActions.AEnum.TRANS_S21_TO_S21_H, self.TActions.AEnum.SETFOO, self.TActions.AEnum.ENTERS21, self.TActions.AEnum.ENTERS211]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s211_to_s211_event_h_guard_true(self): # s21 foo==False: s211.exit, s21.exit, actions.set_foo, s21.entry, s211.entry self.actions.foo = True v = self.TestVector("test_s211_to_s211_event_h_guard_true", self.states["s211"], self.state_machine.h, self.states["s211"], \ [self.TActions.AEnum.CHECKFOO]) self.prove_one_transition(self.state_machine, self.actions, v)
[docs] def test_s211_to_s211_event_a_no_guard(self): # s21 foo==False: s211.exit, s21.exit, actions.set_foo, s21.entry, s211.entry v = self.TestVector("test_s211_to_s211_event_a_no_guard", self.states["s211"], self.state_machine.a, self.states["s211"], \ []) self.prove_one_transition(self.state_machine, self.actions, v) # def test_sequence_AAA(self): # vecs = [ # # self.TestVector("s1 to s211 event f", self.states["s11"], self.state_machine.f, self.states["s211"], \ # # [self.TActions.AEnum.EXITS11, self.TActions.AEnum.EXITS1, self.TActions.AEnum.TRANS_S1_TO_S211_F, self.TActions.AEnum.ENTERS2, self.TActions.AEnum.ENTERS21, self.TActions.AEnum.ENTERS211]), # # self.TestVector("s2 to s1 event c", self.states["s211"], self.state_machine.c, self.states["s11"], \ # # [self.TActions.AEnum.EXITS211, self.TActions.AEnum.EXITS21, self.TActions.AEnum.EXITS2, self.TActions.AEnum.TRANS_S2_TO_S1_C, self.TActions.AEnum.ENTERS1, self.TActions.AEnum.ENTERS11]), # self.TestVector("test_s11_to_s11_event_h_guard_false", self.states["s11"], self.state_machine.h, self.states["s11"], \ # [self.TActions.AEnum.CHECKFOO]), # self.TestVector("s1 to s2 event c", self.states["s11"], self.state_machine.c, self.states["s211"], \ # [self.TActions.AEnum.EXITS11, self.TActions.AEnum.EXITS1, self.TActions.AEnum.TRANS_S1_TO_S2_C, self.TActions.AEnum.ENTERS2, self.TActions.AEnum.ENTERS21, self.TActions.AEnum.ENTERS211]), # ] # self.prove_transition_sequence(self.state_machine, self.actions, vecs) # ------------------------------------------------------------------------------
[docs]class SympleHFSMTestsOptimized(SympleHFSMTests):
[docs] def setUp(self): MyStateMachine.sm_structure.do_optimize() SympleHFSMTests.setUp(self) # ------------------------------------------------------------------------------ # interactive demo of the same state machine, but using different actions implementation to print # out the actions
[docs]def demo(): """ The demo. This is the main method that runs the interactive demo. """ import sys class PrintActions(Actions): """ The Actions printing what they do. """ def __init__(self): self._foo = False def set_foo(self): print("\tfoo set") self._foo = True def unset_foo(self): print("\tfoo unset") self._foo = False def check_foo(self): print("\tchecking foo") return self._foo def check_foo_inverted(self): print("\tchecking !foo") return not self._foo # following are just to prove it works correctly def enter_s0(self): print("\tentering S0") def exit_s0(self): print("\texiting S0") def enter_s1(self): print("\tentering S1") def exit_s1(self): print("\texiting S1") def enter_s11(self): print("\tentering S11") def exit_s11(self): print("\texiting S11") def enter_s2(self): print("\tentering S2") def exit_s2(self): print("\texiting S2") def enter_s21(self): print("\tentering S21") def exit_s21(self): print("\texiting S21") def enter_s211(self): print("\tentering S211") def exit_s211(self): print("\texiting S211") # transition acctions def trans_s1_to_s1_a(self): print("\tTRANS_S1_TO_S1_A") def trans_s1_to_s11_b(self): print("\tTRANS_S1_TO_S11_B") def trans_s21_to_s211_b(self): print("\tTRANS_S21_TO_S211_B") def trans_s1_to_s2_c(self): print("\tTRANS_S1_TO_S2_C") def trans_s2_to_s1_c(self): print("\tTRANS_S2_TO_S1_C") def trans_s1_to_s0_d(self): print("\tTRANS_S1_TO_S0_D") def trans_s211_to_s21_d(self): print("\tTRANS_S211_TO_S21_D") def trans_s0_to_s211_e(self): print("\tTRANS_S0_TO_S211_E") def trans_s1_to_s211_f(self): print("\tTRANS_S1_TO_S211_F") def trans_s2_to_s11_f(self): print("\tTRANS_S2_TO_S11_F") def trans_s11_to_s211_g(self): print("\tTRANS_S11_TO_S211_G") def trans_s211_to_s0_g(self): print("\tTRANS_S211_TO_S0_G") def trans_s11_to_s11_h(self): print("\tTRANS_S11_TO_S11_H") self.unset_foo() def trans_s21_to_s21_h(self): print("\tTRANS_S21_TO_S21_H") self.set_foo() def print_help(): print("") print("usage:") print(" 'quit' : exits the demo") print(" 'help' : prints this help") print(" 'init' : init event to init the state machine") print(" 'exit' : exit event to exit the state machine, caution, no state set afterwards!") print(" 'print' : print the state chart") print(" events : 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'") print("") print("") if __debug__: import os # print("use 'python -O "+os.path.split(__file__)[1]+"' to run the demo!") # return print_help() actions = PrintActions() sm = MyStateMachine(actions) # setup event handlers event_handlers = {'a': sm.a, 'b':sm.b, 'c':sm.c, 'd':sm.d, 'e':sm.e, 'f':sm.f, 'g':sm.g, 'h':sm.h, 'exit':sm.exit, 'init':sm.init} running = True while running: prompt = str(sm.current_state.name if sm.current_state else "None") + " << " # python 3.x compatibility if sys.version_info < (3, ): evt = raw_input(prompt) else: evt = input(prompt) try: if evt == 'quit': running = False elif evt == 'help': print_help() elif evt == 'print': print_chart() else: if evt in list(event_handlers.keys()): # handle event in the statemachine event_handlers[evt]() else: print("not supported event: ", evt) except Exception as e: print("Error:" + str(e))
if __name__ == '__main__': demo()