blob: 6615307da6e31a9248fcdd572c74244d582f4e43 [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:
250 # 256 bytes is where LONG4 begins
251 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.
260 # XXX Damn. pickle.py is still quadratic-time here, due to
261 # XXX long(string, 16). cPickle runs this in an eyeblink, but I
262 # XXX gave up waiting for pickle.py to get beyond "loading". Giving
263 # XXX up for now.
264 return
265 print "building long"
266 nbase = long("deadbeeffeedface", 16)
267 nbase += nbase << 1000000
268 for n in nbase, -nbase:
269 print "dumping"
270 p = self.dumps(n, 2)
271 print "loading"
272 got = self.loads(p)
273 print "checking"
274 self.assertEqual(n, got)
275
Jeremy Hylton66426532001-10-15 21:38:56 +0000276 def test_reduce(self):
Tim Peters19ef62d2001-08-28 22:21:18 +0000277 pass
Jeremy Hylton66426532001-10-15 21:38:56 +0000278
279 def test_getinitargs(self):
280 pass
281
Guido van Rossum04a86612001-12-19 16:58:54 +0000282 def test_metaclass(self):
283 a = use_metaclass()
284 s = self.dumps(a)
285 b = self.loads(s)
286 self.assertEqual(a.__class__, b.__class__)
287
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000288 def test_structseq(self):
289 import time
290 t = time.localtime()
291 s = self.dumps(t)
292 u = self.loads(s)
Tim Peters863ac442002-04-16 01:38:40 +0000293 self.assertEqual(t, u)
Michael W. Hudson0e025302002-03-06 17:11:18 +0000294 import os
295 if hasattr(os, "stat"):
296 t = os.stat(os.curdir)
297 s = self.dumps(t)
298 u = self.loads(s)
299 self.assertEqual(t, u)
300 if hasattr(os, "statvfs"):
301 t = os.statvfs(os.curdir)
302 s = self.dumps(t)
303 u = self.loads(s)
304 self.assertEqual(t, u)
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000305
Guido van Rossumd6c9e632003-01-28 03:49:52 +0000306 # Tests for protocol 2
307
308 def test_long1(self):
309 x = 12345678910111213141516178920L
310 s = self.dumps(x, 2)
311 y = self.loads(s)
312 self.assertEqual(x, y)
313
314 def test_long4(self):
315 x = 12345678910111213141516178920L << (256*8)
316 s = self.dumps(x, 2)
317 y = self.loads(s)
318 self.assertEqual(x, y)
319
Guido van Rossum44f0ea52003-01-28 04:14:51 +0000320 def test_short_tuples(self):
321 a = ()
Guido van Rossum025bc2f2003-01-28 04:20:02 +0000322 b = (1,)
323 c = (1, 2)
324 d = (1, 2, 3)
325 e = (1, 2, 3, 4)
Guido van Rossum44f0ea52003-01-28 04:14:51 +0000326 for proto in 0, 1, 2:
327 for x in a, b, c, d, e:
328 s = self.dumps(x, proto)
329 y = self.loads(s)
330 self.assertEqual(x, y, (proto, x, s, y))
331
Guido van Rossum7d97d312003-01-28 04:25:27 +0000332 def test_singletons(self):
333 for proto in 0, 1, 2:
334 for x in None, False, True:
335 s = self.dumps(x, proto)
336 y = self.loads(s)
337 self.assert_(x is y, (proto, x, s, y))
338
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000339 def test_newobj_tuple(self):
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000340 x = MyTuple([1, 2, 3])
341 x.foo = 42
342 x.bar = "hello"
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000343 s = self.dumps(x, 2)
344 y = self.loads(s)
345 self.assertEqual(tuple(x), tuple(y))
346 self.assertEqual(x.__dict__, y.__dict__)
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000347## import pickletools
348## print
349## pickletools.dis(s)
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000350
351 def test_newobj_list(self):
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000352 x = MyList([1, 2, 3])
353 x.foo = 42
354 x.bar = "hello"
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000355 s = self.dumps(x, 2)
356 y = self.loads(s)
357 self.assertEqual(list(x), list(y))
358 self.assertEqual(x.__dict__, y.__dict__)
Guido van Rossum3d8c01b2003-01-28 19:48:18 +0000359## import pickletools
360## print
361## pickletools.dis(s)
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000362
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000363 def test_newobj_generic(self):
364 for proto in [0, 1, 2]:
365 for C in myclasses:
366 B = C.__base__
367 x = C(C.sample)
368 x.foo = 42
369 s = self.dumps(x, proto)
370## import pickletools
371## print
372## pickletools.dis(s)
373 y = self.loads(s)
374 detail = (proto, C, B, x, y, type(y))
375 self.assertEqual(B(x), B(y), detail)
376 self.assertEqual(x.__dict__, y.__dict__, detail)
377
Tim Peters47a6b132003-01-28 22:34:11 +0000378# XXX Temporary hack, so long as the C implementation of pickle protocol
379# XXX 2 isn't ready. When it is, move the methods in TempAbstractPickleTests
380# XXX into AbstractPickleTests above, and get rid of TempAbstractPickleTests
381# XXX along with the references to it in test_pickle.py.
382class TempAbstractPickleTests(unittest.TestCase):
383
Guido van Rossumc8d6ef52003-01-28 22:02:31 +0000384 def test_newobj_list_slots(self):
385 x = SlotList([1, 2, 3])
386 x.foo = 42
387 x.bar = "hello"
388 s = self.dumps(x, 2)
389 y = self.loads(s)
390 self.assertEqual(list(x), list(y))
391 self.assertEqual(x.__dict__, y.__dict__)
392 self.assertEqual(x.foo, y.foo)
393 self.assertEqual(x.bar, y.bar)
394## import pickletools
395## print
396## pickletools.dis(s)
397
Guido van Rossum0322d0f2003-01-29 06:12:46 +0000398 def test_global_ext1(self):
399 import copy_reg
400 copy_reg.add_extension(__name__, "MyList", 0xf0)
401 try:
402 x = MyList([1, 2, 3])
403 x.foo = 42
404 x.bar = "hello"
405
406 # Dump using protocol 1 for comparison
407 s1 = self.dumps(x, 1)
408 y = self.loads(s1)
409 self.assertEqual(list(x), list(y))
410 self.assertEqual(x.__dict__, y.__dict__)
411 self.assert_(s1.find(__name__) >= 0)
412 self.assert_(s1.find("MyList") >= 0)
413## import pickletools
414## print
415## pickletools.dis(s1)
416
417 # Dump using protocol 2 for test
418 s2 = self.dumps(x, 2)
419 self.assertEqual(s2.find(__name__), -1)
420 self.assertEqual(s2.find("MyList"), -1)
421 y = self.loads(s2)
422 self.assertEqual(list(x), list(y))
423 self.assertEqual(x.__dict__, y.__dict__)
424## import pickletools
425## print
426## pickletools.dis(s2)
427
428 finally:
429 copy_reg.remove_extension(__name__, "MyList", 0xf0)
430
431 def test_global_ext2(self):
432 import copy_reg
433 copy_reg.add_extension(__name__, "MyList", 0xfff0)
434 try:
435 x = MyList()
436 s2 = self.dumps(x, 2)
437 self.assertEqual(s2.find(__name__), -1)
438 self.assertEqual(s2.find("MyList"), -1)
439 y = self.loads(s2)
440 self.assertEqual(list(x), list(y))
441 self.assertEqual(x.__dict__, y.__dict__)
442 finally:
443 copy_reg.remove_extension(__name__, "MyList", 0xfff0)
444
445 def test_global_ext4(self):
446 import copy_reg
447 copy_reg.add_extension(__name__, "MyList", 0xfffff0)
448 try:
449 x = MyList()
450 s2 = self.dumps(x, 2)
451 self.assertEqual(s2.find(__name__), -1)
452 self.assertEqual(s2.find("MyList"), -1)
453 y = self.loads(s2)
454 self.assertEqual(list(x), list(y))
455 self.assertEqual(x.__dict__, y.__dict__)
456 finally:
457 copy_reg.remove_extension(__name__, "MyList", 0xfffff0)
458
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000459class MyInt(int):
460 sample = 1
461
462class MyLong(long):
463 sample = 1L
464
465class MyFloat(float):
466 sample = 1.0
467
468class MyComplex(complex):
469 sample = 1.0 + 0.0j
470
471class MyStr(str):
472 sample = "hello"
473
474class MyUnicode(unicode):
475 sample = u"hello \u1234"
476
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000477class MyTuple(tuple):
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000478 sample = (1, 2, 3)
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000479
480class MyList(list):
Guido van Rossum5d9113d2003-01-29 17:58:45 +0000481 sample = [1, 2, 3]
482
483class MyDict(dict):
484 sample = {"a": 1, "b": 2}
485
486myclasses = [MyInt, MyLong, MyFloat,
487 # MyComplex, # XXX complex somehow doesn't work here :-(
488 MyStr, MyUnicode,
489 MyTuple, MyList, MyDict]
490
Guido van Rossum533dbcf2003-01-28 17:55:05 +0000491
Guido van Rossumc8d6ef52003-01-28 22:02:31 +0000492class SlotList(MyList):
493 __slots__ = ["foo"]
494
Jeremy Hylton66426532001-10-15 21:38:56 +0000495class AbstractPickleModuleTests(unittest.TestCase):
496
497 def test_dump_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 Hylton66426532001-10-15 21:38:56 +0000505
506 def test_load_closed_file(self):
Guido van Rossum3b0a3292002-08-09 16:38:32 +0000507 import os
508 f = open(TESTFN, "w")
509 try:
510 f.close()
511 self.assertRaises(ValueError, self.module.dump, 123, f)
512 finally:
513 os.remove(TESTFN)
Jeremy Hylton4c8be852002-11-13 22:10:47 +0000514
515class AbstractPersistentPicklerTests(unittest.TestCase):
516
517 # This class defines persistent_id() and persistent_load()
518 # functions that should be used by the pickler. All even integers
519 # are pickled using persistent ids.
520
521 def persistent_id(self, object):
522 if isinstance(object, int) and object % 2 == 0:
523 self.id_count += 1
524 return str(object)
525 else:
526 return None
527
528 def persistent_load(self, oid):
529 self.load_count += 1
530 object = int(oid)
531 assert object % 2 == 0
532 return object
533
534 def test_persistence(self):
535 self.id_count = 0
536 self.load_count = 0
537 L = range(10)
538 self.assertEqual(self.loads(self.dumps(L)), L)
539 self.assertEqual(self.id_count, 5)
540 self.assertEqual(self.load_count, 5)
541
542 def test_bin_persistence(self):
543 self.id_count = 0
544 self.load_count = 0
545 L = range(10)
546 self.assertEqual(self.loads(self.dumps(L, 1)), L)
547 self.assertEqual(self.id_count, 5)
548 self.assertEqual(self.load_count, 5)