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_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,
        }
예제 #3
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
예제 #4
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)
예제 #5
0
    def setup_class(self):
        self.eb = EventBus()
        self.event_log = []

        def append_to_event_log(e):
            self.event_log += [e]
        self.eb.register(Model_Changed, append_to_event_log)
예제 #6
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)
예제 #7
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")
예제 #8
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)
예제 #9
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)
예제 #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):
        self.initial_elements = [
            R(1, 1, 10, 10),
            R(2, 2, 20, 20),
            R(3, 3, 30, 30),
        ]
        self.changelist = [ Insert(R(4, 4, 40, 40)) ]  # used for commit later

        self.counter = 0
        self.received_events = []

        def on_change(event):
            self.counter += 1
            self.received_events += [event]

        self.eb = EventBus()
        self.model = CanvasModel(self.eb)
        self.eb.register(Model_Changed, on_change)
예제 #12
0
    def setup_class(self):
        self.elems = [
            R(1, 1, 10, 10),
            R(2, 2, 20, 20),
            R(3, 3, 30, 30),
        ]
        self.changelog = [
            ['some', 'old'],
            ['changes', 'here'],
        ]
        self.counter = 0
        self.received_events = []

        def on_change(event):
            self.counter += 1
            self.received_events += [event]

        self.eb = EventBus()
        self.eb.register(Model_Changed, on_change)
예제 #13
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)
예제 #15
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')
예제 #16
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()
예제 #17
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
        }
예제 #18
0
class Test_CanvasModel(object):
    def setup_class(self):
        self.initial_elements = [
            R(1, 1, 10, 10),
            R(2, 2, 20, 20),
            R(3, 3, 30, 30),
        ]
        self.changelist = [ Insert(R(4, 4, 40, 40)) ]  # used for commit later

        self.counter = 0
        self.received_events = []

        def on_change(event):
            self.counter += 1
            self.received_events += [event]

        self.eb = EventBus()
        self.model = CanvasModel(self.eb)
        self.eb.register(Model_Changed, on_change)

    def test_setting_elems_updates_elems(self):
        to_give = self.initial_elements[:]  # copy
        self.model.elems = to_give
        assert to_give == self.initial_elements  # model didn't change given
        assert self.model.elems == self.initial_elements
        assert self.model._elems == self.initial_elements

    def test_setting_elems_updates_changelog(self):
        assert self.model._changelog == [
            [
                Insert(R(1, 1, 10, 10)),
                Insert(R(2, 2, 20, 20)),
                Insert(R(3, 3, 30, 30)),
            ],
        ]

    def test_setting_elems_informs_listeners(self):
        assert self.counter == 1
        assert len(self.received_events) == 1
        assert self.received_events[0].data == self.model._changelog[0]

    def test_cant_modify_elems_through_getter(self):
        self.model.elems[1] = 'abc'
        self.model.elems.pop(0)
        assert self.model.elems == self.initial_elements

    def test_cant_inject_changes_to_changelog_through_event(self):
        evt = self.received_events[0]
        backup = evt.data[0]
        evt.data[0] == 'abc'
        assert self.model._changelog == [
            [
                Insert(R(1, 1, 10, 10)),
                Insert(R(2, 2, 20, 20)),
                Insert(R(3, 3, 30, 30)),
            ],
        ]
        evt.data[0] = backup

    def test_commit(self):
        self.model.commit(self.changelist)

    def test_commit_informs_listeners(self):
        assert self.counter == 2
        assert len(self.received_events) == 2
        assert self.received_events[1].data == [ Insert(R(4, 4, 40, 40)) ]

    def test_commit_updates_elems(self):
        assert self.model._elems == [
            R(1, 1, 10, 10),
            R(2, 2, 20, 20),
            R(3, 3, 30, 30),
            R(4, 4, 40, 40),
        ]
        assert self.model.elems == self.model._elems

    def test_commit_updates_changelog(self):
        assert self.model._changelog == [
            [
                Insert(R(1, 1, 10, 10)),
                Insert(R(2, 2, 20, 20)),
                Insert(R(3, 3, 30, 30)),
            ],
            [
                Insert(R(4, 4, 40, 40)),
            ]
        ]

    def test_modify_changes_in_changelog_through_commit_argument(self):
        self.changelist[0] = 'abc'
        assert self.model._changelog == [
            [
                Insert(R(1, 1, 10, 10)),
                Insert(R(2, 2, 20, 20)),
                Insert(R(3, 3, 30, 30)),
            ],
            [
                Insert(R(4, 4, 40, 40)),
            ]
        ]

        self.changelist.pop(0)
        assert self.model._changelog == [
            [
                Insert(R(1, 1, 10, 10)),
                Insert(R(2, 2, 20, 20)),
                Insert(R(3, 3, 30, 30)),
            ],
            [
                Insert(R(4, 4, 40, 40)),
            ]
        ]

        assert self.received_events[1].data == [ Insert(R(4, 4, 40, 40)) ]
