File: handler_test.py

package info (click to toggle)
jsonpickle 4.0.2%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,864 kB
  • sloc: python: 6,788; javascript: 654; makefile: 125; sh: 68
file content (140 lines) | stat: -rw-r--r-- 4,291 bytes parent folder | download
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
# 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 unittest

import pytest

import jsonpickle
import jsonpickle.handlers


class CustomObject:
    "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)
        assert 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)
        assert expect.name == actual.name
        assert expect.creator is None
        assert 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)
        assert new_subject['a'] == new_subject['b']
        assert new_subject['b'] == new_subject['c']
        assert new_subject['a'] is new_subject['b']
        assert new_subject['b'] is new_subject['c']

    def test_invalid_class(self):
        with pytest.raises(TypeError):
            jsonpickle.handlers.register('foo', NullHandler)

    def test_base_handler(self):
        a = CustomA('a')
        assert a.creator is None
        assert jsonpickle.decode(jsonpickle.encode(a)).creator is None

        b = CustomB('b')
        assert b.creator is None
        assert jsonpickle.decode(jsonpickle.encode(b)).creator is None

        OtherHandler = type('OtherHandler', (NullHandler,), {})
        jsonpickle.handlers.register(CustomA, OtherHandler, base=True)
        assert self.roundtrip(a).creator is OtherHandler
        assert self.roundtrip(b).creator is OtherHandler

        SpecializedHandler = type('SpecializedHandler', (NullHandler,), {})
        jsonpickle.handlers.register(CustomB, SpecializedHandler)
        assert self.roundtrip(a).creator is OtherHandler
        assert self.roundtrip(b).creator is SpecializedHandler

    def test_decorated_register(self):
        db = DecoratedBase('db')
        dc = DecoratedChild('dc')
        assert self.roundtrip(db).creator is DecoratedHandler
        assert 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)
        assert isinstance(data, dict)
        assert len(data) == 2
        assert data['name'] == 'jarjar'
        assert data['py/object'] == 'sith.lord'