Exemplo n.º 1
0
def test_add_not_a_state_instance():
    class NotState(object):
        pass

    sm = StateMachine('sm')
    s1 = NotState()

    with pytest.raises(StateMachineException) as exc:
        sm.add_state(s1)
    expected = ('Machine "sm" error: Unable to add state of type')
    assert expected in str(exc.value)
Exemplo n.º 2
0
def test_many_initial_states():
    sm = StateMachine('sm')
    s1 = State('s1')
    s2 = State('s2')

    sm.add_state(s1, initial=True)
    with pytest.raises(StateMachineException) as exc:
        sm.add_state(s2, initial=True)
    expected = ('Machine "sm" error: Unable to set initial state to "s2". '
                'Initial state is already set to "s1"')
    assert expected in str(exc.value)
Exemplo n.º 3
0
def test_input_not_iterable():
    sm = StateMachine('sm')
    s1 = State('s1')
    sm.add_state(s1)

    with pytest.raises(StateMachineException) as exc:
        sm.add_transition(s1, None, events=[1], input=2)
    expected = (
        'Machine "sm" error: Unable to add transition, '
        'input is not iterable: 2')
    assert expected in str(exc.value)
Exemplo n.º 4
0
def test_add_not_a_state_instance():
    class NotState(object):
        pass

    sm = StateMachine('sm')
    s1 = NotState()

    with pytest.raises(StateMachineException) as exc:
        sm.add_state(s1)
    expected = ('Machine "sm" error: Unable to add state of type')
    assert expected in str(exc.value)
Exemplo n.º 5
0
def test_add_states_and_set_initial_state():
    m = StateMachine('m')
    s0 = StateMachine('s0')
    s1 = StateMachine('s1')
    s2 = State('s2')

    m.add_states(s0, s1, s2)
    assert all(state in m.states for state in (s0, s1, s2))
    assert m.initial_state is None
    m.set_initial_state(s0)
    m.initialize()
    assert m.initial_state is s0
Exemplo n.º 6
0
def create_regular_users(n):
    for i in range(n):
        index = randint(0, len(valid_ips) - 1)
        ip = valid_ips.pop(index)
        Thread(target=regular_user,
               args=[ip, "generic_username",
                     StateMachine("generic_username")]).start()
Exemplo n.º 7
0
def test_add_state_that_is_already_added_anywhere_in_the_hsm():
    sm = StateMachine('sm')
    s1 = State('s1')
    s2 = State('s2')
    s3 = StateMachine('s3')
    s31 = State('s31')
    s32 = State('s32')

    sm.add_state(s1)
    sm.add_state(s2)
    sm.add_state(s3)
    s3.add_state(s31)
    s3.add_state(s32)

    with pytest.raises(StateMachineException) as exc:
        s3.add_state(s2)
    expected = ('Machine "s3" error: State "s2" is already added '
                'to machine "sm"')
    assert expected in str(exc.value)
Exemplo n.º 8
0
def test_set_previous_state_no_history():
    m = StateMachine('m')
    off = State('Off')
    m.add_state(off, initial=True)
    m.initialize()
    off.handlers = {
        'test_no_history': lambda s, e: m.set_previous_leaf_state()
    }

    assert m.leaf_state == off
    try:
        m.dispatch(_e('test_no_history'))
    except Exception as exc:
        assert not exc
    assert m.leaf_state == off
    assert list(m.leaf_state_stack.deque) == []
Exemplo n.º 9
0
def test_set_previous_state_no_history():
    m = StateMachine('m')
    off = State('Off')
    m.add_state(off, initial=True)
    m.initialize()
    off.handlers = {'test_no_history': lambda s, e: m.set_previous_leaf_state()}

    assert m.leaf_state == off
    try:
        m.dispatch(_e('test_no_history'))
    except Exception as exc:
        assert not exc
    assert m.leaf_state == off
    assert list(m.leaf_state_stack.deque) == []
Exemplo n.º 10
0
def test_no_initial_state():
    sm = StateMachine('sm')
    s1 = State('s1')
    s2 = State('s2')
    try:
        sm.initialize()
    except StateMachineException as exc:
        assert not exc

    sm.add_state(s1)
    sm.add_state(s2)
    with pytest.raises(StateMachineException) as exc:
        sm.initialize()
    expected = ('Machine "sm" error: Machine "sm" has no initial state')
    assert expected in str(exc.value)
Exemplo n.º 11
0
def test_add_states_and_set_initial_state():
    m = StateMachine('m')
    s0 = StateMachine('s0')
    s1 = StateMachine('s1')
    s2 = State('s2')

    m.add_states(s0, s1, s2)
    assert all(state in m.states for state in (s0, s1, s2))
    assert m.initial_state is None
    m.set_initial_state(s0)
    m.initialize()
    assert m.initial_state is s0
Exemplo n.º 12
0
def test_input_not_iterable():
    sm = StateMachine('sm')
    s1 = State('s1')
    sm.add_state(s1)

    with pytest.raises(StateMachineException) as exc:
        sm.add_transition(s1, None, events=[1], input=2)
    expected = ('Machine "sm" error: Unable to add transition, '
                'input is not iterable: 2')
    assert expected in str(exc.value)
Exemplo n.º 13
0
def test_many_initial_states():
    sm = StateMachine('sm')
    s1 = State('s1')
    s2 = State('s2')

    sm.add_state(s1, initial=True)
    with pytest.raises(StateMachineException) as exc:
        sm.add_state(s2, initial=True)
    expected = ('Machine "sm" error: Unable to set initial state to "s2". '
                'Initial state is already set to "s1"')
    assert expected in str(exc.value)
Exemplo n.º 14
0
def test_no_initial_state():
    sm = StateMachine('sm')
    s1 = State('s1')
    s2 = State('s2')
    try:
        sm.initialize()
    except StateMachineException as exc:
        assert not exc

    sm.add_state(s1)
    sm.add_state(s2)
    with pytest.raises(StateMachineException) as exc:
        sm.initialize()
    expected = ('Machine "sm" error: Machine "sm" has no initial state')
    assert expected in str(exc.value)
Exemplo n.º 15
0
        def _get_state_machine(self):
            state_machine = StateMachine('Test')
            state_1 = State('One')
            state_2 = State('Two')

            self.state_1 = state_1
            self.state_2 = state_2

            state_machine.add_state(state_1, initial=True)
            state_machine.add_state(state_2)
            state_machine.add_transition(state_1, state_2, events=['change_state'])
            state_machine.add_transition(state_2, state_1, events=['change_state'])
            state_1.handlers = {
                        'enter': self.entry_func,
                        'exit': self.exit_func
                        }
            state_2.handlers = {
                        'enter': self.entry_func,
                        'exit': self.exit_func
                        }

            state_machine.initialize()
            return state_machine
Exemplo n.º 16
0
def test_transition_on_any_event():
    m = StateMachine('m')
    s0 = State('s0')
    s1 = State('s1')
    m.add_state(s0, initial=True)
    m.add_state(s1)
    m.add_transition(s0, s1, events=[any_event])
    m.add_transition(s1, s0, events=[any_event])
    m.initialize()

    assert m.leaf_state == s0
    m.dispatch(_e('whatever'))
    assert m.leaf_state == s1
    m.dispatch(_e('whatever'))
    assert m.leaf_state == s0
Exemplo n.º 17
0
def test_hsm_init():
    sm = StateMachine('sm')
    s0 = StateMachine('s0')
    s1 = StateMachine('s1')
    s2 = StateMachine('s2')
    s11 = State('s11')
    s12 = State('s12')
    sm.add_state(s0, initial=True)
    s0.add_state(s1, initial=True)
    s1.add_state(s11, initial=True)
    sm.initialize()
    assert sm.state == s0
    assert s0.state == s1
    assert s1.state == s11
    assert sm.leaf_state == s11
Exemplo n.º 18
0
def test_hsm_simple_hsm_transition():
    sm = StateMachine('sm')
    s0 = StateMachine('s0')
    s1 = StateMachine('s1')
    s2 = StateMachine('s2')
    s0.add_state(s1)
    s0.add_state(s2)
    s0.add_transition(s1, s2, events='a')
    s0.add_transition(s2, s1, events='a')
    s11 = State('s11')
    s12 = State('s12')
    sm.add_state(s0, initial=True)
    s0.add_state(s1, initial=True)
    s0.add_state(s2)
    s1.add_state(s11, initial=True)
    sm.initialize()
    assert sm.state == s0
    assert s0.state == s1
    assert s1.state == s11
    assert sm.leaf_state == s11

    sm.dispatch(_e('a'))
    assert sm.state == s0
    assert s0.state == s2
    assert sm.leaf_state == s2

    sm.dispatch(_e('a'))
    assert sm.state == s0
    assert s0.state == s1
    assert s1.state == s11
    assert sm.leaf_state == s11
