1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
from copy import copy
from unittest.mock import Mock, call
import pytest
from psygnal.containers import EventedOrderedSet, EventedSet, OrderedSet
@pytest.fixture
def regular_set():
return set(range(5))
@pytest.fixture(params=[EventedSet, EventedOrderedSet])
def test_set(request, regular_set):
return request.param(regular_set)
@pytest.mark.parametrize(
"meth",
[
# METHOD, ARGS, EXPECTED EVENTS
# primary interface
("add", 2, []),
("add", 10, [call((10,), ())]),
("discard", 2, [call((), (2,))]),
("remove", 2, [call((), (2,))]),
("discard", 10, []),
# parity with set
("update", {3, 4, 5, 6}, [call((5, 6), ())]),
("difference_update", {3, 4, 5, 6}, [call((), (3, 4))]),
("intersection_update", {3, 4, 5, 6}, [call((), (0, 1, 2))]),
("symmetric_difference_update", {3, 4, 5, 6}, [call((5, 6), (3, 4))]),
],
ids=lambda x: x[0],
)
def test_set_interface_parity(test_set: EventedSet, regular_set: set, meth):
method_name, arg, expected = meth
mock = Mock()
test_set.events.items_changed.connect(mock)
test_set_method = getattr(test_set, method_name)
assert tuple(test_set) == tuple(regular_set)
regular_set_method = getattr(regular_set, method_name)
assert test_set_method(arg) == regular_set_method(arg)
assert tuple(test_set) == tuple(regular_set)
mock.assert_has_calls(expected)
assert type(test_set).__name__ in repr(test_set)
def test_set_pop(test_set: EventedSet):
mock = Mock()
test_set.events.items_changed.connect(mock)
npops = len(test_set)
while test_set:
test_set.pop()
assert mock.call_count == npops
with pytest.raises(KeyError):
test_set.pop()
with pytest.raises(KeyError):
test_set.remove(34)
def test_set_clear(test_set: EventedSet):
mock = Mock()
test_set.events.items_changed.connect(mock)
mock.assert_not_called()
test_set.clear()
mock.assert_called_once_with((), (0, 1, 2, 3, 4))
@pytest.mark.parametrize(
"meth",
[
("difference", {3, 4, 5, 6}),
("intersection", {3, 4, 5, 6}),
("issubset", {3, 4}),
("issubset", {3, 4, 5, 6}),
("issubset", {1, 2, 3, 4, 5, 6}),
("issuperset", {3, 4}),
("issuperset", {3, 4, 5, 6}),
("issuperset", {1, 2, 3, 4, 5, 6}),
("symmetric_difference", {3, 4, 5, 6}),
("union", {3, 4, 5, 6}),
],
)
def test_set_new_objects(test_set: EventedSet, regular_set: set, meth):
method_name, arg = meth
test_set_method = getattr(test_set, method_name)
assert tuple(test_set) == tuple(regular_set)
mock = Mock()
test_set.events.items_changed.connect(mock)
regular_set_method = getattr(regular_set, method_name)
result = test_set_method(arg)
assert result == regular_set_method(arg)
assert isinstance(result, (EventedSet, EventedOrderedSet, bool))
assert result is not test_set
mock.assert_not_called()
def test_ordering():
tup = (24, 16, 8, 4, 5, 6)
s_tup = set(tup)
os_tup = OrderedSet(tup)
assert tuple(s_tup) != tup
assert repr(s_tup) == "{4, 5, 6, 8, 16, 24}"
assert tuple(os_tup) == tup
assert repr(os_tup) == "OrderedSet((24, 16, 8, 4, 5, 6))"
os_tup.discard(8)
os_tup.add(8)
assert tuple(os_tup) == (24, 16, 4, 5, 6, 8)
def test_copy(test_set):
from copy import copy
assert test_set.copy() == copy(test_set)
assert test_set is not copy(test_set)
assert isinstance(copy(test_set), type(test_set))
def test_repr(test_set):
if isinstance(test_set, EventedOrderedSet):
assert repr(test_set) == "EventedOrderedSet((0, 1, 2, 3, 4))"
else:
assert repr(test_set) == "EventedSet({0, 1, 2, 3, 4})"
def test_copy_no_sync():
s1 = EventedSet([1, 2, 3])
s2 = copy(s1)
s1.add(4)
assert len(s2) == 3
def test_set_emission_order():
s = EventedSet()
def callback1():
if 1 not in s:
s.add(1)
def callback2():
if 5 not in s:
s.update(range(5, 10))
s.events.items_changed.connect(callback1)
s.events.items_changed.connect(callback2)
mock = Mock()
s.events.items_changed.connect(mock)
s.add(11)
mock.assert_has_calls(
[
call((11,), ()),
call((1,), ()),
call((5, 6, 7, 8, 9), ()),
]
)
|