Exemplo n.º 1
0
def test_edge_detector_from_undef(circuit):
    """Test the edge detector's parameters u_rise, u_fall."""
    setup = []
    i = 0
    for value in (False, True):
        for ur in (False, True, None):
            for uf in (False, True):
                for r in (False, True):
                    dest = edzed.Input(f'test_event_{i}', initdef=None)
                    edzed.Input(f"test_edge_{i}",
                                on_output=edzed.Event(dest,
                                                      efilter=edzed.Edge(
                                                          rise=r,
                                                          u_rise=ur,
                                                          u_fall=uf)),
                                initdef=value)
                    if ur is None:
                        ur = r
                    event = ur if value else uf
                    result = value if event else None
                    setup.append((dest, result, (value, ur, uf, r)))
                    i += 1
    init(circuit)
    for dest, result, args in setup:
        assert dest.output is result, f"failed for (value, u_rise, u_fall, rise) = {args}"
Exemplo n.º 2
0
def test_validators(circuit):
    """Test multiple validators."""
    # order = check, allowed, schema
    inputs = [
        edzed.Input('input1', allowed=[False, True], initdef=False),
        edzed.Input('input2',
                    check=lambda x: isinstance(x, bool),
                    allowed=[False, True],
                    initdef=False),
        edzed.Input('input3',
                    schema=bool,
                    allowed=[False, True],
                    initdef=False),
        edzed.Input('input4', schema=bool, initdef=False),
    ]
    init(circuit)

    VALUES = (None, 1, 99)
    ACCEPTED = [
        (False, True, False),  # because 1 == True, i.e. 1 is in allowed
        (False, False, False),  # no value passes the strict type checking
        (False, True, False),  # similar to input1
        (True, True, True),  # each value will be converted to bool
    ]
    OUTPUT = [
        (False, 1, 1),
        (False, False, False),
        (False, True, True),
        (False, True, True),
    ]
    for inp, acc_list, out_list in zip(inputs, ACCEPTED, OUTPUT):
        inp.event('put', value=inp.initdef)  # reset to default
        for val, acc, out in zip(VALUES, acc_list, out_list):
            assert inp.put(val) is acc
            assert inp.output == out
Exemplo n.º 3
0
def test_no_circular_init_by_event(circuit):
    """Circular (recursive in general) events are forbidden."""
    inp_a = edzed.Input('inp_a', on_output=edzed.Event('inp_b'), initdef='ok')
    inp_b = edzed.Input(
        'inp_b', on_output=edzed.Event('inp_a'))  # cannot send back to inp_a

    with pytest.raises(edzed.EdzedCircuitError,
                       match="Forbidden recursive event"):
        init(circuit)
Exemplo n.º 4
0
def test_no_cross_circuit_events(circuit):
    inp1 = edzed.Input('inp', comment="circuit 1", initdef=None)
    event = edzed.Event(inp1)
    init(circuit)
    event.send(inp1, value=1)
    assert inp1.output == 1

    edzed.reset_circuit()
    inp2 = edzed.Input('inp', comment="circuit 2", initdef=None)
    init(circuit)
    with pytest.raises(edzed.EdzedCircuitError,
                       match="not in the current circuit"):
        event.send(inp2, value=2)
Exemplo n.º 5
0
def test_and_or(circuit):
    """Test unpack=False on AND/OR logical gates."""
    inp0 = edzed.Input('inp0', initdef=False)
    inp1 = edzed.Input('inp1', initdef=False)
    and_gate = edzed.And('AND').connect(inp0, inp1, True)
    or_gate = edzed.Or('OR').connect(inp0, inp1, False)
    init(circuit)
    for v0, v1 in ((0, 0), (0, 1), (1, 0), (1, 1)):
        inp0.put(v0)
        inp1.put(v1)
        and_gate.eval_block()
        or_gate.eval_block()
        assert and_gate.output == bool(v0 and v1)
        assert or_gate.output == bool(v0 or v1)
Exemplo n.º 6
0
def test_init_by_event(circuit):
    """Test initialization by an event."""
    src = edzed.Input('src', on_output=edzed.Event('dest'), initdef='ok')
    dest = edzed.Input('dest',
                       on_output=edzed.Event('mem'))  # note: no inittdef=... !
    mem = EventMemory('mem')
    init(circuit)

    assert src.output == dest.output == 'ok'
    assert mem.output == ('put', {
        'source': 'dest',
        'trigger': 'output',
        'previous': edzed.UNDEF,
        'value': 'ok'
    })
