2
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
3
# See LICENSE for details.
6
"""Test cases for 'jelly' object serialization.
11
from twisted.spread import jelly, pb
13
from twisted.trial import unittest
15
class TestNode(object, jelly.Jellyable):
16
"""An object to test jellyfying of new style class isntances.
19
def __init__(self, parent=None):
21
self.id = parent.id + 1
22
parent.children.append(self)
61
class SimpleJellyTest:
62
def __init__(self, x, y):
66
def isTheSameAs(self, other):
67
return self.__dict__ == other.__dict__
70
class NewStyle(object):
74
class JellyTestCase(unittest.TestCase):
76
testcases for `jelly' module serialization.
79
def testMethodSelfIdentity(self):
84
im_ = jelly.unjelly(jelly.jelly(b)).a.bmethod
85
self.assertEquals(im_.im_class, im_.im_self.__class__)
88
def testNewStyle(self):
96
self.failUnless(isinstance(m, NewStyle))
97
self.assertIdentical(m.n2, m.n3)
100
def testDateTime(self):
101
dtn = datetime.datetime.now()
102
dtd = datetime.datetime.now() - dtn
104
c = jelly.jelly(input)
105
output = jelly.unjelly(c)
106
self.assertEquals(input, output)
107
self.assertNotIdentical(input, output)
110
def testSimple(self):
114
self.failUnless(SimpleJellyTest('a', 'b').isTheSameAs(SimpleJellyTest('a', 'b')))
115
a = SimpleJellyTest(1, 2)
116
cereal = jelly.jelly(a)
117
b = jelly.unjelly(cereal)
118
self.failUnless(a.isTheSameAs(b))
121
def testIdentity(self):
123
test to make sure that objects retain identity properly
129
self.assertIdentical(x[0], x[1])
130
self.assertIdentical(x[0][0], x)
133
self.assertIdentical(z[0], z[1])
134
self.assertIdentical(z[0][0], z)
137
def testUnicode(self):
138
if hasattr(types, 'UnicodeType'):
140
y = jelly.unjelly(jelly.jelly(x))
141
self.assertEquals(x, y)
142
self.assertEquals(type(x), type(y))
145
def testStressReferences(self):
147
toplevelTuple = ({'list': reref}, reref)
148
reref.append(toplevelTuple)
149
s = jelly.jelly(toplevelTuple)
151
self.assertIdentical(z[0]['list'], z[1])
152
self.assertIdentical(z[0]['list'][0], z)
155
def testMoreReferences(self):
161
self.assertIdentical(z[0][0][0], z)
164
def testTypeSecurity(self):
166
test for type-level security of serialization
168
taster = jelly.SecurityOptions()
169
dct = jelly.jelly({})
170
self.assertRaises(jelly.InsecureJelly, jelly.unjelly, dct, taster)
173
def testNewStyleClasses(self):
175
uj = jelly.unjelly(D)
176
self.assertIdentical(D, uj)
179
def testLotsaTypes(self):
181
test for all types currently supported in jelly
184
jelly.unjelly(jelly.jelly(a))
185
jelly.unjelly(jelly.jelly(a.amethod))
186
items = [afunc, [1, 2, 3], not bool(1), bool(1), 'test', 20.3, (1,2,3), None, A, unittest, {'a':1}, A.amethod]
188
self.assertEquals(i, jelly.unjelly(jelly.jelly(i)))
191
def testSetState(self):
194
def __init__(self, other):
196
def __getstate__(self):
198
def __setstate__(self, state):
199
self.other = state[0]
201
return hash(self.other)
205
t3 = TupleState((t1, t2))
206
d = {t1: t1, t2: t2, t3: t3, "t3": t3}
207
t3prime = jelly.unjelly(jelly.jelly(d))["t3"]
208
self.assertIdentical(t3prime.other[0].other, t3prime.other[1].other)
211
def testClassSecurity(self):
213
test for class-level security of serialization
215
taster = jelly.SecurityOptions()
216
taster.allowInstancesOf(A, B)
220
# add a little complexity to the data
223
# and a backreference
226
# first, a friendly insecure serialization
227
friendly = jelly.jelly(a, taster)
228
x = jelly.unjelly(friendly, taster)
229
self.failUnless(isinstance(x.c, jelly.Unpersistable),
230
"C came back: %s" % x.c.__class__)
231
# now, a malicious one
232
mean = jelly.jelly(a)
234
x = jelly.unjelly(mean, taster)
235
self.fail("x came back: %s" % x)
236
except jelly.InsecureJelly:
239
self.assertIdentical(x.x, x.b, "Identity mismatch")
240
#test class serialization
241
friendly = jelly.jelly(A, taster)
242
x = jelly.unjelly(friendly, taster)
243
self.assertIdentical(x, A, "A came back: %s" % x)
246
def testUnjellyable(self):
248
Test that if Unjellyable is used to deserialize a jellied object,
249
state comes out right.
251
class JellyableTestClass(jelly.Jellyable):
253
jelly.setUnjellyableForClass(JellyableTestClass, jelly.Unjellyable)
254
input = JellyableTestClass()
255
input.attribute = 'value'
256
output = jelly.unjelly(jelly.jelly(input))
257
self.assertEquals(output.attribute, 'value')
259
isinstance(output, jelly.Unjellyable),
260
"Got instance of %r, not Unjellyable" % (output.__class__,))
263
def testPersistentStorage(self):
265
def persistentStore(obj, jel, perst = perst):
266
perst[1] = perst[1] + 1
267
perst[0][perst[1]] = obj
270
def persistentLoad(pidstr, unj, perst = perst):
274
a = SimpleJellyTest(1, 2)
275
b = SimpleJellyTest(3, 4)
276
c = SimpleJellyTest(5, 6)
282
jel = jelly.jelly(a, persistentStore = persistentStore)
283
x = jelly.unjelly(jel, persistentLoad = persistentLoad)
285
self.assertIdentical(x.b, x.c.b)
286
# assert len(perst) == 3, "persistentStore should only be called 3 times."
287
self.failUnless(perst[0], "persistentStore was not called.")
288
self.assertIdentical(x.b, a.b, "Persistent storage identity failure.")
291
def testNewStyleClasses(self):
298
m = jelly.unjelly(jel)
299
# Check that it has been restored ok
300
TestNode.classAttr == 5 # Shouldn't override jellied values
301
self._check_newstyle(n,m)
304
def _check_newstyle(self, a, b):
305
self.assertEqual(a.id, b.id)
306
self.assertEqual(a.classAttr, 4)
307
self.assertEqual(b.classAttr, 4)
308
self.assertEqual(len(a.children), len(b.children))
309
for x,y in zip(a.children, b.children):
310
self._check_newstyle(x,y)
314
class ClassA(pb.Copyable, pb.RemoteCopy):
316
self.ref = ClassB(self)
320
class ClassB(pb.Copyable, pb.RemoteCopy):
321
def __init__(self, ref):
326
class CircularReferenceTestCase(unittest.TestCase):
327
def testSimpleCircle(self):
328
jelly.setUnjellyableForClass(ClassA, ClassA)
329
jelly.setUnjellyableForClass(ClassB, ClassB)
330
a = jelly.unjelly(jelly.jelly(ClassA()))
331
self.failUnless(a.ref.ref is a, "Identity not preserved in circular reference")
334
def testCircleWithInvoker(self):
335
class dummyInvokerClass: pass
336
dummyInvoker = dummyInvokerClass()
337
dummyInvoker.serializingPerspective = None
339
jelly.setUnjellyableForClass(ClassA, ClassA)
340
jelly.setUnjellyableForClass(ClassB, ClassB)
341
j = jelly.jelly(a0, invoker=dummyInvoker)
342
a1 = jelly.unjelly(j)
343
self.failUnlessIdentical(a1.ref.ref, a1,
344
"Identity not preserved in circular reference")