def test_transition_action_function_with_event(self, empty_statechart): self.state = False def set_state(event): self.state = event.data['state'] sc = empty_statechart initial = InitialState(sc) default = State(name='default', context=sc) next = State(name='next', context=sc) Transition(start=initial, end=default) Transition(start=default, end=next, event='next', action=set_state) sc.start() sc.dispatch(Event(name='next', data={'state': True})) assert self.state
def test_activate_initial_state(self): startchart = Statechart(name='statechart') initial_state = InitialState(startchart) default_state = State(name='default', context=startchart) Transition(start=initial_state, end=default_state) startchart.start() initial_state.activate(metadata=startchart._metadata, event=None) assert startchart.is_active('default')
def simple_statechart(): sc = Statechart('simple') sc.init = InitialState(sc) sc.state = State(name='state', context=sc) sc.final = FinalState(sc) Transition(start=sc.init, end=sc.state) Transition(start=sc.state, end=sc.final, event=Event('finish')) return sc
def test_transition_from_finished_composite_state(self): statechart = Statechart(name='statechart') statechart_init = InitialState(statechart) composite_state = CompositeState(name='composite', context=statechart) comp_init = InitialState(composite_state) a = State(name='a', context=composite_state) comp_final = FinalState(composite_state) Transition(start=statechart_init, end=composite_state) Transition(start=comp_init, end=a) Transition(start=a, end=comp_final, event=Event('e')) b = State(name='b', context=statechart) Transition(start=composite_state, end=b) statechart.start() assert statechart.is_active('a') statechart.dispatch(Event('e')) assert statechart.is_active('b')
def test_choice_state_transitions(self, state_name, expected_state_name): def is_a(**kwargs): return state_name == 'a' statechart = Statechart(name='statechart') init = InitialState(statechart) state_a = State(name='a', context=statechart) state_b = State(name='b', context=statechart) choice = ChoiceState(context=statechart) Transition(start=init, end=choice) Transition(start=choice, end=state_a, event=None, guard=is_a) Transition(start=choice, end=state_b, event=None, guard=None) # else statechart.start() assert statechart.is_active(expected_state_name)
def test_transition_action_function_with_metadata(self, empty_statechart): sc = empty_statechart sc.metadata.state = True self.state = False def set_state(event): self.state = sc.metadata.state initial = InitialState(sc) default = State(name='default', context=sc) next = State(name='next', context=sc) Transition(start=initial, end=default) Transition(start=default, end=next, event='next', action=set_state) sc.start() sc.dispatch(Event('next')) assert self.state
def test_transition_action_function(self, empty_statechart): self.state = False def set_state(state): self.state = bool(state) set_true = partial(set_state, True) sc = empty_statechart initial = InitialState(sc) default = State(name='default', context=sc) next = State(name='next', context=sc) Transition(start=initial, end=default) Transition(start=default, end=next, event='next', action=set_true) sc.start() sc.dispatch(Event('next')) assert self.state
def test_transition_from_initial_state_with_guard_condition(self): class MyGuard(Guard): def check(self, metadata, event): return False startchart = Statechart(name='statechart') initial_state = InitialState(startchart) default_state = State(name='default', context=startchart) with pytest.raises(RuntimeError): Transition(start=initial_state, end=default_state, event=None, guard=MyGuard())
def composite(name, context): composite = CompositeState(name=name, context=context) composite.init = InitialState(composite) composite.state = State(name='state', context=composite) composite.final = FinalState(composite) Transition(start=composite.init, end=composite.state) Transition(start=composite.state, end=composite.final, event=Event('finish')) return composite
def test_create_cyclic_transition(self, empty_statechart): next_state = State(name='next', context=empty_statechart) transition = Transition(start=next_state, end=next_state) # The transition should be added to the initial state's list of # outgoing transitions. assert transition in next_state._transitions # When executed, the transition should be setup to deactivate the # next state and to re-activate it. assert next_state in transition.deactivate assert next_state in transition.activate
def test_transition_from_initial_state_with_guard_condition(self): startchart = Statechart(name='statechart') initial_state = InitialState(startchart) default_state = State(name='default', context=startchart) def my_guard(**kwargs): return False with pytest.raises(RuntimeError): Transition(start=initial_state, end=default_state, event=None, guard=my_guard)
def test_create_transition(self, empty_statechart): initial_state = InitialState(empty_statechart) next_state = State(name='next', context=empty_statechart) transition = Transition(start=initial_state, end=next_state) # The transition should be added to the initial state's list of # outgoing transitions assert transition in initial_state.transitions # When executed, the transition should be setup to deactivate the # initial state and to activate the next state assert initial_state in transition.deactivate assert next_state in transition.activate
def test_default_transition_isnt_executed_from_unfinished_composite_state( self): statechart = Statechart(name='statechart') statechart_init = InitialState(statechart) composite_state = CompositeState(name='composite', context=statechart) comp_init = InitialState(composite_state) a = State(name='a', context=composite_state) Transition(start=statechart_init, end=composite_state) Transition(start=comp_init, end=a) b = State(name='b', context=statechart) Transition(start=composite_state, end=b) statechart.start() assert statechart.is_active('a') statechart.dispatch(Event('e')) assert statechart.is_active('a')
def test_light_switch(self): """ --Flick--> init ---> Off On <--Flick-- Entry: Light = ON Exit: Light = OFF Internal: Flick: Count++ """ class On(State): def __init__(self, name, context, data): State.__init__(self, name=name, context=context) self.data = data def entry(self, event): self.data['light'] = 'on' def exit(self, event): self.data['light'] = 'off' def handle_internal(self, event): if event.name == 'flick': self.data['on_count'] += 1 sm = Statechart(name='sm') data = dict(light='off', on_count=0) sm.initial_state = InitialState(context=sm) off = State(name='off', context=sm) on = On(name='on', context=sm, data=data) Transition(start=sm.initial_state, end=off) Transition(start=off, end=on, event=Event('flick')) Transition(start=on, end=off, event=Event('flick')) sm.start() assert data['light'] == 'off' sm.dispatch(Event('flick')) assert data['light'] == 'on' assert data['on_count'] == 0 sm.dispatch(Event('flick')) assert data['light'] == 'off' assert data['on_count'] == 1
def test_simple_statechart_finished(self): statechart = Statechart(name='statechart') init = InitialState(statechart) default = State(name='default', context=statechart) final = FinalState(statechart) finish = Event('finish') Transition(start=init, end=default) Transition(start=default, end=final, event=finish) statechart.start() assert statechart.is_active('default') assert not statechart.is_finished() statechart.dispatch(finish) assert statechart.is_finished()
def test_active_states(self): statechart = Statechart(name='a') statechart_init = InitialState(statechart) b = CompositeState(name='b', context=statechart) b_init = InitialState(b) c = CompositeState(name='c', context=b) c_init = InitialState(c) d = State(name='d', context=c) Transition(start=statechart_init, end=b) Transition(start=b_init, end=c) Transition(start=c_init, end=d) statechart.start() assert statechart.active_states() == [statechart, b, c, d]
def test_top_level_internal_transition(self, empty_statechart): sc = empty_statechart sc_init = InitialState(sc) cs = CompositeState(name='cs', context=sc) cs_init = InitialState(cs) cs_default = State(name='cs_default', context=cs) Transition(start=sc_init, end=cs) Transition(start=cs_init, end=cs_default) test_event = Event('internal-event-trigger') InternalTransition(state=cs, event=test_event) sc.start() assert sc.is_active('cs_default') sc.dispatch(test_event) assert sc.is_active('cs_default')
def test_activate_shallow_history_state(self): """ statechart: statechart_init | *** csa ********************** *** csb ************* * * * * * csa_init-csa_hist * * csb_init * * | * --J--> * | * * A --I--> B * <--K-- * C --L--> D * * * * * ****************************** ********************* """ # Top level states statechart = Statechart(name='statechart') csa = CompositeState(name='csa', context=statechart) csb = CompositeState(name='csb', context=statechart) # Child states # statechart statechart_init = InitialState(statechart) # csa csa_init = InitialState(csa) csa_hist = ShallowHistoryState(context=csa) A = State(name='A', context=csa) B = State(name='B', context=csa) # csb csb_init = InitialState(csb) C = State(name='C', context=csb) D = State(name='D', context=csb) # Events I = Event(name='I') J = Event(name='J') K = Event(name='K') L = Event(name='L') # Transitions between states & event triggers Transition(start=statechart_init, end=csa) Transition(start=csa_init, end=csa_hist) Transition(start=csa_hist, end=A) Transition(start=A, end=B, event=I) Transition(start=csa, end=csb, event=J) Transition(start=csb, end=csa, event=K) Transition(start=csb_init, end=C) Transition(start=C, end=D, event=L) # Execute statechart statechart.start() statechart.dispatch(I) # Assert we have reached state B, history should restore this state assert statechart.is_active('B') statechart.dispatch(J) # Assert we have reached state C assert statechart.is_active('C') statechart.dispatch(K) # Assert the history state has restored state B assert statechart.is_active('B')
def test_activate_multiple_shallow_history_states(self): """ statechart: statechart_init | *** csa ***************************************************** *** csc ************* * * * * * csa_init--csa_hist * * csc_init * * | * --K--> * | * * A --I--> *** csb *********************** * <--L-- * D --M--> E * * * * * * * * * csb_init--csb_hist * * ********************* * * | * * * * B --J--> C * * * * * * * ******************************* * * * ************************************************************* """ # Top level states statechart = Statechart(name='statechart') csa = CompositeState(name='csa', context=statechart) csb = CompositeState(name='csb', context=csa) csc = CompositeState(name='csc', context=statechart) # Child states # statechart statechart_init = InitialState(statechart) # csa csa_init = InitialState(csa) csa_hist = ShallowHistoryState(context=csa) A = State(name='A', context=csa) # csb csb_init = InitialState(csb) csb_hist = ShallowHistoryState(context=csb) B = State(name='B', context=csb) C = State(name='C', context=csb) # csc csc_init = InitialState(csc) D = State(name='D', context=csc) E = State(name='E', context=csc) # Events I = Event(name='I') J = Event(name='J') K = Event(name='K') L = Event(name='L') M = Event(name='M') # Transitions between states & event triggers Transition(start=statechart_init, end=csa) Transition(start=csa_init, end=csa_hist) Transition(start=csa_hist, end=A) Transition(start=A, end=csb, event=I) Transition(start=csb_init, end=csb_hist) Transition(start=csb_hist, end=B) Transition(start=B, end=C, event=J) Transition(start=csa, end=csc, event=K) Transition(start=csc, end=csa, event=L) Transition(start=csc_init, end=D) Transition(start=D, end=E, event=M) # Execute statechart statechart.start() statechart.dispatch(I) assert statechart.is_active('B') statechart.dispatch(J) # Assert we have reached state C, csb's history state should restore # this state assert statechart.is_active('C') statechart.dispatch(K) # Assert we have reached state D assert statechart.is_active('D') statechart.dispatch(L) # Assert the history state has restored state C assert statechart.is_active('C')
def test_create_state(self): statechart = Statechart(name='statechart') State(name='anon', context=statechart)
def test_keyboard_example(self): """ Test classic concurrent state keyboard example with concurrent states for caps, num and scroll lock. init - - | v -- keyboard -------------------------------------- | | | init ---> --caps lock off -- | | --- | | <-- | | | -----------------| | | | caps lock pressed caps lock pressed | | | -- caps lock on -- | | | --> | | --- | | ------------------ | | | -------------------------------------------------- | | | init ---> --num lock off --- | | --- | | <-- | | | -----------------| | | | num lock pressed num lock pressed | | | -- num lock on --- | | | --> | | --- | | ------------------ | | | -------------------------------------------------- | | | init ---> -- scroll lock off -- | | --- | | <-- | | | ---------------------| | | | scroll lock pressed scroll lock pressed | | | -- scroll lock on ---| | | | --> | | --- | | ---------------------- | | | -------------------------------------------------- """ statechart = Statechart(name='statechart') start_state = InitialState(statechart) keyboard = ConcurrentState(name='keyboard', context=statechart) Transition(start=start_state, end=keyboard) caps_lock = CompositeState(name='caps_lock', context=keyboard) caps_lock_initial = InitialState(caps_lock) caps_lock_on = State(name='caps_lock_on', context=caps_lock) caps_lock_off = State(name='caps_lock_off', context=caps_lock) caps_lock_pressed = Event(name='caps_lock_pressed') Transition(start=caps_lock_initial, end=caps_lock_off) Transition(start=caps_lock_on, end=caps_lock_off, event=caps_lock_pressed) Transition(start=caps_lock_off, end=caps_lock_on, event=caps_lock_pressed) num_lock = CompositeState(name='num_lock', context=keyboard) num_lock_initial = InitialState(num_lock) num_lock_on = State(name='num_lock_on', context=num_lock) num_lock_off = State(name='num_lock_off', context=num_lock) num_lock_pressed = Event(name='num_lock_pressed') Transition(start=num_lock_initial, end=num_lock_off) Transition(start=num_lock_on, end=num_lock_off, event=num_lock_pressed) Transition(start=num_lock_off, end=num_lock_on, event=num_lock_pressed) scroll_lock = CompositeState(name='scroll_lock', context=keyboard) scroll_lock_initial = InitialState(scroll_lock) scroll_lock_on = State(name='scroll_lock_on', context=scroll_lock) scroll_lock_off = State(name='scroll_lock_off', context=scroll_lock) scroll_lock_pressed = Event(name='scroll_lock_pressed') Transition(start=scroll_lock_initial, end=scroll_lock_off) Transition(start=scroll_lock_on, end=scroll_lock_off, event=scroll_lock_pressed) Transition(start=scroll_lock_off, end=scroll_lock_on, event=scroll_lock_pressed) statechart.start() assert statechart.is_active('keyboard') assert statechart.is_active('caps_lock_off') assert statechart.is_active('num_lock_off') assert statechart.is_active('scroll_lock_off') statechart.dispatch(event=caps_lock_pressed) assert statechart.is_active('caps_lock_on') statechart.dispatch(event=num_lock_pressed) assert statechart.is_active('num_lock_on') statechart.dispatch(event=scroll_lock_pressed) assert statechart.is_active('scroll_lock_on') statechart.dispatch(event=caps_lock_pressed) assert statechart.is_active('caps_lock_off') statechart.dispatch(event=num_lock_pressed) assert statechart.is_active('num_lock_off') statechart.dispatch(event=scroll_lock_pressed) assert statechart.is_active('scroll_lock_off')
def __init__(self, name, context, data): State.__init__(self, name=name, context=context) self.data = data
def __init__(self, name, context): State.__init__(self, name=name, context=context) self.dispatch_called = False self.metadata = None self.event = None
def test_create_state_without_parent(self): with pytest.raises(RuntimeError): State(name='anon', context=None)
def test_deep_local_transitions(self, empty_statechart): sc = empty_statechart init = InitialState(sc) top = CompositeState(name='top', context=sc) top_init = InitialState(top) middle_a = CompositeState(name='middle_a', context=top) middle_b = CompositeState(name='middle_b', context=top) middle_a_init = InitialState(middle_a) bottom_a1 = State(name='bottom_a1', context=middle_a) bottom_a2 = State(name='bottom_a2', context=middle_a) middle_b_init = InitialState(middle_b) bottom_b1 = State(name='bottom_b1', context=middle_b) bottom_b2 = State(name='bottom_b2', context=middle_b) # Setup default transitions Transition(start=init, end=top) Transition(start=top_init, end=middle_a) Transition(start=middle_a_init, end=bottom_a1) Transition(start=middle_b_init, end=bottom_b1) # Setup events to trigger transitions a_to_b = Event('a_to_b') a1_to_a2 = Event('a1_to_a2') b1_to_b2 = Event('b1_to_b2') top_to_middle_a = Event('top_to_middle_a') top_to_middle_b = Event('top_to_middle_b') middle_a_to_a1 = Event('middle_a_to_a1') middle_a_to_a2 = Event('middle_a_to_a2') middle_b_to_b1 = Event('middle_b_to_b1') middle_b_to_b2 = Event('middle_b_to_b2') # Setup external transitions Transition(start=middle_a, end=middle_b, event=a_to_b) Transition(start=bottom_a1, end=bottom_a2, event=a1_to_a2) Transition(start=bottom_a1, end=bottom_a2, event=b1_to_b2) # Setup local transitions Transition(start=top, end=middle_a, event=top_to_middle_a) Transition(start=top, end=middle_b, event=top_to_middle_b) Transition(start=middle_a, end=bottom_a1, event=middle_a_to_a1) Transition(start=middle_a, end=bottom_a2, event=middle_a_to_a2) Transition(start=middle_b, end=bottom_b1, event=middle_b_to_b1) Transition(start=middle_b, end=bottom_b2, event=middle_b_to_b2) sc.start() assert sc.is_active('top') assert sc.is_active('middle_a') assert sc.is_active('bottom_a1') sc.dispatch(middle_a_to_a2) assert sc.is_active('top') assert sc.is_active('middle_a') assert sc.is_active('bottom_a2') sc.dispatch(top_to_middle_b) assert sc.is_active('top') assert sc.is_active('middle_b') assert sc.is_active('bottom_b1') sc.dispatch(top_to_middle_a) assert sc.is_active('top') assert sc.is_active('middle_a') assert sc.is_active('bottom_a1') sc.dispatch(a_to_b) assert sc.is_active('top') assert sc.is_active('middle_b') assert sc.is_active('bottom_b1') sc.dispatch(middle_b_to_b2) assert sc.is_active('top') assert sc.is_active('middle_b') assert sc.is_active('bottom_b2')