예제 #19
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
예제 #20
0
class Test_undo:
    def setup_class(self):
        self.eb = EventBus()
        self.event_log = []

        def append_to_event_log(e):
            self.event_log += [e]
        self.eb.register(Model_Changed, append_to_event_log)

    def test_undo_one_insert(self):
        change_log = [
            [ 'previous' ], [ 'changes' ],  # these remain untouched
            [ Insert(R(1, 1, 1, 1)) ],  # undoes only last changelist
        ]
        model_elems = [ R(3, 3, 3, 3), R(1, 1, 1, 1), R(2, 2, 2, 2) ]
        redo_log = [ [ 'future' ], [ 'changes'] ]

        _undo(change_log, redo_log, self.eb, model_elems)

        assert change_log == [
            [ 'previous' ], [ 'changes' ],
        ]
        assert redo_log == [
            [ Insert(R(1, 1, 1, 1)) ],
            [ 'future' ], [ 'changes'],
        ]
        assert model_elems == [ R(3, 3, 3, 3), R(2, 2, 2, 2) ]

        assert len(self.event_log) == 1
        assert self.event_log[-1].data == [ Remove(R(1, 1, 1, 1)) ]  # inverted


    def test_undo_one_remove(self):
        change_log = [
            [ 'previous' ], [ 'changes' ],
            [ Remove(R(1, 1, 1, 1)) ],
        ]
        model_elems = [ R(2, 2, 2, 2) ]
        redo_log = [ [ 'future' ], [ 'changes'] ]

        _undo(change_log, redo_log, self.eb, model_elems)

        assert change_log == [
            [ 'previous' ], [ 'changes' ],
        ]
        assert redo_log == [
            [ Remove(R(1, 1, 1, 1)) ],
            [ 'future' ], [ 'changes'],
        ]
        assert model_elems == [ R(2, 2, 2, 2), R(1, 1, 1, 1) ]

        assert len(self.event_log) == 2
        assert self.event_log[-1].data == [ Insert(R(1, 1, 1, 1)) ]  # inverted


    def test_undo_one_modify(self):
        change_log = [
            [ 'previous' ], [ 'changes' ],
            [ Modify(R(3, 3, 3, 3), R(1, 1, 1, 1)) ],
        ]
        model_elems = [ R(1, 1, 1, 1), R(2, 2, 2, 2) ]
        redo_log = [ [ 'future' ], [ 'changes'] ]

        _undo(change_log, redo_log, self.eb, model_elems)

        assert change_log == [
            [ 'previous' ], [ 'changes' ],
        ]
        assert redo_log == [
            [ Modify(R(3, 3, 3, 3), R(1, 1, 1, 1)) ],
            [ 'future' ], [ 'changes'],
        ]
        assert model_elems == [ R(3, 3, 3, 3), R(2, 2, 2, 2) ]

        assert len(self.event_log) == 3
        assert self.event_log[-1].data == [ Modify(R(1, 1, 1, 1),
                                                   R(3, 3, 3, 3)) ]  # inverted
