class Test_hsmpy(object):

    def setup_class(self):

        self.worked = 'no'

        def blah(evt, hsm):
            self.worked = 'yes'

        self.states = {
            'top': State({
                'left': State(),
                'right': State(),
            })
        }
        self.trans = {
            'top': {
                Initial: T('left'),
            },
            'left': {
                Step: T('right', action=blah),
            }
        }
        self.eb = EventBus()
        self.hsm = HSM(self.states, self.trans)

    def test_start(self):
        self.hsm.start(self.eb)

    def test_seems_fine(self):
        self.eb.dispatch(Step())
        assert self.worked == 'yes'
        assert len(self.hsm.current_state_set) == 2
예제 #2
0
class Test_perpetual_machine:

    def setup_class(self):
        self.eb = EventBus()

        def increase(evt, hsm):
            hsm.data.count += 1

        self.states = {
            'top': State({
                'a': SteppingState(),
                'b': SteppingState(),
            })
        }
        self.trans = {
            'top': {
                Initial: T('a'),
            },
            'a': {
                Step: T('b', action=increase),
            },
            'b': {
                Step: T('a'),
            }
        }
        self.hsm = HSM(self.states, self.trans)
        self.hsm.data.count = 0

    def test_stops_after_2000_cycles(self):
        self.hsm.start(self.eb)
        assert self.hsm.data.count == 2000
예제 #3
0
class Test_entry_exit_actions:
    def setup_class(self):
        self.states = {
            'top': LoggingState({
                'idle': LoggingState(),
                'drawing': LoggingState({
                    'drawing_rectangle': LoggingState(),
                    'drawing_circle': LoggingState(),
                })
            })
        }

        self.trans = {
            'top': {
                Initial: T('idle'),
            },
            'idle': {
                Step: T('drawing_rectangle'),
            },
            'drawing': {
                Initial: T('drawing_circle'),
                Step: T('idle'),
            },
        }

        self.eb = EventBus()
        self.hsm = HSM(self.states, self.trans)

    def test_in_idle_after_starting(self):
        self.hsm.start(self.eb)
        assert_curr_state(self.hsm, 'idle')

    def test_actions_invoked_after_starting(self):
        assert self.hsm.data._log == {
            'top_enter': 1,
            'idle_enter': 1,
        }

    def test_actions_invoked_after_dispatching_1(self):
        self.eb.dispatch(Step())
        assert self.hsm.data._log == {
            'top_enter': 1,
            'idle_enter': 1,
            'idle_exit': 1,
            'drawing_enter': 1,
            'drawing_rectangle_enter': 1,
        }

    def test_actions_invoked_after_dispatching_2(self):
        self.eb.dispatch(Step())
        assert self.hsm.data._log == {
            'top_enter': 1,
            'idle_enter': 2,
            'idle_exit': 1,
            'drawing_enter': 1,
            'drawing_rectangle_enter': 1,
            'drawing_rectangle_exit': 1,
            'drawing_exit': 1,
        }
예제 #4
0
    def setup_class(self):
        states = {
            'top': LoggingState({
                'A': LoggingState(),
                'B': LoggingState(),
                'C': LoggingState({
                    'C_left': LoggingState(),
                    'C_right': LoggingState(),
                })
            })
        }

        key = lambda _, hsm: hsm.data.foo % 3

        trans = {
            'top': {
                Initial: Choice({ 0: 'A', 1: 'B', 2: 'C' },
                                key=key, default='B')
            },
            'A': {
                Step: Local('top'),
            },
            'B': {
                Step: T('top'),
            },
            'C': {
                Initial: Choice({ False: 'C_left', True: 'C_right' },
                                key=lambda _, hsm: hsm.data.foo % 2 == 0,
                                default='C_left'),
                Step: T('top'),
            },
        }

        self.eb = EventBus()
        self.hsm = HSM(states, trans)
예제 #5
0
    def setup_class(self):
        self.eb = EventBus()
        hsmdata = {
            'initial': 0,
            'closed_enter': 0,
            'closed_exit': 0,
            'opened_enter': 0,
            'opened_exit': 0,
            'trans_opening': 0,
            'trans_closing': 0,
        }

        self.states = {
            'top': State({
                'closed': Closed(),
                'opened': Opened(),
            })
        }

        self.trans = {
            'top': {
                Initial: T('closed', action=get_callback('initial')),
            },
            'closed': {
                OpenDoor: T('opened', action=get_callback('trans_opening'))
            },
            'opened': {
                CloseDoor: T('closed', action=get_callback('trans_closing'))
            }
        }
        self.hsm = HSM(self.states, self.trans)
        self.hsm.data = hsmdata
예제 #6
0
    def setup_class(self):
        self.states = {
            'top': LoggingState({
                'idle': LoggingState(),
                'drawing': LoggingState({
                    'drawing_rectangle': LoggingState(),
                    'drawing_circle': LoggingState(),
                })
            })
        }

        self.trans = {
            'top': {
                Initial: T('idle'),
            },
            'idle': {
                Step: T('drawing_rectangle'),
            },
            'drawing': {
                Initial: T('drawing_circle'),
                Step: T('idle'),
            },
        }

        self.eb = EventBus()
        self.hsm = HSM(self.states, self.trans)
예제 #7
0
    def setup_class(self):
        self.eb = EventBus()

        def increase(evt, hsm):
            hsm.data.count += 1

        self.states = {
            'top': State({
                'a': SteppingState(),
                'b': SteppingState(),
            })
        }
        self.trans = {
            'top': {
                Initial: T('a'),
            },
            'a': {
                Step: T('b', action=increase),
            },
            'b': {
                Step: T('a'),
            }
        }
        self.hsm = HSM(self.states, self.trans)
        self.hsm.data.count = 0
예제 #8
0
class Test_submachines_some_respond:
    def setup_class(self):
        states, trans = make_submachines_async_machine(use_logging=True)
        self.hsm = HSM(states, trans)
        self.eb = EventBus()

    def test_enters_submachines_after_start(self):
        self.hsm.start(self.eb)
        assert self.hsm.data._log == {
            "top_enter": 1,
            "subs_enter": 1,
            "subs[0].top_enter": 1,
            "subs[0].left_enter": 1,
            "subs[1].top_enter": 1,
            "subs[1].left_enter": 1,
        }
        assert_names(self.hsm, "subs[0].left", "subs[0].top", "subs[1].left", "subs[1].top", "subs", "top")

    def test_first_responds_to_A(self):
        self.eb.dispatch(A())
        assert self.hsm.data._log == {
            "top_enter": 1,
            "subs_enter": 1,
            "subs[0].top_enter": 1,
            "subs[0].left_enter": 1,
            "subs[1].top_enter": 1,
            "subs[1].left_enter": 1,
            "subs[0].left_exit": 1,
            "subs[0].right_enter": 1,
        }
        assert_names(self.hsm, "subs[0].right", "subs[0].top", "subs[1].left", "subs[1].top", "subs", "top")

    def test_second_responds_to_B(self):
        self.eb.dispatch(B())
        assert self.hsm.data._log == {
            "top_enter": 1,
            "subs_enter": 1,
            "subs[0].top_enter": 1,
            "subs[0].left_enter": 1,
            "subs[1].top_enter": 1,
            "subs[1].left_enter": 1,
            "subs[0].left_exit": 1,
            "subs[0].right_enter": 1,
            "subs[1].left_exit": 1,
            "subs[1].right_enter": 1,
        }
        assert_names(self.hsm, "subs[0].right", "subs[0].top", "subs[1].right", "subs[1].top", "subs", "top")
