blob: 35ce46a5232813f3fef4f6869d6100dbe9f3c0d1 [file] [log] [blame]
Guido van Rossum581cb932003-02-06 17:52:15 +00001"""Unit tests for the copy module."""
2
3import sys
4import copy
Guido van Rossumc06e3ac2003-02-07 17:30:18 +00005import copy_reg
Guido van Rossum581cb932003-02-06 17:52:15 +00006
7import unittest
8from test import test_support
9
10class TestCopy(unittest.TestCase):
11
12 # Attempt full line coverage of copy.py from top to bottom
13
14 def test_exceptions(self):
15 self.assert_(copy.Error is copy.error)
16 self.assert_(issubclass(copy.Error, Exception))
17
18 # The copy() method
19
20 def test_copy_basic(self):
21 x = 42
22 y = copy.copy(x)
23 self.assertEqual(x, y)
24
25 def test_copy_copy(self):
26 class C(object):
27 def __init__(self, foo):
28 self.foo = foo
29 def __copy__(self):
30 return C(self.foo)
31 x = C(42)
32 y = copy.copy(x)
33 self.assertEqual(y.__class__, x.__class__)
34 self.assertEqual(y.foo, x.foo)
35
Guido van Rossumc06e3ac2003-02-07 17:30:18 +000036 def test_copy_registry(self):
37 class C(object):
38 def __new__(cls, foo):
39 obj = object.__new__(cls)
40 obj.foo = foo
41 return obj
42 def pickle_C(obj):
43 return (C, (obj.foo,))
44 x = C(42)
45 self.assertRaises(TypeError, copy.copy, x)
46 copy_reg.pickle(C, pickle_C, C)
47 y = copy.copy(x)
48
Guido van Rossum581cb932003-02-06 17:52:15 +000049 def test_copy_reduce(self):
50 class C(object):
51 def __reduce__(self):
52 return ""
53 x = C()
54 y = copy.copy(x)
55 self.assert_(y is x)
56
57 def test_copy_cant(self):
Guido van Rossumc7557582003-02-06 19:53:22 +000058 class Meta(type):
Guido van Rossum581cb932003-02-06 17:52:15 +000059 def __getattribute__(self, name):
60 if name == "__reduce__":
61 raise AttributeError, name
62 return object.__getattribute__(self, name)
Guido van Rossumc7557582003-02-06 19:53:22 +000063 class C:
64 __metaclass__ = Meta
Guido van Rossum581cb932003-02-06 17:52:15 +000065 x = C()
66 self.assertRaises(copy.Error, copy.copy, x)
67
68 # Type-specific _copy_xxx() methods
69
70 def test_copy_atomic(self):
71 class Classic:
72 pass
73 class NewStyle(object):
74 pass
75 def f():
76 pass
77 tests = [None, 42, 2L**100, 3.14, True, False, 1j,
78 "hello", u"hello\u1234", f.func_code,
79 NewStyle, xrange(10), Classic]
80 for x in tests:
81 self.assert_(copy.copy(x) is x, `x`)
82
83 def test_copy_list(self):
84 x = [1, 2, 3]
85 self.assertEqual(copy.copy(x), x)
86
87 def test_copy_tuple(self):
88 x = (1, 2, 3)
89 self.assertEqual(copy.copy(x), x)
90
91 def test_copy_dict(self):
92 x = {"foo": 1, "bar": 2}
93 self.assertEqual(copy.copy(x), x)
94
95 def test_copy_inst_vanilla(self):
96 class C:
97 def __init__(self, foo):
98 self.foo = foo
99 def __cmp__(self, other):
100 return cmp(self.foo, other.foo)
101 x = C(42)
102 self.assertEqual(copy.copy(x), x)
103
104 def test_copy_inst_copy(self):
105 class C:
106 def __init__(self, foo):
107 self.foo = foo
108 def __copy__(self):
109 return C(self.foo)
110 def __cmp__(self, other):
111 return cmp(self.foo, other.foo)
112 x = C(42)
113 self.assertEqual(copy.copy(x), x)
114
115 def test_copy_inst_getinitargs(self):
116 class C:
117 def __init__(self, foo):
118 self.foo = foo
119 def __getinitargs__(self):
120 return (self.foo,)
121 def __cmp__(self, other):
122 return cmp(self.foo, other.foo)
123 x = C(42)
124 self.assertEqual(copy.copy(x), x)
125
126 def test_copy_inst_getstate(self):
127 class C:
128 def __init__(self, foo):
129 self.foo = foo
130 def __getstate__(self):
131 return {"foo": self.foo}
132 def __cmp__(self, other):
133 return cmp(self.foo, other.foo)
134 x = C(42)
135 self.assertEqual(copy.copy(x), x)
136
137 def test_copy_inst_setstate(self):
138 class C:
139 def __init__(self, foo):
140 self.foo = foo
141 def __setstate__(self, state):
142 self.foo = state["foo"]
143 def __cmp__(self, other):
144 return cmp(self.foo, other.foo)
145 x = C(42)
146 self.assertEqual(copy.copy(x), x)
147
148 def test_copy_inst_getstate_setstate(self):
149 class C:
150 def __init__(self, foo):
151 self.foo = foo
152 def __getstate__(self):
153 return self.foo
154 def __setstate__(self, state):
155 self.foo = state
156 def __cmp__(self, other):
157 return cmp(self.foo, other.foo)
158 x = C(42)
159 self.assertEqual(copy.copy(x), x)
160
161 # The deepcopy() method
162
163 def test_deepcopy_basic(self):
164 x = 42
165 y = copy.deepcopy(x)
166 self.assertEqual(y, x)
167
168 def test_deepcopy_memo(self):
169 x = []
170 x.append(x)
171 y = copy.deepcopy(x)
172 self.assertEqual(y, x)
173 self.assert_(y is not x)
174 self.assert_(y[0] is not x[0])
175 self.assert_(y is y[0])
176
177 def test_deepcopy_issubclass(self):
178 # XXX Note: there's no way to test the TypeError coming out of
179 # issubclass() -- this can only happen when an extension
180 # module defines a "type" that doesn't formally inherit from
181 # type.
182 class Meta(type):
183 pass
184 class C:
185 __metaclass__ = Meta
186 self.assertEqual(copy.deepcopy(C), C)
187
188 def test_deepcopy_deepcopy(self):
189 class C(object):
190 def __init__(self, foo):
191 self.foo = foo
192 def __deepcopy__(self, memo=None):
193 return C(self.foo)
194 x = C(42)
195 y = copy.deepcopy(x)
196 self.assertEqual(y.__class__, x.__class__)
197 self.assertEqual(y.foo, x.foo)
198
Guido van Rossumc06e3ac2003-02-07 17:30:18 +0000199 def test_deepcopy_registry(self):
200 class C(object):
201 def __new__(cls, foo):
202 obj = object.__new__(cls)
203 obj.foo = foo
204 return obj
205 def pickle_C(obj):
206 return (C, (obj.foo,))
207 x = C(42)
208 self.assertRaises(TypeError, copy.deepcopy, x)
209 copy_reg.pickle(C, pickle_C, C)
210 y = copy.deepcopy(x)
211
Guido van Rossum581cb932003-02-06 17:52:15 +0000212 def test_deepcopy_reduce(self):
213 class C(object):
214 def __reduce__(self):
215 return ""
216 x = C()
217 y = copy.deepcopy(x)
218 self.assert_(y is x)
219
220 def test_deepcopy_cant(self):
Guido van Rossumc7557582003-02-06 19:53:22 +0000221 class Meta(type):
Guido van Rossum581cb932003-02-06 17:52:15 +0000222 def __getattribute__(self, name):
223 if name == "__reduce__":
224 raise AttributeError, name
225 return object.__getattribute__(self, name)
Guido van Rossumc7557582003-02-06 19:53:22 +0000226 class C:
227 __metaclass__ = Meta
Guido van Rossum581cb932003-02-06 17:52:15 +0000228 x = C()
229 self.assertRaises(copy.Error, copy.deepcopy, x)
230
231 # Type-specific _deepcopy_xxx() methods
232
233 def test_deepcopy_atomic(self):
234 class Classic:
235 pass
236 class NewStyle(object):
237 pass
238 def f():
239 pass
240 tests = [None, 42, 2L**100, 3.14, True, False, 1j,
241 "hello", u"hello\u1234", f.func_code,
242 NewStyle, xrange(10)]
243 for x in tests:
244 self.assert_(copy.deepcopy(x) is x, `x`)
245
246 def test_deepcopy_list(self):
247 x = [[1, 2], 3]
248 y = copy.deepcopy(x)
249 self.assertEqual(y, x)
250 self.assert_(x is not y)
251 self.assert_(x[0] is not y[0])
252
253 def test_deepcopy_tuple(self):
254 x = ([1, 2], 3)
255 y = copy.deepcopy(x)
256 self.assertEqual(y, x)
257 self.assert_(x is not y)
258 self.assert_(x[0] is not y[0])
259
260 def test_deepcopy_dict(self):
261 x = {"foo": [1, 2], "bar": 3}
262 y = copy.deepcopy(x)
263 self.assertEqual(y, x)
264 self.assert_(x is not y)
265 self.assert_(x["foo"] is not y["foo"])
266
267 def test_deepcopy_keepalive(self):
268 memo = {}
269 x = 42
270 y = copy.deepcopy(x, memo)
271 self.assert_(memo[id(x)] is x)
272
273 def test_deepcopy_inst_vanilla(self):
274 class C:
275 def __init__(self, foo):
276 self.foo = foo
277 def __cmp__(self, other):
278 return cmp(self.foo, other.foo)
279 x = C([42])
280 y = copy.deepcopy(x)
281 self.assertEqual(y, x)
282 self.assert_(y.foo is not x.foo)
283
284 def test_deepcopy_inst_deepcopy(self):
285 class C:
286 def __init__(self, foo):
287 self.foo = foo
288 def __deepcopy__(self, memo):
289 return C(copy.deepcopy(self.foo, memo))
290 def __cmp__(self, other):
291 return cmp(self.foo, other.foo)
292 x = C([42])
293 y = copy.deepcopy(x)
294 self.assertEqual(y, x)
295 self.assert_(y is not x)
296 self.assert_(y.foo is not x.foo)
297
298 def test_deepcopy_inst_getinitargs(self):
299 class C:
300 def __init__(self, foo):
301 self.foo = foo
302 def __getinitargs__(self):
303 return (self.foo,)
304 def __cmp__(self, other):
305 return cmp(self.foo, other.foo)
306 x = C([42])
307 y = copy.deepcopy(x)
308 self.assertEqual(y, x)
309 self.assert_(y is not x)
310 self.assert_(y.foo is not x.foo)
311
312 def test_deepcopy_inst_getstate(self):
313 class C:
314 def __init__(self, foo):
315 self.foo = foo
316 def __getstate__(self):
317 return {"foo": self.foo}
318 def __cmp__(self, other):
319 return cmp(self.foo, other.foo)
320 x = C([42])
321 y = copy.deepcopy(x)
322 self.assertEqual(y, x)
323 self.assert_(y is not x)
324 self.assert_(y.foo is not x.foo)
325
326 def test_deepcopy_inst_setstate(self):
327 class C:
328 def __init__(self, foo):
329 self.foo = foo
330 def __setstate__(self, state):
331 self.foo = state["foo"]
332 def __cmp__(self, other):
333 return cmp(self.foo, other.foo)
334 x = C([42])
335 y = copy.deepcopy(x)
336 self.assertEqual(y, x)
337 self.assert_(y is not x)
338 self.assert_(y.foo is not x.foo)
339
340 def test_deepcopy_inst_getstate_setstate(self):
341 class C:
342 def __init__(self, foo):
343 self.foo = foo
344 def __getstate__(self):
345 return self.foo
346 def __setstate__(self, state):
347 self.foo = state
348 def __cmp__(self, other):
349 return cmp(self.foo, other.foo)
350 x = C([42])
351 y = copy.deepcopy(x)
352 self.assertEqual(y, x)
353 self.assert_(y is not x)
354 self.assert_(y.foo is not x.foo)
355
356 # _reconstruct()
357
358 def test_reconstruct_string(self):
359 class C(object):
360 def __reduce__(self):
361 return ""
362 x = C()
363 y = copy.copy(x)
364 self.assert_(y is x)
365 y = copy.deepcopy(x)
366 self.assert_(y is x)
367
368 def test_reconstruct_nostate(self):
369 class C(object):
370 def __reduce__(self):
371 return (C, ())
372 x = C()
373 x.foo = 42
374 y = copy.copy(x)
375 self.assert_(y.__class__ is x.__class__)
376 y = copy.deepcopy(x)
377 self.assert_(y.__class__ is x.__class__)
378
379 def test_reconstruct_state(self):
380 class C(object):
381 def __reduce__(self):
382 return (C, (), self.__dict__)
383 def __cmp__(self, other):
384 return cmp(self.__dict__, other.__dict__)
385 x = C()
386 x.foo = [42]
387 y = copy.copy(x)
388 self.assertEqual(y, x)
389 y = copy.deepcopy(x)
390 self.assertEqual(y, x)
391 self.assert_(y.foo is not x.foo)
392
393 def test_reconstruct_state_setstate(self):
394 class C(object):
395 def __reduce__(self):
396 return (C, (), self.__dict__)
397 def __setstate__(self, state):
398 self.__dict__.update(state)
399 def __cmp__(self, other):
400 return cmp(self.__dict__, other.__dict__)
401 x = C()
402 x.foo = [42]
403 y = copy.copy(x)
404 self.assertEqual(y, x)
405 y = copy.deepcopy(x)
406 self.assertEqual(y, x)
407 self.assert_(y.foo is not x.foo)
408
Guido van Rossum90e05b02003-02-06 18:18:23 +0000409 # Additions for Python 2.3 and pickle protocol 2
410
411 def test_reduce_4tuple(self):
412 class C(list):
413 def __reduce__(self):
414 return (C, (), self.__dict__, iter(self))
415 def __cmp__(self, other):
416 return (cmp(list(self), list(other)) or
417 cmp(self.__dict__, other.__dict__))
418 x = C([[1, 2], 3])
419 y = copy.copy(x)
420 self.assertEqual(x, y)
421 self.assert_(x is not y)
422 self.assert_(x[0] is y[0])
423 y = copy.deepcopy(x)
424 self.assertEqual(x, y)
425 self.assert_(x is not y)
426 self.assert_(x[0] is not y[0])
427
428 def test_reduce_5tuple(self):
429 class C(dict):
430 def __reduce__(self):
431 return (C, (), self.__dict__, None, self.iteritems())
432 def __cmp__(self, other):
433 return (cmp(dict(self), list(dict)) or
434 cmp(self.__dict__, other.__dict__))
435 x = C([("foo", [1, 2]), ("bar", 3)])
436 y = copy.copy(x)
437 self.assertEqual(x, y)
438 self.assert_(x is not y)
439 self.assert_(x["foo"] is y["foo"])
440 y = copy.deepcopy(x)
441 self.assertEqual(x, y)
442 self.assert_(x is not y)
443 self.assert_(x["foo"] is not y["foo"])
444
Guido van Rossumc7557582003-02-06 19:53:22 +0000445 def test_copy_slots(self):
446 class C(object):
447 __slots__ = ["foo"]
448 x = C()
449 x.foo = [42]
450 y = copy.copy(x)
451 self.assert_(x.foo is y.foo)
452
453 def test_deepcopy_slots(self):
454 class C(object):
455 __slots__ = ["foo"]
456 x = C()
457 x.foo = [42]
458 y = copy.deepcopy(x)
459 self.assertEqual(x.foo, y.foo)
460 self.assert_(x.foo is not y.foo)
461
462 def test_copy_list_subclass(self):
463 class C(list):
464 pass
465 x = C([[1, 2], 3])
466 x.foo = [4, 5]
467 y = copy.copy(x)
468 self.assertEqual(list(x), list(y))
469 self.assertEqual(x.foo, y.foo)
470 self.assert_(x[0] is y[0])
471 self.assert_(x.foo is y.foo)
472
473 def test_deepcopy_list_subclass(self):
474 class C(list):
475 pass
476 x = C([[1, 2], 3])
477 x.foo = [4, 5]
478 y = copy.deepcopy(x)
479 self.assertEqual(list(x), list(y))
480 self.assertEqual(x.foo, y.foo)
481 self.assert_(x[0] is not y[0])
482 self.assert_(x.foo is not y.foo)
483
Guido van Rossum85233bf2003-02-06 21:25:12 +0000484 def test_copy_tuple_subclass(self):
485 class C(tuple):
486 pass
487 x = C([1, 2, 3])
488 self.assertEqual(tuple(x), (1, 2, 3))
489 y = copy.copy(x)
490 self.assertEqual(tuple(y), (1, 2, 3))
491
492 def test_deepcopy_tuple_subclass(self):
493 class C(tuple):
494 pass
495 x = C([[1, 2], 3])
496 self.assertEqual(tuple(x), ([1, 2], 3))
497 y = copy.deepcopy(x)
498 self.assertEqual(tuple(y), ([1, 2], 3))
499 self.assert_(x is not y)
500 self.assert_(x[0] is not y[0])
501
Guido van Rossum581cb932003-02-06 17:52:15 +0000502def test_main():
503 suite = unittest.TestSuite()
504 suite.addTest(unittest.makeSuite(TestCopy))
505 test_support.run_suite(suite)
506
507if __name__ == "__main__":
508 test_main()