def test_normal_transition_constructor(self): source_state = State("source") destination_state = State("destination") event = Event("event") transition = NormalTransition(source_state, destination_state, event) assert transition.event == event assert transition.source_state == source_state assert transition.destination_state == destination_state
def test_transition_with_invalid_event(self): state_machine = StateMachine("sm") initial_state = State("initial_state") second_state = State("second_state") event = Event("event") state_machine.add_state(initial_state, initial_state=True) state_machine.add_state(second_state) assert state_machine.add_transition(initial_state, second_state, event) is None
def test_with_initial_state(self): state_machine = StateMachine("sm") initial_state = State("initial_state") entry_cb = MagicMock() initial_state.on_entry(entry_cb) state_machine.add_state(initial_state, initial_state=True) state_machine.start("data") assert state_machine.current_state == initial_state entry_cb.assert_called_once_with("data") assert state_machine.is_running()
def test_normal_transition_action(self): source_state = State("source") destination_state = State("destination") event = Event("event") transition = NormalTransition(source_state, destination_state, event) condition_callback = MagicMock(return_value=True) action_callback = MagicMock() transition.add_condition(condition_callback) transition.add_action(action_callback) transition("data") condition_callback.assert_called_once_with("data") action_callback.assert_called_once_with("data")
def test_on_exit(self): callback = MagicMock() state = State("state") state.on_exit(callback) state.start("data") state.stop("data") callback.assert_called_once_with("data")
def test_self_transition_constructor(self): source_state = State("source") event = Event("event") transition = SelfTransition(source_state, event) assert transition.event == event assert transition.source_state == source_state assert transition.destination_state == source_state
def test_null_transition_with_valid_event(self): state_machine = StateMachine("sm") initial_state = State("initial_state") event = Event("event") state_machine.add_state(initial_state, initial_state=True) state_machine.add_event(event) assert state_machine.add_null_transition(initial_state, event) is not None
def test_normal_transition_no_condition(self): entry_callback = MagicMock() exit_callback = MagicMock() source_state = State("source") source_state.on_exit(exit_callback) destination_state = State("destination") destination_state.on_entry(entry_callback) event = Event("event") transition = NormalTransition(source_state, destination_state, event) transition("data") entry_callback.assert_called_once_with("data") exit_callback.assert_called_once_with("data")
def test_event_trigger_propagate_with_child_sm(self): state_machine = StateMachine("sm") exit_cb = MagicMock() entry_cb = MagicMock() initial_state = State("initial_state") second_state = State("second_state") initial_state.on_exit(exit_cb) second_state.on_entry(entry_cb) initial_state.set_child_sm(self.create_child_fsm()) event = Event("event") state_machine.add_state(initial_state, initial_state=True) state_machine.add_state(second_state) state_machine.add_event(event) state_machine.add_transition(initial_state, second_state, event) state_machine.start("data") exit_cb.assert_not_called() entry_cb.assert_not_called() state_machine.trigger_event(event, "data", propagate=True) # child fsm in current state, so the event is caught in child fsm assert state_machine.current_state == initial_state assert initial_state.child_sm.current_state.name == \ "child_second_state"
def test_event_trigger_no_initial_state(self): state_machine = StateMachine("sm") exit_cb = MagicMock() entry_cb = MagicMock() initial_state = State("initial_state") second_state = State("second_state") initial_state.on_exit(exit_cb) second_state.on_entry(entry_cb) event = Event("event") state_machine.add_state(initial_state) state_machine.add_state(second_state) state_machine.add_event(event) state_machine.add_transition(initial_state, second_state, event) with pytest.raises(ValueError): state_machine.trigger_event(event, "data")
def test_set_child_sm(self): child_state_machine = StateMachine("state_machine") state = State("state") assert state.child_sm is None assert not state.has_child_sm() state.set_child_sm(child_state_machine) assert state.child_sm is not None assert state.has_child_sm()
def test_normal_transition_condition_false(self): entry_callback = MagicMock() exit_callback = MagicMock() source_state = State("source") source_state.on_exit(exit_callback) destination_state = State("destination") destination_state.on_entry(entry_callback) event = Event("event") transition = NormalTransition(source_state, destination_state, event) condition_callback = MagicMock(return_value=False) transition.add_condition(condition_callback) transition("data") entry_callback.assert_not_called() exit_callback.assert_not_called() condition_callback.assert_called_once_with("data")
def create_child_fsm(): state_machine = StateMachine("child_sm") exit_cb = MagicMock() entry_cb = MagicMock() initial_state = State("child_initial_state") second_state = State("child_second_state") initial_state.on_exit(exit_cb) second_state.on_entry(entry_cb) event = Event("event") state_machine.add_state(initial_state, initial_state=True) state_machine.add_state(second_state) state_machine.add_event(event) state_machine.add_transition(initial_state, second_state, event) return state_machine
def test_exit_callback(self): exit_sm_cb = MagicMock() state_machine = StateMachine("sm") state_machine.on_exit(exit_sm_cb) initial_state = State("initial_state") second_state = State("second_state") exit_state_error = ExitState("Error") event = Event("event") error_event = Event("error") state_machine.add_state(initial_state, initial_state=True) state_machine.add_state(second_state) state_machine.add_state(exit_state_error) state_machine.add_event(event) state_machine.add_event(error_event) state_machine.add_transition(initial_state, second_state, event) state_machine.add_transition(second_state, exit_state_error, error_event) state_machine.start("data") assert state_machine.current_state == initial_state state_machine.trigger_event(event, "data") assert state_machine.current_state == second_state state_machine.trigger_event(error_event, "data") assert state_machine.current_state == exit_state_error exit_sm_cb.assert_called_once_with(exit_state_error, "data")
def test_null_transition_no_condition(self): entry_callback = MagicMock() exit_callback = MagicMock() source_state = State("source") source_state.on_exit(exit_callback) source_state.on_entry(entry_callback) event = Event("event") transition = NullTransition(source_state, event) transition("data") entry_callback.assert_not_called() exit_callback.assert_not_called()
def test_event_trigger(self): state_machine = StateMachine("sm") exit_cb = MagicMock() entry_cb = MagicMock() initial_state = State("initial_state") second_state = State("second_state") initial_state.on_exit(exit_cb) second_state.on_entry(entry_cb) event = Event("event") state_machine.add_state(initial_state, initial_state=True) state_machine.add_state(second_state) state_machine.add_event(event) state_machine.add_transition(initial_state, second_state, event) state_machine.start("data") exit_cb.assert_not_called() entry_cb.assert_not_called() state_machine.trigger_event(event, "data") exit_cb.assert_called_once_with("data") entry_cb.assert_called_once_with("data")
def test_null_transition_condition_true(self): entry_callback = MagicMock() exit_callback = MagicMock() source_state = State("source") source_state.on_exit(exit_callback) source_state.on_entry(entry_callback) event = Event("event") transition = NullTransition(source_state, event) condition_callback = MagicMock(return_value=True) transition.add_condition(condition_callback) transition("data") entry_callback.assert_not_called() exit_callback.assert_not_called() condition_callback.assert_called_once_with("data")
def test_equality(self): state1 = State("state") state2 = State("state") assert state1 == state2
def test_stop_before_starting(self): state_machine = StateMachine("sm") initial_state = State("initial_state") state_machine.add_state(initial_state, initial_state=True) with pytest.raises(ValueError): state_machine.stop("data")
def test_stop_no_initial_state(self): state_machine = StateMachine("sm") initial_state = State("initial_state") state_machine.add_state(initial_state) with pytest.raises(ValueError): state_machine.stop("data")
def test_constructor_default(self): state = State("state") assert state.name == "state" assert state.child_sm is None assert not state.has_child_sm()
def test_add_same_state_twice(self): state_machine = StateMachine("sm") initial_state = State("initial_state") state_machine.add_state(initial_state, initial_state=True) with pytest.raises(ValueError): state_machine.add_state(initial_state)
def test_set_parent_sm(self): parent_state_machine = StateMachine("state_machine") state = State("state") assert state.parent_sm is None state.set_parent_sm(parent_state_machine) assert state.parent_sm is not None
def test_constructor_with_child(self): child_state_machine = StateMachine("state_machine") state = State("state", child_state_machine) assert state.name == "state" assert state.child_sm is not None assert state.has_child_sm()