예제 #9
0
파일: app.py 프로젝트: bgr/unnamed_gui_tool
def run():
    eventbus = EventBus()
    canvas_model = CanvasModel(eventbus)
    canvas_model.elems = [Ellipse(20, 30, 40, 50), Rectangle(30, 40, 10, 20)]

    eventbus.register(Undo_Requested, lambda _: canvas_model.undo())
    eventbus.register(Redo_Requested, lambda _: canvas_model.redo())

    cvs_view_1, cvs_states_1, cvs_trans_1 = widgets.canvas.make(eventbus,
                                                                canvas_model)
    cvs_view_2, cvs_states_2, cvs_trans_2 = widgets.canvas.make(eventbus,
                                                                canvas_model)

    app_states = {
        'top': {
            'canvas_displayed': State([
                (cvs_states_1, cvs_trans_1),
                (cvs_states_2, cvs_trans_2),
                #(toolbar_states, toolbar_trans),
            ]),
        }
    }

    app_trans = {
        'top': {
            Initial: T('canvas_displayed'),
        }
    }

    hsm = HSM(app_states, app_trans)
    hsm.start(eventbus)

    app_frame = AppFrame(eventbus)

    canvases = JPanel()
    canvases.layout = BoxLayout(canvases, BoxLayout.PAGE_AXIS)

    canvases.add(cvs_view_1)
    canvases.add(cvs_view_2)
    app_frame.add(canvases, BorderLayout.CENTER)

    cvs_view_2.background = Color.GRAY

    app_frame.size = (1100, 1000)
예제 #10
0
    def setup_class(self):
        hsmdata = {
            'top_internal_A': 0,
            'top_internal_B': 0,
            'top_internal_C': 0,
            'idle_internal_A': 0,
            'idle_internal_B': 0,
            'working_internal_A': 0,
            'working_internal_B': 0,
            'leaf_internal_A': 0,
        }

        states = {
            'top': State(states={
                'idle': State(),
                'working': State({
                    'leaf': State(),
                })
            })
        }

        trans = {
            'top': {
                Initial: T('idle'),
                A: Internal(action=get_callback('top_internal_A')),
                B: Internal(action=get_callback('top_internal_B')),
                C: Internal(action=get_callback('top_internal_C')),
            },
            'idle': {
                Step: T('leaf'),
                A: Internal(action=get_callback('idle_internal_A')),
                B: Internal(action=get_callback('idle_internal_B')),
            },
            'working': {
                Initial: T('leaf'),
                A: Internal(action=get_callback('working_internal_A')),
                B: Internal(action=get_callback('working_internal_B')),
            },
            'leaf': {
                A: Internal(action=get_callback('leaf_internal_A')),
            },
        }

        self.eb = EventBus()
        self.hsm = HSM(states, trans)
        self.hsm.data = hsmdata
예제 #11
0
    def setup_class(self):
        sub_states, sub_trans = make_choice_machine(use_logging=True)
        states = {
            "top": LoggingState(
                {
                    "left": LoggingState([(sub_states, sub_trans), (sub_states, sub_trans)]),
                    "right": LoggingState([(sub_states, sub_trans), (sub_states, sub_trans)]),
                }
            )
        }

        key = lambda _, hsm: hsm.data.foo % 2

        trans = {"top": {Initial: Choice({0: "left", 1: "right"}, key=key, default="left"), B: T("top")}}

        self.eb = EventBus()
        self.hsm = HSM(states, trans)
예제 #12
0
    def setup_class(self):
        self.eb = EventBus()
        hsmdata = {
            'initial': 0,
            'start_enter': 0,
            'start_exit': 0,
            'goal_enter': 0,
            'goal_exit': 0,
            'trans_left': 0,
            'trans_right': 0,
            'trans_loop': 0,
            'trans_restart': 0,
        }

        self.start = Start()
        self.goal = Goal()

        self.states = {
            'top': State({
                'start': self.start,
                'goal': self.goal,
            })
        }
        self.trans = {
            'top': {
                Initial: T('start', action=get_callback('initial')),
            },
            'start': {
                MoveLeft: T('goal', action=get_callback('trans_left')),
                MoveRight: T('goal', action=get_callback('trans_right')),
            },
            'goal': {
                Loop: T('goal', action=get_callback('trans_loop')),
                Restart: T('top', action=get_callback('trans_restart')),
            }
        }
        self.hsm = HSM(self.states, self.trans)
        self.hsm.data = hsmdata
    def setup_class(self):

        self.worked = 'no'

        def blah(evt, hsm):
            self.worked = 'yes'

        self.states = {
            'top': State({
                'left': State(),
                'right': State(),
            })
        }
        self.trans = {
            'top': {
                Initial: T('left'),
            },
            'left': {
                Step: T('right', action=blah),
            }
        }
        self.eb = EventBus()
        self.hsm = HSM(self.states, self.trans)
