def test_queues_get_then_put():
    q = tap.Queue(buffer_size=1)
    a = 0

    def pop_and_add():
        nonlocal a
        b = yield q.Get()
        a += b

    def fn():
        assert not q.has_work()
        t1 = yield tap.CallFork(pop_and_add)
        t2 = yield tap.CallFork(pop_and_add)
        t3 = yield tap.CallFork(pop_and_add)
        yield tap.Sleep(0)
        assert a == 0
        yield q.Put(3)
        assert a == 3

        yield tap.Cancel(t2)
        yield q.Put(5)
        assert a == 8

        yield q.Put(5)
        assert a == 8

        t4 = yield tap.CallFork(pop_and_add)
        yield tap.Sleep(0)
        assert a == 13

        yield tap.Join([t1, t3, t4])

    tap.run(fn)
def test_queues_put_then_get_no_buffer():
    q = tap.Queue(buffer_size=0)

    def fn():
        assert not q.has_work()
        t = yield tap.Fork(q.Put(3))
        yield tap.Sleep(0.01)
        assert q.has_work()
        assert (yield q.Get()) == 3
        yield tap.Join(t)

    tap.run(fn)
def test_queues_put_then_get():
    q = tap.Queue(buffer_size=2)

    def fn():
        assert not q.has_work()
        # we have buffer so a put is fine
        yield q.Put(3)
        yield q.Put(5)
        assert q.has_work()
        assert (yield q.Get()) == 3
        assert (yield q.Get()) == 5
        yield q.Put(3)
        yield q.Put(5)

    tap.run(fn)
def test_queues_put_then_get_late_cancel():
    q = tap.Queue(buffer_size=1)

    def put(x):
        yield q.Put(x)

    def fn():
        yield q.Put(3)
        t1 = yield tap.CallFork(put, (5, ))
        t2 = yield tap.CallFork(put, (7, ))
        yield tap.Sleep(0)
        assert (yield q.Get()) == 3
        assert (yield q.Get()) == 5
        yield tap.Cancel(t2)  # too late
        assert (yield q.Get()) == 7
        yield tap.Join([t1])

        t = yield tap.Fork(q.Get())
        yield q.Put(3)
        assert (yield tap.Join(t)) == 3

    tap.run(fn)
def test_queues_put_then_get_cancel():
    q = tap.Queue(buffer_size=1)

    def put(x):
        yield q.Put(x)

    def fn():
        yield q.Put(3)
        t1 = yield tap.CallFork(put, (5, ))
        t2 = yield tap.CallFork(put, (7, ))
        t3 = yield tap.CallFork(put, (9, ))
        yield tap.Sleep(0)
        assert (yield q.Get()) == 3
        yield tap.Cancel(t2)  # not too late to cancel
        assert (yield q.Get()) == 5
        assert (yield q.Get()) == 9
        yield tap.Join([t1, t3])

        t = yield tap.Fork(q.Get())
        yield q.Put(3)
        assert (yield tap.Join(t)) == 3

    tap.run(fn)
def test_queues_block_put():
    q = tap.Queue(buffer_size=1)
    a = 0

    def pop_and_add():
        nonlocal a
        b = yield q.Get()
        a += b

    def fn():
        yield tap.CallFork(pop_and_add)
        yield tap.CallFork(pop_and_add)
        yield q.Put(3)
        yield q.Put(5)
        yield q.Put(5)
        yield q.Put(8)

    with pytest.raises(tap.TapystryError) as x:
        tap.run(fn)
    assert a == 8
    # TODO fix
    assert str(x.value).startswith("Hanging strands detected waiting for Receive(get") or \
        str(x.value).startswith("Hanging strands detected waiting for Call(Put")