blob: 2a1ca179c1b2bd33cff92d4b569c48a5786a21b4 [file] [log] [blame]
Jeremy Hylton66426532001-10-15 21:38:56 +00001import unittest
Guido van Rossum3b0a3292002-08-09 16:38:32 +00002from test.test_support import TestFailed, have_unicode, TESTFN
Tim Peterse089c682001-04-10 03:41:41 +00003
Tim Petersee1a53c2003-02-02 02:57:53 +00004# Tests that try a number of pickle protocols should have a
5# for proto in protocols:
6# kind of outer loop. Bump the 3 to 4 if/when protocol 3 is invented.
7protocols = range(3)
8
Jeremy Hylton66426532001-10-15 21:38:56 +00009class C:
10 def __cmp__(self, other):
11 return cmp(self.__dict__, other.__dict__)
12
13import __main__
14__main__.C = C
15C.__module__ = "__main__"
16
17class myint(int):
18 def __init__(self, x):
19 self.str = str(x)
20
21class initarg(C):
Guido van Rossum1444f672001-12-19 16:38:29 +000022
Jeremy Hylton66426532001-10-15 21:38:56 +000023 def __init__(self, a, b):
24 self.a = a
25 self.b = b
26
27 def __getinitargs__(self):
28 return self.a, self.b
29
Guido van Rossum04a86612001-12-19 16:58:54 +000030class metaclass(type):
31 pass
32
33class use_metaclass(object):
34 __metaclass__ = metaclass
35
Tim Petersee1a53c2003-02-02 02:57:53 +000036# DATA and BINDATA are the protocol 0 and protocol 1 pickles of the object
37# returned by create_data().
38
Jeremy Hylton66426532001-10-15 21:38:56 +000039# break into multiple strings to avoid confusing font-lock-mode
Tim Peters461922a2001-04-09 20:07:05 +000040DATA = """(lp1
Tim Peterse9358162001-01-22 22:05:20 +000041I0
42aL1L
Tim Peters461922a2001-04-09 20:07:05 +000043aF2
Tim Peterse9358162001-01-22 22:05:20 +000044ac__builtin__
45complex
Tim Peters461922a2001-04-09 20:07:05 +000046p2
47""" + \
48"""(F3
49F0
50tRp3
51aI1
52aI-1
53aI255
54aI-255
55aI-256
56aI65535
57aI-65535
58aI-65536
59aI2147483647
60aI-2147483647
61aI-2147483648
62a""" + \
63"""(S'abc'
Tim Peterse9358162001-01-22 22:05:20 +000064p4
65g4
Tim Peters461922a2001-04-09 20:07:05 +000066""" + \
Guido van Rossum42f92da2001-04-16 00:28:21 +000067"""(i__main__
Tim Peterse9358162001-01-22 22:05:20 +000068C
69p5
Tim Peters461922a2001-04-09 20:07:05 +000070""" + \
Tim Peterse9358162001-01-22 22:05:20 +000071"""(dp6
72S'foo'
73p7
74I1
75sS'bar'
76p8
77I2
78sbg5
79tp9
80ag9
81aI5
82a.
83"""
84
Tim Peters461922a2001-04-09 20:07:05 +000085BINDATA = ']q\x01(K\x00L1L\nG@\x00\x00\x00\x00\x00\x00\x00' + \
86 'c__builtin__\ncomplex\nq\x02(G@\x08\x00\x00\x00\x00\x00' + \
87 '\x00G\x00\x00\x00\x00\x00\x00\x00\x00tRq\x03K\x01J\xff\xff' + \
88 '\xff\xffK\xffJ\x01\xff\xff\xffJ\x00\xff\xff\xffM\xff\xff' + \
89 'J\x01\x00\xff\xffJ\x00\x00\xff\xffJ\xff\xff\xff\x7fJ\x01\x00' + \
Guido van Rossum42f92da2001-04-16 00:28:21 +000090 '\x00\x80J\x00\x00\x00\x80(U\x03abcq\x04h\x04(c__main__\n' + \
Tim Peters461922a2001-04-09 20:07:05 +000091 'C\nq\x05oq\x06}q\x07(U\x03fooq\x08K\x01U\x03barq\tK\x02ubh' + \
92 '\x06tq\nh\nK\x05e.'
Tim Peterse0c446b2001-10-18 21:57:37 +000093
Jeremy Hylton66426532001-10-15 21:38:56 +000094def create_data():
Tim Peterse9358162001-01-22 22:05:20 +000095 c = C()
96 c.foo = 1
97 c.bar = 2
98 x = [0, 1L, 2.0, 3.0+0j]
Tim Peters461922a2001-04-09 20:07:05 +000099 # Append some integer test cases at cPickle.c's internal size
100 # cutoffs.
101 uint1max = 0xff
102 uint2max = 0xffff
103 int4max = 0x7fffffff
104 x.extend([1, -1,
105 uint1max, -uint1max, -uint1max-1,
106 uint2max, -uint2max, -uint2max-1,
107 int4max, -int4max, -int4max-1])
Tim Peterse9358162001-01-22 22:05:20 +0000108 y = ('abc', 'abc', c, c)
109 x.append(y)
110 x.append(y)
111 x.append(5)
Jeremy Hylton66426532001-10-15 21:38:56 +0000112 return x
Tim Petersc58440f2001-04-09 17:16:31 +0000113
Jeremy Hylton66426532001-10-15 21:38:56 +0000114class AbstractPickleTests(unittest.TestCase):
Tim Petersc58440f2001-04-09 17:16:31 +0000115
Jeremy Hylton66426532001-10-15 21:38:56 +0000116 _testdata = create_data()
Tim Petersc58440f2001-04-09 17:16:31 +0000117
Jeremy Hylton66426532001-10-15 21:38:56 +0000118 def setUp(self):
119 # subclass must define self.dumps, self.loads, self.error
Tim Peterse9358162001-01-22 22:05:20 +0000120 pass
Tim Petersc58440f2001-04-09 17:16:31 +0000121
Jeremy Hylton66426532001-10-15 21:38:56 +0000122 def test_misc(self):
123 # test various datatypes not tested by testdata
124 x = myint(4)
125 s = self.dumps(x)
126 y = self.loads(s)
127 self.assertEqual(x, y)
Tim Peterse9358162001-01-22 22:05:20 +0000128
Jeremy Hylton66426532001-10-15 21:38:56 +0000129 x = (1, ())
130 s = self.dumps(x)
131 y = self.loads(s)
132 self.assertEqual(x, y)
Tim Peterse9358162001-01-22 22:05:20 +0000133
Jeremy Hylton66426532001-10-15 21:38:56 +0000134 x = initarg(1, x)
135 s = self.dumps(x)
136 y = self.loads(s)
137 self.assertEqual(x, y)
Tim Peterse9358162001-01-22 22:05:20 +0000138
Jeremy Hylton66426532001-10-15 21:38:56 +0000139 # XXX test __reduce__ protocol?
140
141 def test_identity(self):
142 s = self.dumps(self._testdata)
143 x = self.loads(s)
144 self.assertEqual(x, self._testdata)
145
146 def test_constant(self):
147 x = self.loads(DATA)
148 self.assertEqual(x, self._testdata)
149 x = self.loads(BINDATA)
150 self.assertEqual(x, self._testdata)
151
152 def test_binary(self):
153 s = self.dumps(self._testdata, 1)
154 x = self.loads(s)
155 self.assertEqual(x, self._testdata)
156
157 def test_recursive_list(self):
158 l = []
159 l.append(l)
160 s = self.dumps(l)
161 x = self.loads(s)
162 self.assertEqual(x, l)
163 self.assertEqual(x, x[0])
164 self.assertEqual(id(x), id(x[0]))
165
166 def test_recursive_dict(self):
167 d = {}
168 d[1] = d
169 s = self.dumps(d)
170 x = self.loads(s)
171 self.assertEqual(x, d)
172 self.assertEqual(x[1], x)
173 self.assertEqual(id(x[1]), id(x))
174
175 def test_recursive_inst(self):
176 i = C()
177 i.attr = i
178 s = self.dumps(i)
179 x = self.loads(s)
180 self.assertEqual(x, i)
181 self.assertEqual(x.attr, x)
182 self.assertEqual(id(x.attr), id(x))
183
184 def test_recursive_multi(self):
185 l = []
186 d = {1:l}
187 i = C()
188 i.attr = d
189 l.append(i)
190 s = self.dumps(l)
191 x = self.loads(s)
192 self.assertEqual(x, l)
193 self.assertEqual(x[0], i)
194 self.assertEqual(x[0].attr, d)
195 self.assertEqual(x[0].attr[1], x)
196 self.assertEqual(x[0].attr[1][0], i)
197 self.assertEqual(x[0].attr[1][0].attr, d)
198
199 def test_garyp(self):
200 self.assertRaises(self.error, self.loads, 'garyp')
201
202 def test_insecure_strings(self):
203 insecure = ["abc", "2 + 2", # not quoted
Martin v. Löwis8a8da792002-08-14 07:46:28 +0000204 #"'abc' + 'def'", # not a single quoted string
Jeremy Hylton66426532001-10-15 21:38:56 +0000205 "'abc", # quote is not closed
206 "'abc\"", # open quote and close quote don't match
207 "'abc' ?", # junk after close quote
Martin v. Löwiseb3f00a2002-08-14 08:22:50 +0000208 "'\\'", # trailing backslash
Jeremy Hylton66426532001-10-15 21:38:56 +0000209 # some tests of the quoting rules
Martin v. Löwis8a8da792002-08-14 07:46:28 +0000210 #"'abc\"\''",
211 #"'\\\\a\'\'\'\\\'\\\\\''",
Jeremy Hylton66426532001-10-15 21:38:56 +0000212 ]
213 for s in insecure:
214 buf = "S" + s + "\012p0\012."
215 self.assertRaises(ValueError, self.loads, buf)
216
Martin v. Löwis339d0f72001-08-17 18:39:25 +0000217 if have_unicode:
Jeremy Hylton66426532001-10-15 21:38:56 +0000218 def test_unicode(self):
219 endcases = [unicode(''), unicode('<\\u>'), unicode('<\\\u1234>'),
220 unicode('<\n>'), unicode('<\\>')]
Tim Petersee1a53c2003-02-02 02:57:53 +0000221 for proto in protocols:
222 for u in endcases:
223 p = self.dumps(u, proto)
224 u2 = self.loads(p)
225 self.assertEqual(u2, u)
Tim Peterse089c682001-04-10 03:41:41 +0000226
Jeremy Hylton66426532001-10-15 21:38:56 +0000227 def test_ints(self):
228 import sys
Tim Petersee1a53c2003-02-02 02:57:53 +0000229 for proto in protocols:
230 n = sys.maxint
231 while n:
232 for expected in (-n, n):
233 s = self.dumps(expected, proto)
234 n2 = self.loads(s)
235 self.assertEqual(expected, n2)
236 n = n >> 1
Tim Peters19ef62d2001-08-28 22:21:18 +0000237
Jeremy Hylton66426532001-10-15 21:38:56 +0000238 def test_maxint64(self):
239 maxint64 = (1L << 63) - 1
240 data = 'I' + str(maxint64) + '\n.'
241 got = self.loads(data)
242 self.assertEqual(got, maxint64)
243
244 # Try too with a bogus literal.
245 data = 'I' + str(maxint64) + 'JUNK\n.'
246 self.assertRaises(ValueError, self.loads, data)
247
Tim Petersee1a53c2003-02-02 02:57:53 +0000248 def test_long(self):
249 for proto in protocols:
Tim Petersbf2674b2003-02-02 07:51:32 +0000250 # 256 bytes is where LONG4 begins.
Tim Petersee1a53c2003-02-02 02:57:53 +0000251 for nbits in 1, 8, 8*254, 8*255, 8*256, 8*257:
252 nbase = 1L << nbits
253 for npos in nbase-1, nbase, nbase+1:
254 for n in npos, -npos:
255 pickle = self.dumps(n, proto)
256 got = self.loads(pickle)
257 self.assertEqual(n, got)
258 # Try a monster. This is quadratic-time in protos 0 & 1, so don't
259 # bother with those.
Tim Petersee1a53c2003-02-02 02:57:53 +0000260 nbase = long("deadbeeffeedface", 16)
261 nbase += nbase << 1000000
262 for n in nbase, -nbase:
Tim Petersee1a53c2003-02-02 02:57:53 +0000263 p = self.dumps(n, 2)
Tim Petersee1a53c2003-02-02 02:57:53 +0000264 got = self.loads(p)
Tim Petersee1a53c2003-02-02 02:57:53 +0000265 self.assertEqual(n, got)
266
Jeremy Hylton66426532001-10-15 21:38:56 +0000267 def test_reduce(self):
Tim Peters19ef62d2001-08-28 22:21:18 +0000268 pass
Jeremy Hylton66426532001-10-15 21:38:56 +0000269
270 def test_getinitargs(self):
271 pass
272
Guido van Rossum04a86612001-12-19 16:58:54 +0000273 def test_metaclass(self):
274 a = use_metaclass()
275 s = self.dumps(a)
276 b = self.loads(s)
277 self.assertEqual(a.__class__, b.__class__)
278
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000279 def test_structseq(self):
280 import time
281 t = time.localtime()
282 s = self.dumps(t)
283 u = self.loads(s)
Tim Peters863ac442002-04-16 01:38:40 +0000284 self.assertEqual(t, u)
Michael W. Hudson0e025302002-03-06 17:11:18 +0000285 import os
286 if hasattr(os, "stat"):
287 t = os.stat(os.curdir)
288 s = self.dumps(t)
289 u = self.loads(s)
290 self.assertEqual(t, u)
291 if hasattr(os, "statvfs"):
292 t = os.statvfs(os.curdir)
293 s = self.dumps(t)
294 u = self.loads(s)
295 self.assertEqual(t, u)
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000296
Guido van Rossumd6c9e632003-01-28 03:49:52 +0000297 # Tests for protocol 2
298
299 def test_long1(self):
300 x = 12345678910111213141516178920L
301 s = self.dumps(x, 2)
302 y = self.loads(s)
303 self.assertEqual(x, y)
304
305 def test_long4(self):
306 x = 12345678910111213141516178920L << (256*8)
307 s = self.dumps(x, 2)
308 y = self.loads(s)
309 self.assertEqual(x, y)
310
Guido van Rossum44f0ea52003-01-28 04:14:51 +0000311 def test_short_tuples(self):
312 a = ()
Guido van Rossum025bc2f2003-01-28 04:20:02 +0000313 b = (1,)
314 c = (1, 2)
315 d = (1, 2, 3)
316 e = (1, 2, 3, 4)
Guido van Rossum44f0ea52003-01-28 04:14:51 +0000317 for proto in 0, 1, 2:
318 for x in a, b, c, d, e:
319 s = self.dumps(x, proto)
320 y = self.loads(s)
321 self.assertEqual(x, y, (proto, x, s, y))
322
Guido van Rossum7d97d312003-01-28 04:25:27 +0000323 def test_singletons(self):
324 for proto in 0, 1, 2:
325 for x in None, False, True:
326 s = self.dumps(x, proto)
327 y = self.loads(s)
328 self.assert_(x is y, (proto, x, s, y))
329
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000330 def test_newobj_tuple(self):
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000331 x = MyTuple([1, 2, 3])
332 x.foo = 42
333 x.bar = "hello"
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000334 s = self.dumps(x, 2)
335 y = self.loads(s)
336 self.assertEqual(tuple(x), tuple(y))
337 self.assertEqual(x.__dict__, y.__dict__)
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000338## import pickletools
339## print
340## pickletools.dis(s)
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000341
342 def test_newobj_list(self):
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000343 x = MyList([1, 2, 3])
344 x.foo = 42
345 x.bar = "hello"
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000346 s = self.dumps(x, 2)
347 y = self.loads(s)
348 self.assertEqual(list(x), list(y))
349 self.assertEqual(x.__dict__, y.__dict__)
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000350## import pickletools
351## print
352## pickletools.dis(s)
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000353
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000354 def test_newobj_generic(self):
355 for proto in [0, 1, 2]:
356 for C in myclasses:
357 B = C.__base__
358 x = C(C.sample)
359 x.foo = 42
360 s = self.dumps(x, proto)
361## import pickletools
362## print
363## pickletools.dis(s)
364 y = self.loads(s)
365 detail = (proto, C, B, x, y, type(y))
366 self.assertEqual(B(x), B(y), detail)
367 self.assertEqual(x.__dict__, y.__dict__, detail)
368
Tim Peters47a6b132003-01-28 22:34:11 +0000369# XXX Temporary hack, so long as the C implementation of pickle protocol
370# XXX 2 isn't ready. When it is, move the methods in TempAbstractPickleTests
371# XXX into AbstractPickleTests above, and get rid of TempAbstractPickleTests
372# XXX along with the references to it in test_pickle.py.
373class TempAbstractPickleTests(unittest.TestCase):
374
Guido van Rossumc8d6ef52003-01-28 22:02:31 +0000375 def test_newobj_list_slots(self):
376 x = SlotList([1, 2, 3])
377 x.foo = 42
378 x.bar = "hello"
379 s = self.dumps(x, 2)
380 y = self.loads(s)
381 self.assertEqual(list(x), list(y))
382 self.assertEqual(x.__dict__, y.__dict__)
383 self.assertEqual(x.foo, y.foo)
384 self.assertEqual(x.bar, y.bar)
385## import pickletools
386## print
387## pickletools.dis(s)
388
Guido van Rossum0322d0f2003-01-29 06:12:46 +0000389 def test_global_ext1(self):
390 import copy_reg
391 copy_reg.add_extension(__name__, "MyList", 0xf0)
392 try:
393 x = MyList([1, 2, 3])
394 x.foo = 42
395 x.bar = "hello"
396
397 # Dump using protocol 1 for comparison
398 s1 = self.dumps(x, 1)
399 y = self.loads(s1)
400 self.assertEqual(list(x), list(y))
401 self.assertEqual(x.__dict__, y.__dict__)
402 self.assert_(s1.find(__name__) >= 0)
403 self.assert_(s1.find("MyList") >= 0)
404## import pickletools
405## print
406## pickletools.dis(s1)
407
408 # Dump using protocol 2 for test
409 s2 = self.dumps(x, 2)
410 self.assertEqual(s2.find(__name__), -1)
411 self.assertEqual(s2.find("MyList"), -1)
412 y = self.loads(s2)
413 self.assertEqual(list(x), list(y))
414 self.assertEqual(x.__dict__, y.__dict__)
415## import pickletools
416## print
417## pickletools.dis(s2)
418
419 finally:
420 copy_reg.remove_extension(__name__, "MyList", 0xf0)
421
422 def test_global_ext2(self):
423 import copy_reg
424 copy_reg.add_extension(__name__, "MyList", 0xfff0)
425 try:
426 x = MyList()
427 s2 = self.dumps(x, 2)
428 self.assertEqual(s2.find(__name__), -1)
429 self.assertEqual(s2.find("MyList"), -1)
430 y = self.loads(s2)
431 self.assertEqual(list(x), list(y))
432 self.assertEqual(x.__dict__, y.__dict__)
433 finally:
434 copy_reg.remove_extension(__name__, "MyList", 0xfff0)
435
436 def test_global_ext4(self):
437 import copy_reg
438 copy_reg.add_extension(__name__, "MyList", 0xfffff0)
439 try:
440 x = MyList()
441 s2 = self.dumps(x, 2)
442 self.assertEqual(s2.find(__name__), -1)
443 self.assertEqual(s2.find("MyList"), -1)
444 y = self.loads(s2)
445 self.assertEqual(list(x), list(y))
446 self.assertEqual(x.__dict__, y.__dict__)
447 finally:
448 copy_reg.remove_extension(__name__, "MyList", 0xfffff0)
449
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000450class MyInt(int):
451 sample = 1
452
453class MyLong(long):
454 sample = 1L
455
456class MyFloat(float):
457 sample = 1.0
458
459class MyComplex(complex):
460 sample = 1.0 + 0.0j
461
462class MyStr(str):
463 sample = "hello"
464
465class MyUnicode(unicode):
466 sample = u"hello \u1234"
467
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000468class MyTuple(tuple):
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000469 sample = (1, 2, 3)
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000470
471class MyList(list):
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000472 sample = [1, 2, 3]
473
474class MyDict(dict):
475 sample = {"a": 1, "b": 2}
476
477myclasses = [MyInt, MyLong, MyFloat,
478 # MyComplex, # XXX complex somehow doesn't work here :-(
479 MyStr, MyUnicode,
480 MyTuple, MyList, MyDict]
481
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000482
Guido van Rossumc8d6ef52003-01-28 22:02:31 +0000483class SlotList(MyList):
484 __slots__ = ["foo"]
485
Jeremy Hylton66426532001-10-15 21:38:56 +0000486class AbstractPickleModuleTests(unittest.TestCase):
487
488 def test_dump_closed_file(self):
Guido van Rossum3b0a3292002-08-09 16:38:32 +0000489 import os
490 f = open(TESTFN, "w")
491 try:
492 f.close()
493 self.assertRaises(ValueError, self.module.dump, 123, f)
494 finally:
495 os.remove(TESTFN)
Jeremy Hylton66426532001-10-15 21:38:56 +0000496
497 def test_load_closed_file(self):
Guido van Rossum3b0a3292002-08-09 16:38:32 +0000498 import os
499 f = open(TESTFN, "w")
500 try:
501 f.close()
502 self.assertRaises(ValueError, self.module.dump, 123, f)
503 finally:
504 os.remove(TESTFN)
Jeremy Hylton4c8be852002-11-13 22:10:47 +0000505
506class AbstractPersistentPicklerTests(unittest.TestCase):
507
508 # This class defines persistent_id() and persistent_load()
509 # functions that should be used by the pickler. All even integers
510 # are pickled using persistent ids.
511
512 def persistent_id(self, object):
513 if isinstance(object, int) and object % 2 == 0:
514 self.id_count += 1
515 return str(object)
516 else:
517 return None
518
519 def persistent_load(self, oid):
520 self.load_count += 1
521 object = int(oid)
522 assert object % 2 == 0
523 return object
524
525 def test_persistence(self):
526 self.id_count = 0
527 self.load_count = 0
528 L = range(10)
529 self.assertEqual(self.loads(self.dumps(L)), L)
530 self.assertEqual(self.id_count, 5)
531 self.assertEqual(self.load_count, 5)
532
533 def test_bin_persistence(self):
534 self.id_count = 0
535 self.load_count = 0
536 L = range(10)
537 self.assertEqual(self.loads(self.dumps(L, 1)), L)
538 self.assertEqual(self.id_count, 5)
539 self.assertEqual(self.load_count, 5)