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