예제 #14
0
class Test_internal_transitions:
    def setup_class(self):
        hsmdata = {
            'top_internal_A': 0,
            'top_internal_B': 0,
            'top_internal_C': 0,
            'idle_internal_A': 0,
            'idle_internal_B': 0,
            'working_internal_A': 0,
            'working_internal_B': 0,
            'leaf_internal_A': 0,
        }

        states = {
            'top': State(states={
                'idle': State(),
                'working': State({
                    'leaf': State(),
                })
            })
        }

        trans = {
            'top': {
                Initial: T('idle'),
                A: Internal(action=get_callback('top_internal_A')),
                B: Internal(action=get_callback('top_internal_B')),
                C: Internal(action=get_callback('top_internal_C')),
            },
            'idle': {
                Step: T('leaf'),
                A: Internal(action=get_callback('idle_internal_A')),
                B: Internal(action=get_callback('idle_internal_B')),
            },
            'working': {
                Initial: T('leaf'),
                A: Internal(action=get_callback('working_internal_A')),
                B: Internal(action=get_callback('working_internal_B')),
            },
            'leaf': {
                A: Internal(action=get_callback('leaf_internal_A')),
            },
        }

        self.eb = EventBus()
        self.hsm = HSM(states, trans)
        self.hsm.data = hsmdata

    def test_in_idle_after_starting(self):
        self.hsm.start(self.eb)
        assert_curr_state(self.hsm, 'idle')

    def test_idle_responds_to_A(self):
        self.eb.dispatch(A())
        assert self.hsm.data == {
            'top_internal_A': 0,
            'top_internal_B': 0,
            'top_internal_C': 0,
            'idle_internal_A': 1,
            'idle_internal_B': 0,
            'working_internal_A': 0,
            'working_internal_B': 0,
            'leaf_internal_A': 0,
        }
        assert_curr_state(self.hsm, 'idle')

    def test_idle_responds_to_B(self):
        self.eb.dispatch(B())
        assert self.hsm.data == {
            'top_internal_A': 0,
            'top_internal_B': 0,
            'top_internal_C': 0,
            'idle_internal_A': 1,
            'idle_internal_B': 1,
            'working_internal_A': 0,
            'working_internal_B': 0,
            'leaf_internal_A': 0,
        }
        assert_curr_state(self.hsm, 'idle')

    def test_top_responds_to_C_from_idle(self):
        self.eb.dispatch(C())
        assert self.hsm.data == {
            'top_internal_A': 0,
            'top_internal_B': 0,
            'top_internal_C': 1,
            'idle_internal_A': 1,
            'idle_internal_B': 1,
            'working_internal_A': 0,
            'working_internal_B': 0,
            'leaf_internal_A': 0,
        }
        assert_curr_state(self.hsm, 'idle')

    def test_in_leaf_after_dispatching_Step(self):
        self.eb.dispatch(Step())
        assert_curr_state(self.hsm, 'leaf')
        assert self.hsm.data == {  # nothing changed
            'top_internal_A': 0,
            'top_internal_B': 0,
            'top_internal_C': 1,
            'idle_internal_A': 1,
            'idle_internal_B': 1,
            'working_internal_A': 0,
            'working_internal_B': 0,
            'leaf_internal_A': 0,
        }

    def test_leaf_responds_to_A(self):
        self.eb.dispatch(A())
        assert self.hsm.data == {
            'top_internal_A': 0,
            'top_internal_B': 0,
            'top_internal_C': 1,
            'idle_internal_A': 1,
            'idle_internal_B': 1,
            'working_internal_A': 0,
            'working_internal_B': 0,
            'leaf_internal_A': 1,
        }
        assert_curr_state(self.hsm, 'leaf')

    def test_working_responds_to_B_from_leaf(self):
        self.eb.dispatch(B())
        assert self.hsm.data == {
            'top_internal_A': 0,
            'top_internal_B': 0,
            'top_internal_C': 1,
            'idle_internal_A': 1,
            'idle_internal_B': 1,
            'working_internal_A': 0,
            'working_internal_B': 1,
            'leaf_internal_A': 1,
        }
        assert_curr_state(self.hsm, 'leaf')

    def test_top_responds_to_C_from_leaf(self):
        self.eb.dispatch(C())
        assert self.hsm.data == {
            'top_internal_A': 0,
            'top_internal_B': 0,
            'top_internal_C': 2,
            'idle_internal_A': 1,
            'idle_internal_B': 1,
            'working_internal_A': 0,
            'working_internal_B': 1,
            'leaf_internal_A': 1,
        }
        assert_curr_state(self.hsm, 'leaf')
예제 #15
0
 def setup_class(self):
     self.states, self.trans = make_miro_machine(use_logging=True)
     self.hsm = HSM(self.states, self.trans)
     self.eb = EventBus()