예제 #21
0
class Test_commit(object):

    def setup_class(self):
        self.elems = [
            R(1, 1, 10, 10),
            R(2, 2, 20, 20),
            R(3, 3, 30, 30),
        ]
        self.changelog = [
            ['some', 'old'],
            ['changes', 'here'],
        ]
        self.counter = 0
        self.received_events = []

        def on_change(event):
            self.counter += 1
            self.received_events += [event]

        self.eb = EventBus()
        self.eb.register(Model_Changed, on_change)

    # insert

    def test_insert(self):
        cl = [
            Insert(R(10, 5, -5, 5)),  # fix
            Insert(R(4, 4, 4, 4)),
        ]
        _commit(cl, self.changelog, self.eb, self.elems)
        assert self.elems == [
            R(1, 1, 10, 10),
            R(2, 2, 20, 20),
            R(3, 3, 30, 30),
            R(5, 5, 5, 5),
            R(4, 4, 4, 4),
        ]

    def test_received_event_after_insert(self):
        assert self.counter == 1
        assert len(self.received_events) == 1
        assert isinstance(self.received_events[0], Model_Changed)

    def test_event_data_contains_insert_changes(self):
        assert self.received_events[0].data == [
            Insert(R(5, 5, 5, 5)),
            Insert(R(4, 4, 4, 4)),
        ]

    def test_changes_appended_to_changelog_after_insert(self):
        assert self.changelog == [
            ['some', 'old'],
            ['changes', 'here'],
            self.received_events[0].data,
        ]

    # modify

    def test_modify(self):
        cl = [
            Modify(R(1, 1, 10, 10), R(100, 1100, 1000, -1000)),  # fix
            Modify(R(5, 5, 5, 5), R(55, 5, 5, 5)),
        ]
        _commit(cl, self.changelog, self.eb, self.elems)
        assert self.elems == [
            R(100, 100, 1000, 1000),
            R(2, 2, 20, 20),
            R(3, 3, 30, 30),
            R(55, 5, 5, 5),
            R(4, 4, 4, 4),
        ]

    def test_received_event_after_modify(self):
        assert self.counter == 2
        assert len(self.received_events) == 2
        assert isinstance(self.received_events[1], Model_Changed)

    def test_event_data_contains_modify_changes(self):
        assert self.received_events[1].data == [
            Modify(R(1, 1, 10, 10), R(100, 100, 1000, 1000)),
            Modify(R(5, 5, 5, 5), R(55, 5, 5, 5)),
        ]

    def test_changes_appended_to_changelog_after_modify(self):
        assert self.changelog == [
            ['some', 'old'],
            ['changes', 'here'],
            self.received_events[0].data,
            self.received_events[1].data,
        ]

    # remove

    def test_remove(self):
        cl = [
            Remove(R(3, 3, 30, 30)),
            Remove(R(2, 2, 20, 20)),
        ]
        _commit(cl, self.changelog, self.eb, self.elems)
        assert self.elems == [
            R(100, 100, 1000, 1000),
            R(55, 5, 5, 5),
            R(4, 4, 4, 4),
        ]

    def test_received_event_after_remove(self):
        assert self.counter == 3
        assert len(self.received_events) == 3
        assert isinstance(self.received_events[2], Model_Changed)

    def test_event_data_contains_remove_changes(self):
        assert self.received_events[2].data == [
            Remove(R(3, 3, 30, 30)),
            Remove(R(2, 2, 20, 20)),
        ]

    def test_changes_appended_to_changelog_after_remove(self):
        assert self.changelog == [
            ['some', 'old'],
            ['changes', 'here'],
            self.received_events[0].data,
            self.received_events[1].data,
            self.received_events[2].data,
        ]
예제 #22
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,
        }
예제 #23
0
 def setup_class(self):
     states, trans = make_submachines_async_machine(use_logging=True)
     self.hsm = HSM(states, trans)
     self.eb = EventBus()
예제 #24
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,
        }
예제 #25
0
import quadpy
from quadpy.rectangle import Rectangle
from hsmpy import HSM, State, T, Initial, Internal, Choice, EventBus, Event


# you can enable logging to see what's going on under the hood of HSM
#import logging
#logging.basicConfig(level=logging.DEBUG)


# tool aliases
Selection_tool, Drawing_tool = ('Select', 'Draw')

# eventbus will be used for all events
# Tkinter events will also be routed through it
eb = EventBus()


# HSM events
class Tool_Changed(Event): pass
class Mouse_Event(Event):
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.data = (x, y)
class Canvas_Up(Mouse_Event): pass
class Canvas_Down(Mouse_Event): pass
class Canvas_Move(Mouse_Event): pass