Exemplo n.º 19
0
def test_internal_vs_external_transitions():
    test_list = []

    class Foo(object):
        value = True

    def on_enter(state, event):
        test_list.append(('enter', state))

    def on_exit(state, event):
        test_list.append(('exit', state))

    def set_foo(state, event):
        Foo.value = True
        test_list.append('set_foo')

    def unset_foo(state, event):
        Foo.value = False
        test_list.append('unset_foo')

    def action_i(state, event):
        test_list.append('action_i')
        return True

    def action_j(state, event):
        test_list.append('action_j')
        return True

    def action_k(state, event):
        test_list.append('action_k')
        return True

    def action_l(state, event):
        test_list.append('action_l')

    def action_m(state, event):
        test_list.append('action_m')

    def action_n(state, event):
        test_list.append('action_n')
        return True

    m = StateMachine('m')
    # exit = m.add_state('exit', terminal=True)
    s0 = StateMachine('s0')
    s1 = StateMachine('s1')
    s2 = StateMachine('s2')

    s11 = State('s11')
    s21 = StateMachine('s21')
    s211 = State('s211')
    s212 = State('s212')

    m.add_state(s0, initial=True)
    s0.add_state(s1, initial=True)
    s0.add_state(s2)
    s1.add_state(s11, initial=True)
    s2.add_state(s21, initial=True)
    s21.add_state(s211, initial=True)
    s21.add_state(s212)

    states = [m, s0, s1, s11, s2, s21, s211, s212]
    for state in states:
        state.handlers = {'enter': on_enter, 'exit': on_exit}

    s0.add_transition(s1, s1, events='a')
    s0.add_transition(s1, s11, events='b')
    s2.add_transition(s21, s211, events='b')
    s0.add_transition(s1, s2, events='c')
    s0.add_transition(s2, s1, events='c')
    s0.add_transition(s1, s0, events='d')
    s21.add_transition(s211, s21, events='d')
    m.add_transition(s0, s211, events='e')
    m.add_transition(s0, s212, events='z')
    s0.add_transition(s2, s11, events='f')
    s0.add_transition(s1, s211, events='f')
    s1.add_transition(s11, s211, events='g')
    s21.add_transition(s211, s0, events='g')

    m.initialize()

    # Internal transitions
    m.add_transition(s0, None, events='i', action=action_i)
    s0.add_transition(s1, None, events='j', action=action_j)
    s0.add_transition(s2, None, events='k', action=action_k)
    s1.add_transition(s11, None, events='n', action=action_n)
    s1.add_transition(s11,
                      None,
                      events='h',
                      condition=lambda s, e: Foo.value is True,
                      action=unset_foo)
    s2.add_transition(s21,
                      None,
                      events='l',
                      condition=lambda s, e: Foo.value is True,
                      action=action_l)
    s21.add_transition(s211, None, events='m', action=action_m)
    # External transition
    s2.add_transition(s21,
                      s21,
                      events='h',
                      condition=lambda s, e: Foo.value is False,
                      action=set_foo)

    m.initialize()

    test_list[:] = []
    m.dispatch(_e('i'))
    assert test_list == ['action_i']
    assert m.leaf_state == s11

    test_list[:] = []
    m.dispatch(_e('j'))
    assert test_list == ['action_j']
    assert m.leaf_state == s11

    test_list[:] = []
    m.dispatch(_e('n'))
    assert test_list == ['action_n']
    assert m.leaf_state == s11

    # This transition toggles state between s11 and s211
    m.dispatch(_e('c'))
    assert m.leaf_state == s211

    test_list[:] = []
    m.dispatch(_e('i'))
    assert test_list == ['action_i']
    assert m.leaf_state == s211

    test_list[:] = []
    m.dispatch(_e('k'))
    assert test_list == ['action_k']
    assert m.leaf_state == s211

    test_list[:] = []
    m.dispatch(_e('m'))
    assert test_list == ['action_m']
    assert m.leaf_state == s211

    test_list[:] = []
    m.dispatch(_e('n'))
    assert test_list == []
    assert m.leaf_state == s211

    # This transition toggles state between s11 and s211
    m.dispatch(_e('c'))
    assert m.leaf_state == s11

    test_list[:] = []
    assert Foo.value is True
    m.dispatch(_e('h'))
    assert Foo.value is False
    assert test_list == ['unset_foo']
    assert m.leaf_state == s11

    test_list[:] = []
    m.dispatch(_e('h'))
    assert test_list == []  # Do nothing if foo is False
    assert m.leaf_state == s11

    # This transition toggles state between s11 and s211
    m.dispatch(_e('c'))
    assert m.leaf_state == s211

    test_list[:] = []
    assert Foo.value is False
    m.dispatch(_e('h'))
    assert test_list == [('exit', s211), ('exit', s21), 'set_foo',
                         ('enter', s21), ('enter', s211)]
    assert Foo.value is True
    assert m.leaf_state == s211

    test_list[:] = []
    m.dispatch(_e('h'))
    assert test_list == []
    assert m.leaf_state == s211
Exemplo n.º 20
0
def test_hsm_simple_hsm_transition():
    sm = StateMachine('sm')
    s0 = StateMachine('s0')
    s1 = StateMachine('s1')
    s2 = StateMachine('s2')
    s0.add_state(s1)
    s0.add_state(s2)
    s0.add_transition(s1, s2, events='a')
    s0.add_transition(s2, s1, events='a')
    s11 = State('s11')
    s12 = State('s12')
    sm.add_state(s0, initial=True)
    s0.add_state(s1, initial=True)
    s0.add_state(s2)
    s1.add_state(s11, initial=True)
    sm.initialize()
    assert sm.state == s0
    assert s0.state == s1
    assert s1.state == s11
    assert sm.leaf_state == s11

    sm.dispatch(_e('a'))
    assert sm.state == s0
    assert s0.state == s2
    assert sm.leaf_state == s2

    sm.dispatch(_e('a'))
    assert sm.state == s0
    assert s0.state == s1
    assert s1.state == s11
    assert sm.leaf_state == s11
Exemplo n.º 21
0
def test_hsm_init():
    sm = StateMachine('sm')
    s0 = StateMachine('s0')
    s1 = StateMachine('s1')
    s2 = StateMachine('s2')
    s11 = State('s11')
    s12 = State('s12')
    sm.add_state(s0, initial=True)
    s0.add_state(s1, initial=True)
    s1.add_state(s11, initial=True)
    sm.initialize()
    assert sm.state == s0
    assert s0.state == s1
    assert s1.state == s11
    assert sm.leaf_state == s11
Exemplo n.º 22
0
def test_transition_on_any_event():
    m = StateMachine('m')
    s0 = State('s0')
    s1 = State('s1')
    m.add_state(s0, initial=True)
    m.add_state(s1)
    m.add_transition(s0, s1, events=[any_event])
    m.add_transition(s1, s0, events=[any_event])
    m.initialize()

    assert m.leaf_state == s0
    m.dispatch(_e('whatever'))
    assert m.leaf_state == s1
    m.dispatch(_e('whatever'))
    assert m.leaf_state == s0
Exemplo n.º 23
0
def test_transition_from_and_to_machine_itself():
    sm = StateMachine('sm')
    s1 = State('s1')
    s2 = State('s2')
    sm.add_state(s1, initial=True)
    sm.add_state(s2)

    with pytest.raises(StateMachineException) as exc:
        sm.add_transition(sm, s1, events=['sm->s1'])
    expected = (
        'Machine "sm" error: Unable to add transition from unknown state "sm"')
    assert expected in str(exc.value)
    sm.add_transition(s1, sm, events=['s1->sm'])
    sm.initialize()

    assert sm.state == s1
    sm.dispatch(_e('sm->s1'))
    assert sm.state == s1
    assert list(sm.state_stack.deque) == []
    sm.dispatch(_e('s1->sm'))
    assert sm.state == s1
    assert list(sm.state_stack.deque) == [s1]
    sm.dispatch(_e('sm->s1'))
    assert sm.state == s1
    assert list(sm.state_stack.deque) == [s1]
    sm.dispatch(_e('s1->sm'))
    assert sm.state == s1
    assert list(sm.state_stack.deque) == [s1, s1]
Exemplo n.º 24
0
def test_state_stack_high_tree():
    sm = StateMachine('sm')
    s0 = StateMachine('s0')
    s01 = StateMachine('s01')
    s011 = StateMachine('s011')
    s0111 = State('s0111')
    s0112 = State('s0112')
    s0113 = StateMachine('s0113')
    s01131 = State('s01131')

    sm.add_state(s0, initial=True)
    s0.add_state(s01, initial=True)
    s01.add_state(s011, initial=True)
    s011.add_state(s0111, initial=True)
    s011.add_state(s0112)
    s011.add_state(s0113)
    s0113.add_state(s01131, initial=True)

    s011.add_transition(s0111, s0113, events=['a'])
    sm.initialize()

    assert sm.leaf_state == s0111
    sm.dispatch(_e('a'))
    assert list(sm.state_stack.deque) == []
    assert list(s0.state_stack.deque) == []
    assert list(s01.state_stack.deque) == []
    assert list(s011.state_stack.deque) == [s0111]
    assert list(s011.leaf_state_stack.deque) == []
    assert list(s0113.state_stack.deque) == []
    assert list(sm.leaf_state_stack.deque) == [s0111]
