Commit 66426538 authored by Jeremy Hylton's avatar Jeremy Hylton

Covert pickle tests to use unittest.

Extend tests to cover a few more cases.  For cPickle, test several of
the undocumented features.
parent 499ab6a6
test_cpickle
dumps()
loads()
ok
loads() DATA
ok
dumps() binary
loads() binary
ok
loads() BINDATA
ok
dumps() RECURSIVE
ok
test_pickle
dumps()
loads()
ok
loads() DATA
ok
dumps() binary
loads() binary
ok
loads() BINDATA
ok
dumps() RECURSIVE
ok
# test_pickle and test_cpickle both use this. import unittest
from test_support import TestFailed, have_unicode from test_support import TestFailed, have_unicode
import sys
# break into multiple strings to please font-lock-mode class C:
def __cmp__(self, other):
return cmp(self.__dict__, other.__dict__)
import __main__
__main__.C = C
C.__module__ = "__main__"
class myint(int):
def __init__(self, x):
self.str = str(x)
class initarg(C):
def __init__(self, a, b):
self.a = a
self.b = b
def __getinitargs__(self):
return self.a, self.b
# break into multiple strings to avoid confusing font-lock-mode
DATA = """(lp1 DATA = """(lp1
I0 I0
aL1L aL1L
...@@ -57,18 +75,8 @@ BINDATA = ']q\x01(K\x00L1L\nG@\x00\x00\x00\x00\x00\x00\x00' + \ ...@@ -57,18 +75,8 @@ BINDATA = ']q\x01(K\x00L1L\nG@\x00\x00\x00\x00\x00\x00\x00' + \
'\x00\x80J\x00\x00\x00\x80(U\x03abcq\x04h\x04(c__main__\n' + \ '\x00\x80J\x00\x00\x00\x80(U\x03abcq\x04h\x04(c__main__\n' + \
'C\nq\x05oq\x06}q\x07(U\x03fooq\x08K\x01U\x03barq\tK\x02ubh' + \ 'C\nq\x05oq\x06}q\x07(U\x03fooq\x08K\x01U\x03barq\tK\x02ubh' + \
'\x06tq\nh\nK\x05e.' '\x06tq\nh\nK\x05e.'
class C: def create_data():
def __cmp__(self, other):
return cmp(self.__dict__, other.__dict__)
import __main__
__main__.C = C
C.__module__ = "__main__"
# Call this with the module to be tested (pickle or cPickle).
def dotest(pickle):
c = C() c = C()
c.foo = 1 c.foo = 1
c.bar = 2 c.bar = 2
...@@ -86,153 +94,159 @@ def dotest(pickle): ...@@ -86,153 +94,159 @@ def dotest(pickle):
x.append(y) x.append(y)
x.append(y) x.append(y)
x.append(5) x.append(5)
r = [] return x
r.append(r)
class AbstractPickleTests(unittest.TestCase):
print "dumps()"
s = pickle.dumps(x) _testdata = create_data()
print "loads()" def setUp(self):
x2 = pickle.loads(s) # subclass must define self.dumps, self.loads, self.error
if x2 == x:
print "ok"
else:
print "bad"
print "loads() DATA"
x2 = pickle.loads(DATA)
if x2 == x:
print "ok"
else:
print "bad"
print "dumps() binary"
s = pickle.dumps(x, 1)
print "loads() binary"
x2 = pickle.loads(s)
if x2 == x:
print "ok"
else:
print "bad"
print "loads() BINDATA"
x2 = pickle.loads(BINDATA)
if x2 == x:
print "ok"
else:
print "bad"
print "dumps() RECURSIVE"
s = pickle.dumps(r)
x2 = pickle.loads(s)
if x2 == r:
print "ok"
else:
print "bad"
# don't create cyclic garbage
del x2[0]
del r[0]
# Test protection against closed files
import tempfile, os
fn = tempfile.mktemp()
f = open(fn, "w")
f.close()
try:
pickle.dump(123, f)
except ValueError:
pass
else:
print "dump to closed file should raise ValueError"
f = open(fn, "r")
f.close()
try:
pickle.load(f)
except ValueError:
pass pass
else:
print "load from closed file should raise ValueError" def test_misc(self):
os.remove(fn) # test various datatypes not tested by testdata
x = myint(4)
# Test specific bad cases s = self.dumps(x)
for i in range(10): y = self.loads(s)
try: self.assertEqual(x, y)
x = pickle.loads('garyp')
except KeyError, y: x = (1, ())
# pickle s = self.dumps(x)
del y y = self.loads(s)
except pickle.BadPickleGet, y: self.assertEqual(x, y)
# cPickle
del y x = initarg(1, x)
else: s = self.dumps(x)
print "unexpected success!" y = self.loads(s)
break self.assertEqual(x, y)
# Test insecure strings # XXX test __reduce__ protocol?
insecure = ["abc", "2 + 2", # not quoted
"'abc' + 'def'", # not a single quoted string def test_identity(self):
"'abc", # quote is not closed s = self.dumps(self._testdata)
"'abc\"", # open quote and close quote don't match x = self.loads(s)
"'abc' ?", # junk after close quote self.assertEqual(x, self._testdata)
# some tests of the quoting rules
"'abc\"\''", def test_constant(self):
"'\\\\a\'\'\'\\\'\\\\\''", x = self.loads(DATA)
] self.assertEqual(x, self._testdata)
for s in insecure: x = self.loads(BINDATA)
buf = "S" + s + "\012p0\012." self.assertEqual(x, self._testdata)
try:
x = pickle.loads(buf) def test_binary(self):
except ValueError: s = self.dumps(self._testdata, 1)
pass x = self.loads(s)
else: self.assertEqual(x, self._testdata)
print "accepted insecure string: %s" % repr(buf)
def test_recursive_list(self):
# Test some Unicode end cases l = []
l.append(l)
s = self.dumps(l)
x = self.loads(s)
self.assertEqual(x, l)
self.assertEqual(x, x[0])
self.assertEqual(id(x), id(x[0]))
def test_recursive_dict(self):
d = {}
d[1] = d
s = self.dumps(d)
x = self.loads(s)
self.assertEqual(x, d)
self.assertEqual(x[1], x)
self.assertEqual(id(x[1]), id(x))
def test_recursive_inst(self):
i = C()
i.attr = i
s = self.dumps(i)
x = self.loads(s)
self.assertEqual(x, i)
self.assertEqual(x.attr, x)
self.assertEqual(id(x.attr), id(x))
def test_recursive_multi(self):
l = []
d = {1:l}
i = C()
i.attr = d
l.append(i)
s = self.dumps(l)
x = self.loads(s)
self.assertEqual(x, l)
self.assertEqual(x[0], i)
self.assertEqual(x[0].attr, d)
self.assertEqual(x[0].attr[1], x)
self.assertEqual(x[0].attr[1][0], i)
self.assertEqual(x[0].attr[1][0].attr, d)
def test_garyp(self):
self.assertRaises(self.error, self.loads, 'garyp')
def test_insecure_strings(self):
insecure = ["abc", "2 + 2", # not quoted
"'abc' + 'def'", # not a single quoted string
"'abc", # quote is not closed
"'abc\"", # open quote and close quote don't match
"'abc' ?", # junk after close quote
# some tests of the quoting rules
"'abc\"\''",
"'\\\\a\'\'\'\\\'\\\\\''",
]
for s in insecure:
buf = "S" + s + "\012p0\012."
self.assertRaises(ValueError, self.loads, buf)
if have_unicode: if have_unicode:
endcases = [unicode(''), unicode('<\\u>'), unicode('<\\\u1234>'), def test_unicode(self):
unicode('<\n>'), unicode('<\\>')] endcases = [unicode(''), unicode('<\\u>'), unicode('<\\\u1234>'),
else: unicode('<\n>'), unicode('<\\>')]
endcases = [] for u in endcases:
for u in endcases: p = self.dumps(u)
try: u2 = self.loads(p)
u2 = pickle.loads(pickle.dumps(u)) self.assertEqual(u2, u)
except Exception, msg:
print "Endcase exception: %s => %s(%s)" % \ def test_ints(self):
(`u`, msg.__class__.__name__, str(msg)) import sys
else: n = sys.maxint
if u2 != u: while n:
print "Endcase failure: %s => %s" % (`u`, `u2`) for expected in (-n, n):
s = self.dumps(expected)
# Test the full range of Python ints. n2 = self.loads(s)
n = sys.maxint self.assertEqual(expected, n2)
while n: n = n >> 1
for expected in (-n, n):
for binary_mode in (0, 1): def test_maxint64(self):
s = pickle.dumps(expected, binary_mode) maxint64 = (1L << 63) - 1
got = pickle.loads(s) data = 'I' + str(maxint64) + '\n.'
if expected != got: got = self.loads(data)
raise TestFailed("for %s-mode pickle of %d, pickle " self.assertEqual(got, maxint64)
"string is %s, loaded back as %s" % (
binary_mode and "binary" or "text", # Try too with a bogus literal.
expected, data = 'I' + str(maxint64) + 'JUNK\n.'
repr(s), self.assertRaises(ValueError, self.loads, data)
got))
n = n >> 1 def test_reduce(self):
# Fake a pickle from a sizeof(long)==8 box.
maxint64 = (1L << 63) - 1
data = 'I' + str(maxint64) + '\n.'
got = pickle.loads(data)
if maxint64 != got:
raise TestFailed("maxint64 test failed %r %r" % (maxint64, got))
# Try too with a bogus literal.
data = 'I' + str(maxint64) + 'JUNK\n.'
try:
got = pickle.loads(data)
except ValueError:
pass pass
else:
raise TestFailed("should have raised error on bogus INT literal") def test_getinitargs(self):
pass
class AbstractPickleModuleTests(unittest.TestCase):
def test_dump_closed_file(self):
import tempfile, os
fn = tempfile.mktemp()
f = open(fn, "w")
f.close()
self.assertRaises(ValueError, self.module.dump, 123, f)
os.remove(fn)
def test_load_closed_file(self):
import tempfile, os
fn = tempfile.mktemp()
f = open(fn, "w")
f.close()
self.assertRaises(ValueError, self.module.dump, 123, f)
os.remove(fn)
import cPickle import cPickle
import pickletester from cStringIO import StringIO
pickletester.dotest(cPickle) from pickletester import AbstractPickleTests, AbstractPickleModuleTests
from test_support import run_unittest
class cPickleTests(AbstractPickleTests, AbstractPickleModuleTests):
def setUp(self):
self.dumps = cPickle.dumps
self.loads = cPickle.loads
error = cPickle.BadPickleGet
module = cPickle
class cPicklePicklerTests(AbstractPickleTests):
def dumps(self, arg, bin=0):
f = StringIO()
p = cPickle.Pickler(f, bin)
p.dump(arg)
f.seek(0)
return f.read()
def loads(self, buf):
f = StringIO(buf)
p = cPickle.Unpickler(f)
return p.load()
error = cPickle.BadPickleGet
class cPickleListPicklerTests(AbstractPickleTests):
def dumps(self, arg, bin=0):
p = cPickle.Pickler(bin)
p.dump(arg)
return p.getvalue()
def loads(self, *args):
f = StringIO(args[0])
p = cPickle.Unpickler(f)
return p.load()
error = cPickle.BadPickleGet
class cPickleFastPicklerTests(AbstractPickleTests):
def dumps(self, arg, bin=0):
f = StringIO()
p = cPickle.Pickler(f, bin)
p.fast = 1
p.dump(arg)
f.seek(0)
return f.read()
def loads(self, *args):
f = StringIO(args[0])
p = cPickle.Unpickler(f)
return p.load()
error = cPickle.BadPickleGet
def test_recursive_list(self):
self.assertRaises(ValueError,
AbstractPickleTests.test_recursive_list,
self)
def test_recursive_inst(self):
self.assertRaises(ValueError,
AbstractPickleTests.test_recursive_inst,
self)
def test_recursive_dict(self):
self.assertRaises(ValueError,
AbstractPickleTests.test_recursive_dict,
self)
def test_recursive_multi(self):
self.assertRaises(ValueError,
AbstractPickleTests.test_recursive_multi,
self)
if __name__ == "__main__":
run_unittest(cPickleTests)
run_unittest(cPicklePicklerTests)
run_unittest(cPickleListPicklerTests)
run_unittest(cPickleFastPicklerTests)
import pickle import pickle
import pickletester from cStringIO import StringIO
pickletester.dotest(pickle) from pickletester import AbstractPickleTests, AbstractPickleModuleTests
from test_support import run_unittest
class PickleTests(AbstractPickleTests, AbstractPickleModuleTests):
def setUp(self):
self.dumps = pickle.dumps
self.loads = pickle.loads
module = pickle
error = KeyError
class PicklerTests(AbstractPickleTests):
error = KeyError
def dumps(self, arg, bin=0):
f = StringIO()
p = pickle.Pickler(f, bin)
p.dump(arg)
f.seek(0)
return f.read()
def loads(self, buf):
f = StringIO(buf)
u = pickle.Unpickler(f)
return u.load()
if __name__ == "__main__":
run_unittest(PickleTests)
run_unittest(PicklerTests)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment