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_perpetual_machine: def setup_class(self): self.eb = EventBus() def increase(evt, hsm): hsm.data.count += 1 self.states = { 'top': State({ 'a': SteppingState(), 'b': SteppingState(), }) } self.trans = { 'top': { Initial: T('a'), }, 'a': { Step: T('b', action=increase), }, 'b': { Step: T('a'), } } self.hsm = HSM(self.states, self.trans) self.hsm.data.count = 0 def test_stops_after_2000_cycles(self): self.hsm.start(self.eb) assert self.hsm.data.count == 2000
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): 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 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() def increase(evt, hsm): hsm.data.count += 1 self.states = { 'top': State({ 'a': SteppingState(), 'b': SteppingState(), }) } self.trans = { 'top': { Initial: T('a'), }, 'a': { Step: T('b', action=increase), }, 'b': { Step: T('a'), } } self.hsm = HSM(self.states, self.trans) self.hsm.data.count = 0
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): 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): 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): 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 }
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): 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, }
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, }
default='dragging_marquee', key=lambda e, h: len(elems_under_cursor(e, h)) > 0), }, 'dragging_marquee': { Canvas_Move: Internal(action=drag_marquee_rect), }, 'moving_elements': { Canvas_Move: Internal(action=move_elements), }, ### 'draw_tool_chosen': { Initial: T('draw_tool_hovering'), Canvas_Up: T('draw_tool_hovering'), }, 'draw_tool_hovering': { Canvas_Down: T('drawing', action=initialize_rectangle), }, 'drawing': { Canvas_Move: Internal(action=draw_rectangle), }, } # initialize HSM with defined states and transitions and run hsm = HSM(states, transitions) hsm.start(eb) eb.dispatch(Tool_Changed(Drawing_tool)) root.mainloop()
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_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_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")