Exemplo n.º 25
0
def test_state_stack():
    sm = StateMachine('sm')
    s1 = State('s1')
    s2 = State('s2')
    s3 = StateMachine('s3')
    s31 = State('s31')
    s32 = State('s32')

    sm.add_state(s1, initial=True)
    sm.add_state(s2)
    sm.add_state(s3)
    s3.add_state(s31, initial=True)
    s3.add_state(s32)

    sm.add_transition(s1, s2, events=['s1->s2'])
    sm.add_transition(s2, s1, events=['s2->s1'])
    sm.add_transition(s1, s3, events=['a'])
    s3.add_transition(s31, s32, events=['b'])
    sm.initialize()

    assert sm.state == s1
    assert sm.leaf_state == s1

    sm.dispatch(_e('s1->s2'))
    assert sm.state == s2
    assert sm.leaf_state == s2
    assert list(sm.state_stack.deque) == [s1]

    sm.dispatch(_e('s2->s1'))
    assert sm.state == s1
    assert sm.leaf_state == s1
    assert list(sm.state_stack.deque) == [s1, s2]

    sm.dispatch(_e('a'))
    assert sm.state == s3
    assert sm.leaf_state == s31
    assert s3.leaf_state == s31
    assert list(sm.state_stack.deque) == [s1, s2, s1]
    assert list(s3.state_stack.deque) == []

    sm.dispatch(_e('b'))
    assert sm.state == s3
    assert sm.leaf_state == s32
    assert s3.state == s32
    assert s3.leaf_state == s32
    assert list(sm.state_stack.deque) == [s1, s2, s1]
    assert list(s3.state_stack.deque) == [s31]
Exemplo n.º 26
0
def test_internal_vs_external_transitions():
    test_list = []

    class Foo(object):
        value = True

    def on_enter(state, event):
        test_list.append(('enter', state))

    def on_exit(state, event):
        test_list.append(('exit', state))

    def set_foo(state, event):
        Foo.value = True
        test_list.append('set_foo')

    def unset_foo(state, event):
        Foo.value = False
        test_list.append('unset_foo')

    def action_i(state, event):
        test_list.append('action_i')
        return True

    def action_j(state, event):
        test_list.append('action_j')
        return True

    def action_k(state, event):
        test_list.append('action_k')
        return True

    def action_l(state, event):
        test_list.append('action_l')

    def action_m(state, event):
        test_list.append('action_m')

    def action_n(state, event):
        test_list.append('action_n')
        return True

    m = StateMachine('m')
    # exit = m.add_state('exit', terminal=True)
    s0 = StateMachine('s0')
    s1 = StateMachine('s1')
    s2 = StateMachine('s2')

    s11 = State('s11')
    s21 = StateMachine('s21')
    s211 = State('s211')
    s212 = State('s212')

    m.add_state(s0, initial=True)
    s0.add_state(s1, initial=True)
    s0.add_state(s2)
    s1.add_state(s11, initial=True)
    s2.add_state(s21, initial=True)
    s21.add_state(s211, initial=True)
    s21.add_state(s212)

    states = [m, s0, s1, s11, s2, s21, s211, s212]
    for state in states:
        state.handlers = {'enter': on_enter, 'exit': on_exit}

    s0.add_transition(s1, s1, events='a')
    s0.add_transition(s1, s11, events='b')
    s2.add_transition(s21, s211, events='b')
    s0.add_transition(s1, s2, events='c')
    s0.add_transition(s2, s1, events='c')
    s0.add_transition(s1, s0, events='d')
    s21.add_transition(s211, s21, events='d')
    m.add_transition(s0, s211, events='e')
    m.add_transition(s0, s212, events='z')
    s0.add_transition(s2, s11, events='f')
    s0.add_transition(s1, s211, events='f')
    s1.add_transition(s11, s211, events='g')
    s21.add_transition(s211, s0, events='g')

    m.initialize()

    # Internal transitions
    m.add_transition(s0, None, events='i', action=action_i)
    s0.add_transition(s1, None, events='j', action=action_j)
    s0.add_transition(s2, None, events='k', action=action_k)
    s1.add_transition(s11, None, events='n', action=action_n)
    s1.add_transition(s11, None, events='h',
                      condition=lambda s, e: Foo.value is True, action=unset_foo)
    s2.add_transition(s21, None, events='l',
                      condition=lambda s, e: Foo.value is True, action=action_l)
    s21.add_transition(s211, None, events='m', action=action_m)
    # External transition
    s2.add_transition(s21, s21, events='h',
                      condition=lambda s, e: Foo.value is False, action=set_foo)

    m.initialize()

    test_list[:] = []
    m.dispatch(_e('i'))
    assert test_list == ['action_i']
    assert m.leaf_state == s11

    test_list[:] = []
    m.dispatch(_e('j'))
    assert test_list == ['action_j']
    assert m.leaf_state == s11

    test_list[:] = []
    m.dispatch(_e('n'))
    assert test_list == ['action_n']
    assert m.leaf_state == s11

    # This transition toggles state between s11 and s211
    m.dispatch(_e('c'))
    assert m.leaf_state == s211

    test_list[:] = []
    m.dispatch(_e('i'))
    assert test_list == ['action_i']
    assert m.leaf_state == s211

    test_list[:] = []
    m.dispatch(_e('k'))
    assert test_list == ['action_k']
    assert m.leaf_state == s211

    test_list[:] = []
    m.dispatch(_e('m'))
    assert test_list == ['action_m']
    assert m.leaf_state == s211

    test_list[:] = []
    m.dispatch(_e('n'))
    assert test_list == []
    assert m.leaf_state == s211

    # This transition toggles state between s11 and s211
    m.dispatch(_e('c'))
    assert m.leaf_state == s11

    test_list[:] = []
    assert Foo.value is True
    m.dispatch(_e('h'))
    assert Foo.value is False
    assert test_list == ['unset_foo']
    assert m.leaf_state == s11

    test_list[:] = []
    m.dispatch(_e('h'))
    assert test_list == []  # Do nothing if foo is False
    assert m.leaf_state == s11

    # This transition toggles state between s11 and s211
    m.dispatch(_e('c'))
    assert m.leaf_state == s211

    test_list[:] = []
    assert Foo.value is False
    m.dispatch(_e('h'))
    assert test_list == [('exit', s211), ('exit', s21), 'set_foo', ('enter', s21), ('enter', s211)]
    assert Foo.value is True
    assert m.leaf_state == s211

    test_list[:] = []
    m.dispatch(_e('h'))
    assert test_list == []
    assert m.leaf_state == s211
Exemplo n.º 27
0
def test_state_instance_passed_to_an_event_handler():
    m = StateMachine('m')
    s0 = StateMachine('s0')
    s1 = State('s1')
    s2 = State('s2')
    m.add_state(s0, initial=True)
    s0.add_state(s1, initial=True)
    s0.add_state(s2)

    def on_enter(state, event):
        source_event = event.cargo['source_event']
        source_event.cargo['test_list'].append(('enter', state))
        assert state == m.leaf_state

    def on_exit(state, event):
        source_event = event.cargo['source_event']
        source_event.cargo['test_list'].append(('exit', state))
        assert state == m.leaf_state

    def before(state, event):
        assert state == s1
        assert state == m.leaf_state

    def action(state, event):
        assert state == s1
        assert state == m.leaf_state

    def after(state, event):
        assert state == s2
        assert state == m.leaf_state

    def on_internal(state, event):
        assert state == s1
        assert state == m.leaf_state

    def do(state, event):
        # It's an action on the top machine, the `leaf_state` is NOT `state`
        assert state != m.leaf_state
        assert state == m

    def condition(state, event):
        assert state == s1
        assert state == m.leaf_state
        return True

    m.add_transition(s0, s0, events='a')
    s0.add_transition(s1, None, events=['internal'],
                      before=on_internal, action=on_internal, after=on_internal)
    s0.add_transition(s1, s2, events='b',
                      before=before, action=action, after=after, condition=condition)
    s0.add_transition(s2, s1, events='b')

    for state in [m, s0, s1, s2]:
        state.handlers = {'enter': on_enter, 'exit': on_exit}

    m.handlers = {'do': do}

    m.initialize()

    test_list = []
    m.dispatch(_e('a', test_list=test_list))
    assert test_list == [('exit', s1), ('exit', s0), ('enter', s0), ('enter', s1)]

    m.dispatch(_e('b', test_list=test_list))
    m.dispatch(_e('do'))
    m.dispatch(_e('b', test_list=test_list))

    m.dispatch(_e('internal'))
