blob: 58a1f8790ae23cc1b80cd12f43881cf22c9777d8 [file] [log] [blame]
Georg Brandl9dba5d92008-05-18 16:27:29 +00001import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002from test import support
Georg Brandl9dba5d92008-05-18 16:27:29 +00003from weakref import proxy, ref, WeakSet
4import operator
5import copy
6import string
7import os
8from random import randrange, shuffle
9import sys
10import warnings
11import collections
12from collections import UserString as ustr
Antoine Pitrouc1baa602010-01-08 17:54:23 +000013import gc
14import contextlib
Georg Brandl9dba5d92008-05-18 16:27:29 +000015
16
17class Foo:
18 pass
19
20
21class TestWeakSet(unittest.TestCase):
22
23 def setUp(self):
24 # need to keep references to them
25 self.items = [ustr(c) for c in ('a', 'b', 'c')]
26 self.items2 = [ustr(c) for c in ('x', 'y', 'z')]
27 self.letters = [ustr(c) for c in string.ascii_letters]
28 self.s = WeakSet(self.items)
29 self.d = dict.fromkeys(self.items)
30 self.obj = ustr('F')
31 self.fs = WeakSet([self.obj])
32
33 def test_methods(self):
34 weaksetmethods = dir(WeakSet)
35 for method in dir(set):
Georg Brandl02c0bbb2008-05-18 21:04:46 +000036 if method == 'test_c_api' or method.startswith('_'):
Georg Brandl9dba5d92008-05-18 16:27:29 +000037 continue
Ezio Melottib58e0bd2010-01-23 15:40:09 +000038 self.assertIn(method, weaksetmethods,
Georg Brandl19219702008-05-18 17:10:40 +000039 "WeakSet missing method " + method)
Georg Brandl9dba5d92008-05-18 16:27:29 +000040
41 def test_new_or_init(self):
42 self.assertRaises(TypeError, WeakSet, [], 2)
43
44 def test_len(self):
45 self.assertEqual(len(self.s), len(self.d))
46 self.assertEqual(len(self.fs), 1)
47 del self.obj
48 self.assertEqual(len(self.fs), 0)
49
50 def test_contains(self):
51 for c in self.letters:
52 self.assertEqual(c in self.s, c in self.d)
Georg Brandlf8de3fe2010-12-03 07:55:44 +000053 # 1 is not weakref'able, but that TypeError is caught by __contains__
54 self.assertNotIn(1, self.s)
Benjamin Peterson577473f2010-01-19 00:09:57 +000055 self.assertIn(self.obj, self.fs)
Georg Brandl9dba5d92008-05-18 16:27:29 +000056 del self.obj
Benjamin Peterson577473f2010-01-19 00:09:57 +000057 self.assertNotIn(ustr('F'), self.fs)
Georg Brandl9dba5d92008-05-18 16:27:29 +000058
59 def test_union(self):
60 u = self.s.union(self.items2)
61 for c in self.letters:
62 self.assertEqual(c in u, c in self.d or c in self.items2)
63 self.assertEqual(self.s, WeakSet(self.items))
64 self.assertEqual(type(u), WeakSet)
65 self.assertRaises(TypeError, self.s.union, [[]])
66 for C in set, frozenset, dict.fromkeys, list, tuple:
67 x = WeakSet(self.items + self.items2)
68 c = C(self.items2)
69 self.assertEqual(self.s.union(c), x)
70
71 def test_or(self):
72 i = self.s.union(self.items2)
73 self.assertEqual(self.s | set(self.items2), i)
74 self.assertEqual(self.s | frozenset(self.items2), i)
75
76 def test_intersection(self):
77 i = self.s.intersection(self.items2)
78 for c in self.letters:
79 self.assertEqual(c in i, c in self.d and c in self.items2)
80 self.assertEqual(self.s, WeakSet(self.items))
81 self.assertEqual(type(i), WeakSet)
82 for C in set, frozenset, dict.fromkeys, list, tuple:
83 x = WeakSet([])
84 self.assertEqual(self.s.intersection(C(self.items2)), x)
85
86 def test_isdisjoint(self):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000087 self.assertTrue(self.s.isdisjoint(WeakSet(self.items2)))
88 self.assertTrue(not self.s.isdisjoint(WeakSet(self.letters)))
Georg Brandl9dba5d92008-05-18 16:27:29 +000089
90 def test_and(self):
91 i = self.s.intersection(self.items2)
92 self.assertEqual(self.s & set(self.items2), i)
93 self.assertEqual(self.s & frozenset(self.items2), i)
94
95 def test_difference(self):
96 i = self.s.difference(self.items2)
97 for c in self.letters:
98 self.assertEqual(c in i, c in self.d and c not in self.items2)
99 self.assertEqual(self.s, WeakSet(self.items))
100 self.assertEqual(type(i), WeakSet)
101 self.assertRaises(TypeError, self.s.difference, [[]])
102
103 def test_sub(self):
104 i = self.s.difference(self.items2)
105 self.assertEqual(self.s - set(self.items2), i)
106 self.assertEqual(self.s - frozenset(self.items2), i)
107
108 def test_symmetric_difference(self):
109 i = self.s.symmetric_difference(self.items2)
110 for c in self.letters:
111 self.assertEqual(c in i, (c in self.d) ^ (c in self.items2))
112 self.assertEqual(self.s, WeakSet(self.items))
113 self.assertEqual(type(i), WeakSet)
114 self.assertRaises(TypeError, self.s.symmetric_difference, [[]])
115
116 def test_xor(self):
117 i = self.s.symmetric_difference(self.items2)
118 self.assertEqual(self.s ^ set(self.items2), i)
119 self.assertEqual(self.s ^ frozenset(self.items2), i)
120
121 def test_sub_and_super(self):
122 pl, ql, rl = map(lambda s: [ustr(c) for c in s], ['ab', 'abcde', 'def'])
123 p, q, r = map(WeakSet, (pl, ql, rl))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000124 self.assertTrue(p < q)
125 self.assertTrue(p <= q)
126 self.assertTrue(q <= q)
127 self.assertTrue(q > p)
128 self.assertTrue(q >= p)
129 self.assertFalse(q < r)
130 self.assertFalse(q <= r)
131 self.assertFalse(q > r)
132 self.assertFalse(q >= r)
133 self.assertTrue(set('a').issubset('abc'))
134 self.assertTrue(set('abc').issuperset('a'))
135 self.assertFalse(set('a').issubset('cbs'))
136 self.assertFalse(set('cbs').issuperset('a'))
Georg Brandl9dba5d92008-05-18 16:27:29 +0000137
138 def test_gc(self):
139 # Create a nest of cycles to exercise overall ref count check
Robert Schuppenies4ad1d6f2009-05-17 17:32:20 +0000140 s = WeakSet(Foo() for i in range(1000))
Georg Brandl9dba5d92008-05-18 16:27:29 +0000141 for elem in s:
142 elem.cycle = s
143 elem.sub = elem
Robert Schuppenies4ad1d6f2009-05-17 17:32:20 +0000144 elem.set = WeakSet([elem])
Georg Brandl9dba5d92008-05-18 16:27:29 +0000145
146 def test_subclass_with_custom_hash(self):
147 # Bug #1257731
148 class H(WeakSet):
149 def __hash__(self):
150 return int(id(self) & 0x7fffffff)
151 s=H()
152 f=set()
153 f.add(s)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000154 self.assertIn(s, f)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000155 f.remove(s)
156 f.add(s)
157 f.discard(s)
158
159 def test_init(self):
160 s = WeakSet()
161 s.__init__(self.items)
162 self.assertEqual(s, self.s)
163 s.__init__(self.items2)
164 self.assertEqual(s, WeakSet(self.items2))
165 self.assertRaises(TypeError, s.__init__, s, 2);
166 self.assertRaises(TypeError, s.__init__, 1);
167
168 def test_constructor_identity(self):
169 s = WeakSet(self.items)
170 t = WeakSet(s)
171 self.assertNotEqual(id(s), id(t))
172
Georg Brandl9dba5d92008-05-18 16:27:29 +0000173 def test_hash(self):
174 self.assertRaises(TypeError, hash, self.s)
175
176 def test_clear(self):
177 self.s.clear()
Robert Schuppenies4ad1d6f2009-05-17 17:32:20 +0000178 self.assertEqual(self.s, WeakSet([]))
Georg Brandl9dba5d92008-05-18 16:27:29 +0000179 self.assertEqual(len(self.s), 0)
180
181 def test_copy(self):
182 dup = self.s.copy()
183 self.assertEqual(self.s, dup)
184 self.assertNotEqual(id(self.s), id(dup))
185
186 def test_add(self):
187 x = ustr('Q')
188 self.s.add(x)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000189 self.assertIn(x, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000190 dup = self.s.copy()
191 self.s.add(x)
192 self.assertEqual(self.s, dup)
193 self.assertRaises(TypeError, self.s.add, [])
194 self.fs.add(Foo())
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000195 self.assertTrue(len(self.fs) == 1)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000196 self.fs.add(self.obj)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000197 self.assertTrue(len(self.fs) == 1)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000198
199 def test_remove(self):
200 x = ustr('a')
201 self.s.remove(x)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000202 self.assertNotIn(x, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000203 self.assertRaises(KeyError, self.s.remove, x)
204 self.assertRaises(TypeError, self.s.remove, [])
205
206 def test_discard(self):
207 a, q = ustr('a'), ustr('Q')
208 self.s.discard(a)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000209 self.assertNotIn(a, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000210 self.s.discard(q)
211 self.assertRaises(TypeError, self.s.discard, [])
212
213 def test_pop(self):
214 for i in range(len(self.s)):
215 elem = self.s.pop()
Benjamin Peterson577473f2010-01-19 00:09:57 +0000216 self.assertNotIn(elem, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000217 self.assertRaises(KeyError, self.s.pop)
218
219 def test_update(self):
220 retval = self.s.update(self.items2)
221 self.assertEqual(retval, None)
222 for c in (self.items + self.items2):
Benjamin Peterson577473f2010-01-19 00:09:57 +0000223 self.assertIn(c, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000224 self.assertRaises(TypeError, self.s.update, [[]])
225
226 def test_update_set(self):
227 self.s.update(set(self.items2))
228 for c in (self.items + self.items2):
Benjamin Peterson577473f2010-01-19 00:09:57 +0000229 self.assertIn(c, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000230
231 def test_ior(self):
232 self.s |= set(self.items2)
233 for c in (self.items + self.items2):
Benjamin Peterson577473f2010-01-19 00:09:57 +0000234 self.assertIn(c, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000235
236 def test_intersection_update(self):
237 retval = self.s.intersection_update(self.items2)
238 self.assertEqual(retval, None)
239 for c in (self.items + self.items2):
240 if c in self.items2 and c in self.items:
Benjamin Peterson577473f2010-01-19 00:09:57 +0000241 self.assertIn(c, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000242 else:
Benjamin Peterson577473f2010-01-19 00:09:57 +0000243 self.assertNotIn(c, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000244 self.assertRaises(TypeError, self.s.intersection_update, [[]])
245
246 def test_iand(self):
247 self.s &= set(self.items2)
248 for c in (self.items + self.items2):
249 if c in self.items2 and c in self.items:
Benjamin Peterson577473f2010-01-19 00:09:57 +0000250 self.assertIn(c, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000251 else:
Benjamin Peterson577473f2010-01-19 00:09:57 +0000252 self.assertNotIn(c, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000253
254 def test_difference_update(self):
255 retval = self.s.difference_update(self.items2)
256 self.assertEqual(retval, None)
257 for c in (self.items + self.items2):
258 if c in self.items and c not in self.items2:
Benjamin Peterson577473f2010-01-19 00:09:57 +0000259 self.assertIn(c, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000260 else:
Benjamin Peterson577473f2010-01-19 00:09:57 +0000261 self.assertNotIn(c, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000262 self.assertRaises(TypeError, self.s.difference_update, [[]])
263 self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])
264
265 def test_isub(self):
266 self.s -= set(self.items2)
267 for c in (self.items + self.items2):
268 if c in self.items and c not in self.items2:
Benjamin Peterson577473f2010-01-19 00:09:57 +0000269 self.assertIn(c, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000270 else:
Benjamin Peterson577473f2010-01-19 00:09:57 +0000271 self.assertNotIn(c, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000272
273 def test_symmetric_difference_update(self):
274 retval = self.s.symmetric_difference_update(self.items2)
275 self.assertEqual(retval, None)
276 for c in (self.items + self.items2):
277 if (c in self.items) ^ (c in self.items2):
Benjamin Peterson577473f2010-01-19 00:09:57 +0000278 self.assertIn(c, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000279 else:
Benjamin Peterson577473f2010-01-19 00:09:57 +0000280 self.assertNotIn(c, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000281 self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])
282
283 def test_ixor(self):
284 self.s ^= set(self.items2)
285 for c in (self.items + self.items2):
286 if (c in self.items) ^ (c in self.items2):
Benjamin Peterson577473f2010-01-19 00:09:57 +0000287 self.assertIn(c, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000288 else:
Benjamin Peterson577473f2010-01-19 00:09:57 +0000289 self.assertNotIn(c, self.s)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000290
291 def test_inplace_on_self(self):
292 t = self.s.copy()
293 t |= t
294 self.assertEqual(t, self.s)
295 t &= t
296 self.assertEqual(t, self.s)
297 t -= t
298 self.assertEqual(t, WeakSet())
299 t = self.s.copy()
300 t ^= t
301 self.assertEqual(t, WeakSet())
302
Robert Schuppenies4ad1d6f2009-05-17 17:32:20 +0000303 def test_eq(self):
304 # issue 5964
305 self.assertTrue(self.s == self.s)
306 self.assertTrue(self.s == WeakSet(self.items))
307 self.assertFalse(self.s == set(self.items))
308 self.assertFalse(self.s == list(self.items))
309 self.assertFalse(self.s == tuple(self.items))
310 self.assertFalse(self.s == WeakSet([Foo]))
311 self.assertFalse(self.s == 1)
312
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000313 def test_weak_destroy_while_iterating(self):
314 # Issue #7105: iterators shouldn't crash when a key is implicitly removed
315 # Create new items to be sure no-one else holds a reference
316 items = [ustr(c) for c in ('a', 'b', 'c')]
317 s = WeakSet(items)
318 it = iter(s)
319 next(it) # Trigger internal iteration
320 # Destroy an item
321 del items[-1]
322 gc.collect() # just in case
323 # We have removed either the first consumed items, or another one
324 self.assertIn(len(list(it)), [len(items), len(items) - 1])
325 del it
326 # The removal has been committed
327 self.assertEqual(len(s), len(items))
328
329 def test_weak_destroy_and_mutate_while_iterating(self):
330 # Issue #7105: iterators shouldn't crash when a key is implicitly removed
331 items = [ustr(c) for c in string.ascii_letters]
332 s = WeakSet(items)
333 @contextlib.contextmanager
334 def testcontext():
335 try:
336 it = iter(s)
337 next(it)
338 # Schedule an item for removal and recreate it
339 u = ustr(str(items.pop()))
340 gc.collect() # just in case
341 yield u
342 finally:
343 it = None # should commit all removals
344
345 with testcontext() as u:
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000346 self.assertNotIn(u, s)
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000347 with testcontext() as u:
348 self.assertRaises(KeyError, s.remove, u)
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000349 self.assertNotIn(u, s)
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000350 with testcontext() as u:
351 s.add(u)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000352 self.assertIn(u, s)
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000353 t = s.copy()
354 with testcontext() as u:
355 s.update(t)
356 self.assertEqual(len(s), len(t))
357 with testcontext() as u:
358 s.clear()
359 self.assertEqual(len(s), 0)
360
Georg Brandl9dba5d92008-05-18 16:27:29 +0000361
362def test_main(verbose=None):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000363 support.run_unittest(TestWeakSet)
Georg Brandl9dba5d92008-05-18 16:27:29 +0000364
365if __name__ == "__main__":
366 test_main(verbose=True)