Example #1
0
def test_conditional_goto(circuit):
    """Test the EventCond + Goto combination."""
    # Note: Goto(EventCond(...)) is wrong, Goto expects an FSM state, not an event
    class B4(edzed.FSM):
        STATES = ('A', 'B', 'C', 'D')

    b4 = B4('4states')
    init(circuit)

    event = edzed.EventCond(edzed.Goto('B'), edzed.Goto('D'))
    b4.event(event, value=False)
    assert b4.state == 'D'
    b4.event(event, value=True)
    assert b4.state == 'B'
Example #2
0
def test_persistent_state(circuit):
    class Dummy(edzed.FSM):
        STATES = list("ABCDEF")

    def forbidden():
        assert False

    mem = EventMemory('mem')
    fsm = Dummy(
        'test', persistent=True,
        enter_D=forbidden, on_enter_D=edzed.Event(mem, '+D'),
        on_exit_D=edzed.Event(mem, '-D')
        )
    assert fsm.key == "<Dummy 'test'>"
    storage = {fsm.key: ['D', None, {'x':'y', '_z':3}]}    # (state, timer, sdata)
    circuit.set_persistent_data(storage)
    # enter_D and on_enter_D will be suppressed
    init(circuit)
    assert fsm.sdata == {'x':'y', '_z':3}

    assert fsm.state == 'D'
    assert mem.output is None

    fsm.event(edzed.Goto('F'))
    assert mem.output == (
        '-D',
        # '_z' is not present in 'sdata', because it is considered private
        {'source': 'test', 'trigger': 'exit', 'state': 'D', 'sdata': {'x':'y'}, 'value': 'D'}
        )
    del fsm.sdata['x']
    assert storage == {fsm.key: ('F', None, {'_z':3})}
Example #3
0
def test_goto(circuit):
    """Test the Goto special event."""
    class B123(edzed.FSM):
        STATES = ('S1', 'S2', 'S3')
        EVENTS = [
            ('step', 'S1', 'S2'),
            ('step', 'S2', 'S3'),
            ('step', 'S3', 'S1')
            ]

    b123 = B123('b123fsm')
    init(circuit)

    assert b123.state == 'S1'

    b123.event('step')
    assert b123.state == 'S2'

    b123.event(edzed.Goto('S1'))
    assert b123.state == 'S1'

    with pytest.raises(ValueError, match="Unknown state"):
        b123.event(edzed.Goto('S99'))
Example #4
0
def test_no_transition_chaining2(circuit):
    """Test forbidden chained transition"""
    class ABC(edzed.FSM):
        STATES = ['A', 'B', 'C']
        EVENTS = [
            ('start', ['A'], 'B')
            ]

    # a FSM can't send events to itself this way
    abc = ABC('abc', on_enter_B=edzed.Event('abc', edzed.Goto('C')))
    init(circuit)

    with pytest.raises(edzed.EdzedCircuitError, match='Forbidden recursive event'):
        abc.event('start')
Example #5
0
class AfterRun(edzed.FSM):
    STATES = ['off', 'on', 'prepare_afterrun', 'afterrun']
    EVENTS = [
        ['start', ['off'], 'on'],
        ['stop', ['on'], 'prepare_afterrun'],
    ]
    TIMERS = {
        'afterrun': (None, edzed.Goto('off'))
    }

    def enter_on(self):
        self.sdata['started'] = time.time()

    def enter_prepare_afterrun(self):
        duration = (time.time() - self.sdata.pop('started')) * (self.x_percentage / 100.0)
        self.event(edzed.Goto('afterrun'), duration=duration)

    def calc_output(self):
        return self.state != 'off'
Example #6
0
def test_transition_chaining(circuit):
    """Test the chained transition A->B->C->D."""
    class ABCD(edzed.FSM):
        STATES = ['A', 'B', 'C', 'D']
        EVENTS = [
            ('start', ['A'], 'B')
            ]
        def enter_B(self):
            self.event(edzed.Goto('C'))
        def enter_C(self):
            self.event(edzed.Goto('D'))
        def calc_output(self):
            assert self.state not in ('B', 'C')    # no output for intermediate states
            return f'in_{self.state}'

    abcd = ABCD(
        'abcd',
        on_enter_B=edzed.Event('mem', '+B'),
        on_exit_B=edzed.Event('mem', '-B'),
        on_enter_C=edzed.Event('mem', '+C'),
        on_exit_C=edzed.Event('mem', '-C'),
        on_exit_D=edzed.Event('mem', '-D'),
        )
    mem = EventMemory('mem')
    init(circuit)

    assert abcd.state == 'A'
    assert abcd.output == 'in_A'
    assert mem.output is None
    abcd.event('start')
    assert abcd.state == 'D'
    assert abcd.output == 'in_D'
    assert mem.output is None   # no events for intermediate states
    abcd.event(edzed.Goto('A'))
    assert abcd.state == 'A'
    assert abcd.output == 'in_A'
    assert mem.output == (
        '-D',
        {'source': 'abcd', 'trigger': 'exit', 'state': 'D', 'sdata': {}, 'value': 'in_D'}
        )
Example #7
0
 def enter_off_0(self):
     self.event(edzed.Goto('off'), duration=(1.0 - self._dc) * PERIOD)
Example #8
0
 def enter_on_0(self):
     self.event(edzed.Goto('on'), duration=self._dc * PERIOD)
Example #9
0
 def enter_B(self):
     self.event(edzed.Goto('A'))
Example #10
0
 def enter_A(self):
     self.event(edzed.Goto('B'))
Example #11
0
 def exit_A(self):
     self.event(edzed.Goto('C'))     # can't do this in exit_STATE (only in enter_STATE)
Example #12
0
 def enter_B(self):
     self.event(edzed.Goto('C'))     # this is OK
     self.event(edzed.Goto('C'))     # but only once!
Example #13
0
 def enter_C(self):
     self.event(edzed.Goto('D'))
Example #14
0
 def enter_prepare_afterrun(self):
     duration = (time.time() - self.sdata.pop('started')) * (self.x_percentage / 100.0)
     self.event(edzed.Goto('afterrun'), duration=duration)