# Twisted, the Framework of Your Internet # Copyright (C) 2001 Matthew W. Lefkowitz # # This library is free software; you can redistribute it and/or # modify it under the terms of version 2.1 of the GNU Lesser General Public # License as published by the Free Software Foundation. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """Test cases for 'jelly' object serialization. """ import types from twisted.trial import unittest from twisted.spread import jelly #from twisted import sexpy from twisted.python.compat import bool class A: """ dummy class """ def amethod(self): pass def afunc(self): pass class B: """ dummy class """ def bmethod(self): pass class C: """ dummy class """ def cmethod(self): pass class SimpleJellyTest: def __init__(self, x, y): self.x = x self.y = y def isTheSameAs(self, other): return self.__dict__ == other.__dict__ try: object haveObject = 0 # 1 # more work to be done before this really works except: haveObject = 0 else: class NewStyle(object): pass class JellyTestCase(unittest.TestCase): """ testcases for `jelly' module serialization. """ def testMethodSelfIdentity(self): a = A() b = B() a.bmethod = b.bmethod b.a = a im_ = jelly.unjelly(jelly.jelly(b)).a.bmethod self.assertEquals(im_.im_class, im_.im_self.__class__) if haveObject: def testNewStyle(self): n = NewStyle() n.x = 1 n2 = NewStyle() n.n2 = n2 n.n3 = n2 c = jelly.jelly(n) m = jelly.unjelly(c) assert isinstance(m, NewStyle) assert m.n2 is m.n3 def testSimple(self): """ simplest test case """ assert SimpleJellyTest('a', 'b').isTheSameAs(SimpleJellyTest('a', 'b')) a = SimpleJellyTest(1, 2) cereal = jelly.jelly(a) b = jelly.unjelly(cereal) assert a.isTheSameAs(b) def testIdentity(self): """ test to make sure that objects retain identity properly """ x = [] y = (x) x.append(y) x.append(y) assert x[0] is x[1] assert x[0][0] is x s = jelly.jelly(x) z = jelly.unjelly(s) assert z[0] is z[1] assert z[0][0] is z def testUnicode(self): if hasattr(types, 'UnicodeType'): x = 'blah' assert jelly.unjelly(jelly.jelly(unicode(x))) == x def testStressReferences(self): reref = [] toplevelTuple = ({'list': reref}, reref) reref.append(toplevelTuple) s = jelly.jelly(toplevelTuple) z = jelly.unjelly(s) assert z[0]['list'] is z[1] assert z[0]['list'][0] is z def testPersistentStorage(self): perst = [{}, 1] def persistentStore(obj, jel, perst = perst): perst[1] = perst[1] + 1 perst[0][perst[1]] = obj return str(perst[1]) def persistentLoad(pidstr, unj, perst = perst): pid = int(pidstr) return perst[0][pid] a = SimpleJellyTest(1, 2) b = SimpleJellyTest(3, 4) c = SimpleJellyTest(5, 6) a.b = b a.c = c c.b = b jel = jelly.jelly(a, persistentStore = persistentStore) x = jelly.unjelly(jel, persistentLoad = persistentLoad) assert x.b is x.c.b, "Identity failure." # assert len(perst) == 3, "persistentStore should only be called 3 times." assert perst[0], "persistentStore was not called." assert x.b is a.b, "Persistent storage identity failure." def testTypeSecurity(self): """ test for type-level security of serialization """ taster = jelly.SecurityOptions() dct = jelly.jelly({}) try: jelly.unjelly(dct, taster) assert 0, "Insecure Jelly unjellied successfully." except jelly.InsecureJelly: # OK, works pass def testLotsaTypes(self): """ test for all types currently supported in jelly """ a = A() jelly.unjelly(jelly.jelly(a)) jelly.unjelly(jelly.jelly(a.amethod)) items = [afunc, [1, 2, 3], not bool(1), bool(1), 'test', 20.3, (1,2,3), None, A, unittest, {'a':1}, A.amethod] for i in items: self.assertEquals(i, jelly.unjelly(jelly.jelly(i))) def testSetState(self): global TupleState class TupleState: def __init__(self, other): self.other = other def __getstate__(self): return (self.other,) def __setstate__(self, state): self.other = state[0] def __hash__(self): return hash(self.other) a = A() t1 = TupleState(a) t2 = TupleState(a) t3 = TupleState((t1, t2)) d = {t1: t1, t2: t2, t3: t3, "t3": t3} t3prime = jelly.unjelly(jelly.jelly(d))["t3"] assert t3prime.other[0].other is t3prime.other[1].other def testClassSecurity(self): """ test for class-level security of serialization """ taster = jelly.SecurityOptions() taster.allowInstancesOf(A, B) a = A() b = B() c = C() # add a little complexity to the data a.b = b a.c = c # and a backreference a.x = b b.c = c # first, a friendly insecure serialization friendly = jelly.jelly(a, taster) x = jelly.unjelly(friendly, taster) assert isinstance(x.c, jelly.Unpersistable), "C came back: %s" % x.c.__class__ # now, a malicious one mean = jelly.jelly(a) try: x = jelly.unjelly(mean, taster) assert 0, "x came back: %s" % x except jelly.InsecureJelly: # OK pass assert x.x is x.b, "Identity mismatch" #test class serialization friendly = jelly.jelly(A, taster) x = jelly.unjelly(friendly, taster) assert x is A, "A came back: %s" % x testCases = [JellyTestCase]