Exemplo n.º 7
0
def test_on_every_output(circuit):
    """Test that on_output generates events."""
    dest = EventMemory('dest')
    dest_every = EventMemory('dest_every')
    src = edzed.Input('src',
                      on_output=edzed.Event(dest, etype='ev'),
                      on_every_output=edzed.Event(dest_every, etype='ev'),
                      initdef=None)
    init(circuit)

    CDATA = {'source': 'src', 'trigger': 'output'}
    src.put(0)
    assert dest.output == dest_every.output == ('ev', {
        **CDATA, 'previous': None,
        'value': 0
    })
    src.put(911)
    assert dest.output == dest_every.output == ('ev', {
        **CDATA, 'previous': 0,
        'value': 911
    })
    dest.event('ev', cleared=True)
    dest_every.event('ev', cleared=True)
    src.put(911)
    assert dest.output == ('ev', {'cleared': True})
    assert dest_every.output == ('ev', {
        **CDATA, 'previous': 911,
        'value': 911
    })
Exemplo n.º 8
0
def test_invert(circuit):
    """Shortcut '_not_blk' creates an inverter block connected to blk."""
    src = edzed.Input('src', allowed=(True, False), initdef=False)
    id1 = edzed.FuncBlock('identity1', func=lambda x: x).connect('src')
    id2 = edzed.FuncBlock('identity2', func=lambda x: x).connect('_not_src')
    # verify that _not_src shortcut may be used multiple times
    id3 = edzed.FuncBlock('identity3', func=lambda x: x).connect('_not_src')

    # _not_src does not exist yet
    assert sum(1 for blk in circuit.getblocks()) == 4
    with pytest.raises(KeyError):
        circuit.findblock('_not_src')
    init(circuit)
    # _not_src was just created automatically by finalize()
    assert sum(1 for blk in circuit.getblocks()) == 5
    invert = circuit.findblock('_not_src')

    for value in (True, False, True, False):
        src.put(value)
        invert.eval_block()
        id1.eval_block()
        id2.eval_block()
        id3.eval_block()
        assert id1.output is value
        assert id2.output is id3.output is not value
Exemplo n.º 9
0
async def output_async(circuit,
                       *,
                       log,
                       t1=0.1,
                       t2=0.0,
                       test_error=False,
                       mstop=True,
                       on_error=None,
                       **kwargs):
    async def wait120(arg):
        logger.put(f'start {arg}')
        if test_error:
            # pylint: disable=pointless-statement
            1 / 0  # BOOM!
        await asyncio.sleep(0.12)
        logger.put(f'stop {arg}')
        return f'ok {arg}'

    try:
        inp = edzed.Input('inp', initdef='i1', on_output=edzed.Event('echo'))
        logger = TimeLogger('logger', mstop=mstop)
        edzed.OutputAsync('echo', coro=wait120, on_error=on_error, **kwargs)
        asyncio.create_task(circuit.run_forever())
        await asyncio.sleep(t1)
        if circuit.is_ready():  # skip after an error,
            inp.put('i2')
            if t2 > 0.0:
                await asyncio.sleep(t2)
            inp.put('i3')
            await asyncio.sleep(0.05)
        await circuit.shutdown()
        logger.put("END")
    finally:
        logger.compare(log)
Exemplo n.º 10
0
def test_chained_dataedit(circuit):
    """Chaining of event data edit functions is allowed."""
    def check(expected):
        def _check(data):
            assert data == expected
            return data

        return _check

    src = edzed.Input(
        'src',
        on_output=edzed.Event(
            'dest',
            efilter=(
                edzed.not_from_undef,
                check({'source': 'src', 'trigger': 'output', 'previous': None, 'value': 'V'}),
                edzed.DataEdit \
                    .permit('source', 'trigger', 'value') \
                    .setdefault(source='fake') \
                    .copy('value', 'saved') \
                    .rename('source', 'src'),
                check(
                    {'src': 'src', 'trigger': 'output', 'saved': 'V', 'value': 'V'}),
                edzed.DataEdit.permit('trigger', 'src') \
                    .modify('src', lambda x: x[::-1]) \
                    .add(a=1)
            )),
        initdef=None)
    dest = EventMemory('dest')
    init(circuit)

    src.put('V')
    assert dest.output == ('put', {'a': 1, 'src': 'crs', 'trigger': 'output'})