예제 #16
0
class Test_miro_machine:
    def setup_class(self):
        self.states, self.trans = make_miro_machine(use_logging=True)
        self.hsm = HSM(self.states, self.trans)
        self.eb = EventBus()

    def test_step_1_in_s211_after_starting(self):
        self.hsm.start(self.eb)
        assert_curr_state(self.hsm, 's211')
        assert self.hsm.data.foo is False
        assert self.hsm.data._log == {
            'top_enter': 1,
            's_enter': 1,
            's2_enter': 1,
            's21_enter': 1,
            's211_enter': 1,
        }

    def test_step_2_in_s11_after_G(self):
        self.eb.dispatch(G())
        assert_curr_state(self.hsm, 's11')
        assert self.hsm.data._log == {
            'top_enter': 1,
            's_enter': 1,
            's2_enter': 1,
            's21_enter': 1,
            's211_enter': 1,

            's211_exit': 1,
            's21_exit': 1,
            's2_exit': 1,
            's1_enter': 1,
            's11_enter': 1,
        }

    def test_step_3_dont_change_foo_after_I(self):
        assert self.hsm.data.foo is False
        self.eb.dispatch(I())
        assert self.hsm.data.foo is False
        assert_curr_state(self.hsm, 's11')
        assert self.hsm.data._log == {
            'top_enter': 1,
            's_enter': 1,
            's2_enter': 1,
            's21_enter': 1,
            's211_enter': 1,
            's211_exit': 1,
            's21_exit': 1,
            's2_exit': 1,
            's1_enter': 1,
            's11_enter': 1,
            # no change
        }

    def test_step_4_in_s11_after_A(self):
        self.eb.dispatch(A())
        assert_curr_state(self.hsm, 's11')
        assert self.hsm.data._log == {
            'top_enter': 1,
            's_enter': 1,
            's2_enter': 1,
            's21_enter': 1,
            's211_enter': 1,
            's211_exit': 1,
            's21_exit': 1,
            's2_exit': 1,

            's11_exit': 1,
            's1_exit': 1,
            's1_enter': 2,
            's11_enter': 2,
        }


    def test_step_5_in_s11_after_D(self):
        assert self.hsm.data.foo is False
        self.eb.dispatch(D())
        assert self.hsm.data.foo is True
        assert_curr_state(self.hsm, 's11')
        assert self.hsm.data._log == {
            'top_enter': 1,
            's_enter': 1,
            's2_enter': 1,
            's21_enter': 1,
            's211_enter': 1,
            's211_exit': 1,
            's21_exit': 1,
            's2_exit': 1,

            's1_exit': 2,
            's1_enter': 3,
            's11_exit': 2,
            's11_enter': 3,
        }

    def test_step_6_in_s11_after_D(self):
        assert self.hsm.data.foo is True
        self.eb.dispatch(D())
        assert self.hsm.data.foo is False
        assert_curr_state(self.hsm, 's11')
        assert self.hsm.data._log == {
            'top_enter': 1,
            's_enter': 1,
            's2_enter': 1,
            's21_enter': 1,
            's211_enter': 1,
            's211_exit': 1,
            's21_exit': 1,
            's2_exit': 1,
            's1_exit': 2,
            's1_enter': 3,

            's11_exit': 3,
            's11_enter': 4,
        }

    def test_step_7_in_s211_after_C(self):
        self.eb.dispatch(C())
        assert_curr_state(self.hsm, 's211')
        assert self.hsm.data._log == {
            'top_enter': 1,
            's_enter': 1,
            's211_exit': 1,
            's21_exit': 1,
            's2_exit': 1,
            's1_enter': 3,
            's11_enter': 4,

            's11_exit': 4,
            's1_exit': 3,
            's2_enter': 2,
            's21_enter': 2,
            's211_enter': 2,
        }

    def test_step_8_in_s11_after_E(self):
        self.eb.dispatch(E())
        assert_curr_state(self.hsm, 's11')
        assert self.hsm.data._log == {
            'top_enter': 1,
            's_enter': 1,
            's11_exit': 4,
            's1_exit': 3,
            's2_enter': 2,
            's21_enter': 2,
            's211_enter': 2,

            's211_exit': 2,
            's21_exit': 2,
            's2_exit': 2,
            's1_enter': 4,
            's11_enter': 5,
        }

    def test_step_9_in_s11_after_E(self):
        self.eb.dispatch(E())
        assert_curr_state(self.hsm, 's11')
        assert self.hsm.data._log == {
            'top_enter': 1,
            's_enter': 1,
            's2_enter': 2,
            's21_enter': 2,
            's211_enter': 2,
            's211_exit': 2,
            's21_exit': 2,
            's2_exit': 2,

            's11_exit': 5,
            's1_exit': 4,
            's1_enter': 5,
            's11_enter': 6,
        }

    def test_step_10_in_s211_after_G(self):
        self.eb.dispatch(G())
        assert_curr_state(self.hsm, 's211')
        assert self.hsm.data._log == {
            'top_enter': 1,
            's_enter': 1,
            's2_enter': 2,
            's21_enter': 2,
            's211_enter': 2,
            's211_exit': 2,
            's21_exit': 2,
            's2_exit': 2,
            's1_enter': 5,
            's11_enter': 6,

            's11_exit': 6,
            's1_exit': 5,
            's2_enter': 3,
            's21_enter': 3,
            's211_enter': 3,
        }

    def test_step_11_s2_responds_to_I(self):
        assert self.hsm.data.foo is False
        self.eb.dispatch(I())
        assert self.hsm.data.foo is True
        assert self.hsm.data._log == {
            'top_enter': 1,
            's_enter': 1,
            's2_enter': 2,
            's21_enter': 2,
            's211_enter': 2,
            's211_exit': 2,
            's21_exit': 2,
            's2_exit': 2,
            's1_enter': 5,
            's11_enter': 6,
            's11_exit': 6,
            's1_exit': 5,
            's2_enter': 3,
            's21_enter': 3,
            's211_enter': 3,
            # no change
        }

    def test_step_12_s_responds_to_I(self):
        assert self.hsm.data.foo is True
        self.eb.dispatch(I())
        assert self.hsm.data.foo is False
        assert self.hsm.data._log == {
            'top_enter': 1,
            's_enter': 1,
            's2_enter': 2,
            's21_enter': 2,
            's211_enter': 2,
            's211_exit': 2,
            's21_exit': 2,
            's2_exit': 2,
            's1_enter': 5,
            's11_enter': 6,
            's11_exit': 6,
            's1_exit': 5,
            's2_enter': 3,
            's21_enter': 3,
            's211_enter': 3,
            # no change
        }
예제 #17
0
 def setup_class(self):
     states, trans = make_submachines_async_machine(use_logging=True)
     self.hsm = HSM(states, trans)
     self.eb = EventBus()
예제 #18
0
class Test_Choice_transitions:
    def setup_class(self):
        sub_states, sub_trans = make_choice_machine(use_logging=True)
        states = {
            "top": LoggingState(
                {
                    "left": LoggingState([(sub_states, sub_trans), (sub_states, sub_trans)]),
                    "right": LoggingState([(sub_states, sub_trans), (sub_states, sub_trans)]),
                }
            )
        }

        key = lambda _, hsm: hsm.data.foo % 2

        trans = {"top": {Initial: Choice({0: "left", 1: "right"}, key=key, default="left"), B: T("top")}}

        self.eb = EventBus()
        self.hsm = HSM(states, trans)

    def test_start_in_right_C_foo_3(self):
        self.hsm.data.foo = 3
        self.hsm.start(self.eb)
        assert_names(
            self.hsm,
            "top",
            "right",
            "right[0].top",
            "right[0].A",
            "right[0].B",
            "right[0].C",
            "right[1].top",
            "right[1].A",
            "right[1].B",
            "right[1].C",
        )
        assert self.hsm.data._log == {
            "top_enter": 1,
            "right_enter": 1,
            "right[0].top_enter": 1,
            "right[0].A_enter": 1,
            "right[0].B_enter": 1,
            "right[0].C_enter": 1,
            "right[1].top_enter": 1,
            "right[1].A_enter": 1,
            "right[1].B_enter": 1,
            "right[1].C_enter": 1,
        }

    def test_in_right_F_dispatch_A_5(self):
        self.eb.dispatch(A(5))
        assert_names(
            self.hsm,
            "top",
            "right",
            "right[0].top",
            "right[0].D",
            "right[0].E",
            "right[0].F",
            "right[1].top",
            "right[1].D",
            "right[1].E",
            "right[1].F",
        )
        assert self.hsm.data._log == {
            "top_enter": 1,
            "right_enter": 1,
            "right[0].top_enter": 1,
            "right[0].A_enter": 1,
            "right[0].B_enter": 1,
            "right[0].C_enter": 1,
            "right[1].top_enter": 1,
            "right[1].A_enter": 1,
            "right[1].B_enter": 1,
            "right[1].C_enter": 1,
            "right[0].C_exit": 1,
            "right[0].B_exit": 1,
            "right[0].A_exit": 1,
            "right[0].D_enter": 1,
            "right[0].E_enter": 1,
            "right[0].F_enter": 1,
            "right[1].C_exit": 1,
            "right[1].B_exit": 1,
            "right[1].A_exit": 1,
            "right[1].D_enter": 1,
            "right[1].E_enter": 1,
            "right[1].F_enter": 1,
        }

    def test_in_left_F_dispatch_B_foo_4(self):
        self.hsm.data.foo = 4
        self.eb.dispatch(B())
        assert_names(
            self.hsm,
            "top",
            "left",
            "left[0].top",
            "left[0].D",
            "left[0].E",
            "left[0].F",
            "left[1].top",
            "left[1].D",
            "left[1].E",
            "left[1].F",
        )
        assert self.hsm.data._log == {
            "right_enter": 1,
            "right[0].top_enter": 1,
            "right[0].A_enter": 1,
            "right[0].B_enter": 1,
            "right[0].C_enter": 1,
            "right[1].top_enter": 1,
            "right[1].A_enter": 1,
            "right[1].B_enter": 1,
            "right[1].C_enter": 1,
            "right[0].C_exit": 1,
            "right[0].B_exit": 1,
            "right[0].A_exit": 1,
            "right[0].D_enter": 1,
            "right[0].E_enter": 1,
            "right[0].F_enter": 1,
            "right[1].C_exit": 1,
            "right[1].B_exit": 1,
            "right[1].A_exit": 1,
            "right[1].D_enter": 1,
            "right[1].E_enter": 1,
            "right[1].F_enter": 1,
            "right[0].D_exit": 1,
            "right[0].E_exit": 1,
            "right[0].F_exit": 1,
            "right[0].top_exit": 1,
            "right[1].D_exit": 1,
            "right[1].E_exit": 1,
            "right[1].F_exit": 1,
            "right[1].top_exit": 1,
            "right_exit": 1,
            "top_exit": 1,
            "top_enter": 2,
            "left_enter": 1,
            "left[0].top_enter": 1,
            "left[0].D_enter": 1,
            "left[0].E_enter": 1,
            "left[0].F_enter": 1,
            "left[1].top_enter": 1,
            "left[1].D_enter": 1,
            "left[1].E_enter": 1,
            "left[1].F_enter": 1,
        }