Exemplo n.º 28
0
def test_state_can_handle_hashable_types():
    my_mock = mock.Mock()
    test_set = frozenset([1, 2])

    m = StateMachine('m')
    s0 = State('s0')
    s1 = State('s1')

    m.add_state(s0, initial=True)
    m.add_state(s1)

    def do(state, event):
        my_mock(state, event.name)
        assert event.state_machine == m

    for state in s0, s1:
        state.handlers = {
            '&': do,
            frozenset([1,2]): do
        }

    m.add_transition(s0, s1, events=['&', test_set])
    m.add_transition(s1, s0, events=['&', test_set])
    m.initialize()
    assert m.leaf_state == s0
    m.dispatch(_e('&'))
    assert m.leaf_state == s1
    assert my_mock.call_args[0] == (s0, '&')
    m.dispatch(_e(test_set))
    assert m.leaf_state == s0
    assert my_mock.call_args[0] == (s1, test_set)
    m.dispatch(_e(test_set))
    assert m.leaf_state == s1
    m.dispatch(_e('&'))
    assert m.leaf_state == s0
    assert my_mock.call_count == 4
Exemplo n.º 29
0
def test_internal_transition():
    class Foo(object):
        def __init__(self):
            self.value = False
    foo = Foo()

    def on_enter(state, event):
        foo.value = True

    def on_exit(state, event):
        foo.value = True

    idling = State('idling')
    idling.handlers = {
        'enter': on_enter,
        'exit': on_exit,
    }

    sm = StateMachine('sm')
    sm.add_state(idling, initial=True)
    sm.add_transition(idling, None, events=['internal_transition'])
    sm.add_transition(idling, idling, events=['external_transition'])
    sm.initialize()
    sm.dispatch(_e('internal_transition'))
    assert foo.value is False
    sm.dispatch(_e('external_transition'))
    assert foo.value is True
Exemplo n.º 30
0
def test_state_can_handle_hashable_types():
    my_mock = mock.Mock()
    test_set = frozenset([1, 2])

    m = StateMachine('m')
    s0 = State('s0')
    s1 = State('s1')

    m.add_state(s0, initial=True)
    m.add_state(s1)

    def do(state, event):
        my_mock(state, event.name)
        assert event.state_machine == m

    for state in s0, s1:
        state.handlers = {'&': do, frozenset([1, 2]): do}

    m.add_transition(s0, s1, events=['&', test_set])
    m.add_transition(s1, s0, events=['&', test_set])
    m.initialize()
    assert m.leaf_state == s0
    m.dispatch(_e('&'))
    assert m.leaf_state == s1
    assert my_mock.call_args[0] == (s0, '&')
    m.dispatch(_e(test_set))
    assert m.leaf_state == s0
    assert my_mock.call_args[0] == (s1, test_set)
    m.dispatch(_e(test_set))
    assert m.leaf_state == s1
    m.dispatch(_e('&'))
    assert m.leaf_state == s0
    assert my_mock.call_count == 4
Exemplo n.º 31
0
def test_add_transition_event_with_input():
    sm = StateMachine('sm')
    s1 = State('s1')
    s2 = State('s2')
    s3 = State('s3')
    sm.add_state(s1, initial=True)
    sm.add_state(s2)
    sm.add_state(s3)

    sm.add_transition(s1, s2, events=['a'], input=['go_to_s2'])
    sm.add_transition(s1, s3, events=['a'], input=['go_to_s3'])
    sm.add_transition(s2, s1, events=['a'])
    sm.add_transition(s3, s1, events=['a'])
    sm.initialize()

    assert sm.state == s1
    sm.dispatch(_e('a', input='go_to_s2'))
    assert sm.state == s2
    sm.dispatch(_e('a'))
    assert sm.state == s1
    sm.dispatch(_e('a', input='go_to_s3'))
    assert sm.state == s3
    sm.dispatch(_e('a'))
    assert sm.state == s1
Exemplo n.º 32
0
def test_internal_transition():
    class Foo(object):
        def __init__(self):
            self.value = False

    foo = Foo()

    def on_enter(state, event):
        foo.value = True

    def on_exit(state, event):
        foo.value = True

    idling = State('idling')
    idling.handlers = {
        'enter': on_enter,
        'exit': on_exit,
    }

    sm = StateMachine('sm')
    sm.add_state(idling, initial=True)
    sm.add_transition(idling, None, events=['internal_transition'])
    sm.add_transition(idling, idling, events=['external_transition'])
    sm.initialize()
    sm.dispatch(_e('internal_transition'))
    assert foo.value is False
    sm.dispatch(_e('external_transition'))
    assert foo.value is True
Exemplo n.º 33
0
def test_transition_to_history():
    oven = StateMachine('Oven')
    door_closed = StateMachine('DoorClosed')
    door_open = State('DoorOpen')
    heating = StateMachine('Heating')
    toasting = State('Toasting')
    baking = State('Baking')
    off = State('Off')

    oven.add_state(door_closed, initial=True)
    oven.add_state(door_open)
    door_closed.add_state(off, initial=True)
    door_closed.add_state(heating)
    heating.add_state(baking, initial=True)
    heating.add_state(toasting)

    oven.add_transition(door_closed, toasting, events=['toast'])
    oven.add_transition(door_closed, baking, events=['bake'])
    oven.add_transition(door_closed, off, events=['off', 'timeout'])
    oven.add_transition(door_closed, door_open, events=['open'])

    door_open.handlers = {'close': lambda s, e: oven.set_previous_leaf_state()}

    oven.initialize()

    assert oven.leaf_state == off
    oven.dispatch(_e('open'))
    assert oven.leaf_state == door_open
    try:
        oven.dispatch(_e('close'))
    except Exception as exc:
        assert not exc
    assert oven.leaf_state == off
    assert list(oven.leaf_state_stack.deque) == [off, door_open]

    oven.dispatch(_e('bake'))
    assert oven.leaf_state == baking
    oven.dispatch(_e('open'))
    assert oven.leaf_state == door_open
    try:
        oven.dispatch(_e('close'))
    except Exception as exc:
        assert not exc
    assert oven.leaf_state == baking
    expected = [off, door_open, off, baking, door_open]
    assert list(oven.leaf_state_stack.deque) == expected
Exemplo n.º 34
0
def test_hsm_get_transition():
    sm = StateMachine('sm')
    s0 = StateMachine('s0')
    s1 = StateMachine('s1')
    s2 = StateMachine('s2')
    s0.add_state(s1)
    s0.add_state(s2)
    s0.add_transition(s1, s2, events='a')
    s11 = State('s11')
    s12 = State('s12')
    sm.add_state(s0, initial=True)
    s0.add_state(s1, initial=True)
    s1.add_state(s11, initial=True)
    sm.initialize()
    transition = sm._get_transition(_e('a'))
    assert s1 == transition['from_state']
    assert s2 == transition['to_state']
Exemplo n.º 35
0
def test_add_state_that_is_already_added_anywhere_in_the_hsm():
    sm = StateMachine('sm')
    s1 = State('s1')
    s2 = State('s2')
    s3 = StateMachine('s3')
    s31 = State('s31')
    s32 = State('s32')

    sm.add_state(s1)
    sm.add_state(s2)
    sm.add_state(s3)
    s3.add_state(s31)
    s3.add_state(s32)

    with pytest.raises(StateMachineException) as exc:
        s3.add_state(s2)
    expected = ('Machine "s3" error: State "s2" is already added '
                'to machine "sm"')
    assert expected in str(exc.value)