Exemplo n.º 11
0
def test_multiple_events(circuit):
    """Test multiple events."""
    dest1 = EventMemory('dest2')
    dest2 = EventMemory('dest1')
    src = edzed.Input('src',
                      on_output=[
                          edzed.Event(dest=dest1, etype='ev1'),
                          edzed.Event(dest=dest2, etype='ev2')
                      ],
                      initdef=None)
    init(circuit)

    CDATA = {'source': 'src', 'trigger': 'output'}
    src.put(0)
    assert dest1.output == ('ev1', {**CDATA, 'previous': None, 'value': 0})
    assert dest2.output == ('ev2', {**CDATA, 'previous': None, 'value': 0})
    src.put(911)
    assert dest1.output[1] == dest2.output[1] == {
        **CDATA, 'previous': 0,
        'value': 911
    }
    src.put('last')
    assert dest1.output[1] == dest2.output[1] == {
        **CDATA, 'previous': 911,
        'value': 'last'
    }
Exemplo n.º 12
0
async def output_func(circuit,
                      *,
                      log,
                      v2=2,
                      on_error=None,
                      mstop=True,
                      **kwargs):
    def worker(arg):
        v = 12 // arg
        logger.put(v)
        return 100 + v

    try:
        inp = edzed.Input('inp', initdef=6, on_output=edzed.Event('echo'))
        logger = TimeLogger('logger', mstop=mstop)
        edzed.OutputFunc('echo', func=worker, on_error=on_error, **kwargs)
        asyncio.create_task(circuit.run_forever())
        await asyncio.sleep(0.05)
        inp.put(v2)
        if circuit.is_ready():  # skip after an error,
            await asyncio.sleep(0.05)
            inp.put(3)
        await circuit.shutdown()
        logger.put("END")
    finally:
        logger.compare(log)
Exemplo n.º 13
0
def test_on_output(circuit):
    """Test that on_output generates events."""
    dest = EventMemory('dest')
    src = edzed.Input('src',
                      check=lambda x: x != 'NO!',
                      on_output=edzed.Event(dest, etype='ev'),
                      initdef=None)
    init(circuit)

    CDATA = {'source': 'src', 'trigger': 'output'}
    src.put(0)
    assert dest.output == ('ev', {**CDATA, 'previous': None, 'value': 0})
    src.put(911)
    assert dest.output == ('ev', {**CDATA, 'previous': 0, 'value': 911})
    src.put('string')
    assert dest.output == ('ev', {**CDATA, 'previous': 911, 'value': 'string'})

    dest.event('clear')
    src.put('string')  # same value, no change, no output event
    assert dest.output == ('clear', {})
    src.put('NO!')  # forbidden value (check=...), no output event
    assert dest.output == ('clear', {})

    src.put(0)
    assert dest.output == ('ev', {**CDATA, 'previous': 'string', 'value': 0})
Exemplo n.º 14
0
async def test_nostart_nopersistent(circuit):
    """Persistent data are not touched if the start fails."""
    class NoStart(edzed.CBlock):
        def start(self):
            raise RuntimeError("failed start")

        def calc_output(self):
            return None

    NoStart('nostart')
    inp1 = edzed.Input('input1', persistent=True)
    edzed.Input('input2', persistent=True, initdef=0)
    pd = {inp1.key: 33}
    circuit.set_persistent_data(pd)
    with pytest.raises(RuntimeError):
        await circuit.run_forever()
    assert pd == {inp1.key: 33}
Exemplo n.º 15
0
def test_not_from_undef(circuit):
    """Test the not_from_undef filter."""
    dest = edzed.Input('dest', initdef=None)
    src = edzed.Input('src',
                      on_output=edzed.Event(dest,
                                            efilter=edzed.not_from_undef),
                      initdef=1)
    init(circuit)

    assert src.output == 1
    assert dest.output is None  # UNDEF -> 1 suppressed by the filter
    src.put(3)
    assert src.output == 3
    assert dest.output == 3
    src.put(5)
    assert src.output == 5
    assert dest.output == 5
Exemplo n.º 16
0
def test_expiration(circuit):
    """Test the internal state expiration"""
    inp1 = edzed.Input('inp1', initdef=91, persistent=True)
    inp2 = edzed.Input('inp2', initdef=92, persistent=True, expiration=None)
    inp3 = edzed.Input('inp3', initdef=93, persistent=True, expiration=10)
    inp4 = edzed.Input('inp4', initdef=94, persistent=True, expiration="1m30s")

    storage = {
        inp1.key: 1, inp2.key: 2, inp3.key: 3, inp4.key: 4,
        'edzed-stop-time': time.time() - 12.0,  # 12 seconds old
        }
    circuit.set_persistent_data(storage)
    init(circuit)

    assert inp1.output == 1     # no expiration
    assert inp2.output == 2     # no expiration
    assert inp3.output == 93    # state expired, init from default
    assert inp4.output == 4     # not expired