예제 #19
0
class Test_Choice_transitions:
    def setup_class(self):
        states = {
            'top': LoggingState({
                'A': LoggingState(),
                'B': LoggingState(),
                'C': LoggingState({
                    'C_left': LoggingState(),
                    'C_right': LoggingState(),
                })
            })
        }

        key = lambda _, hsm: hsm.data.foo % 3

        trans = {
            'top': {
                Initial: Choice({ 0: 'A', 1: 'B', 2: 'C' },
                                key=key, default='B')
            },
            'A': {
                Step: Local('top'),
            },
            'B': {
                Step: T('top'),
            },
            'C': {
                Initial: Choice({ False: 'C_left', True: 'C_right' },
                                key=lambda _, hsm: hsm.data.foo % 2 == 0,
                                default='C_left'),
                Step: T('top'),
            },
        }

        self.eb = EventBus()
        self.hsm = HSM(states, trans)

    def test_start_in_B_foo_1(self):
        self.hsm.data.foo = 1
        self.hsm.start(self.eb)
        assert_curr_state(self.hsm, 'B')
        assert self.hsm.data._log == {
            'top_enter': 1,
            'B_enter': 1,
        }

    def test_in_A_foo_0(self):
        self.hsm.data.foo = 0
        self.eb.dispatch(Step())
        assert_curr_state(self.hsm, 'A')
        assert self.hsm.data._log == {
            'B_enter': 1,

            'B_exit': 1,
            'top_exit': 1,
            'top_enter': 2,
            'A_enter': 1,
        }

    def test_in_C_right_foo_2(self):
        self.hsm.data.foo = 2
        self.eb.dispatch(Step())
        assert_curr_state(self.hsm, 'C_right')
        assert self.hsm.data._log == {
            'B_enter': 1,
            'B_exit': 1,
            'top_exit': 1,
            'top_enter': 2,
            'A_enter': 1,

            'A_exit': 1,
            'C_enter': 1,
            'C_right_enter': 1,
        }

    def test_in_C_left_foo_5(self):
        self.hsm.data.foo = 5
        self.eb.dispatch(Step())
        assert_curr_state(self.hsm, 'C_left')
        assert self.hsm.data._log == {
            'B_enter': 1,
            'B_exit': 1,
            'A_enter': 1,
            'A_exit': 1,
            'C_right_enter': 1,

            'C_right_exit': 1,
            'C_exit': 1,
            'top_exit': 2,
            'top_enter': 3,
            'C_enter': 2,
            'C_left_enter': 1,
        }

    def test_in_A_left_foo_6(self):
        self.hsm.data.foo = 6
        self.eb.dispatch(Step())
        assert_curr_state(self.hsm, 'A')
        assert self.hsm.data._log == {
            'B_enter': 1,
            'B_exit': 1,
            'A_exit': 1,
            'C_right_enter': 1,
            'C_right_exit': 1,
            'C_enter': 2,
            'C_left_enter': 1,

            'C_left_exit': 1,
            'C_exit': 2,
            'top_exit': 3,
            'top_enter': 4,
            'A_enter': 2,
        }
예제 #20
0
            default='dragging_marquee',
            key=lambda e, h: len(elems_under_cursor(e, h)) > 0),
    },
    'dragging_marquee': {
        Canvas_Move: Internal(action=drag_marquee_rect),
    },
    'moving_elements': {
        Canvas_Move: Internal(action=move_elements),
    },
    ###
    'draw_tool_chosen': {
        Initial: T('draw_tool_hovering'),
        Canvas_Up: T('draw_tool_hovering'),
    },
    'draw_tool_hovering': {
        Canvas_Down: T('drawing', action=initialize_rectangle),
    },
    'drawing': {
        Canvas_Move: Internal(action=draw_rectangle),
    },
}


# initialize HSM with defined states and transitions and run

hsm = HSM(states, transitions)
hsm.start(eb)
eb.dispatch(Tool_Changed(Drawing_tool))

