aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/pyrsistent/py2/tests/vector_test.py
diff options
context:
space:
mode:
authorshmel1k <shmel1k@ydb.tech>2023-11-26 18:16:14 +0300
committershmel1k <shmel1k@ydb.tech>2023-11-26 18:43:30 +0300
commitb8cf9e88f4c5c64d9406af533d8948deb050d695 (patch)
tree218eb61fb3c3b96ec08b4d8cdfef383104a87d63 /contrib/python/pyrsistent/py2/tests/vector_test.py
parent523f645a83a0ec97a0332dbc3863bb354c92a328 (diff)
downloadydb-b8cf9e88f4c5c64d9406af533d8948deb050d695.tar.gz
add kikimr_configure
Diffstat (limited to 'contrib/python/pyrsistent/py2/tests/vector_test.py')
-rw-r--r--contrib/python/pyrsistent/py2/tests/vector_test.py934
1 files changed, 934 insertions, 0 deletions
diff --git a/contrib/python/pyrsistent/py2/tests/vector_test.py b/contrib/python/pyrsistent/py2/tests/vector_test.py
new file mode 100644
index 0000000000..aa59ea0c1c
--- /dev/null
+++ b/contrib/python/pyrsistent/py2/tests/vector_test.py
@@ -0,0 +1,934 @@
+import os
+import pickle
+import pytest
+
+from pyrsistent._pvector import python_pvector
+
+
+@pytest.fixture(scope='session', params=['pyrsistent._pvector', 'pvectorc'])
+def pvector(request):
+ if request.param == 'pvectorc' and os.environ.get('PYRSISTENT_NO_C_EXTENSION'):
+ pytest.skip('Configured to not run tests for C extension')
+
+ m = pytest.importorskip(request.param)
+ if request.param == 'pyrsistent._pvector':
+ return m.python_pvector
+ return m.pvector
+
+
+def test_literalish_works():
+ from pyrsistent import pvector, v
+ assert v() is pvector()
+ assert v(1, 2) == pvector([1, 2])
+
+
+def test_empty_initialization(pvector):
+ seq = pvector()
+ assert len(seq) == 0
+
+ with pytest.raises(IndexError) as error:
+ x = seq[0]
+ assert str(error.value) == 'Index out of range: 0'
+
+
+def test_initialization_with_one_element(pvector):
+ seq = pvector([3])
+ assert len(seq) == 1
+ assert seq[0] == 3
+
+
+def test_append_works_and_does_not_affect_original_within_tail(pvector):
+ seq1 = pvector([3])
+ seq2 = seq1.append(2)
+
+ assert len(seq1) == 1
+ assert seq1[0] == 3
+
+ assert len(seq2) == 2
+ assert seq2[0] == 3
+ assert seq2[1] == 2
+
+
+def test_append_works_and_does_not_affect_original_outside_tail(pvector):
+ original = pvector([])
+ seq = original
+
+ for x in range(33):
+ seq = seq.append(x)
+
+ assert len(seq) == 33
+ assert seq[0] == 0
+ assert seq[31] == 31
+ assert seq[32] == 32
+
+ assert len(original) == 0
+
+
+def test_append_when_root_overflows(pvector):
+ seq = pvector([])
+
+ for x in range(32 * 33):
+ seq = seq.append(x)
+
+ seq = seq.append(10001)
+
+ for i in range(32 * 33):
+ assert seq[i] == i
+
+ assert seq[32 * 33] == 10001
+
+
+def test_multi_level_sequence(pvector):
+ seq = pvector(range(8000))
+ seq2 = seq.append(11)
+
+ assert seq[5] == 5
+ assert seq2[7373] == 7373
+ assert seq2[8000] == 11
+
+
+def test_multi_level_sequence_from_iterator(pvector):
+ seq = pvector(iter(range(8000)))
+ seq2 = seq.append(11)
+
+ assert seq[5] == 5
+ assert seq2[7373] == 7373
+ assert seq2[8000] == 11
+
+
+def test_random_insert_within_tail(pvector):
+ seq = pvector([1, 2, 3])
+
+ seq2 = seq.set(1, 4)
+
+ assert seq2[1] == 4
+ assert seq[1] == 2
+
+
+def test_random_insert_outside_tail(pvector):
+ seq = pvector(range(20000))
+
+ seq2 = seq.set(19000, 4)
+
+ assert seq2[19000] == 4
+ assert seq[19000] == 19000
+
+
+def test_insert_beyond_end(pvector):
+ seq = pvector(range(2))
+ seq2 = seq.set(2, 50)
+ assert seq2[2] == 50
+
+ with pytest.raises(IndexError) as error:
+ seq2.set(19, 4)
+
+ assert str(error.value) == 'Index out of range: 19'
+
+
+def test_insert_with_index_from_the_end(pvector):
+ x = pvector([1, 2, 3, 4])
+
+ assert x.set(-2, 5) == pvector([1, 2, 5, 4])
+
+
+def test_insert_with_too_negative_index(pvector):
+ x = pvector([1, 2, 3, 4])
+
+ with pytest.raises(IndexError):
+ x.set(-5, 17)
+
+
+def test_iteration(pvector):
+ y = 0
+ seq = pvector(range(2000))
+ for x in seq:
+ assert x == y
+ y += 1
+
+ assert y == 2000
+
+
+def test_zero_extend(pvector):
+ the_list = []
+ seq = pvector()
+ seq2 = seq.extend(the_list)
+ assert seq == seq2
+
+
+def test_short_extend(pvector):
+ # Extend within tail length
+ the_list = [1, 2]
+ seq = pvector()
+ seq2 = seq.extend(the_list)
+
+ assert len(seq2) == len(the_list)
+ assert seq2[0] == the_list[0]
+ assert seq2[1] == the_list[1]
+
+
+def test_long_extend(pvector):
+ # Multi level extend
+ seq = pvector()
+ length = 2137
+
+ # Extend from scratch
+ seq2 = seq.extend(range(length))
+ assert len(seq2) == length
+ for i in range(length):
+ assert seq2[i] == i
+
+ # Extend already filled vector
+ seq3 = seq2.extend(range(length, length + 5))
+ assert len(seq3) == length + 5
+ for i in range(length + 5):
+ assert seq3[i] == i
+
+ # Check that the original vector is still intact
+ assert len(seq2) == length
+ for i in range(length):
+ assert seq2[i] == i
+
+
+def test_slicing_zero_length_range(pvector):
+ seq = pvector(range(10))
+ seq2 = seq[2:2]
+
+ assert len(seq2) == 0
+
+
+def test_slicing_range(pvector):
+ seq = pvector(range(10))
+ seq2 = seq[2:4]
+
+ assert list(seq2) == [2, 3]
+
+
+def test_slice_identity(pvector):
+ # Pvector is immutable, no need to make a copy!
+ seq = pvector(range(10))
+
+ assert seq is seq[::]
+
+
+def test_slicing_range_with_step(pvector):
+ seq = pvector(range(100))
+ seq2 = seq[2:12:3]
+
+ assert list(seq2) == [2, 5, 8, 11]
+
+
+def test_slicing_no_range_but_step(pvector):
+ seq = pvector(range(10))
+ seq2 = seq[::2]
+
+ assert list(seq2) == [0, 2, 4, 6, 8]
+
+
+def test_slicing_reverse(pvector):
+ seq = pvector(range(10))
+ seq2 = seq[::-1]
+
+ assert seq2[0] == 9
+ assert seq2[1] == 8
+ assert len(seq2) == 10
+
+ seq3 = seq[-3: -7: -1]
+ assert seq3[0] == 7
+ assert seq3[3] == 4
+ assert len(seq3) == 4
+
+
+def test_delete_index(pvector):
+ seq = pvector([1, 2, 3])
+ assert seq.delete(0) == pvector([2, 3])
+ assert seq.delete(1) == pvector([1, 3])
+ assert seq.delete(2) == pvector([1, 2])
+ assert seq.delete(-1) == pvector([1, 2])
+ assert seq.delete(-2) == pvector([1, 3])
+ assert seq.delete(-3) == pvector([2, 3])
+
+
+def test_delete_index_out_of_bounds(pvector):
+ with pytest.raises(IndexError):
+ pvector([]).delete(0)
+ with pytest.raises(IndexError):
+ pvector([]).delete(-1)
+
+
+def test_delete_index_malformed(pvector):
+ with pytest.raises(TypeError):
+ pvector([]).delete('a')
+
+
+def test_delete_slice(pvector):
+ seq = pvector(range(5))
+ assert seq.delete(1, 4) == pvector([0, 4])
+ assert seq.delete(4, 1) == seq
+ assert seq.delete(0, 1) == pvector([1, 2, 3, 4])
+ assert seq.delete(6, 8) == seq
+ assert seq.delete(-1, 1) == seq
+ assert seq.delete(1, -1) == pvector([0, 4])
+
+
+def test_remove(pvector):
+ seq = pvector(range(5))
+ assert seq.remove(3) == pvector([0, 1, 2, 4])
+
+
+def test_remove_first_only(pvector):
+ seq = pvector([1, 2, 3, 2, 1])
+ assert seq.remove(2) == pvector([1, 3, 2, 1])
+
+
+def test_remove_index_out_of_bounds(pvector):
+ seq = pvector(range(5))
+ with pytest.raises(ValueError) as err:
+ seq.remove(5)
+ assert 'not in' in str(err.value)
+
+
+def test_addition(pvector):
+ v = pvector([1, 2]) + pvector([3, 4])
+
+ assert list(v) == [1, 2, 3, 4]
+
+
+def test_sorted(pvector):
+ seq = pvector([5, 2, 3, 1])
+ assert [1, 2, 3, 5] == sorted(seq)
+
+
+def test_boolean_conversion(pvector):
+ assert not bool(pvector())
+ assert bool(pvector([1]))
+
+
+def test_access_with_negative_index(pvector):
+ seq = pvector([1, 2, 3, 4])
+
+ assert seq[-1] == 4
+ assert seq[-4] == 1
+
+
+def test_index_error_positive(pvector):
+ with pytest.raises(IndexError):
+ pvector([1, 2, 3])[3]
+
+
+def test_index_error_negative(pvector):
+ with pytest.raises(IndexError):
+ pvector([1, 2, 3])[-4]
+
+
+def test_is_sequence(pvector):
+ from pyrsistent._compat import Sequence
+ assert isinstance(pvector(), Sequence)
+
+
+def test_empty_repr(pvector):
+ assert str(pvector()) == "pvector([])"
+
+
+def test_non_empty_repr(pvector):
+ v = pvector([1, 2, 3])
+ assert str(v) == "pvector([1, 2, 3])"
+
+ # There's some state that needs to be reset between calls in the native version,
+ # test that multiple invocations work.
+ assert str(v) == "pvector([1, 2, 3])"
+
+
+def test_repr_when_contained_object_contains_reference_to_self(pvector):
+ x = [1, 2, 3]
+ v = pvector([1, 2, x])
+ x.append(v)
+ assert str(v) == 'pvector([1, 2, [1, 2, 3, pvector([1, 2, [...]])]])'
+
+ # Run a GC to provoke any potential misbehavior
+ import gc
+ gc.collect()
+
+
+def test_is_hashable(pvector):
+ from pyrsistent._compat import Hashable
+ v = pvector([1, 2, 3])
+ v2 = pvector([1, 2, 3])
+
+ assert hash(v) == hash(v2)
+ assert isinstance(pvector(), Hashable)
+
+
+def test_refuses_to_hash_when_members_are_unhashable(pvector):
+ v = pvector([1, 2, [1, 2]])
+
+ with pytest.raises(TypeError):
+ hash(v)
+
+
+def test_compare_same_vectors(pvector):
+ v = pvector([1, 2])
+ assert v == v
+ assert pvector() == pvector()
+
+
+def test_compare_with_other_type_of_object(pvector):
+ assert pvector([1, 2]) != 'foo'
+
+
+def test_compare_equal_vectors(pvector):
+ v1 = pvector([1, 2])
+ v2 = pvector([1, 2])
+ assert v1 == v2
+ assert v1 >= v2
+ assert v1 <= v2
+
+
+def test_compare_different_vectors_same_size(pvector):
+ v1 = pvector([1, 2])
+ v2 = pvector([1, 3])
+ assert v1 != v2
+
+
+def test_compare_different_vectors_different_sizes(pvector):
+ v1 = pvector([1, 2])
+ v2 = pvector([1, 2, 3])
+ assert v1 != v2
+
+
+def test_compare_lt_gt(pvector):
+ v1 = pvector([1, 2])
+ v2 = pvector([1, 2, 3])
+ assert v1 < v2
+ assert v2 > v1
+
+
+def test_repeat(pvector):
+ v = pvector([1, 2])
+ assert 5 * pvector() is pvector()
+ assert v is 1 * v
+ assert 0 * v is pvector()
+ assert 2 * pvector([1, 2]) == pvector([1, 2, 1, 2])
+ assert -3 * pvector([1, 2]) is pvector()
+
+
+def test_transform_zero_key_length(pvector):
+ x = pvector([1, 2])
+
+ assert x.transform([], 3) == 3
+
+
+def test_transform_base_case(pvector):
+ x = pvector([1, 2])
+
+ assert x.transform([1], 3) == pvector([1, 3])
+
+
+def test_transform_nested_vectors(pvector):
+ x = pvector([1, 2, pvector([3, 4]), 5])
+
+ assert x.transform([2, 0], 999) == pvector([1, 2, pvector([999, 4]), 5])
+
+
+def test_transform_when_appending(pvector):
+ from pyrsistent import m
+ x = pvector([1, 2])
+
+ assert x.transform([2, 'd'], 999) == pvector([1, 2, m(d=999)])
+
+
+def test_transform_index_error_out_range(pvector):
+ x = pvector([1, 2, pvector([3, 4]), 5])
+
+ with pytest.raises(IndexError):
+ x.transform([2, 10], 999)
+
+
+def test_transform_index_error_wrong_type(pvector):
+ x = pvector([1, 2, pvector([3, 4]), 5])
+
+ with pytest.raises(TypeError):
+ x.transform([2, 'foo'], 999)
+
+
+def test_transform_non_setable_type(pvector):
+ x = pvector([1, 2, 5])
+
+ with pytest.raises(TypeError):
+ x.transform([2, 3], 999)
+
+
+def test_reverse(pvector):
+ x = pvector([1, 2, 5])
+
+ assert list(reversed(x)) == [5, 2, 1]
+
+
+def test_contains(pvector):
+ x = pvector([1, 2, 5])
+
+ assert 2 in x
+ assert 3 not in x
+
+
+def test_index(pvector):
+ x = pvector([1, 2, 5])
+
+ assert x.index(5) == 2
+
+
+def test_index_not_found(pvector):
+ x = pvector([1, 2, 5])
+
+ with pytest.raises(ValueError):
+ x.index(7)
+
+
+def test_index_not_found_with_limits(pvector):
+ x = pvector([1, 2, 5, 1])
+
+ with pytest.raises(ValueError):
+ x.index(1, 1, 3)
+
+
+def test_count(pvector):
+ x = pvector([1, 2, 5, 1])
+
+ assert x.count(1) == 2
+ assert x.count(4) == 0
+
+
+def test_empty_truthiness(pvector):
+ assert pvector([1])
+ assert not pvector([])
+
+
+def test_pickling_empty_vector(pvector):
+ assert pickle.loads(pickle.dumps(pvector(), -1)) == pvector()
+
+
+def test_pickling_non_empty_vector(pvector):
+ assert pickle.loads(pickle.dumps(pvector([1, 'a']), -1)) == pvector([1, 'a'])
+
+
+def test_mset_basic_assignments(pvector):
+ v1 = pvector(range(2000))
+ v2 = v1.mset(1, -1, 505, -505, 1998, -1998)
+
+ # Original not changed
+ assert v1[1] == 1
+ assert v1[505] == 505
+ assert v1[1998] == 1998
+
+ # Other updated
+ assert v2[1] == -1
+ assert v2[505] == -505
+ assert v2[1998] == -1998
+
+
+def test_mset_odd_number_of_arguments(pvector):
+ v = pvector([0, 1])
+
+ with pytest.raises(TypeError):
+ v.mset(0, 10, 1)
+
+
+def test_mset_index_out_of_range(pvector):
+ v = pvector([0, 1])
+
+ with pytest.raises(IndexError):
+ v.mset(3, 10)
+
+
+def test_evolver_no_update(pvector):
+ # This is mostly a test against memory leaks in the C implementation
+ v = pvector(range(40))
+
+ assert v.evolver().persistent() == v
+
+
+def test_evolver_deallocate_dirty_evolver(pvector):
+ # Ref count handling in native implementation
+ v = pvector(range(3220))
+ e = v.evolver()
+ e[10] = -10
+ e[3220] = -3220
+
+
+def test_evolver_simple_update_in_tree(pvector):
+ v = pvector(range(35))
+ e = v.evolver()
+ e[10] = -10
+
+ assert e[10] == -10
+ assert e.persistent()[10] == -10
+
+
+def test_evolver_set_out_of_range(pvector):
+ v = pvector([0])
+ e = v.evolver()
+ with pytest.raises(IndexError) as error:
+ e[10] = 1
+ assert str(error.value) == "Index out of range: 10"
+
+def test_evolver_multi_level_multi_update_in_tree(pvector):
+ # This test is mostly to detect memory/ref count issues in the native implementation
+ v = pvector(range(3500))
+ e = v.evolver()
+
+ # Update differs between first and second time since the
+ # corresponding node will be marked as dirty the first time only.
+ e[10] = -10
+ e[11] = -11
+ e[10] = -1000
+
+ # Update in neighbour node
+ e[50] = -50
+ e[50] = -5000
+
+ # Update in node in other half of vector
+ e[3000] = -3000
+ e[3000] = -30000
+
+ # Before freezing
+ assert e[10] == -1000
+ assert e[11] == -11
+ assert e[50] == -5000
+ assert e[3000] == -30000
+
+ # Run a GC to provoke any potential misbehavior
+ import gc
+ gc.collect()
+
+ v2 = e.persistent()
+ assert v2[10] == -1000
+ assert v2[50] == -5000
+ assert v2[3000] == -30000
+
+ # Run a GC to provoke any potential misbehavior
+ gc.collect()
+
+ # After freezing
+ assert e[10] == -1000
+ assert e[11] == -11
+ assert e[50] == -5000
+ assert e[3000] == -30000
+
+ # Original stays the same
+ assert v[10] == 10
+ assert v[50] == 50
+ assert v[3000] == 3000
+
+
+def test_evolver_simple_update_in_tail(pvector):
+ v = pvector(range(35))
+ e = v.evolver()
+ e[33] = -33
+
+ assert e[33] == -33
+ assert e.persistent()[33] == -33
+ assert v[33] == 33
+
+
+def test_evolver_simple_update_just_outside_vector(pvector):
+ v = pvector()
+ e = v.evolver()
+ e[0] = 1
+
+ assert e[0] == 1
+ assert e.persistent()[0] == 1
+ assert len(v) == 0
+
+
+def test_evolver_append(pvector):
+ v = pvector()
+ e = v.evolver()
+ e.append(1000)
+ assert e[0] == 1000
+
+ e[0] = 2000
+ assert e[0] == 2000
+ assert list(e.persistent()) == [2000]
+ assert list(v) == []
+
+
+def test_evolver_extend(pvector):
+ v = pvector([1000])
+ e = v.evolver()
+ e.extend([2000, 3000])
+ e[2] = 20000
+
+ assert list(e.persistent()) == [1000, 2000, 20000]
+ assert list(v) == [1000]
+
+
+def test_evolver_assign_and_read_with_negative_indices(pvector):
+ v = pvector([1, 2, 3])
+ e = v.evolver()
+ e[-1] = 4
+ e.extend([11, 12, 13])
+ e[-1] = 33
+
+ assert e[-1] == 33
+ assert list(e.persistent()) == [1, 2, 4, 11, 12, 33]
+
+
+def test_evolver_non_integral_access(pvector):
+ e = pvector([1]).evolver()
+
+ with pytest.raises(TypeError):
+ x = e['foo']
+
+
+def test_evolver_non_integral_assignment(pvector):
+ e = pvector([1]).evolver()
+
+ with pytest.raises(TypeError):
+ e['foo'] = 1
+
+
+def test_evolver_out_of_bounds_access(pvector):
+ e = pvector([1]).evolver()
+
+ with pytest.raises(IndexError):
+ x = e[1]
+
+
+def test_evolver_out_of_bounds_assignment(pvector):
+ e = pvector([1]).evolver()
+
+ with pytest.raises(IndexError):
+ e[2] = 1
+
+
+def test_no_dependencies_between_evolvers_from_the_same_pvector(pvector):
+ original_list = list(range(40))
+ v = pvector(original_list)
+ e1 = v.evolver()
+ e2 = v.evolver()
+
+ e1.extend([1, 2, 3])
+ e1[2] = 20
+ e1[35] = 350
+
+ e2.extend([-1, -2, -3])
+ e2[2] = -20
+ e2[35] = -350
+
+ e1_expected = original_list + [1, 2, 3]
+ e1_expected[2] = 20
+ e1_expected[35] = 350
+ assert list(e1.persistent()) == e1_expected
+
+ e2_expected = original_list + [-1, -2, -3]
+ e2_expected[2] = -20
+ e2_expected[35] = -350
+ assert list(e2.persistent()) == e2_expected
+
+
+def test_pvectors_produced_from_the_same_evolver_do_not_interfere(pvector):
+ original_list = list(range(40))
+ v = pvector(original_list)
+ e = v.evolver()
+
+ e.extend([1, 2, 3])
+ e[2] = 20
+ e[35] = 350
+
+ v1 = e.persistent()
+ v1_expected = original_list + [1, 2, 3]
+ v1_expected[2] = 20
+ v1_expected[35] = 350
+
+ e.extend([-1, -2, -3])
+ e[3] = -30
+ e[36] = -360
+
+ v2 = e.persistent()
+ v2_expected = v1_expected + [-1, -2, -3]
+ v2_expected[3] = -30
+ v2_expected[36] = -360
+
+ assert list(v1) == v1_expected
+ assert list(v2) == v2_expected
+
+
+def test_evolver_len(pvector):
+ e = pvector([1, 2, 3]).evolver()
+ e.extend([4, 5])
+
+ assert len(e) == 5
+
+
+def test_evolver_is_dirty(pvector):
+ e = pvector([1, 2, 3]).evolver()
+ assert not e.is_dirty()
+
+ e.append(4)
+ assert e.is_dirty
+
+ e.persistent()
+ assert not e.is_dirty()
+
+ e[2] = 2000
+ assert e.is_dirty
+
+ e.persistent()
+ assert not e.is_dirty()
+
+
+def test_vector_insert_one_step_beyond_end(pvector):
+ # This test exists to get the transform functionality under memory
+ # leak supervision. Most of the transformation tests are in test_transform.py.
+ v = pvector([1, 2])
+ assert v.transform([2], 3) == pvector([1, 2, 3])
+
+
+def test_evolver_with_no_updates_returns_same_pvector(pvector):
+ v = pvector([1, 2])
+ assert v.evolver().persistent() is v
+
+
+def test_evolver_returns_itself_on_evolving_operations(pvector):
+ # Does this to be able to chain operations
+ v = pvector([1, 2])
+ assert v.evolver().append(3).extend([4, 5]).set(1, 6).persistent() == pvector([1, 6, 3, 4, 5])
+
+
+def test_evolver_delete_by_index(pvector):
+ e = pvector([1, 2, 3]).evolver()
+
+ del e[0]
+
+ assert e.persistent() == python_pvector([2, 3])
+ assert e.append(4).persistent() == python_pvector([2, 3, 4])
+
+
+def test_evolver_delete_function_by_index(pvector):
+ e = pvector([1, 2, 3]).evolver()
+
+ assert e.delete(1).persistent() == python_pvector([1, 3])
+
+
+def test_evolver_delete_function_by_index_multiple_times(pvector):
+ SIZE = 40
+ e = pvector(range(SIZE)).evolver()
+ for i in range(SIZE):
+ assert e[0] == i
+ assert list(e.persistent()) == list(range(i, SIZE))
+ del e[0]
+
+ assert e.persistent() == list()
+
+
+def test_evolver_delete_function_invalid_index(pvector):
+ e = pvector([1, 2]).evolver()
+
+ with pytest.raises(TypeError):
+ del e["e"]
+
+
+def test_delete_of_non_existing_element(pvector):
+ e = pvector([1, 2]).evolver()
+
+ with pytest.raises(IndexError):
+ del e[2]
+
+ del e[0]
+ del e[0]
+
+ with pytest.raises(IndexError):
+ del e[0]
+
+ assert e.persistent() == pvector()
+
+
+def test_append_followed_by_delete(pvector):
+ e = pvector([1, 2]).evolver()
+
+ e.append(3)
+
+ del e[2]
+
+
+def test_evolver_set_followed_by_delete(pvector):
+ evolver = pvector([1, 2]).evolver()
+ evolver[1] = 3
+
+ assert [evolver[i] for i in range(len(evolver))] == [1, 3]
+
+ del evolver[0]
+
+ assert evolver.persistent() == pvector([3])
+
+
+def test_compare_with_list(pvector):
+ v = pvector([1, 2, 3])
+
+ assert v == [1, 2, 3]
+ assert v != [1, 2]
+ assert v > [1, 2]
+ assert v < [2, 2]
+ assert [1, 2] < v
+ assert v <= [1, 2, 3]
+ assert v <= [1, 2, 4]
+ assert v >= [1, 2, 3]
+ assert v >= [1, 2]
+
+
+def test_compare_with_non_iterable(pvector):
+ assert pvector([1, 2, 3]) != 5
+ assert not (pvector([1, 2, 3]) == 5)
+
+
+def test_python_no_c_extension_with_environment_variable():
+ from six.moves import reload_module
+ import pyrsistent._pvector
+ import pyrsistent
+ import os
+
+ os.environ['PYRSISTENT_NO_C_EXTENSION'] = 'TRUE'
+
+ reload_module(pyrsistent._pvector)
+ reload_module(pyrsistent)
+
+ assert type(pyrsistent.pvector()) is pyrsistent._pvector.PythonPVector
+
+ del os.environ['PYRSISTENT_NO_C_EXTENSION']
+
+ reload_module(pyrsistent._pvector)
+ reload_module(pyrsistent)
+
+
+def test_supports_weakref(pvector):
+ import weakref
+ weakref.ref(pvector())
+
+def test_get_evolver_referents(pvector):
+ """The C implementation of the evolver should expose the original PVector
+ to the gc only once.
+ """
+ if pvector.__module__ == 'pyrsistent._pvector':
+ pytest.skip("This test only applies to pvectorc")
+ import gc
+ v = pvector([1, 2, 3])
+ e = v.evolver()
+ assert len([x for x in gc.get_referents(e) if x is v]) == 1
+
+
+def test_failing_repr(pvector):
+ # See https://github.com/tobgu/pyrsistent/issues/84
+ class A(object):
+ def __repr__(self):
+ raise ValueError('oh no!')
+
+ with pytest.raises(ValueError):
+ repr(pvector([A()]))
+
+
+def test_iterable(pvector):
+ """
+ PVectors can be created from iterables even though they can't be len()
+ hinted.
+ """
+
+ assert pvector(iter("a")) == pvector(iter("a"))