Exemplo n.º 17
0
def test_schema(circuit):
    """schema validator test."""
    inp = edzed.Input('input', schema=lambda x: int(x) + 100, initdef=23)
    init(circuit)

    assert inp.output == 123  # schema is applied also to the default
    assert inp.event('put', value='string') is False
    assert inp.output == 123
    assert inp.event('put', value='68') is True
    assert inp.output == 168
Exemplo n.º 18
0
def test_override(circuit):
    """Test the override block."""
    SENTINEL = 999
    inp = edzed.Input('inp', initdef=None)
    override = edzed.Input('ctrl', initdef=SENTINEL)
    out = edzed.Override('test', null_value=SENTINEL).connect(input=inp, override=override)
    init(circuit)

    TEST_VALUES = (17, 3.14, SENTINEL, True, False, None, "LAST")

    for value in TEST_VALUES:
        inp.event('put', value=value)
        out.eval_block()
        assert out.output == value

    for value in TEST_VALUES:
        override.event('put', value=value)
        out.eval_block()
        assert out.output == (value if value != SENTINEL else "LAST")   # parenthesis required
Exemplo n.º 19
0
def test_check(circuit):
    """check validator test."""
    inp = edzed.Input('input', check=lambda x: x % 5 == 0, initdef=5)
    init(circuit)

    assert inp.output == 5
    assert inp.put(25) is True
    assert inp.output == 25
    assert inp.put(68) is False
    assert inp.output == 25
Exemplo n.º 20
0
def test_delta(circuit):
    """Test the Delta filter."""
    trace = []

    def tee(data):
        trace.append(data['value'])
        return data

    dest = edzed.Input('dest', initdef=None)
    src = edzed.Input('src',
                      on_output=edzed.Event(dest,
                                            efilter=[edzed.Delta(1.7), tee]),
                      initdef=0)
    init(circuit)

    for num in (0, 1, 0, 2, 3.69, 3.71, 5, 6, 7, 8, 15, 13.5, 16.5, 12):
        src.put(num)
    assert trace == [0, 2, 3.71, 6, 8, 15, 12]
    assert dest.output == 12
Exemplo n.º 21
0
def test_edge_detector(circuit):
    """Test the edge detector's parameters rise and fall."""
    SEQ1 = (False, True, False, True, False, True, False, True)
    SEQ2 = (True, False, True, False, True)

    cnt = edzed.Counter('counter')
    i = 0
    setup = []
    for r in (False, True):
        for f in (False, True):
            inp1 = edzed.Input(f"test{i}_seq1",
                               on_output=edzed.Event(cnt,
                                                     'inc',
                                                     efilter=edzed.Edge(
                                                         rise=r, fall=f)),
                               initdef=SEQ1[0])
            inp2 = edzed.Input(f"test{i}_seq2",
                               on_output=edzed.Event(cnt,
                                                     'inc',
                                                     efilter=edzed.Edge(
                                                         rise=r, fall=f)),
                               initdef=SEQ2[0])
            s1 = s2 = 0  # s1, s2 = expected event count for SEQ1, SEQ2
            if r:
                s1 += 4  # 4 rising edges
                s2 += 2  # 3 rising edges, but 1 of them is initial
                # and is counted immediately at the block creation
            if f:
                s1 += 3  # 4 falling edges, but 1 of them is initial
                # and is suppressed by uf=False (default)
                s2 += 2  # 2 falling edges
            setup.append((inp1, SEQ1, s1, (r, f)))
            setup.append((inp2, SEQ2, s2, (r, f)))
            i += 1
    init(circuit)
    assert cnt.output == 2  # 2 times the initial rising edge of S2R1F10 and S2R1F1

    for inp, seq, result, args in setup:
        cnt.put(0)
        assert cnt.output == 0
        for val in seq:
            inp.put(val)
        assert cnt.output == result, f"failed for {inp.name}, (rise, fall) = {args}"
Exemplo n.º 22
0
def test_save_state_sync(circuit):
    """By default the state is saved after each event (sync_state=True)."""
    storage = dict()
    inp = edzed.Input('ipers', initdef=99, persistent=True)
    circuit.set_persistent_data(storage)
    init(circuit)

    assert inp.output == 99
    assert storage == {inp.key: 99}
    inp.event('put', value=3.14)
    assert storage == {inp.key: 3.14}
Exemplo n.º 23
0
def test_load_state(circuit):
    """The saved state is loaded in preference to the default."""
    inp = edzed.Input('ipers', initdef=99, persistent=True)
    storage = {inp.key: 'saved'}
    circuit.set_persistent_data(storage)
    init(circuit)

    assert storage == {inp.key: 'saved'}
    assert inp.output == 'saved'
    inp.event('put', value=3.14)
    assert storage == {inp.key: 3.14}
