Completed
Pull Request — master (#694)
by Eric
02:14
created

DummySerializer   A

Complexity

Total Complexity 4

Size/Duplication

Total Lines 7
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 2
Metric Value
c 2
b 0
f 2
dl 0
loc 7
rs 10
wmc 4

2 Methods

Rating   Name   Duplication   Size   Complexity  
A _do_deserialize() 0 3 2
A _do_serialize() 0 2 2
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
"""
5
test_serialization
6
------------------
7
8
Tests for `cookiecutter.serialization` module.
9
"""
10
11
from __future__ import unicode_literals
12
13
import pytest
14
import sys
15
import os
16
17
from cookiecutter.serialization import \
18
    SerializationFacade, JsonSerializer, AbstractSerializer, \
19
    get_context as get_context_in_hooks, put_context as put_context_in_hooks, \
20
    remove_persisent
21
from cookiecutter.exceptions import UnknownSerializerType, \
22
    BadSerializedStringFormat, InvalidSerializerType, InvalidType
23
24
25
@pytest.fixture
26
def _encode_serialized(serialized):
27
    """
28
    helper method to simulate the SerializationFacade.__encode behaviour
29
    """
30
    return serialized.decode().replace("\n", "*")
31
32
33
@pytest.fixture
34
def get_context():
35
    """
36
    helper method to get a bunch of context objects
37
    """
38
    context = {
39
        "my_key": "my_val"
40
    }
41
42
    context2 = {
43
        "my_key2": "my_val2"
44
    }
45
46
    json_serialized = _encode_serialized(JsonSerializer().serialize(context))
47
48
    return {
49
        'object': context,
50
        'object2': context2,
51
        'json': 'json|' + json_serialized + '$'
52
    }
53
54
55
@pytest.fixture
56
def get_serializers():
57
    """
58
    helper method to get a bunch of serializers
59
    """
60
    class FakeSerializer(object):
61
        def serialize(self, subject):
62
            return b'serialized'
63
64
        def deserialize(self, string):
65
            return {}
66
67
    class DummySerializer(AbstractSerializer):
68
        def _do_serialize(self, subject):
69
            return ' serialized text' if 'my_key2' in subject else 'serialized'
70
71
        def _do_deserialize(self, string):
72
            return get_context()['object2'] if 'serialized text' in string \
73
                else get_context()['object']
74
75
    return {
76
        'fake': FakeSerializer,
77
        'dummy': DummySerializer
78
    }
79
80
81
class TestSerialization(object):
82
83
    def setup_method(self, method):
84
        remove_persisent(SerializationFacade)
85
        assert SerializationFacade.__name__ not in os.environ
86
87
    def __get_serialized_context(self, type, serializer, object=None):
88
        """
89
        helper method to get a serialized context for comparison
90
        :param type: the type of the serializer
91
        :param serializer: the serializer to use
92
        :param object: the object to serialize
93
        """
94
        context = get_context()['object'] if object is None else object
95
        return type + '|' \
96
                    + _encode_serialized(serializer.serialize(context)) \
97
                    + '$'
98
99
    def test_default_serialize(self):
100
        """
101
        serialize a context object with the default available serializer
102
        """
103
        assert get_context()['json'] == SerializationFacade().serialize(
104
            get_context()['object'])
105
106
    def test_default_deserialize(self):
107
        """
108
        deserialize a context string with the default available serializer
109
        """
110
111
        assert get_context()['object'] == SerializationFacade().deserialize(
112
            get_context()['json'])
113
114
    def test_not_registered_serializer_during_serialization(self):
115
        """
116
        ensure a non registered serializer cannot be called during
117
        serialization
118
        """
119
        with pytest.raises(UnknownSerializerType) as excinfo:
120
            _type = 'not_registered'
121
            SerializationFacade().use(_type).serialize(get_context()['object'])
122
123
            assert _type in excinfo.message
124
125
    def test_not_registered_serializer_during_deserialization(self):
126
        """
127
        ensure a non registered serializer cannot be called during
128
        deserialization
129
        """
130
        with pytest.raises(UnknownSerializerType) as excinfo:
131
            _type = 'not_registered'
132
            serialized = _type + '|somestring$'
133
            SerializationFacade().deserialize(serialized)
134
135
            assert _type in excinfo.message
136
137
    def test_register_serializer(self):
138
        """
139
        register a custom serializer class
140
        """
141
        _type = 'dummy'
142
        context = get_context()['object']
143
        kclass = get_serializers()[_type]
144
        facade = SerializationFacade()
145
        facade.register(_type, kclass)
146
        expected = self.__get_serialized_context(_type, kclass(), context)
147
148
        assert expected == facade.use(_type).serialize(context)
149
        assert context == facade.deserialize(expected)
150
151
    def test_register_serializer_accepts_object(self):
152
        """
153
        register a custom serializer instance
154
        """
155
        _type = 'dummy'
156
        context = get_context()['object']
157
        serializer = get_serializers()[_type]()
158
        facade = SerializationFacade()
159
        facade.register(_type, serializer)
160
        expected = self.__get_serialized_context(_type, serializer, context)
161
162
        assert expected == facade.use(_type).serialize(context)
163
164
    def test_serializer_api_check(self):
165
        """
166
        enforce the given serializer to extends AbstractSerializer
167
        """
168
        with pytest.raises(InvalidType) as excinfo:
169
            SerializationFacade().register(
170
                'fake', get_serializers()['fake']
171
            )
172
173
        assert 'AbstractSerializer' in excinfo.value.message
174
175
    def test_get_serialization_type(self):
176
        """
177
        get the type of the current serializer
178
        """
179
        _type = 'dummy'
180
        serializer = get_serializers()[_type]()
181
        facade = SerializationFacade()
182
        facade.register(_type, serializer)
183
        serialized = self.__get_serialized_context(_type, serializer)
184
185
        assert 'json' == facade.get_type()
186
        facade.deserialize(serialized)
187
        assert _type == facade.get_type()
188
189
    def test_use_specific_serializer(self):
190
        """
191
        a registered serializer can be specified before the serialization
192
        """
193
        _type = 'dummy'
194
        context = get_context()['object']
195
        serializer = get_serializers()['dummy']()
196
        facade = SerializationFacade()
197
        facade.register(_type, serializer)
198
        expected = self.__get_serialized_context(_type, serializer, context)
199
200
        assert expected == facade.use(_type).serialize(context)
201
202
    def test_existing_serializer_can_be_replaced(self):
203
        """
204
        overwrite an existing serializer with a custom one
205
        """
206
        _type = 'json'
207
        context = get_context()['object']
208
        serializer = get_serializers()['dummy']()
209
        facade = SerializationFacade()
210
        facade.register(_type, serializer)
211
        expected = self.__get_serialized_context(_type, serializer, context)
212
213
        assert expected == facade.serialize(context)
214
215
    def test_serializer_list_can_be_set_at_facade_initialization(self):
216
        """
217
        initialize the serialization facade with a bunch of serializers
218
        """
219
        _type = 'dummy'
220
        context = get_context()['object']
221
        serializer = get_serializers()[_type]()
222
        dict = {
223
            _type: serializer
224
        }
225
        facade = SerializationFacade(dict)
226
        expected = self.__get_serialized_context(_type, serializer, context)
227
228
        assert expected == facade.use(_type).serialize(context)
229
230
    def test_missing_type_in_serialized_string(self):
231
        """
232
        ensure that a string passed to the deserialize method contains the
233
        serializer type
234
        """
235
        expected = 'Serialized string should be of the form'
236
        with pytest.raises(BadSerializedStringFormat) as excinfo:
237
            SerializationFacade().deserialize('{"my_key": "my_val"}')
238
239
        assert expected in excinfo.value.message
240
241
    def test_serializer_valid_types(self):
242
        """
243
        ensure a serializer type contains only some allowed characters
244
        """
245
        context = get_context()['object']
246
        serializer = get_serializers()['dummy']()
247
248
        valid_types = {
249
            'v_a-l.idTyPe0123456789': serializer,
250
            '_type': serializer,
251
            'Type': serializer
252
        }
253
        facade = SerializationFacade(valid_types)
254
255
        not_valid_types = [
256
            '-type',
257
            '.type',
258
            '_.type',
259
            '9type',
260
            '_9type',
261
            'typ|e',
262
            'typ:e',
263
            'typ!e',
264
        ]
265
266
        for _type in valid_types:
267
            expected = self.__get_serialized_context(
268
                _type, serializer, context)
269
            assert expected == facade.use(_type).serialize(context)
270
271
        for _type in not_valid_types:
272
            with pytest.raises(InvalidSerializerType):
273
                facade.register(_type, serializer)
274
275
    def test_deserialize_the_last_serialized_string_found(self):
276
        """
277
        deserialize method should treat only the last serialized string part
278
        """
279
        _type = 'dummy'
280
        expected = get_context()['object2']
281
        serializer = get_serializers()[_type]()
282
        part1 = self.__get_serialized_context(_type, serializer)
283
        part2 = self.__get_serialized_context(_type, serializer, expected)
284
        serialized = 'dummy text ' + part1 + 'another dummy text ' + part2
285
        facade = SerializationFacade({
286
            _type: serializer
287
        })
288
289
        assert expected == facade.deserialize(serialized)
290
291
    def test_module_get_context(self, mocker):
292
        """
293
        serialization module context getter that should be used in hooks
294
        :param mocker: mock library handler
295
        """
296
        mocker.patch('sys.stdin.readlines',
297
                     return_value=[get_context()['json']])
298
        assert get_context()['object'] == get_context_in_hooks()
299
        mocker.stopall()
300
301
    def test_module_put_context(self, mocker):
302
        """
303
        serialization module context setter that should be used in hooks
304
        :param mocker: mock library handler
305
        """
306
        stdout = mocker.patch('sys.stdout')
307
        args = {
308
            'getvalue.return_value': get_context()['json']
309
        }
310
        stdout.configure_mock(**args)
311
        put_context_in_hooks(get_context()['object'])
312
        assert get_context()['json'] == sys.stdout.getvalue()
313
        mocker.stopall()
314