root.mainloop()
예제 #21
0
class Test_loops_and_multiple_paths_machine():

    def setup_class(self):
        self.eb = EventBus()
        hsmdata = {
            'initial': 0,
            'start_enter': 0,
            'start_exit': 0,
            'goal_enter': 0,
            'goal_exit': 0,
            'trans_left': 0,
            'trans_right': 0,
            'trans_loop': 0,
            'trans_restart': 0,
        }

        self.start = Start()
        self.goal = Goal()

        self.states = {
            'top': State({
                'start': self.start,
                'goal': self.goal,
            })
        }
        self.trans = {
            'top': {
                Initial: T('start', action=get_callback('initial')),
            },
            'start': {
                MoveLeft: T('goal', action=get_callback('trans_left')),
                MoveRight: T('goal', action=get_callback('trans_right')),
            },
            'goal': {
                Loop: T('goal', action=get_callback('trans_loop')),
                Restart: T('top', action=get_callback('trans_restart')),
            }
        }
        self.hsm = HSM(self.states, self.trans)
        self.hsm.data = hsmdata

    def test_doesnt_respond_to_events_before_starting(self):
        assert all([v == 0 for v in self.hsm.data.values()])
        self.eb.dispatch(MoveLeft())
        self.eb.dispatch(MoveRight())
        self.eb.dispatch(Loop())
        self.eb.dispatch(Restart())
        assert all([v == 0 for v in self.hsm.data.values()])

    def test_in_start_state_after_starting(self):
        self.hsm.start(self.eb)
        assert_curr_state(self.hsm, 'start')
        assert self.hsm.data['initial'] == 1
        assert self.hsm.data['start_enter'] == 1
        assert self.hsm.data.values().count(0) == 7

    def test_ignore_loop_and_restart_events_while_in_start(self):
        self.eb.dispatch(Loop())
        self.eb.dispatch(Restart())
        assert_curr_state(self.hsm, 'start')
        assert self.hsm.data['initial'] == 1
        assert self.hsm.data['start_enter'] == 1
        assert self.hsm.data.values().count(0) == 7

    def test_transition_to_goal_via_right(self):
        self.eb.dispatch(MoveRight())
        assert_curr_state(self.hsm, 'goal')
        assert self.hsm.data['start_enter'] == 1
        assert self.hsm.data['start_exit'] == 1  # changed
        assert self.hsm.data['goal_enter'] == 1  # changed
        assert self.hsm.data['goal_exit'] == 0
        assert self.hsm.data['trans_left'] == 0
        assert self.hsm.data['trans_right'] == 1  # changed
        assert self.hsm.data['trans_loop'] == 0
        assert self.hsm.data['trans_restart'] == 0

    def test_ignore_left_and_right_events_while_in_goal(self):
        self.eb.dispatch(MoveLeft())
        self.eb.dispatch(MoveRight())
        assert_curr_state(self.hsm, 'goal')
        assert self.hsm.data['start_enter'] == 1
        assert self.hsm.data['start_exit'] == 1
        assert self.hsm.data['goal_enter'] == 1
        assert self.hsm.data['goal_exit'] == 0
        assert self.hsm.data['trans_left'] == 0
        assert self.hsm.data['trans_right'] == 1
        assert self.hsm.data['trans_loop'] == 0
        assert self.hsm.data['trans_restart'] == 0

    def test_loop_in_goal(self):
        self.eb.dispatch(Loop())
        assert_curr_state(self.hsm, 'goal')
        assert self.hsm.data['start_enter'] == 1
        assert self.hsm.data['start_exit'] == 1
        assert self.hsm.data['goal_enter'] == 2  # changed
        assert self.hsm.data['goal_exit'] == 1  # changed
        assert self.hsm.data['trans_left'] == 0
        assert self.hsm.data['trans_right'] == 1
        assert self.hsm.data['trans_loop'] == 1  # changed
        assert self.hsm.data['trans_restart'] == 0
        self.eb.dispatch(Loop())
        assert_curr_state(self.hsm, 'goal')
        assert self.hsm.data['start_enter'] == 1
        assert self.hsm.data['start_exit'] == 1
        assert self.hsm.data['goal_enter'] == 3  # changed
        assert self.hsm.data['goal_exit'] == 2  # changed
        assert self.hsm.data['trans_left'] == 0
        assert self.hsm.data['trans_right'] == 1
        assert self.hsm.data['trans_loop'] == 2  # changed
        assert self.hsm.data['trans_restart'] == 0
        self.eb.dispatch(Loop())
        assert_curr_state(self.hsm, 'goal')
        assert self.hsm.data['start_enter'] == 1
        assert self.hsm.data['start_exit'] == 1
        assert self.hsm.data['goal_enter'] == 4  # changed
        assert self.hsm.data['goal_exit'] == 3  # changed
        assert self.hsm.data['trans_left'] == 0
        assert self.hsm.data['trans_right'] == 1
        assert self.hsm.data['trans_loop'] == 3  # changed
        assert self.hsm.data['trans_restart'] == 0

    def test_restart(self):
        assert self.hsm.data['initial'] == 1
        self.eb.dispatch(Restart())
        assert_curr_state(self.hsm, 'start')
        assert self.hsm.data['initial'] == 2  # changed
        assert self.hsm.data['start_enter'] == 2  # changed
        assert self.hsm.data['start_exit'] == 1
        assert self.hsm.data['goal_enter'] == 4
        assert self.hsm.data['goal_exit'] == 4  # changed
        assert self.hsm.data['trans_left'] == 0
        assert self.hsm.data['trans_right'] == 1
        assert self.hsm.data['trans_loop'] == 3
        assert self.hsm.data['trans_restart'] == 1  # changed

    def test_ignore_loop_and_restart_events_while_in_start_2(self):
        self.eb.dispatch(Loop())
        self.eb.dispatch(Restart())
        assert self.hsm.data['initial'] == 2
        assert self.hsm.data['start_enter'] == 2
        assert self.hsm.data['start_exit'] == 1
        assert self.hsm.data['goal_enter'] == 4
        assert self.hsm.data['goal_exit'] == 4
        assert self.hsm.data['trans_left'] == 0
        assert self.hsm.data['trans_right'] == 1
        assert self.hsm.data['trans_loop'] == 3
        assert self.hsm.data['trans_restart'] == 1

    def test_transition_to_goal_via_left(self):
        self.eb.dispatch(MoveLeft())
        assert_curr_state(self.hsm, 'goal')
        assert self.hsm.data['start_enter'] == 2
        assert self.hsm.data['start_exit'] == 2  # changed
        assert self.hsm.data['goal_enter'] == 5  # changed
        assert self.hsm.data['goal_exit'] == 4
        assert self.hsm.data['trans_left'] == 1  # changed
        assert self.hsm.data['trans_right'] == 1
        assert self.hsm.data['trans_loop'] == 3
        assert self.hsm.data['trans_restart'] == 1

    def test_doesnt_respond_to_events_after_stopping(self):
        self.hsm.stop()
        self.eb.dispatch(MoveLeft())
        self.eb.dispatch(MoveRight())
        self.eb.dispatch(Loop())
        self.eb.dispatch(Restart())
        assert self.hsm.data['initial'] == 2
        assert self.hsm.data['start_enter'] == 2
        assert self.hsm.data['start_exit'] == 2
        assert self.hsm.data['goal_enter'] == 5
        assert self.hsm.data['goal_exit'] == 4
        assert self.hsm.data['trans_left'] == 1
        assert self.hsm.data['trans_right'] == 1
        assert self.hsm.data['trans_loop'] == 3
        assert self.hsm.data['trans_restart'] == 1
