2
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
3
# See LICENSE for details.
9
from twisted.trial import unittest
12
import cPickle as pickle
17
import cStringIO as StringIO
22
from twisted.persisted import styles, aot
25
class VersionTestCase(unittest.TestCase):
26
def testNullVersionUpgrade(self):
30
pkcl = pickle.dumps(NullVersioned())
31
class NullVersioned(styles.Versioned):
32
persistenceVersion = 1
33
def upgradeToVersion1(self):
35
mnv = pickle.loads(pkcl)
37
assert mnv.ok, "initial upgrade not run!"
39
def testVersionUpgrade(self):
41
class MyVersioned(styles.Versioned):
42
persistenceVersion = 2
43
persistenceForgets = ['garbagedata']
49
self.garbagedata = lambda q: 'cant persist'
51
def upgradeToVersion3(self):
54
def upgradeToVersion4(self):
57
assert not (mv.v3 or mv.v4), "hasn't been upgraded yet"
58
pickl = pickle.dumps(mv)
59
MyVersioned.persistenceVersion = 4
60
obj = pickle.loads(pickl)
62
assert obj.v3, "didn't do version 3 upgrade"
63
assert obj.v4, "didn't do version 4 upgrade"
64
pickl = pickle.dumps(obj)
65
obj = pickle.loads(pickl)
67
assert obj.v3 == 1, "upgraded unnecessarily"
68
assert obj.v4 == 1, "upgraded unnecessarily"
70
def testNonIdentityHash(self):
71
global ClassWithCustomHash
72
class ClassWithCustomHash(styles.Versioned):
73
def __init__(self, unique, hash):
79
v1 = ClassWithCustomHash('v1', 0)
80
v2 = ClassWithCustomHash('v2', 0)
82
pkl = pickle.dumps((v1, v2))
84
ClassWithCustomHash.persistenceVersion = 1
85
ClassWithCustomHash.upgradeToVersion1 = lambda self: setattr(self, 'upgraded', True)
86
v1, v2 = pickle.loads(pkl)
88
self.assertEquals(v1.unique, 'v1')
89
self.assertEquals(v2.unique, 'v2')
90
self.failUnless(v1.upgraded)
91
self.failUnless(v2.upgraded)
93
def testUpgradeDeserializesObjectsRequiringUpgrade(self):
94
global ToyClassA, ToyClassB
95
class ToyClassA(styles.Versioned):
97
class ToyClassB(styles.Versioned):
101
pklA, pklB = pickle.dumps(x), pickle.dumps(y)
103
ToyClassA.persistenceVersion = 1
104
def upgradeToVersion1(self):
105
self.y = pickle.loads(pklB)
107
ToyClassA.upgradeToVersion1 = upgradeToVersion1
108
ToyClassB.persistenceVersion = 1
109
ToyClassB.upgradeToVersion1 = lambda self: setattr(self, 'upgraded', True)
111
x = pickle.loads(pklA)
113
self.failUnless(x.y.upgraded)
115
class MyEphemeral(styles.Ephemeral):
117
def __init__(self, x):
121
class EphemeralTestCase(unittest.TestCase):
123
def testEphemeral(self):
125
self.assertEquals(o.__class__, MyEphemeral)
126
self.assertEquals(o.x, 3)
128
pickl = pickle.dumps(o)
129
o = pickle.loads(pickl)
131
self.assertEquals(o.__class__, styles.Ephemeral)
132
self.assert_(not hasattr(o, 'x'))
137
def __init__(self, x):
161
from twisted.persisted import marmalade
165
class Marmaladeable(marmalade.DOMJellyable):
169
def __init__(self, integer, instance, name, sequence):
170
self.integer = integer
171
self.instance = instance
172
self.sequence = sequence
175
def jellyToDOM_1(self, jellier, element):
176
from twisted.python.reflect import qual
177
element.setAttribute("integer", str(self.integer))
178
element.setAttribute("instance", qual(self.instance.__class__)) # not l33t enough
179
element.setAttribute("name", str(self.name))
180
# oops forgot self.sequence
182
def unjellyFromDOM_1(self, unjellier, element):
183
from twisted.python.reflect import namedClass
184
self.integer = int(element.getAttribute("integer"))
185
self.instance = namedClass(element.getAttribute("instance"))()
186
self.name = element.getAttribute("name")
187
# just give us any ol' list
188
self.sequence = [self.instance, self.instance]
190
def jellyToDOM_2(self, jellier, element):
191
element.setAttribute("integer", str(self.integer))
192
element.setAttribute("name", str(self.name))
193
instanceNode = jellier.jellyToNode(self.instance) # l33ter!
194
instanceNode.setAttribute("parent:role", "instance")
195
element.appendChild(instanceNode)
197
for seqel in self.sequence:
198
seqNode = jellier.jellyToNode(seqel)
199
seqNode.setAttribute("parent:role", "sequence:%d" % i)
200
element.appendChild(seqNode)
203
def unjellyFromDOM_2(self, unjellier, element):
204
self.integer = int(element.getAttribute("integer"))
205
self.name = element.getAttribute("name")
207
# Note to people reading this as an example: if you don't use
208
# "unjellyInto", and instead use "unjellyFromNode", it will appear to
209
# work. _however_, it will also have some really surprising results
210
# when you have references in your application; i.e. you will get
211
# _Dereference instances in places where you thought you should have
212
# references to back-referenced data. I am working on making this
214
from twisted.web.microdom import Element
217
for node in element.childNodes:
218
if isinstance(node, Element):
219
if node.getAttribute("parent:role") == 'instance':
220
unjellier.unjellyAttribute(self, "instance", node)
222
self.sequence.append(None)
223
unjellier.unjellyLater(node).addCallback(
224
self.gotSequenceItem, i)
227
def gotSequenceItem(self, seqitem, num):
228
self.sequence[num] = seqitem
231
class MarmaladeTestCase(unittest.TestCase):
233
def testMarmaladeable(self):
234
m = Marmaladeable(1, B(), "testing", [1, 2, 3])
235
s = marmalade.jellyToXML(m)
236
u = marmalade.unjellyFromXML(s)
237
assert u.sequence == [u.instance, u.instance]
238
u.sequence.append(u.instance)
239
u.jellyDOMVersion = 2
240
s2 = marmalade.jellyToXML(u)
241
u2 = marmalade.unjellyFromXML(s2)
242
self.assertEquals( u2.sequence, [u2.instance, u2.instance, u2.instance])
244
def testCopyReg(self):
246
sio = StringIO.StringIO()
248
assert marmalade.unjellyFromXML(marmalade.jellyToXML({1:sio}))[1].getvalue() == s
250
def testMethodSelfIdentity(self):
253
a.bmethod = b.bmethod
255
im_ = marmalade.unjellyFromXML(marmalade.jellyToXML(b)).a.bmethod
256
self.assertEquals(im_.im_class, im_.im_self.__class__)
258
def testBasicIdentity(self):
259
# Anyone wanting to make this datastructure more complex, and thus this
260
# test more comprehensive, is welcome to do so.
261
dj = marmalade.DOMJellier().jellyToNode
262
d = {'hello': 'world', "method": dj}
264
"he\tllo\n\n\"x world!",
265
u"goodbye \n\t\u1010 world!",
266
1, 1.0, 100 ** 100l, unittest, marmalade.DOMJellier, d,
275
uj = marmalade.unjellyFromXML(marmalade.jellyToXML([l, l]))
276
assert uj[0] is uj[1]
277
assert uj[1][0:5] == l[0:5]
279
class PicklingTestCase(unittest.TestCase):
280
"""Test pickling of extra object types."""
282
def testModule(self):
283
pickl = pickle.dumps(styles)
284
o = pickle.loads(pickl)
285
self.assertEquals(o, styles)
287
def testClassMethod(self):
288
pickl = pickle.dumps(Pickleable.getX)
289
o = pickle.loads(pickl)
290
self.assertEquals(o, Pickleable.getX)
292
def testInstanceMethod(self):
294
pickl = pickle.dumps(obj.getX)
295
o = pickle.loads(pickl)
296
self.assertEquals(o(), 4)
297
self.assertEquals(type(o), type(obj.getX))
299
def testStringIO(self):
300
f = StringIO.StringIO()
302
pickl = pickle.dumps(f)
303
o = pickle.loads(pickl)
304
self.assertEquals(type(o), type(f))
305
self.assertEquals(f.getvalue(), "abc")
309
def __init__(self, x):
315
def __getstate__(self):
317
def __setstate__(self, state):
320
class AOTTestCase(unittest.TestCase):
321
def testSimpleTypes(self):
322
obj = (1, 2.0, 3j, True, slice(1, 2, 3), 'hello', u'world', sys.maxint + 1, None, Ellipsis)
323
rtObj = aot.unjellyFromSource(aot.jellyToSource(obj))
324
self.assertEquals(obj, rtObj)
326
def testMethodSelfIdentity(self):
329
a.bmethod = b.bmethod
331
im_ = aot.unjellyFromSource(aot.jellyToSource(b)).a.bmethod
332
self.assertEquals(im_.im_class, im_.im_self.__class__)
334
def testBasicIdentity(self):
335
# Anyone wanting to make this datastructure more complex, and thus this
336
# test more comprehensive, is welcome to do so.
337
aj = aot.AOTJellier().jellyToAO
338
d = {'hello': 'world', "method": aj}
340
"he\tllo\n\n\"x world!",
341
u"goodbye \n\t\u1010 world!",
342
1, 1.0, 100 ** 100l, unittest, aot.AOTJellier, d,
349
uj = aot.unjellyFromSource(aot.jellyToSource([l, l]))
350
assert uj[0] is uj[1]
351
assert uj[1][0:5] == l[0:5]
354
def testNonDictState(self):
356
a.state = "meringue!"
357
assert aot.unjellyFromSource(aot.jellyToSource(a)).state == a.state
359
def testCopyReg(self):
361
sio = StringIO.StringIO()
363
uj = aot.unjellyFromSource(aot.jellyToSource(sio))
364
# print repr(uj.__dict__)
365
assert uj.getvalue() == s
367
def testFunkyReferences(self):
368
o = EvilSourceror(EvilSourceror([]))
369
j1 = aot.jellyToAOT(o)
370
oj = aot.unjellyFromAOT(j1)
373
assert oj.a.b is oj.b
374
assert oj.c is not oj.c.c
376
testCases = [VersionTestCase, EphemeralTestCase, PicklingTestCase]