Exemplo n.º 36
0
def test_enter_exit_on_transitions():
    test_list = []

    def on_enter(state, event):
        test_list.append(('enter', state))

    def on_exit(state, event):
        test_list.append(('exit', state))

    m = StateMachine('m')
    # exit = m.add_state('exit', terminal=True)
    s0 = StateMachine('s0')
    s1 = StateMachine('s1')
    s2 = StateMachine('s2')

    s11 = State('s11')
    s21 = StateMachine('s21')
    s211 = State('s211')
    s212 = State('s212')

    m.add_state(s0, initial=True)
    s0.add_state(s1, initial=True)
    s0.add_state(s2)
    s1.add_state(s11, initial=True)
    s2.add_state(s21, initial=True)
    s21.add_state(s211, initial=True)
    s21.add_state(s212)

    states = [m, s0, s1, s11, s2, s21, s211, s212]
    for state in states:
        state.handlers = {'enter': on_enter, 'exit': on_exit}

    s0.add_transition(s1, s1, events='a')
    s0.add_transition(s1, s11, events='b')
    s2.add_transition(s21, s211, events='b')
    s0.add_transition(s1, s2, events='c')
    s0.add_transition(s2, s1, events='c')
    s0.add_transition(s1, s0, events='d')
    s21.add_transition(s211, s21, events='d')
    m.add_transition(s0, s211, events='e')
    m.add_transition(s0, s212, events='z')
    s0.add_transition(s2, s11, events='f')
    s0.add_transition(s1, s211, events='f')
    s1.add_transition(s11, s211, events='g')
    s21.add_transition(s211, s0, events='g')

    m.initialize()

    test_list[:] = []
    m.dispatch(_e('a'))
    assert test_list == [('exit', s11), ('exit', s1), ('enter', s1),
                         ('enter', s11)]

    test_list[:] = []
    m.dispatch(_e('b'))
    assert test_list == [('exit', s11), ('enter', s11)]
    m.dispatch(_e('c'))
    test_list[:] = []
    m.dispatch(_e('b'))
    assert test_list == [('exit', s211), ('enter', s211)]
    m.dispatch(_e('c'))

    test_list[:] = []
    m.dispatch(_e('c'))
    assert test_list == [('exit', s11), ('exit', s1), ('enter', s2),
                         ('enter', s21), ('enter', s211)]
    test_list[:] = []
    m.dispatch(_e('c'))
    assert test_list == [('exit', s211), ('exit', s21), ('exit', s2),
                         ('enter', s1), ('enter', s11)]

    test_list[:] = []
    m.dispatch(_e('d'))
    assert test_list == [('exit', s11), ('exit', s1), ('enter', s1),
                         ('enter', s11)]
    m.dispatch(_e('c'))
    test_list[:] = []
    m.dispatch(_e('d'))
    assert test_list == [('exit', s211), ('enter', s211)]
    m.dispatch(_e('c'))

    test_list[:] = []
    m.dispatch(_e('e'))
    assert test_list == [('exit', s11), ('exit', s1), ('enter', s2),
                         ('enter', s21), ('enter', s211)]
    test_list[:] = []
    m.dispatch(_e('e'))
    assert test_list == [('exit', s211), ('exit', s21), ('exit', s2),
                         ('enter', s2), ('enter', s21), ('enter', s211)]

    test_list[:] = []
    m.dispatch(_e('f'))
    assert test_list == [('exit', s211), ('exit', s21), ('exit', s2),
                         ('enter', s1), ('enter', s11)]
    test_list[:] = []
    m.dispatch(_e('f'))
    assert test_list == [('exit', s11), ('exit', s1), ('enter', s2),
                         ('enter', s21), ('enter', s211)]

    test_list[:] = []
    m.dispatch(_e('g'))
    assert test_list == [('exit', s211), ('exit', s21), ('exit', s2),
                         ('enter', s1), ('enter', s11)]
    test_list[:] = []
    m.dispatch(_e('g'))
    assert test_list == [('exit', s11), ('exit', s1), ('enter', s2),
                         ('enter', s21), ('enter', s211)]

    test_list[:] = []
    m.dispatch(_e('z'))
    assert test_list == [('exit', s211), ('exit', s21), ('exit', s2),
                         ('enter', s2), ('enter', s21), ('enter', s212)]
    assert m.leaf_state == s212

    test_list[:] = []
    m.dispatch(_e('c'))
    assert test_list == [('exit', s212), ('exit', s21), ('exit', s2),
                         ('enter', s1), ('enter', s11)]
    assert m.leaf_state == s11

    test_list[:] = []
    m.dispatch(_e('g'))
    assert m.leaf_state == s211
    assert test_list == [('exit', s11), ('exit', s1), ('enter', s2),
                         ('enter', s21), ('enter', s211)]
    assert m.leaf_state == s211
Exemplo n.º 37
0
def test_state_stack_high_tree():
    sm = StateMachine('sm')
    s0 = StateMachine('s0')
    s01 = StateMachine('s01')
    s011 = StateMachine('s011')
    s0111 = State('s0111')
    s0112 = State('s0112')
    s0113 = StateMachine('s0113')
    s01131 = State('s01131')

    sm.add_state(s0, initial=True)
    s0.add_state(s01, initial=True)
    s01.add_state(s011, initial=True)
    s011.add_state(s0111, initial=True)
    s011.add_state(s0112)
    s011.add_state(s0113)
    s0113.add_state(s01131, initial=True)

    s011.add_transition(s0111, s0113, events=['a'])
    sm.initialize()

    assert sm.leaf_state == s0111
    sm.dispatch(_e('a'))
    assert list(sm.state_stack.deque) == []
    assert list(s0.state_stack.deque) == []
    assert list(s01.state_stack.deque) == []
    assert list(s011.state_stack.deque) == [s0111]
    assert list(s011.leaf_state_stack.deque) == []
    assert list(s0113.state_stack.deque) == []
    assert list(sm.leaf_state_stack.deque) == [s0111]
Exemplo n.º 38
0
def test_add_transition_unknown_state():
    sm = StateMachine('sm')
    s1 = State('s1')
    s2 = State('s2')  # This state isn't added to sm
    s3 = StateMachine('s3')
    s31 = State('s31')
    s32 = State('s32')  # This state isn't added to s3

    sm.add_state(s1)
    sm.add_state(s3)
    s3.add_state(s31)

    with pytest.raises(StateMachineException) as exc:
        sm.add_transition(s1, s2, events='a')
    expected = (
        'Machine "sm" error: Unable to add transition to unknown state "s2"')
    assert expected in str(exc.value)

    with pytest.raises(StateMachineException) as exc:
        sm.add_transition(s2, s1, events='a')
    expected = (
        'Machine "sm" error: Unable to add transition from unknown state "s2"')
    assert expected in str(exc.value)

    with pytest.raises(StateMachineException) as exc:
        sm.add_transition(s1, s32, events='a')
    expected = (
        'Machine "sm" error: Unable to add transition to unknown state "s32"')
    assert expected in str(exc.value)

    with pytest.raises(StateMachineException) as exc:
        sm.add_transition(s32, s1, events='a')
    expected = (
        'Machine "sm" error: Unable to add transition from unknown state "s32"'
    )
    assert expected in str(exc.value)
Exemplo n.º 39
0
def test_add_transition_event_with_input():
    sm = StateMachine('sm')
    s1 = State('s1')
    s2 = State('s2')
    s3 = State('s3')
    sm.add_state(s1, initial=True)
    sm.add_state(s2)
    sm.add_state(s3)

    sm.add_transition(s1, s2, events=['a'], input=['go_to_s2'])
    sm.add_transition(s1, s3, events=['a'], input=['go_to_s3'])
    sm.add_transition(s2, s1, events=['a'])
    sm.add_transition(s3, s1, events=['a'])
    sm.initialize()

    assert sm.state == s1
    sm.dispatch(_e('a', input='go_to_s2'))
    assert sm.state == s2
    sm.dispatch(_e('a'))
    assert sm.state == s1
    sm.dispatch(_e('a', input='go_to_s3'))
    assert sm.state == s3
    sm.dispatch(_e('a'))
    assert sm.state == s1
Exemplo n.º 40
0
def test_hsm_get_transition():
    sm = StateMachine('sm')
    s0 = StateMachine('s0')
    s1 = StateMachine('s1')
    s2 = StateMachine('s2')
    s0.add_state(s1)
    s0.add_state(s2)
    s0.add_transition(s1, s2, events='a')
    s11 = State('s11')
    s12 = State('s12')
    sm.add_state(s0, initial=True)
    s0.add_state(s1, initial=True)
    s1.add_state(s11, initial=True)
    sm.initialize()
    transition = sm._get_transition(_e('a'))
    assert s1 == transition['from_state']
    assert s2 == transition['to_state']
