1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
# -*- coding: utf-8 -*-
#
# Copyright (C) 2013 Jason R. Coombs <jaraco@jaraco.com>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution.
import doctest
import unittest
import jsonpickle
import jsonpickle.handlers
class CustomObject(object):
"A class to be serialized by a custom handler"
def __init__(self, name=None, creator=None):
self.name = name
self.creator = creator
def __eq__(self, other):
return self.name == other.name
class CustomA(CustomObject):
pass
class CustomB(CustomA):
pass
class NullHandler(jsonpickle.handlers.BaseHandler):
def flatten(self, obj, data):
data['name'] = obj.name
return data
def restore(self, obj):
return CustomObject(obj['name'], creator=type(self))
class DecoratedBase(CustomObject):
pass
class DecoratedChild(DecoratedBase):
pass
@jsonpickle.handlers.register(DecoratedBase, base=True)
class DecoratedHandler(NullHandler):
pass
class SithHandler(jsonpickle.handlers.BaseHandler):
"""(evil) serialization handler that rewrites the entire object"""
def flatten(self, obj, data):
data['name'] = obj.name
data['py/object'] = 'sith.lord'
return data
class HandlerTestCase(unittest.TestCase):
def setUp(self):
jsonpickle.handlers.register(CustomObject, NullHandler)
def tearDown(self):
jsonpickle.handlers.unregister(CustomObject)
def roundtrip(self, ob):
encoded = jsonpickle.encode(ob)
decoded = jsonpickle.decode(encoded)
self.assertEqual(decoded, ob)
return decoded
def test_custom_handler(self):
"""Ensure that the custom handler is indeed used"""
expect = CustomObject('jarjar')
encoded = jsonpickle.encode(expect)
actual = jsonpickle.decode(encoded)
self.assertEqual(expect.name, actual.name)
self.assertTrue(expect.creator is None)
self.assertTrue(actual.creator is NullHandler)
def test_references(self):
"""
Ensure objects handled by a custom handler are properly dereferenced.
"""
ob = CustomObject()
# create a dictionary which contains several references to ob
subject = dict(a=ob, b=ob, c=ob)
# ensure the subject can be roundtripped
new_subject = self.roundtrip(subject)
self.assertEqual(new_subject['a'], new_subject['b'])
self.assertEqual(new_subject['b'], new_subject['c'])
self.assertTrue(new_subject['a'] is new_subject['b'])
self.assertTrue(new_subject['b'] is new_subject['c'])
def test_invalid_class(self):
self.assertRaises(TypeError, jsonpickle.handlers.register, 'foo', NullHandler)
def test_base_handler(self):
a = CustomA('a')
self.assertTrue(a.creator is None)
self.assertTrue(jsonpickle.decode(jsonpickle.encode(a)).creator is None)
b = CustomB('b')
self.assertTrue(b.creator is None)
self.assertTrue(jsonpickle.decode(jsonpickle.encode(b)).creator is None)
OtherHandler = type('OtherHandler', (NullHandler,), {})
jsonpickle.handlers.register(CustomA, OtherHandler, base=True)
self.assertTrue(self.roundtrip(a).creator is OtherHandler)
self.assertTrue(self.roundtrip(b).creator is OtherHandler)
SpecializedHandler = type('SpecializedHandler', (NullHandler,), {})
jsonpickle.handlers.register(CustomB, SpecializedHandler)
self.assertTrue(self.roundtrip(a).creator is OtherHandler)
self.assertTrue(self.roundtrip(b).creator is SpecializedHandler)
def test_decorated_register(self):
db = DecoratedBase('db')
dc = DecoratedChild('dc')
self.assertTrue(self.roundtrip(db).creator is DecoratedHandler)
self.assertTrue(self.roundtrip(dc).creator is DecoratedHandler)
def test_custom_handler_can_rewrite_everything(self):
"""Test the low-level pickling structures"""
jsonpickle.handlers.unregister(CustomObject)
jsonpickle.handlers.register(CustomObject, SithHandler)
obj = CustomObject('jarjar') # secret sith lord jarjar
pickler = jsonpickle.pickler.Pickler()
data = pickler.flatten(obj)
self.assertTrue(isinstance(data, dict))
self.assertEqual(len(data), 2)
self.assertEqual('jarjar', data['name'])
self.assertEqual('sith.lord', data['py/object'])
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(HandlerTestCase))
suite.addTest(doctest.DocTestSuite(jsonpickle.handlers))
return suite
if __name__ == '__main__':
unittest.main(defaultTest='suite')
|