# create Tkinter GUI
예제 #26
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")
예제 #27
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
예제 #28
0
class Test_redo:
    def setup_class(self):
        self.eb = EventBus()
        self.event_log = []

        def append_to_event_log(e):
            self.event_log += [e]
        self.eb.register(Model_Changed, append_to_event_log)

    def test_redo_one_insert(self):
        change_log = [ [ 'previous' ], [ 'changes' ] ]
        model_elems = [ R(2, 2, 2, 2) ]
        redo_log = [ [ Insert(R(1, 1, 1, 1)) ], [ 'future' ], [ 'changes'] ]

        _redo(change_log, redo_log, self.eb, model_elems)

        assert change_log == [
            [ 'previous' ], [ 'changes' ],
            [ Insert(R(1, 1, 1, 1)) ],
        ]
        assert redo_log == [ [ 'future' ], [ 'changes'] ]
        assert model_elems == [ R(2, 2, 2, 2), R(1, 1, 1, 1) ]

        assert len(self.event_log) == 1
        assert self.event_log[-1].data == [ Insert(R(1, 1, 1, 1)) ]


    def test_redo_one_remove(self):
        change_log = [ [ 'previous' ], [ 'changes' ] ]
        model_elems = [ R(1, 1, 1, 1), R(2, 2, 2, 2) ]
        redo_log = [ [ Remove(R(1, 1, 1, 1)) ], [ 'future' ], [ 'changes'] ]

        _redo(change_log, redo_log, self.eb, model_elems)

        assert change_log == [
            [ 'previous' ], [ 'changes' ],
            [ Remove(R(1, 1, 1, 1)) ],
        ]
        assert redo_log == [ [ 'future' ], [ 'changes'] ]
        assert model_elems == [ R(2, 2, 2, 2) ]

        assert len(self.event_log) == 2
        assert self.event_log[-1].data == [ Remove(R(1, 1, 1, 1)) ]


    def test_redo_one_modify(self):
        change_log = [ [ 'previous' ], [ 'changes' ] ]
        model_elems = [ R(1, 1, 1, 1), R(2, 2, 2, 2) ]
        redo_log = [
            [ Modify(R(1, 1, 1, 1), R(3, 3, 3, 3)) ],
            [ 'future' ], [ 'changes']
        ]

        _redo(change_log, redo_log, self.eb, model_elems)

        assert change_log == [
            [ 'previous' ], [ 'changes' ],
            [ Modify(R(1, 1, 1, 1), R(3, 3, 3, 3)) ],
        ]
        assert redo_log == [ [ 'future' ], [ 'changes'] ]
        assert model_elems == [ R(3, 3, 3, 3), R(2, 2, 2, 2) ]

        assert len(self.event_log) == 3
        assert self.event_log[-1].data == [ Modify(R(1, 1, 1, 1),
                                                   R(3, 3, 3, 3)) ]


    def test_model_one_undo_redo(self):
        model = CanvasModel(self.eb)
        model.commit([ Insert(R(1, 1, 1, 1)) ])
        assert model._elems == [ R(1, 1, 1, 1) ]
        assert model._changelog == [ [ Insert(R(1, 1, 1, 1)) ] ]
        assert model._redolog == []
        model.undo()
        assert model._elems == []
        assert model._changelog == []
        assert model._redolog == [ [ Insert(R(1, 1, 1, 1)) ] ]
        model.redo()
        assert model._elems == [ R(1, 1, 1, 1) ]
        assert model._changelog == [ [ Insert(R(1, 1, 1, 1)) ] ]
        assert model._redolog == []

    def test_model_two_undo_redos(self):
        model = CanvasModel(self.eb)
        model.commit([ Insert(R(1, 1, 1, 1)) ])
        model.commit([ Insert(R(2, 2, 2, 2)) ])
        assert model._elems == [ R(1, 1, 1, 1), R(2, 2, 2, 2) ]
        assert model._changelog == [
            [Insert(R(1, 1, 1, 1))],
            [Insert(R(2, 2, 2, 2))]
        ]
        assert model._redolog == []

        model.undo()
        assert model._elems == [ R(1, 1, 1, 1) ]
        assert model._changelog == [ [ Insert(R(1, 1, 1, 1)) ] ]
        assert model._redolog == [ [ Insert(R(2, 2, 2, 2)) ] ]

        model.undo()
        assert model._elems == []
        assert model._changelog == []
        assert model._redolog == [
            [ Insert(R(1, 1, 1, 1)) ],
            [ Insert(R(2, 2, 2, 2)) ],
        ]

        model.redo()
        assert model._elems == [ R(1, 1, 1, 1) ]
        assert model._changelog == [ [ Insert(R(1, 1, 1, 1)) ] ]
        assert model._redolog == [ [ Insert(R(2, 2, 2, 2)) ] ]

        model.redo()
        assert model._elems == [ R(1, 1, 1, 1), R(2, 2, 2, 2) ]
        assert model._changelog == [
            [Insert(R(1, 1, 1, 1))],
            [Insert(R(2, 2, 2, 2))]
        ]
        assert model._redolog == []

    def test_model_commit_clears_redo_log(self):
        model = CanvasModel(self.eb)
        model.commit([ Insert(R(1, 1, 1, 1)) ])
        model.commit([ Insert(R(2, 2, 2, 2)) ])

        model.undo()

        model.commit([ Insert(R(3, 3, 3, 3)) ])  # this one clears redo log
        assert model._elems == [ R(1, 1, 1, 1), R(3, 3, 3, 3) ]
        assert model._changelog == [
            [Insert(R(1, 1, 1, 1))],
            [Insert(R(3, 3, 3, 3))]
        ]
        assert model._redolog == []