Exemplo n.º 41
0
def test_enter_exit_on_transitions():
    test_list = []

    m = StateMachine('m')
    # exit = m.add_state('exit', terminal=True)
    s0 = StateMachine('s0')
    s1 = StateMachine('s1')
    s2 = StateMachine('s2')

    def on_enter(state, event):
        assert state == m.leaf_state
        test_list.append(('enter', state))

    def on_exit(state, event):
        assert state == m.leaf_state
        test_list.append(('exit', state))

    s11 = State('s11')
    s21 = StateMachine('s21')
    s211 = State('s211')
    s212 = State('s212')

    m.add_state(s0, initial=True)
    s0.add_state(s1, initial=True)
    s0.add_state(s2)
    s1.add_state(s11, initial=True)
    s2.add_state(s21, initial=True)
    s21.add_state(s211, initial=True)
    s21.add_state(s212)

    states = [m, s0, s1, s11, s2, s21, s211, s212]
    for state in states:
        state.handlers = {'enter': on_enter, 'exit': on_exit}

    s0.add_transition(s1, s1, events='a')
    s0.add_transition(s1, s11, events='b')
    s2.add_transition(s21, s211, events='b')
    s0.add_transition(s1, s2, events='c')
    s0.add_transition(s2, s1, events='c')
    s0.add_transition(s1, s0, events='d')
    s21.add_transition(s211, s21, events='d')
    m.add_transition(s0, s211, events='e')
    m.add_transition(s0, s212, events='z')
    s0.add_transition(s2, s11, events='f')
    s0.add_transition(s1, s211, events='f')
    s1.add_transition(s11, s211, events='g')
    s21.add_transition(s211, s0, events='g')

    m.initialize()

    test_list[:] = []
    m.dispatch(_e('a'))
    assert test_list == [('exit', s11), ('exit', s1), ('enter', s1), ('enter', s11)]

    test_list[:] = []
    m.dispatch(_e('b'))
    assert test_list == [('exit', s11), ('enter', s11)]
    m.dispatch(_e('c'))
    test_list[:] = []
    m.dispatch(_e('b'))
    assert test_list == [('exit', s211), ('enter', s211)]
    m.dispatch(_e('c'))

    test_list[:] = []
    m.dispatch(_e('c'))
    assert test_list == [('exit', s11), ('exit', s1), ('enter', s2), ('enter', s21), ('enter', s211)]
    test_list[:] = []
    m.dispatch(_e('c'))
    assert test_list == [('exit', s211), ('exit', s21),  ('exit', s2), ('enter', s1), ('enter', s11)]

    test_list[:] = []
    m.dispatch(_e('d'))
    assert test_list == [('exit', s11), ('exit', s1),  ('enter', s1), ('enter', s11)]
    m.dispatch(_e('c'))
    test_list[:] = []
    m.dispatch(_e('d'))
    assert test_list == [('exit', s211), ('enter', s211)]
    m.dispatch(_e('c'))

    test_list[:] = []
    m.dispatch(_e('e'))
    assert test_list == [('exit', s11), ('exit', s1),  ('enter', s2), ('enter', s21), ('enter', s211)]
    test_list[:] = []
    m.dispatch(_e('e'))
    assert test_list == [('exit', s211), ('exit', s21),  ('exit', s2), ('enter', s2), ('enter', s21), ('enter', s211)]

    test_list[:] = []
    m.dispatch(_e('f'))
    assert test_list == [('exit', s211), ('exit', s21),  ('exit', s2), ('enter', s1), ('enter', s11)]
    test_list[:] = []
    m.dispatch(_e('f'))
    assert test_list == [('exit', s11), ('exit', s1),  ('enter', s2), ('enter', s21), ('enter', s211)]

    test_list[:] = []
    m.dispatch(_e('g'))
    assert test_list == [('exit', s211), ('exit', s21),  ('exit', s2), ('enter', s1), ('enter', s11)]
    test_list[:] = []
    m.dispatch(_e('g'))
    assert test_list == [('exit', s11), ('exit', s1),  ('enter', s2), ('enter', s21), ('enter', s211)]

    test_list[:] = []
    m.dispatch(_e('z'))
    assert test_list == [('exit', s211), ('exit', s21), ('exit', s2), ('enter', s2), ('enter', s21), ('enter', s212)]
    assert m.leaf_state == s212

    test_list[:] = []
    m.dispatch(_e('c'))
    assert test_list == [('exit', s212), ('exit', s21), ('exit', s2), ('enter', s1), ('enter', s11)]
    assert m.leaf_state == s11

    test_list[:] = []
    m.dispatch(_e('g'))
    assert m.leaf_state == s211
    assert test_list == [('exit', s11), ('exit', s1),  ('enter', s2), ('enter', s21), ('enter', s211)]
    assert m.leaf_state == s211
Exemplo n.º 42
0
    def _get_state_machine(self):
        oven = StateMachine('Oven')
        door_closed = StateMachine('Door closed')
        door_open = State('Door open')
        heating = HeatingState('Heating')
        toasting = State('Toasting')
        baking = State('Baking')
        off = State('Off')

        oven.add_state(door_closed, initial=True)
        oven.add_state(door_open)
        door_closed.add_state(off, initial=True)
        door_closed.add_state(heating)
        heating.add_state(baking, initial=True)
        heating.add_state(toasting)

        oven.add_transition(door_closed, toasting, events=['toast'])
        oven.add_transition(door_closed, baking, events=['bake'])
        oven.add_transition(door_closed, off, events=['off', 'timeout'])
        oven.add_transition(door_closed, door_open, events=['open'])

        # This time, a state behaviour is handled by Oven's methods.
        door_open.handlers = {
            'enter': self.on_open_enter,
            'exit': self.on_open_exit,
            'close': self.on_door_close
        }

        oven.initialize()
        return oven
Exemplo n.º 43
0
def test_add_transition_unknown_state():
    sm = StateMachine('sm')
    s1 = State('s1')
    s2 = State('s2')  # This state isn't added to sm
    s3 = StateMachine('s3')
    s31 = State('s31')
    s32 = State('s32')  # This state isn't added to s3

    sm.add_state(s1)
    sm.add_state(s3)
    s3.add_state(s31)

    with pytest.raises(StateMachineException) as exc:
        sm.add_transition(s1, s2, events='a')
    expected = (
        'Machine "sm" error: Unable to add transition to unknown state "s2"')
    assert expected in str(exc.value)

    with pytest.raises(StateMachineException) as exc:
        sm.add_transition(s2, s1, events='a')
    expected = (
        'Machine "sm" error: Unable to add transition from unknown state "s2"')
    assert expected in str(exc.value)

    with pytest.raises(StateMachineException) as exc:
        sm.add_transition(s1, s32, events='a')
    expected = (
        'Machine "sm" error: Unable to add transition to unknown state "s32"')
    assert expected in str(exc.value)

    with pytest.raises(StateMachineException) as exc:
        sm.add_transition(s32, s1, events='a')
    expected = (
        'Machine "sm" error: Unable to add transition from unknown state "s32"')
    assert expected in str(exc.value)
Exemplo n.º 44
0
def test_state_stack():
    sm = StateMachine('sm')
    s1 = State('s1')
    s2 = State('s2')
    s3 = StateMachine('s3')
    s31 = State('s31')
    s32 = State('s32')

    sm.add_state(s1, initial=True)
    sm.add_state(s2)
    sm.add_state(s3)
    s3.add_state(s31, initial=True)
    s3.add_state(s32)

    sm.add_transition(s1, s2, events=['s1->s2'])
    sm.add_transition(s2, s1, events=['s2->s1'])
    sm.add_transition(s1, s3, events=['a'])
    s3.add_transition(s31, s32, events=['b'])
    sm.initialize()

    assert sm.state == s1
    assert sm.leaf_state == s1

    sm.dispatch(_e('s1->s2'))
    assert sm.state == s2
    assert sm.leaf_state == s2
    assert list(sm.state_stack.deque) == [s1]

    sm.dispatch(_e('s2->s1'))
    assert sm.state == s1
    assert sm.leaf_state == s1
    assert list(sm.state_stack.deque) == [s1, s2]

    sm.dispatch(_e('a'))
    assert sm.state == s3
    assert sm.leaf_state == s31
    assert s3.leaf_state == s31
    assert list(sm.state_stack.deque) == [s1, s2, s1]
    assert list(s3.state_stack.deque) == []

    sm.dispatch(_e('b'))
    assert sm.state == s3
    assert sm.leaf_state == s32
    assert s3.state == s32
    assert s3.leaf_state == s32
    assert list(sm.state_stack.deque) == [s1, s2, s1]
    assert list(s3.state_stack.deque) == [s31]

    # Brute force rollback of the previous state
    s3.state = s3.state_stack.pop()
    sm.state = sm.state_stack.pop()
    assert sm.state == s1
    assert sm.leaf_state == s1
    assert s3.state == s31
    assert s3.leaf_state == s31
    assert list(sm.state_stack.deque) == [s1, s2]
    assert list(s3.state_stack.deque) == []
Exemplo n.º 45
0
def test_revert_to_previous_state():
    m = StateMachine('m')
    off = State('Off')
    on = State('On')
    m.add_state(off, initial=True)
    m.add_state(on)
    m.add_transition(on, off, events=['off'])
    m.add_transition(off, on, events=['on'])
    m.initialize()
    off.handlers = {
        'test_no_history': lambda s, e: m.revert_to_previous_leaf_state()
    }

    assert m.leaf_state == off
    try:
        m.dispatch(_e('test_no_history'))
    except Exception as exc:
        assert not exc
    assert m.leaf_state == off
    assert list(m.leaf_state_stack.deque) == []

    m.dispatch(_e('on'))
    assert m.leaf_state == on
    assert list(m.leaf_state_stack.deque) == [off]
    m.dispatch(_e('off'))
    assert m.leaf_state == off
    assert list(m.leaf_state_stack.deque) == [off, on]

    try:
        m.dispatch(_e('test_no_history'))
    except Exception as exc:
        assert not exc
    assert m.leaf_state == on
    assert list(m.leaf_state_stack.deque) == [off]

    # Nothing should change now as the "on" state doesn't handle the
    # "test_no_history"" event.
    try:
        m.dispatch(_e('test_no_history'))
    except Exception as exc:
        assert not exc
    assert m.leaf_state == on
    assert list(m.leaf_state_stack.deque) == [off]