예제 #22
0
class Test_simple_two_state_door_machine:
    def setup_class(self):
        self.eb = EventBus()
        hsmdata = {
            'initial': 0,
            'closed_enter': 0,
            'closed_exit': 0,
            'opened_enter': 0,
            'opened_exit': 0,
            'trans_opening': 0,
            'trans_closing': 0,
        }

        self.states = {
            'top': State({
                'closed': Closed(),
                'opened': Opened(),
            })
        }

        self.trans = {
            'top': {
                Initial: T('closed', action=get_callback('initial')),
            },
            'closed': {
                OpenDoor: T('opened', action=get_callback('trans_opening'))
            },
            'opened': {
                CloseDoor: T('closed', action=get_callback('trans_closing'))
            }
        }
        self.hsm = HSM(self.states, self.trans)
        self.hsm.data = hsmdata

    def test_doesnt_respond_to_events_before_starting(self):
        assert all([v == 0 for v in self.hsm.data.values()])
        self.eb.dispatch(OpenDoor())
        self.eb.dispatch(CloseDoor())
        assert all([v == 0 for v in self.hsm.data.values()])

    def test_in_closed_state_after_starting(self):
        self.hsm.start(self.eb)
        assert_curr_state(self.hsm, 'closed')
        assert self.hsm.data['initial'] == 1
        assert self.hsm.data['closed_enter'] == 1
        assert self.hsm.data.values().count(0) == 5

    def test_ignores_close_while_closed(self):
        self.eb.dispatch(CloseDoor())
        assert_curr_state(self.hsm, 'closed')
        assert self.hsm.data['initial'] == 1
        assert self.hsm.data['closed_enter'] == 1
        assert self.hsm.data.values().count(0) == 5

    def test_transition_to_opened(self):
        self.eb.dispatch(OpenDoor())
        assert_curr_state(self.hsm, 'opened')
        assert self.hsm.data['initial'] == 1
        assert self.hsm.data['closed_enter'] == 1
        assert self.hsm.data['closed_exit'] == 1  # changed
        assert self.hsm.data['opened_enter'] == 1  # changed
        assert self.hsm.data['opened_exit'] == 0
        assert self.hsm.data['trans_opening'] == 1  # changed
        assert self.hsm.data['trans_closing'] == 0

    def test_ignores_open_while_opened(self):
        self.eb.dispatch(OpenDoor())
        assert_curr_state(self.hsm, 'opened')
        assert self.hsm.data['closed_enter'] == 1
        assert self.hsm.data['closed_exit'] == 1
        assert self.hsm.data['opened_enter'] == 1
        assert self.hsm.data['opened_exit'] == 0
        assert self.hsm.data['trans_opening'] == 1
        assert self.hsm.data['trans_closing'] == 0

    def test_transition_to_closed(self):
        self.eb.dispatch(CloseDoor())
        assert_curr_state(self.hsm, 'closed')
        assert self.hsm.data['closed_enter'] == 2  # changed
        assert self.hsm.data['closed_exit'] == 1
        assert self.hsm.data['opened_enter'] == 1
        assert self.hsm.data['opened_exit'] == 1  # changed
        assert self.hsm.data['trans_opening'] == 1
        assert self.hsm.data['trans_closing'] == 1  # changed

    def test_ignores_close_while_closed_again(self):
        self.eb.dispatch(CloseDoor())
        assert_curr_state(self.hsm, 'closed')
        assert self.hsm.data['closed_enter'] == 2
        assert self.hsm.data['closed_exit'] == 1
        assert self.hsm.data['opened_enter'] == 1
        assert self.hsm.data['opened_exit'] == 1
        assert self.hsm.data['trans_opening'] == 1
        assert self.hsm.data['trans_closing'] == 1

    def test_transition_to_opened_again(self):
        self.eb.dispatch(OpenDoor())
        assert_curr_state(self.hsm, 'opened')
        assert self.hsm.data['closed_enter'] == 2
        assert self.hsm.data['closed_exit'] == 2  # changed
        assert self.hsm.data['opened_enter'] == 2  # changed
        assert self.hsm.data['opened_exit'] == 1
        assert self.hsm.data['trans_opening'] == 2  # changed
        assert self.hsm.data['trans_closing'] == 1

    def test_transition_to_closed_again(self):
        self.eb.dispatch(CloseDoor())
        assert_curr_state(self.hsm, 'closed')
        assert self.hsm.data['initial'] == 1
        assert self.hsm.data['closed_enter'] == 3  # changed
        assert self.hsm.data['closed_exit'] == 2
        assert self.hsm.data['opened_enter'] == 2
        assert self.hsm.data['opened_exit'] == 2  # changed
        assert self.hsm.data['trans_opening'] == 2
        assert self.hsm.data['trans_closing'] == 2  # changed

    def test_doesnt_respond_to_events_after_stopping(self):
        self.hsm.stop()
        self.eb.dispatch(CloseDoor())
        self.eb.dispatch(OpenDoor())
        assert self.hsm.data['initial'] == 1
        assert self.hsm.data['closed_enter'] == 3  # changed
        assert self.hsm.data['closed_exit'] == 2
        assert self.hsm.data['opened_enter'] == 2
        assert self.hsm.data['opened_exit'] == 2  # changed
        assert self.hsm.data['trans_opening'] == 2
        assert self.hsm.data['trans_closing'] == 2  # changed
