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
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, }
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 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 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 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)
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")
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)
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 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 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 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)
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)
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')
def setup_class(self): self.states, self.trans = make_miro_machine(use_logging=True) self.hsm = HSM(self.states, self.trans) self.eb = EventBus()
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 }
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)) ]
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
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
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, ]
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, }
def setup_class(self): states, trans = make_submachines_async_machine(use_logging=True) self.hsm = HSM(states, trans) self.eb = EventBus()
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, }
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
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")
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
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 == []