Exemplo n.º 46
0
def test_transition_from_and_to_machine_itself():
    sm = StateMachine('sm')
    s1 = State('s1')
    s2 = State('s2')
    sm.add_state(s1, initial=True)
    sm.add_state(s2)

    with pytest.raises(StateMachineException) as exc:
        sm.add_transition(sm, s1, events=['sm->s1'])
    expected = (
        'Machine "sm" error: Unable to add transition from unknown state "sm"')
    assert expected in str(exc.value)
    sm.add_transition(s1, sm, events=['s1->sm'])
    sm.initialize()

    assert sm.state == s1
    sm.dispatch(_e('sm->s1'))
    assert sm.state == s1
    assert list(sm.state_stack.deque) == []
    sm.dispatch(_e('s1->sm'))
    assert sm.state == s1
    assert list(sm.state_stack.deque) == [s1]
    sm.dispatch(_e('sm->s1'))
    assert sm.state == s1
    assert list(sm.state_stack.deque) == [s1]
    sm.dispatch(_e('s1->sm'))
    assert sm.state == s1
    assert list(sm.state_stack.deque) == [s1, s1]
Exemplo n.º 47
0
from pysm import State, StateMachine, Event

on = State('on')
off = State('off')

sm = StateMachine('sm')
sm.add_state(on, initial=True)
sm.add_state(off)

sm.add_transition(on, off, events=['off'])
sm.add_transition(off, on, events=['on'])

sm.initialize()

def test():
    assert sm.state == on
    sm.dispatch(Event('off'))
    assert sm.state == off
    sm.dispatch(Event('on'))
    assert sm.state == on


if __name__ == '__main__':
    test()
Exemplo n.º 48
0
def test_transition_to_history():
    oven = StateMachine('Oven')
    door_closed = StateMachine('DoorClosed')
    door_open = State('DoorOpen')
    heating = StateMachine('Heating')
    toasting = State('Toasting')
    baking = State('Baking')
    off = State('Off')

    oven.add_state(door_closed, initial=True)
    oven.add_state(door_open)
    door_closed.add_state(off, initial=True)
    door_closed.add_state(heating)
    heating.add_state(baking, initial=True)
    heating.add_state(toasting)

    oven.add_transition(door_closed, toasting, events=['toast'])
    oven.add_transition(door_closed, baking, events=['bake'])
    oven.add_transition(door_closed, off, events=['off', 'timeout'])
    oven.add_transition(door_closed, door_open, events=['open'])

    door_open.handlers = {'close': lambda s, e: oven.set_previous_leaf_state()}

    oven.initialize()

    assert oven.leaf_state == off
    oven.dispatch(_e('open'))
    assert oven.leaf_state == door_open
    try:
        oven.dispatch(_e('close'))
    except Exception as exc:
        assert not exc
    assert oven.leaf_state == off
    assert list(oven.leaf_state_stack.deque) == [off, door_open]

    oven.dispatch(_e('bake'))
    assert oven.leaf_state == baking
    oven.dispatch(_e('open'))
    assert oven.leaf_state == door_open
    try:
        oven.dispatch(_e('close'))
    except Exception as exc:
        assert not exc
    assert oven.leaf_state == baking
    expected = [off, door_open, off, baking, door_open]
    assert list(oven.leaf_state_stack.deque) == expected
Exemplo n.º 49
0
    print('action_l')

def action_m(state, event):
    print('action_m')

def action_n(state, event):
    print('action_n')

def is_foo(state, event):
    return foo is True

def is_not_foo(state, event):
    return foo is False


m = StateMachine('m')
s0 = StateMachine('s0')
s1 = StateMachine('s1')
s2 = StateMachine('s2')
s11 = State('s11')
s21 = StateMachine('s21')
s211 = State('s211')

m.add_state(s0, initial=True)
s0.add_state(s1, initial=True)
s0.add_state(s2)
s1.add_state(s11, initial=True)
s2.add_state(s21, initial=True)
s21.add_state(s211, initial=True)

# Internal transitions
Exemplo n.º 50
0
def test_revert_to_previous_state():
    m = StateMachine('m')
    off = State('Off')
    on = State('On')
    m.add_state(off, initial=True)
    m.add_state(on)
    m.add_transition(on, off, events=['off'])
    m.add_transition(off, on, events=['on'])
    m.initialize()
    off.handlers = {
        'test_no_history': lambda s, e: m.revert_to_previous_leaf_state()
    }

    assert m.leaf_state == off
    try:
        m.dispatch(_e('test_no_history'))
    except Exception as exc:
        assert not exc
    assert m.leaf_state == off
    assert list(m.leaf_state_stack.deque) == []

    m.dispatch(_e('on'))
    assert m.leaf_state == on
    assert list(m.leaf_state_stack.deque) == [off]
    m.dispatch(_e('off'))
    assert m.leaf_state == off
    assert list(m.leaf_state_stack.deque) == [off, on]

    try:
        m.dispatch(_e('test_no_history'))
    except Exception as exc:
        assert not exc
    assert m.leaf_state == on
    assert list(m.leaf_state_stack.deque) == [off, on]
Exemplo n.º 51
0
    def _get_state_machine(self):
        oven = StateMachine(
            'Oven'
        )  # composition: Oven not isa StateMachine but contains one, linked below ((KXOQEIF))
        door_closed = StateMachine('Door closed')  # a StateMachine isa State
        door_open = State('Door open')
        heating = HeatingState()
        off = State('Off')

        oven.add_state(door_closed, initial=True)
        oven.add_state(door_open)
        door_closed.add_state(off, initial=True)
        door_closed.add_state(heating)

        # https://pysm.readthedocs.io/en/latest/pysm_module.html
        # So the order of calls on an event is as follows:
        # State’s event handler
        # condition callback
        # # before callback
        # exit handlers
        # action callback
        # enter handlers
        # after callback

        oven.add_transition(door_closed,
                            heating.toasting,
                            events=['toast'],
                            after=heating.action)
        oven.add_transition(door_closed,
                            heating.baking,
                            events=['bake'],
                            after=heating.action)
        oven.add_transition(door_closed, off, events=['off', 'timeout'])
        oven.add_transition(door_closed, door_open, events=['open'])

        # This time, a state behaviour is handled by Oven's methods.
        # ((KXOQEIF))
        door_open.handlers = {
            'enter': self.on_open_enter,
            'exit': self.on_open_exit,
            'close': self.on_door_close
        }

        # https://pysm.readthedocs.io/en/latest/pysm_module.html
        # If using nested state machines (HSM), initialize() has to be called on a root state machine in the hierarchy.
        oven.initialize()
        return oven
Exemplo n.º 52
0
 def __init__(self):
     super().__init__()
     self.sm = StateMachine("sm")
Exemplo n.º 53
0
def test_state_machine_reference_present_in_event_with_nested_machines():
    m = StateMachine('m')
    s0 = StateMachine('s0')
    s1 = StateMachine('s1')
    s2 = State('s2')

    m.add_state(s0, initial=True)
    s0.add_state(s1, initial=True)
    s1.add_state(s2, initial=True)

    def do(state, event):
        assert event.state_machine == m
        assert state == m.leaf_state

    for state in s0, s1, s2:
        state.handlers = {'enter': do, 'exit': do, 'do': do}

    m.add_transition(s0, s2, events=['do'])
    m.initialize()
    m.dispatch(_e('do'))
Exemplo n.º 54
0
    def _get_statemachine(self):
        dlg = StateMachine('memlog dialog')
        self.at_top = State('at top')
        self.in_middle = State('in middle')
        self.at_bottom = State('at bottom')

        dlg.add_state(self.at_top, initial=True)
        self.window_cursor_pos = 0
        self.total_cursor_pos = 0
        self.total_at_top_pos = 0
        dlg.add_state(self.in_middle)
        dlg.add_state(self.at_bottom)

        dlg.add_transition(self.at_top,
                           self.in_middle,
                           events=['down_key'],
                           action=self.move_down)
        dlg.add_transition(self.at_bottom,
                           self.in_middle,
                           events=['up_key'],
                           action=self.move_up)

        # higher specificity: external transition, logically overwrites external transition (because it comes first)
        # IMPORTANT: add first, otherwise the up_key/down_key events are always handled by the 2 internal transitions below
        dlg.add_transition(self.in_middle,
                           self.at_top,
                           events=['up_key'],
                           condition=self.is_at_second,
                           action=self.move_up)
        dlg.add_transition(self.in_middle,
                           self.at_bottom,
                           events=['down_key'],
                           condition=self.is_at_second_last,
                           action=self.move_down)

        # lower specificity: internal transition
        dlg.add_transition(self.in_middle,
                           None,
                           events=['up_key'],
                           action=self.move_up)
        dlg.add_transition(self.in_middle,
                           None,
                           events=['down_key'],
                           action=self.move_down)

        dlg.add_transition(self.at_top,
                           None,
                           events=['up_key'],
                           condition=self.has_more_up,
                           action=self.scroll_up)
        dlg.add_transition(self.at_bottom,
                           None,
                           events=['down_key'],
                           condition=self.has_more_down,
                           action=self.scroll_down)

        dlg.initialize()
        return dlg