예제 #23
0
class Test_all_submachines_respond_to_event:
    def setup_class(self):
        states, trans = make_submachines_machine(use_logging=True)
        self.hsm = HSM(states, trans)
        self.eb = EventBus()

    def test_enters_submachines_after_start(self):
        self.hsm.start(self.eb)
        assert self.hsm.data._log == {"top_enter": 1, "left_enter": 1, "left[0].top_enter": 1, "left[0].start_enter": 1}
        assert_names(self.hsm, "left[0].start", "left[0].top", "left", "top")

    def test_event_A_captured_by_left_submachine(self):
        self.eb.dispatch(A())
        assert self.hsm.data._log == {
            "top_enter": 1,
            "left_enter": 1,
            "left[0].top_enter": 1,
            "left[0].start_enter": 1,
            "left[0].start_exit": 1,
            "left[0].right_enter": 1,
        }
        assert_names(self.hsm, "left[0].right", "left[0].top", "left", "top")

    def test_terminate_left_submachine(self):
        self.eb.dispatch(TERMINATE())
        assert self.hsm.data._log == {
            "top_enter": 1,
            "left_enter": 1,
            "left[0].top_enter": 1,
            "left[0].start_enter": 1,
            "left[0].start_exit": 1,
            "left[0].right_enter": 1,
            "left[0].right_exit": 1,
            "left[0].final_enter": 1,
        }
        assert_names(self.hsm, "left[0].final", "left[0].top", "left", "top")

    def test_event_A_transitions_to_right(self):
        self.eb.dispatch(A())
        assert self.hsm.data._log == {
            "top_enter": 1,
            "left_enter": 1,
            "left[0].top_enter": 1,
            "left[0].start_enter": 1,
            "left[0].start_exit": 1,
            "left[0].right_enter": 1,
            "left[0].right_exit": 1,
            "left[0].final_enter": 1,
            "left[0].final_exit": 1,
            "left[0].top_exit": 1,
            "left_exit": 1,
            "right_enter": 1,
            "subs_enter": 1,
            "subs[0].top_enter": 1,
            "subs[0].start_enter": 1,
            "subs[1].top_enter": 1,
            "subs[1].start_enter": 1,
        }
        assert_names(
            self.hsm, "subs[0].start", "subs[0].top", "subs", "subs[1].start", "subs[1].top", "subs", "right", "top"
        )

    def test_event_A_captured_by_right_submachines(self):
        self.eb.dispatch(A())
        assert self.hsm.data._log == {
            "top_enter": 1,
            "left_enter": 1,
            "left[0].top_enter": 1,
            "left[0].start_enter": 1,
            "left[0].start_exit": 1,
            "left[0].right_enter": 1,
            "left[0].right_exit": 1,
            "left[0].final_enter": 1,
            "left[0].final_exit": 1,
            "left[0].top_exit": 1,
            "left_exit": 1,
            "right_enter": 1,
            "subs_enter": 1,
            "subs[0].top_enter": 1,
            "subs[0].start_enter": 1,
            "subs[1].top_enter": 1,
            "subs[1].start_enter": 1,
            "subs[0].start_exit": 1,
            "subs[0].right_enter": 1,
            "subs[1].start_exit": 1,
            "subs[1].right_enter": 1,
        }
        assert_names(
            self.hsm, "subs[0].right", "subs[0].top", "subs", "subs[1].right", "subs[1].top", "subs", "right", "top"
        )

    def test_event_A_captured_by_right_submachines_again(self):
        self.eb.dispatch(A())
        assert self.hsm.data._log == {
            "top_enter": 1,
            "left_enter": 1,
            "left[0].top_enter": 1,
            "left[0].start_enter": 1,
            "left[0].start_exit": 1,
            "left[0].right_enter": 1,
            "left[0].right_exit": 1,
            "left[0].final_enter": 1,
            "left[0].final_exit": 1,
            "left[0].top_exit": 1,
            "left_exit": 1,
            "right_enter": 1,
            "subs_enter": 1,
            "subs[0].top_enter": 1,
            "subs[1].top_enter": 1,
            "subs[0].start_exit": 1,
            "subs[0].right_enter": 1,
            "subs[1].start_exit": 1,
            "subs[1].right_enter": 1,
            "subs[0].right_exit": 1,
            "subs[0].start_enter": 2,
            "subs[1].right_exit": 1,
            "subs[1].start_enter": 2,
        }
        assert_names(
            self.hsm, "subs[0].start", "subs[0].top", "subs", "subs[1].start", "subs[1].top", "subs", "right", "top"
        )

    def test_terminate_right_submachine(self):
        self.eb.dispatch(TERMINATE())
        assert self.hsm.data._log == {
            "top_enter": 1,
            "left_enter": 1,
            "left[0].top_enter": 1,
            "left[0].start_enter": 1,
            "left[0].start_exit": 1,
            "left[0].right_enter": 1,
            "left[0].right_exit": 1,
            "left[0].final_enter": 1,
            "left[0].final_exit": 1,
            "left[0].top_exit": 1,
            "left_exit": 1,
            "right_enter": 1,
            "subs_enter": 1,
            "subs[0].top_enter": 1,
            "subs[1].top_enter": 1,
            "subs[0].right_enter": 1,
            "subs[1].right_enter": 1,
            "subs[0].right_exit": 1,
            "subs[0].start_enter": 2,
            "subs[1].right_exit": 1,
            "subs[1].start_enter": 2,
            "subs[0].start_exit": 2,
            "subs[0].final_enter": 1,
            "subs[1].start_exit": 2,
            "subs[1].final_enter": 1,
        }
        assert_names(
            self.hsm, "subs[0].final", "subs[0].top", "subs", "subs[1].final", "subs[1].top", "subs", "right", "top"
        )

    def test_event_A_transitions_to_dumb(self):
        self.eb.dispatch(A())
        assert self.hsm.data._log == {
            "top_enter": 1,
            "left_enter": 1,
            "left[0].top_enter": 1,
            "left[0].start_enter": 1,
            "left[0].start_exit": 1,
            "left[0].right_enter": 1,
            "left[0].right_exit": 1,
            "left[0].final_enter": 1,
            "left[0].final_exit": 1,
            "left[0].top_exit": 1,
            "left_exit": 1,
            "right_enter": 1,
            "subs_enter": 1,
            "subs[0].top_enter": 1,
            "subs[1].top_enter": 1,
            "subs[0].right_enter": 1,
            "subs[1].right_enter": 1,
            "subs[0].right_exit": 1,
            "subs[0].start_enter": 2,
            "subs[1].right_exit": 1,
            "subs[1].start_enter": 2,
            "subs[0].start_exit": 2,
            "subs[0].final_enter": 1,
            "subs[1].start_exit": 2,
            "subs[1].final_enter": 1,
            "subs[0].final_exit": 1,
            "subs[0].top_exit": 1,
            "subs[1].final_exit": 1,
            "subs[1].top_exit": 1,
            "subs_exit": 1,
            "dumb_enter": 1,
        }
        assert_names(self.hsm, "dumb", "right", "top")

    def test_event_A_transitions_to_left_again(self):
        self.eb.dispatch(A())
        assert self.hsm.data._log == {
            "top_enter": 1,
            "left[0].start_exit": 1,
            "left[0].right_enter": 1,
            "left[0].right_exit": 1,
            "left[0].final_enter": 1,
            "left[0].final_exit": 1,
            "left[0].top_exit": 1,
            "left_exit": 1,
            "right_enter": 1,
            "subs_enter": 1,
            "subs[0].top_enter": 1,
            "subs[1].top_enter": 1,
            "subs[0].right_enter": 1,
            "subs[1].right_enter": 1,
            "subs[0].right_exit": 1,
            "subs[0].start_enter": 2,
            "subs[1].right_exit": 1,
            "subs[1].start_enter": 2,
            "subs[0].start_exit": 2,
            "subs[0].final_enter": 1,
            "subs[1].start_exit": 2,
            "subs[1].final_enter": 1,
            "subs[0].final_exit": 1,
            "subs[0].top_exit": 1,
            "subs[1].final_exit": 1,
            "subs[1].top_exit": 1,
            "subs_exit": 1,
            "dumb_enter": 1,
            "dumb_exit": 1,
            "right_exit": 1,
            "left_enter": 2,
            "left[0].top_enter": 2,
            "left[0].start_enter": 2,
        }
        assert_names(self.hsm, "left[0].start", "left[0].top", "left", "top")