Exemplo n.º 24
0
def test_error_checking(circuit):
    dest = edzed.Input('dest', initdef=0)
    init(circuit)

    with pytest.raises(TypeError, match="string"):
        dest.event(333)  # event name must be a string or a EventType
    with pytest.raises(ValueError, match="empty"):
        dest.event('')
    with pytest.raises(edzed.EdzedUnknownEvent):
        dest.event("no_such_event")
    with pytest.raises(edzed.EdzedUnknownEvent):
        dest.event("no_such_event")
Exemplo n.º 25
0
async def test_instability_2(circuit):
    """Test a stable circuit that becomes instable."""
    ctrl = edzed.Input('ctrl', initdef=False)
    edzed.FuncBlock('xor',
                    func=lambda a, b: bool(a) != bool(b)).connect(ctrl, 'xor')
    simtask = asyncio.create_task(circuit.run_forever())
    await circuit.wait_init()
    assert ctrl.output is not edzed.UNDEF
    # so far so good, but now create an instability
    ctrl.put(True)
    with pytest.raises(edzed.EdzedCircuitError, match="instability"):
        await asyncio.wait_for(simtask, timeout=1.0)
Exemplo n.º 26
0
def test_init(circuit):
    """Initial value is assigned on init."""
    INITIAL = 'default_value'
    inp = edzed.Input('input', initdef=INITIAL)
    assert inp.output is edzed.UNDEF
    init(circuit)

    assert inp.output == INITIAL
    inp.event('put', value=3.14)
    assert inp.output == 3.14
    inp.event('put', value=inp.initdef)  # reset to default
    assert inp.output == INITIAL
Exemplo n.º 27
0
def test_dataedit_add_output(circuit):
    """Test add_output."""
    add = edzed.Input('add', initdef=12)
    dest = EventMemory('dest')
    src = edzed.Input('src',
                      on_output=edzed.Event(
                          dest,
                          etype='ev',
                          efilter=edzed.DataEdit.add_output('A',
                                                            add).add_output(
                                                                'self', 'src'),
                      ),
                      initdef=3)
    init(circuit)

    CDATA = {'source': 'src', 'trigger': 'output'}
    src.put(4)
    assert dest.output[1] == {
        **CDATA, 'previous': 3,
        'value': 4,
        'self': 4,
        'A': 12
    }
    add.put('old')
    add.put('new')
    src.put(5)
    assert dest.output[1] == {
        **CDATA, 'previous': 4,
        'value': 5,
        'self': 5,
        'A': 'new'
    }
    src.put(6)
    assert dest.output[1] == {
        **CDATA, 'previous': 5,
        'value': 6,
        'self': 6,
        'A': 'new'
    }
Exemplo n.º 28
0
def test_filter(circuit):
    """Test event filter."""
    def even_numbers_only(data):
        return data.get('value', 1) % 2 == 0

    dest = edzed.Input('dest', initdef=None)
    src = edzed.Input('src',
                      on_output=edzed.Event(dest, efilter=even_numbers_only),
                      initdef=0)
    init(circuit)

    assert src.output == 0
    assert dest.output == 0
    src.put(1)
    assert src.output == 1
    assert dest.output == 0
    src.put(8)
    assert src.output == 8
    assert dest.output == 8
    src.put(33)
    assert src.output == 33
    assert dest.output == 8
Exemplo n.º 29
0
def test_remove_unused(circuit):
    """
    Verify that unused keys are removed.

    All 'edzed-*' keys are reserved for internal use and are preserved.
    """
    inp = edzed.Input('ipers', initdef=1, persistent=True)
    storage = {inp.key: 2, 'wtf': 3, 'edzed-xyz': 4}
    circuit.set_persistent_data(storage)
    init(circuit)

    assert inp.output == 2
    assert storage == {inp.key: 2, 'edzed-xyz': 4}  # without the 'wtf' item
Exemplo n.º 30
0
def test_allowed(circuit):
    """allowed validator test."""
    ALLOWED = (False, 'YES', 2.5)
    NOT_ALLOWED = (True, None, '', 'hello', 99)
    inp = edzed.Input('input', allowed=ALLOWED, initdef=False)
    init(circuit)

    for v in ALLOWED:
        assert inp.event('put', value=v) is True
        assert inp.output == v
    last = inp.output
    for v in NOT_ALLOWED:
        assert inp.event('put', value=v) is False
        assert inp.output == last