Exemplo n.º 55
0
    def _get_state_machine(self):
        oven = StateMachine('Oven')
        door_closed = StateMachine('Door closed')
        door_open = State('Door open')
        heating = HeatingState('Heating')
        toasting = State('Toasting')
        baking = State('Baking')
        off = State('Off')

        oven.add_state(door_closed, initial=True)
        oven.add_state(door_open)
        door_closed.add_state(off, initial=True)
        door_closed.add_state(heating)
        heating.add_state(baking, initial=True)
        heating.add_state(toasting)

        oven.add_transition(door_closed, toasting, events=['toast'])
        oven.add_transition(door_closed, baking, events=['bake'])
        oven.add_transition(door_closed, off, events=['off', 'timeout'])
        oven.add_transition(door_closed, door_open, events=['open'])

        # This time, a state behaviour is handled by Oven's methods.
        door_open.handlers = {
            'enter': self.on_open_enter,
            'exit': self.on_open_exit,
            'close': self.on_door_close
        }

        oven.initialize()
        return oven
Exemplo n.º 56
0
    def init_statemachine(self):
        self.m = StateMachine('m')
        self.s0 = StateMachine('s0')
        self.s1 = StateMachine('s1')
        self.s2 = StateMachine('s2')
        self.s11 = State('s11')
        self.s21 = StateMachine('s21')
        self.s211 = State('s211')

        m = self.m
        s0 = self.s0
        s1 = self.s1
        s2 = self.s2
        s11 = self.s11
        s21 = self.s21
        s211 = self.s211

        m.add_state(s0, initial=True)
        s0.add_state(s1, initial=True)
        s0.add_state(s2)
        s1.add_state(s11, initial=True)
        s2.add_state(s21, initial=True)
        s21.add_state(s211, initial=True)

        # Internal transitions
        # beziehen events und angehängte actions, die auf den state gehen
        m.add_transition(s0, None, events='i', action=self.action_i)
        s0.add_transition(s1, None, events='j', action=self.action_j)
        s0.add_transition(s2, None, events='k', action=self.action_k)
        s1.add_transition(s11,
                          None,
                          events='h',
                          condition=self.is_foo,
                          action=self.unset_foo)
        s1.add_transition(s11, None, events='n', action=self.action_n)
        s21.add_transition(s211, None, events='m', action=self.action_m)
        s2.add_transition(s21,
                          None,
                          events='l',
                          condition=self.is_foo,
                          action=self.action_l)

        # External transition
        m.add_transition(s0, s211, events='e')
        s0.add_transition(s1, s0, events='d')
        s0.add_transition(s1, s11, events='b')
        s0.add_transition(s1, s1, events='a')
        s0.add_transition(s1, s211, events='f')
        s0.add_transition(s1, s2, events='c')
        s0.add_transition(s2, s11, events='f')
        s0.add_transition(s2, s1, events='c')
        s1.add_transition(s11, s211, events='g')
        s21.add_transition(s211, s0, events='g')
        s21.add_transition(s211, s21, events='d')
        s2.add_transition(s21, s211, events='b')
        s2.add_transition(s21,
                          s21,
                          events='h',
                          condition=self.is_not_foo,
                          action=self.set_foo)

        # Attach enter/exit handlers
        states = [m, s0, s1, s11, s2, s21, s211]
        for state in states:
            state.handlers = {'enter': self.on_enter, 'exit': self.on_exit}

        self.m.initialize()
Exemplo n.º 57
0
 def get_state_machine(self):
     sm = StateMachine('sm')
     initial = State('Initial')
     number = State('BuildingNumber')
     sm.add_state(initial, initial=True)
     sm.add_state(number)
     sm.add_transition(initial, number,
                       events=['parse'], input=py_string.digits,
                       action=self.start_building_number)
     sm.add_transition(number, None,
                       events=['parse'], input=py_string.digits,
                       action=self.build_number)
     sm.add_transition(number, initial,
                       events=['parse'], input=py_string.whitespace)
     sm.add_transition(initial, None,
                       events=['parse'], input='+-*/',
                       action=self.do_operation)
     sm.add_transition(initial, None,
                       events=['parse'], input='=',
                       action=self.do_equal)
     sm.initialize()
     return sm
Exemplo n.º 58
0
class Statemachine1:
    def __init__(self):
        self.foo = True
        self.init_statemachine()

    def init_statemachine(self):
        self.m = StateMachine('m')
        self.s0 = StateMachine('s0')
        self.s1 = StateMachine('s1')
        self.s2 = StateMachine('s2')
        self.s11 = State('s11')
        self.s21 = StateMachine('s21')
        self.s211 = State('s211')

        m = self.m
        s0 = self.s0
        s1 = self.s1
        s2 = self.s2
        s11 = self.s11
        s21 = self.s21
        s211 = self.s211

        m.add_state(s0, initial=True)
        s0.add_state(s1, initial=True)
        s0.add_state(s2)
        s1.add_state(s11, initial=True)
        s2.add_state(s21, initial=True)
        s21.add_state(s211, initial=True)

        # Internal transitions
        # beziehen events und angehängte actions, die auf den state gehen
        m.add_transition(s0, None, events='i', action=self.action_i)
        s0.add_transition(s1, None, events='j', action=self.action_j)
        s0.add_transition(s2, None, events='k', action=self.action_k)
        s1.add_transition(s11,
                          None,
                          events='h',
                          condition=self.is_foo,
                          action=self.unset_foo)
        s1.add_transition(s11, None, events='n', action=self.action_n)
        s21.add_transition(s211, None, events='m', action=self.action_m)
        s2.add_transition(s21,
                          None,
                          events='l',
                          condition=self.is_foo,
                          action=self.action_l)

        # External transition
        m.add_transition(s0, s211, events='e')
        s0.add_transition(s1, s0, events='d')
        s0.add_transition(s1, s11, events='b')
        s0.add_transition(s1, s1, events='a')
        s0.add_transition(s1, s211, events='f')
        s0.add_transition(s1, s2, events='c')
        s0.add_transition(s2, s11, events='f')
        s0.add_transition(s2, s1, events='c')
        s1.add_transition(s11, s211, events='g')
        s21.add_transition(s211, s0, events='g')
        s21.add_transition(s211, s21, events='d')
        s2.add_transition(s21, s211, events='b')
        s2.add_transition(s21,
                          s21,
                          events='h',
                          condition=self.is_not_foo,
                          action=self.set_foo)

        # Attach enter/exit handlers
        states = [m, s0, s1, s11, s2, s21, s211]
        for state in states:
            state.handlers = {'enter': self.on_enter, 'exit': self.on_exit}

        self.m.initialize()

    def on_enter(self, state, event):
        print('enter state {0}'.format(state.name))

    def on_exit(self, state, event):
        print('exit state {0}'.format(state.name))

    def set_foo(self, state, event):
        global foo
        print('set foo')
        self.foo = True

    def unset_foo(self, state, event):
        global foo
        print('unset foo')
        self.foo = False

    def action_i(self, state, event):
        print('action_i')

    def action_j(self, state, event):
        print('action_j')

    def action_k(self, state, event):
        print('action_k')

    def action_l(self, state, event):
        print('action_l')

    def action_m(self, state, event):
        print('action_m')

    def action_n(self, state, event):
        print('action_n')

    def is_foo(self, state, event):
        return self.foo is True

    def is_not_foo(self, state, event):
        return self.foo is False

    def test(self):
        m = self.m

        assert m.leaf_state == self.s11
        m.dispatch(Event('a'))
        assert m.leaf_state == self.s11
        # This transition toggles state between s11 and s211
        m.dispatch(Event('c'))
        assert m.leaf_state == self.s211
        m.dispatch(Event('b'))
        assert m.leaf_state == self.s211
        m.dispatch(Event('i'))
        assert m.leaf_state == self.s211
        m.dispatch(Event('c'))
        assert m.leaf_state == self.s11
        assert self.foo is True
        m.dispatch(Event('h'))
        assert self.foo is False
        assert m.leaf_state == self.s11
        # Do nothing if foo is False
        m.dispatch(Event('h'))
        assert m.leaf_state == self.s11
        # This transition toggles state between s11 and s211
        m.dispatch(Event('c'))
        assert m.leaf_state == self.s211
        assert self.foo is False
        m.dispatch(Event('h'))
        assert self.foo is True
        assert m.leaf_state == self.s211
        m.dispatch(Event('h'))
        assert m.leaf_state == self.s211
Exemplo n.º 59
0
def test_previous_state_event_none():
    m = StateMachine('m')
    s0 = StateMachine('s0')
    s1 = StateMachine('s1')
    s11 = State('s11')
    s12 = State('s12')

    m.add_state(s0, initial=True)
    s0.add_state(s1, initial=True)
    s1.add_state(s11, initial=True)
    s1.add_state(s12)

    m.add_transition(s0, s12, events='a')

    m.initialize()

    assert list(m.leaf_state_stack.deque) == []
    m.dispatch(_e('a'))
    assert list(m.leaf_state_stack.deque) == [s11]

    try:
        m.set_previous_leaf_state(event=None)
    except Exception as exc:
        assert not exc
    assert list(m.leaf_state_stack.deque) == [s11, s12]