def test_composite_statechart_finished(self): statechart = Statechart(name='statechart') init = InitialState(statechart) final = FinalState(statechart) composite = CompositeState(name='composite', context=statechart) composite_init = InitialState(composite) composite_default = State(name='composite_default', context=composite) composite_final = FinalState(composite) finish = Event('finish') Transition(start=init, end=composite) Transition(start=composite_init, end=composite_default) Transition(start=composite_default, end=composite_final, event=finish) Transition(start=composite, end=final) statechart.start() assert statechart.is_active('composite') assert statechart.is_active('composite_default') assert not statechart.is_finished() statechart.dispatch(finish) assert statechart.is_finished()
def state(): statechart = Statechart(name="statechart") initial_state = InitialState(statechart) next_state = State(name="next", context=statechart) Transition(initial_state, next_state) statechart.start() return next_state
def test_choice_state_transitions(self, choice, expected_state_name): class MyMetadata(Metadata): def __init__(self): super().__init__() self.value = None class IsA(Guard): def check(self, metadata, event): return metadata.value == 'a' myMetadata = MyMetadata() myMetadata.value = choice statechart = Statechart(name='statechart', metadata=myMetadata) 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=IsA()) Transition(start=choice, end=state_b, event=None, guard=ElseGuard()) statechart.start() assert statechart.is_active(expected_state_name)
def concurrent_statechart(): 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 sc = Statechart('simple') sc.init = InitialState(sc) sc.concurrent = ConcurrentState(name='compound', context=sc) sc.concurrent.composite_a = composite(name='a', context=sc.concurrent) sc.concurrent.composite_b = composite(name='b', context=sc.concurrent) sc.concurrent.composite_c = composite(name='c', context=sc.concurrent) sc.final = FinalState(sc) Transition(start=sc.init, end=sc.concurrent) Transition(start=sc.concurrent, end=sc.final, event=Event('finish')) return sc
def state(): statechart = Statechart(name='statechart') initial_state = InitialState(statechart) next_state = State(name='next', context=statechart) Transition(initial_state, next_state) statechart.start() return next_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 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_composite_statechart_finished(self): statechart = Statechart(name="statechart") init = InitialState(statechart) final = FinalState(statechart) composite = CompositeState(name="composite", context=statechart) composite_init = InitialState(composite) composite_default = State(name="composite_default", context=composite) composite_final = FinalState(composite) finish = Event("finish") Transition(start=init, end=composite) Transition(start=composite_init, end=composite_default) Transition(start=composite_default, end=composite_final, event=finish) Transition(start=composite, end=final) statechart.start() assert statechart.is_active("composite") assert statechart.is_active("composite_default") assert not statechart.is_finished() statechart.dispatch(finish) assert statechart.is_finished()
def test_default_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) c = State(name='c', context=statechart) d = State(name='d', context=statechart) Transition(start=composite_state, end=c, event=Event('f')) Transition(start=composite_state, end=b, event=Event('e')) Transition(start=composite_state, end=d) statechart.start() assert statechart.is_active('a') statechart.dispatch(Event('e')) assert statechart.is_active('d')
def test_transition_from_initial_state_with_event_trigger(self): 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=Event('event'))
def test_multiple_transitions_from_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) with pytest.raises(RuntimeError): Transition(start=initial_state, end=default_state)
def test_cannot_create_multiple_shallow_history_states(self): startchart = Statechart(name='statechart') composite_state = CompositeState(name='composite', context=startchart) ShallowHistoryState(composite_state) with pytest.raises(RuntimeError): ShallowHistoryState(composite_state)
def test_add_transition(self): statechart = Statechart(name='statechart') initial_state = InitialState(statechart) default_state = State(name='default', context=statechart) default_transition = Transition(start=initial_state, end=default_state) assert default_transition in initial_state._transitions
def test_default_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) c = State(name="c", context=statechart) d = State(name="d", context=statechart) Transition(start=composite_state, end=c, event=Event("f")) Transition(start=composite_state, end=b, event=Event("e")) Transition(start=composite_state, end=d) statechart.start() assert statechart.is_active("a") statechart.dispatch(Event("e")) assert statechart.is_active("d")
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_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_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 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 main() -> None: """Code here shows how everything is wired together. The following lines are the expected output: state 'state-a' got event 'None' state 'state-b' got event 'Event(name="to-state-b", data={})' """ # Create the state machine -- the root context of every workflow. state_machine = Statechart("state-machine") # Create the workflow metadata with all the data accessible to all states and workflows. metadata = WorkflowMetadata(a=10, b="foo", c="bar") # Create the workflow factory backed by the workflow metadata. factory = WorkflowFactory(metadata) # Create the main workflow using the workflow factory. main_workflow = factory.create_workflow("main-workflow", state_machine, MainWorkflow) # Set up the main transitions. init = InitialState(state_machine) final = FinalState(state_machine) Transition(init, main_workflow) Transition(main_workflow, final, event=Event("final")) # Run the state machine. state_machine.start() state_machine.dispatch(Event("to-state-b"))
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_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_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_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_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")
class Main: def __init__(self): self.sm = Statechart() self.ti = TimerService() self.cb = Callback(self.sm) def setup(self): self.sm.timer_service = self.ti self.sm.operation_callback = self.cb self.sm.enter() def run(self): try: while True: self.sm.user.raise_clock() time.sleep(1) self.sm.run_cycle() except KeyboardInterrupt: self.shutdown() def shutdown(self): print('State machine shuts down.') self.sm.exit() print('Bye!')
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_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 test_create_shallow_history_state(self): startchart = Statechart(name='statechart') composite_state = CompositeState(name='composite', context=startchart) ShallowHistoryState(composite_state)
def test_submachines(self): statechart = Statechart(name="statechart") init = InitialState(statechart) top_a = self.Submachine("top a", statechart) top_b = self.Submachine("top b", statechart) top_a_to_b = Event("top ab") Transition(start=init, end=top_a) Transition(start=top_a, end=top_b, event=top_a_to_b) statechart.start() assert statechart.is_active("top a") assert statechart.is_active("sub state a") statechart.dispatch(top_a.sub_a_to_b) assert statechart.is_active("top a") assert statechart.is_active("sub state b") statechart.dispatch(top_a_to_b) assert statechart.is_active("top b") assert statechart.is_active("sub state a") statechart.dispatch(top_a.sub_a_to_b) assert statechart.is_active("top b") assert statechart.is_active("sub state b")
def test_submachines(self): statechart = Statechart(name='statechart') init = InitialState(statechart) top_a = self.Submachine('top a', statechart) top_b = self.Submachine('top b', statechart) top_a_to_b = Event('top ab') Transition(start=init, end=top_a) Transition(start=top_a, end=top_b, event=top_a_to_b) statechart.start() assert statechart.is_active('top a') assert statechart.is_active('sub state a') statechart.dispatch(top_a.sub_a_to_b) assert statechart.is_active('top a') assert statechart.is_active('sub state b') statechart.dispatch(top_a_to_b) assert statechart.is_active('top b') assert statechart.is_active('sub state a') statechart.dispatch(top_a.sub_a_to_b) assert statechart.is_active('top b') assert statechart.is_active('sub state b')
def test_missing_transition_from_initial_state(self): startchart = Statechart(name='statechart') InitialState(startchart) with pytest.raises(RuntimeError): startchart.start()
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_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 test_create_initial_state(self): startchart = Statechart(name='statechart') InitialState(startchart)
def test_create_state(self): statechart = Statechart(name='statechart') State(name='anon', context=statechart)
def test_add_transition(self): statechart = Statechart(name='statechart') final_state = FinalState(statechart) with pytest.raises(RuntimeError): Transition(start=final_state, end=statechart)
def test_create_statechart(self): Statechart(name='statechart')