2015-03-22 18:21:15 +00:00
|
|
|
"""
|
|
|
|
Property-based tests using https://warehouse.python.org/project/hypothesis/
|
|
|
|
"""
|
|
|
|
|
2015-04-29 18:29:33 +00:00
|
|
|
import pytest
|
|
|
|
|
2015-03-22 18:21:15 +00:00
|
|
|
from functools import reduce
|
|
|
|
from math import isnan
|
|
|
|
from operator import or_
|
|
|
|
|
|
|
|
from hypothesis import assume, given, strategy
|
|
|
|
from hypothesis.specifiers import dictionary
|
|
|
|
|
2015-05-26 05:37:42 +00:00
|
|
|
from bidict import bidict, frozenbidict
|
2015-03-22 18:21:15 +00:00
|
|
|
|
|
|
|
|
2015-04-29 18:29:33 +00:00
|
|
|
def inv(d):
|
|
|
|
return {v: k for (k, v) in d.items()}
|
|
|
|
|
|
|
|
def prune_dup_vals(d):
|
|
|
|
pruned = inv(inv(d))
|
|
|
|
assume(len(pruned) >= 0.5 * len(d))
|
|
|
|
return pruned
|
2015-03-22 18:21:15 +00:00
|
|
|
|
|
|
|
immutable_types_ = (None, bool, int, float, str, bytes, tuple(), frozenset())
|
|
|
|
immutable_types = reduce(or_, map(strategy, immutable_types_))
|
2015-04-29 18:29:33 +00:00
|
|
|
d = strategy(dictionary(immutable_types, immutable_types)).map(prune_dup_vals)
|
2015-03-22 18:21:15 +00:00
|
|
|
|
2015-04-29 18:29:33 +00:00
|
|
|
@given(d)
|
|
|
|
def test_len(d):
|
|
|
|
assert len(d) == len(inv(d)) == len(bidict(d))
|
2015-03-22 18:21:15 +00:00
|
|
|
|
2015-04-29 18:29:33 +00:00
|
|
|
def isnan_(x):
|
|
|
|
return isnan(x) if isinstance(x, float) else False
|
2015-03-22 18:21:15 +00:00
|
|
|
|
2015-04-29 18:29:33 +00:00
|
|
|
def both_nan(a, b):
|
|
|
|
return isnan_(a) and isnan_(b)
|
2015-03-22 18:21:15 +00:00
|
|
|
|
2015-04-29 18:29:33 +00:00
|
|
|
@given(d)
|
|
|
|
def test_bidirectional_mappings(d):
|
|
|
|
b = bidict(d)
|
2015-03-22 18:21:15 +00:00
|
|
|
for k, v in b.items():
|
|
|
|
v_ = b[k]
|
2015-04-29 18:29:33 +00:00
|
|
|
k_ = b.inv[v]
|
|
|
|
assert k == k_ or both_nan(k, k_)
|
|
|
|
assert v == v_ or both_nan(v, v_)
|
2015-03-22 18:21:15 +00:00
|
|
|
|
2015-04-29 18:29:33 +00:00
|
|
|
@given(d)
|
|
|
|
def test_getitem_with_slice(d):
|
|
|
|
b = bidict(d)
|
|
|
|
for k, v in b.items():
|
|
|
|
# https://bidict.readthedocs.org/en/latest/caveats.html#none-breaks-the-slice-syntax
|
|
|
|
if v is not None:
|
|
|
|
k_ = b[:v]
|
|
|
|
assert k == k_ or both_nan(k, k_)
|
|
|
|
if k is not None:
|
|
|
|
v_ = b.inv[:k]
|
|
|
|
assert v == v_ or both_nan(v, v_)
|
|
|
|
|
|
|
|
@given(d)
|
|
|
|
def test_inv_identity(d):
|
|
|
|
b = bidict(d)
|
2015-03-22 18:21:15 +00:00
|
|
|
assert b is b.inv.inv is ~~b
|
|
|
|
assert b.inv is b.inv.inv.inv is ~b
|
2015-04-29 18:29:33 +00:00
|
|
|
|
|
|
|
# work around https://bitbucket.org/pypy/pypy/issue/1974
|
|
|
|
nan = float('nan')
|
|
|
|
WORKAROUND_NAN_BUG = (nan, nan) != (nan, nan)
|
|
|
|
|
|
|
|
@given(d)
|
|
|
|
def test_equality(d):
|
2015-05-04 15:08:25 +00:00
|
|
|
if WORKAROUND_NAN_BUG:
|
|
|
|
assume(nan not in d)
|
2015-04-29 18:29:33 +00:00
|
|
|
i = inv(d)
|
2015-05-04 15:08:25 +00:00
|
|
|
if WORKAROUND_NAN_BUG:
|
|
|
|
assume(nan not in i)
|
2015-04-29 18:29:33 +00:00
|
|
|
b = bidict(d)
|
|
|
|
assert b == d
|
|
|
|
assert ~b == i
|
|
|
|
assert not b != d
|
|
|
|
assert not ~b != i
|
2015-05-26 05:37:42 +00:00
|
|
|
|
|
|
|
@given(d)
|
|
|
|
def test_frozenbidict_hash(d):
|
|
|
|
f = frozenbidict(d)
|
|
|
|
assert hash(f)
|