diff options
author | shmel1k <shmel1k@ydb.tech> | 2023-11-26 18:16:14 +0300 |
---|---|---|
committer | shmel1k <shmel1k@ydb.tech> | 2023-11-26 18:43:30 +0300 |
commit | b8cf9e88f4c5c64d9406af533d8948deb050d695 (patch) | |
tree | 218eb61fb3c3b96ec08b4d8cdfef383104a87d63 /contrib/python/pyrsistent/py2/tests/hypothesis_vector_test.py | |
parent | 523f645a83a0ec97a0332dbc3863bb354c92a328 (diff) | |
download | ydb-b8cf9e88f4c5c64d9406af533d8948deb050d695.tar.gz |
add kikimr_configure
Diffstat (limited to 'contrib/python/pyrsistent/py2/tests/hypothesis_vector_test.py')
-rw-r--r-- | contrib/python/pyrsistent/py2/tests/hypothesis_vector_test.py | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/contrib/python/pyrsistent/py2/tests/hypothesis_vector_test.py b/contrib/python/pyrsistent/py2/tests/hypothesis_vector_test.py new file mode 100644 index 0000000000..e634204ec2 --- /dev/null +++ b/contrib/python/pyrsistent/py2/tests/hypothesis_vector_test.py @@ -0,0 +1,304 @@ +""" +Hypothesis-based tests for pvector. +""" + +import gc + +from pyrsistent._compat import Iterable +from functools import wraps +from pyrsistent import PClass, field + +from pytest import fixture + +from pyrsistent import pvector, discard + +from hypothesis import strategies as st, assume +from hypothesis.stateful import RuleBasedStateMachine, Bundle, rule + + +class TestObject(object): + """ + An object that might catch reference count errors sometimes. + """ + def __init__(self): + self.id = id(self) + + def __repr__(self): + return "<%s>" % (self.id,) + + def __del__(self): + # If self is a dangling memory reference this check might fail. Or + # segfault :) + if self.id != id(self): + raise RuntimeError() + + +@fixture(scope="module") +def gc_when_done(request): + request.addfinalizer(gc.collect) + + +def test_setup(gc_when_done): + """ + Ensure we GC when tests finish. + """ + + +# Pairs of a list and corresponding pvector: +PVectorAndLists = st.lists(st.builds(TestObject)).map( + lambda l: (l, pvector(l))) + + +def verify_inputs_unmodified(original): + """ + Decorator that asserts that the wrapped function does not modify its + inputs. + """ + def to_tuples(pairs): + return [(tuple(l), tuple(pv)) for (l, pv) in pairs] + + @wraps(original) + def wrapper(self, **kwargs): + inputs = [k for k in kwargs.values() if isinstance(k, Iterable)] + tuple_inputs = to_tuples(inputs) + try: + return original(self, **kwargs) + finally: + # Ensure inputs were unmodified: + assert to_tuples(inputs) == tuple_inputs + return wrapper + + +def assert_equal(l, pv): + assert l == pv + assert len(l) == len(pv) + length = len(l) + for i in range(length): + assert l[i] == pv[i] + for i in range(length): + for j in range(i, length): + assert l[i:j] == pv[i:j] + assert l == list(iter(pv)) + + +class PVectorBuilder(RuleBasedStateMachine): + """ + Build a list and matching pvector step-by-step. + + In each step in the state machine we do same operation on a list and + on a pvector, and then when we're done we compare the two. + """ + sequences = Bundle("sequences") + + @rule(target=sequences, start=PVectorAndLists) + def initial_value(self, start): + """ + Some initial values generated by a hypothesis strategy. + """ + return start + + @rule(target=sequences, former=sequences) + @verify_inputs_unmodified + def append(self, former): + """ + Append an item to the pair of sequences. + """ + l, pv = former + obj = TestObject() + l2 = l[:] + l2.append(obj) + return l2, pv.append(obj) + + @rule(target=sequences, start=sequences, end=sequences) + @verify_inputs_unmodified + def extend(self, start, end): + """ + Extend a pair of sequences with another pair of sequences. + """ + l, pv = start + l2, pv2 = end + # compare() has O(N**2) behavior, so don't want too-large lists: + assume(len(l) + len(l2) < 50) + l3 = l[:] + l3.extend(l2) + return l3, pv.extend(pv2) + + @rule(target=sequences, former=sequences, data=st.data()) + @verify_inputs_unmodified + def remove(self, former, data): + """ + Remove an item from the sequences. + """ + l, pv = former + assume(l) + l2 = l[:] + i = data.draw(st.sampled_from(range(len(l)))) + del l2[i] + return l2, pv.delete(i) + + @rule(target=sequences, former=sequences, data=st.data()) + @verify_inputs_unmodified + def set(self, former, data): + """ + Overwrite an item in the sequence. + """ + l, pv = former + assume(l) + l2 = l[:] + i = data.draw(st.sampled_from(range(len(l)))) + obj = TestObject() + l2[i] = obj + return l2, pv.set(i, obj) + + @rule(target=sequences, former=sequences, data=st.data()) + @verify_inputs_unmodified + def transform_set(self, former, data): + """ + Transform the sequence by setting value. + """ + l, pv = former + assume(l) + l2 = l[:] + i = data.draw(st.sampled_from(range(len(l)))) + obj = TestObject() + l2[i] = obj + return l2, pv.transform([i], obj) + + @rule(target=sequences, former=sequences, data=st.data()) + @verify_inputs_unmodified + def transform_discard(self, former, data): + """ + Transform the sequence by discarding a value. + """ + l, pv = former + assume(l) + l2 = l[:] + i = data.draw(st.sampled_from(range(len(l)))) + del l2[i] + return l2, pv.transform([i], discard) + + @rule(target=sequences, former=sequences, data=st.data()) + @verify_inputs_unmodified + def subset(self, former, data): + """ + A subset of the previous sequence. + """ + l, pv = former + assume(l) + i = data.draw(st.sampled_from(range(len(l)))) + j = data.draw(st.sampled_from(range(len(l)))) + return l[i:j], pv[i:j] + + @rule(pair=sequences) + @verify_inputs_unmodified + def compare(self, pair): + """ + The list and pvector must match. + """ + l, pv = pair + # compare() has O(N**2) behavior, so don't want too-large lists: + assume(len(l) < 50) + assert_equal(l, pv) + + +PVectorBuilderTests = PVectorBuilder.TestCase + + +class EvolverItem(PClass): + original_list = field() + original_pvector = field() + current_list = field() + current_evolver = field() + + +class PVectorEvolverBuilder(RuleBasedStateMachine): + """ + Build a list and matching pvector evolver step-by-step. + + In each step in the state machine we do same operation on a list and + on a pvector evolver, and then when we're done we compare the two. + """ + sequences = Bundle("evolver_sequences") + + @rule(target=sequences, start=PVectorAndLists) + def initial_value(self, start): + """ + Some initial values generated by a hypothesis strategy. + """ + l, pv = start + return EvolverItem(original_list=l, + original_pvector=pv, + current_list=l[:], + current_evolver=pv.evolver()) + + @rule(item=sequences) + def append(self, item): + """ + Append an item to the pair of sequences. + """ + obj = TestObject() + item.current_list.append(obj) + item.current_evolver.append(obj) + + @rule(start=sequences, end=sequences) + def extend(self, start, end): + """ + Extend a pair of sequences with another pair of sequences. + """ + # compare() has O(N**2) behavior, so don't want too-large lists: + assume(len(start.current_list) + len(end.current_list) < 50) + start.current_evolver.extend(end.current_list) + start.current_list.extend(end.current_list) + + @rule(item=sequences, data=st.data()) + def delete(self, item, data): + """ + Remove an item from the sequences. + """ + assume(item.current_list) + i = data.draw(st.sampled_from(range(len(item.current_list)))) + del item.current_list[i] + del item.current_evolver[i] + + @rule(item=sequences, data=st.data()) + def setitem(self, item, data): + """ + Overwrite an item in the sequence using ``__setitem__``. + """ + assume(item.current_list) + i = data.draw(st.sampled_from(range(len(item.current_list)))) + obj = TestObject() + item.current_list[i] = obj + item.current_evolver[i] = obj + + @rule(item=sequences, data=st.data()) + def set(self, item, data): + """ + Overwrite an item in the sequence using ``set``. + """ + assume(item.current_list) + i = data.draw(st.sampled_from(range(len(item.current_list)))) + obj = TestObject() + item.current_list[i] = obj + item.current_evolver.set(i, obj) + + @rule(item=sequences) + def compare(self, item): + """ + The list and pvector evolver must match. + """ + item.current_evolver.is_dirty() + # compare() has O(N**2) behavior, so don't want too-large lists: + assume(len(item.current_list) < 50) + # original object unmodified + assert item.original_list == item.original_pvector + # evolver matches: + for i in range(len(item.current_evolver)): + assert item.current_list[i] == item.current_evolver[i] + # persistent version matches + assert_equal(item.current_list, item.current_evolver.persistent()) + # original object still unmodified + assert item.original_list == item.original_pvector + + +PVectorEvolverBuilderTests = PVectorEvolverBuilder.TestCase |