blob: 89bc824206c46cf85f7fe479ad91f5eb0a24a487 [file] [log] [blame] [edit]
from math import floor, ceil, trunc
from threading import Semaphore
import pytest
from more_executors import Executors, f_return, f_return_error, f_proxy, f_map
def test_len():
xlist = f_proxy(f_return([1, 2, 3]))
xint = f_proxy(f_return(42))
xstr = f_proxy(f_return("hello"))
assert len(xlist) == 3
assert len(xstr) == 5
with pytest.raises(TypeError) as exc:
len(xint)
assert "has no len" in str(exc.value)
def test_attrs():
xdict = f_proxy(f_return({"foo": "bar", "baz": "quux"}))
assert sorted(xdict.keys()) == ["baz", "foo"]
assert sorted(xdict.values()) == ["bar", "quux"]
with pytest.raises(AttributeError):
xdict.no_such_attr()
def test_dict():
xdict = f_proxy(f_return({"foo": "bar", "baz": "quux"}))
assert xdict["foo"] == "bar"
assert "baz" in xdict
xdict["added"] = 123
assert "added" in xdict
del xdict["foo"]
assert "foo" not in xdict
with pytest.raises(KeyError):
assert xdict["no_such_key"]
def test_iter():
xlist = f_proxy(f_return(["a", "b", "c"]))
xstr = f_proxy(f_return("xyz"))
xint = f_proxy(f_return(12))
list_elems = []
for elem in xlist:
list_elems.append(elem)
assert list_elems == ["a", "b", "c"]
str_elems = []
for elem in xstr:
str_elems.append(elem)
assert str_elems == ["x", "y", "z"]
with pytest.raises(TypeError) as exc:
for _ in xint:
pass
assert "not iterable" in str(exc.value)
def test_math_basic():
xstr = f_proxy(f_return("xyz"))
xint = f_proxy(f_return(12))
xfloat = f_proxy(f_return(5.0))
assert xstr * 2 == "xyzxyz"
assert xstr + "abc" == "xyzabc"
assert xint + 2 == 14
assert xint - 2 == 10
assert xint % 10 == 2
assert xint / 2 == 6
assert xint**2 == 144
assert xfloat // 2.0 == 2.0
assert divmod(xint, 5) == (2, 2)
def test_math_round():
xstr = f_proxy(f_return("xyz"))
xint = f_proxy(f_return(12))
xfloat = f_proxy(f_return(5.5))
assert round(xint) == 12
assert round(xfloat) == 6.0
assert floor(xint) == 12
assert floor(xfloat) == 5.0
assert ceil(xint) == 12
assert ceil(xfloat) == 6.0
assert trunc(xint) == 12
assert trunc(xfloat) == 5.0
with pytest.raises(Exception):
assert round(xstr) == "foo"
def test_bits():
xbin = f_proxy(f_return(0b00110))
assert xbin << 1 == 0b01100
assert xbin >> 1 == 0b00011
assert xbin & 0b10010 == 0b00010
assert xbin | 0b10010 == 0b10110
assert xbin ^ 0b10010 == 0b10100
def test_sign():
xint = f_proxy(f_return(123))
xnegint = f_proxy(f_return(-123))
assert -xint == -123
assert +xint == 123
assert abs(xnegint) == 123
assert ~xint == -124
assert ~xnegint == 122
assert ~~xint == 123
assert ~~xnegint == -123
def test_num_types():
xint = f_proxy(f_return(123))
xfloat = f_proxy(f_return(1.23))
assert float(xint) == 123.0
assert complex(xint) == complex(123)
assert int(xfloat) == 1
def test_bool():
xtrue = f_proxy(f_return(True))
xfalse = f_proxy(f_return(False))
xempty = f_proxy(f_return([]))
# All of these count as truthy, as we want to allow testing if
# a future was returned without blocking
assert xtrue
assert xfalse
assert xempty
def test_map():
sem = Semaphore(0)
with Executors.thread_pool() as exc:
# This future cannot possibly proceed until we unblock the semaphore.
f = exc.submit(sem.acquire)
f = f_proxy(f)
# If bug #278 exists, we will hang here indefinitely.
f = f_map(f, lambda _: 123)
# If bug is fixed, future is still not evaluated.
# Let it proceed now.
sem.release()
assert f.result() == 123
def test_attribute_error():
error = AttributeError("quux!")
prox = f_proxy(f_return_error(error))
# I should be able to get the exception normally
assert prox.exception() is error
# If I try to iterate, it should raise the exception
with pytest.raises(Exception) as excinfo:
iter(prox)
# The raised exception should be exactly the underlying value
assert excinfo.value is error