tests.test_nested_attributes   A
last analyzed

Complexity

Total Complexity 25

Size/Duplication

Total Lines 375
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 191
dl 0
loc 375
rs 10
c 0
b 0
f 0
wmc 25

21 Methods

Rating   Name   Duplication   Size   Complexity  
A TestNestedTwice.test_nested_dict_item_value_change_triggers_save() 0 21 1
A NestedDictionary2.__init__() 0 3 1
A Top.__repr__() 0 2 1
A TestNestedOnce.test_delete_index_triggers_save() 0 33 1
A TestNestedOnce.test_get_by_index_triggers_load() 0 7 1
A TestNestedOnce.test_set_dict_as_attribute_triggers_save() 0 11 1
A TestNestedTwice.test_dict_in_list_value_change_triggers_save() 0 18 1
A NestedDictionary3.__init__() 0 4 1
A Top.__init__() 0 3 1
A TestNestedTwice.test_list_in_dict_append_triggers_save() 0 24 2
A NestedDictionary3.__repr__() 0 3 1
A NestedList.__repr__() 0 2 1
A NestedList2.__repr__() 0 2 1
A NestedDictionary.__init__() 0 4 1
A TestNestedOnce.test_set_by_index_triggers_save() 0 28 1
A TestNestedTwice.test_nested_list_item_value_change_triggers_save() 0 28 1
A StatusDictionary.__init__() 0 5 2
A TestNestedOnce.test_append_triggers_save() 0 17 1
A NestedDictionary.__repr__() 0 2 1
A NestedList3.__repr__() 0 2 1
A NestedDictionary2.__repr__() 0 3 1

1 Function

Rating   Name   Duplication   Size   Complexity  
B describe_aliases() 0 70 2
1
"""Integration tests for nested attributes."""
2
3
# pylint: disable=missing-docstring,no-self-use,attribute-defined-outside-init,no-member
4
# pylint: disable=unused-variable,misplaced-comparison-constant
5
6
from unittest.mock import patch
7
8
import pytest
0 ignored issues
show
introduced by
Unable to import 'pytest'
Loading history...
9
from expecter import expect
0 ignored issues
show
introduced by
Unable to import 'expecter'
Loading history...
10
11
import yorm
12
13
from . import strip, log
14
15
16
@yorm.attr(status=yorm.types.Boolean)
17
@yorm.attr(checked=yorm.types.Integer)
18
class StatusDictionary(yorm.types.Dictionary):
19
20
    def __init__(self, status, checked):
21
        self.status = status
22
        self.checked = checked
23
        if self.checked == 42:
24
            raise RuntimeError
25
26
27
@yorm.attr(all=yorm.types.Float)
28
class NestedList3(yorm.types.List):
29
30
    def __repr__(self):
31
        return "<nested-list-3 {}>".format((id(self)))
32
33
34
@yorm.attr(nested_list_3=NestedList3)
35
@yorm.attr(number=yorm.types.Float)
36
class NestedDictionary3(yorm.types.AttributeDictionary):
37
38
    def __init__(self):
39
        super().__init__()
40
        self.number = 0
41
        self.nested_list_3 = []
42
43
    def __repr__(self):
44
        print(self.number)  # trigger a potential recursion issue
45
        return "<nested-dictionary-3 {}>".format((id(self)))
46
47
48
@yorm.attr(all=yorm.types.Float)
49
class NestedList2(yorm.types.List):
50
51
    def __repr__(self):
52
        return "<nested-list-2 {}>".format((id(self)))
53
54
55
@yorm.attr(nested_dict_3=NestedDictionary3)
56
@yorm.attr(number=yorm.types.Float)
57
class NestedDictionary2(yorm.types.AttributeDictionary):
58
59
    def __init__(self):
60
        super().__init__()
61
        self.number = 0
62
63
    def __repr__(self):
64
        print(self.number)  # trigger a potential recursion issue
65
        return "<nested-dictionary-2 {}>".format((id(self)))
66
67
68
@yorm.attr(nested_list_2=NestedList2)
69
@yorm.attr(number=yorm.types.Float)
70
class NestedDictionary(yorm.types.AttributeDictionary):
71
72
    def __init__(self):
73
        super().__init__()
74
        self.number = 0
75
        self.nested_list_2 = []
76
77
    def __repr__(self):
78
        return "<nested-dictionary {}>".format((id(self)))
79
80
81
@yorm.attr(all=NestedDictionary2)
82
class NestedList(yorm.types.List):
83
84
    def __repr__(self):
85
        return "<nested-list {}>".format((id(self)))
86
87
88
@yorm.attr(nested_dict=NestedDictionary)
89
@yorm.attr(nested_list=NestedList)
90
@yorm.sync("sample.yml")
91
class Top:
92
93
    def __init__(self):
94
        self.nested_list = []
95
        self.nested_dict = {}
96
97
    def __repr__(self):
98
        return "<top {}>".format((id(self)))
99
100
101
@patch('yorm.settings.fake', True)
102
class TestNestedOnce:
103
104
    def test_append_triggers_save(self):
105
        top = Top()
106
        log("Appending dictionary to list...")
107
        top.nested_list.append({'number': 1})
108
        log("Checking text...")
109
        assert strip("""
110
        nested_dict:
111
          nested_list_2:
112
          -
113
          number: 0.0
114
        nested_list:
115
        - nested_dict_3:
116
            nested_list_3:
117
            -
118
            number: 0.0
119
          number: 1.0
120
        """) == top.__mapper__.text
121
122
    def test_set_by_index_triggers_save(self):
123
        top = Top()
124
        top.nested_list = [{'number': 1.5}]
125
        assert strip("""
126
        nested_dict:
127
          nested_list_2:
128
          -
129
          number: 0.0
130
        nested_list:
131
        - nested_dict_3:
132
            nested_list_3:
133
            -
134
            number: 0.0
135
          number: 1.5
136
        """) == top.__mapper__.text
137
        top.nested_list[0] = {'number': 1.6}
138
        assert strip("""
139
        nested_dict:
140
          nested_list_2:
141
          -
142
          number: 0.0
143
        nested_list:
144
        - nested_dict_3:
145
            nested_list_3:
146
            -
147
            number: 0.0
148
          number: 1.6
149
        """) == top.__mapper__.text
150
151
    def test_get_by_index_triggers_load(self):
152
        top = Top()
153
        top.__mapper__.text = strip("""
154
        nested_list:
155
        - number: 1.7
156
        """)
157
        assert 1.7 == top.nested_list[0].number
158
159
    def test_delete_index_triggers_save(self):
160
        top = Top()
161
        top.nested_list = [{'number': 1.8}, {'number': 1.9}]
162
        assert strip("""
163
        nested_dict:
164
          nested_list_2:
165
          -
166
          number: 0.0
167
        nested_list:
168
        - nested_dict_3:
169
            nested_list_3:
170
            -
171
            number: 0.0
172
          number: 1.8
173
        - nested_dict_3:
174
            nested_list_3:
175
            -
176
            number: 0.0
177
          number: 1.9
178
        """) == top.__mapper__.text
179
        del top.nested_list[0]
180
        assert strip("""
181
        nested_dict:
182
          nested_list_2:
183
          -
184
          number: 0.0
185
        nested_list:
186
        - nested_dict_3:
187
            nested_list_3:
188
            -
189
            number: 0.0
190
          number: 1.9
191
        """) == top.__mapper__.text
192
193
    def test_set_dict_as_attribute_triggers_save(self):
194
        top = Top()
195
        top.nested_dict.number = 2
196
        assert strip("""
197
        nested_dict:
198
          nested_list_2:
199
          -
200
          number: 2.0
201
        nested_list:
202
        -
203
        """) == top.__mapper__.text
204
205
206
@patch('yorm.settings.fake', True)
207
class TestNestedTwice:
208
209
    def test_nested_list_item_value_change_triggers_save(self):
210
        top = Top()
211
        top.nested_list = [{'number': 3}]
212
        assert strip("""
213
        nested_dict:
214
          nested_list_2:
215
          -
216
          number: 0.0
217
        nested_list:
218
        - nested_dict_3:
219
            nested_list_3:
220
            -
221
            number: 0.0
222
          number: 3.0
223
        """) == top.__mapper__.text
224
        top.nested_list[0].number = 4
225
        assert strip("""
226
        nested_dict:
227
          nested_list_2:
228
          -
229
          number: 0.0
230
        nested_list:
231
        - nested_dict_3:
232
            nested_list_3:
233
            -
234
            number: 0.0
235
          number: 4.0
236
        """) == top.__mapper__.text
237
238
    def test_nested_dict_item_value_change_triggers_save(self):
239
        top = Top()
240
        top.nested_dict = {'nested_list_2': [5]}
241
        assert strip("""
242
        nested_dict:
243
          nested_list_2:
244
          - 5.0
245
          number: 0.0
246
        nested_list:
247
        -
248
        """) == top.__mapper__.text
249
        top.nested_dict.nested_list_2.append(6)
250
        assert strip("""
251
        nested_dict:
252
          nested_list_2:
253
          - 5.0
254
          - 6.0
255
          number: 0.0
256
        nested_list:
257
        -
258
        """) == top.__mapper__.text
259
260
    def test_dict_in_list_value_change_triggers_save(self):
261
        top = Top()
262
        log("Appending to list...")
263
        top.nested_list.append('foobar')
264
        log("Setting nested value...")
265
        top.nested_list[0].nested_dict_3.number = 8
266
        assert strip("""
267
        nested_dict:
268
          nested_list_2:
269
          -
270
          number: 0.0
271
        nested_list:
272
        - nested_dict_3:
273
            nested_list_3:
274
            -
275
            number: 8.0
276
          number: 0.0
277
        """) == top.__mapper__.text
278
279
    def test_list_in_dict_append_triggers_save(self):
280
        top = Top()
281
        top.nested_list.append('foobar')
282
        top.nested_list.append('foobar')
283
        for nested_dict_2 in top.nested_list:
284
            nested_dict_2.number = 9
285
            nested_dict_2.nested_dict_3.nested_list_3.append(10)
286
        assert strip("""
287
        nested_dict:
288
          nested_list_2:
289
          -
290
          number: 0.0
291
        nested_list:
292
        - nested_dict_3:
293
            nested_list_3:
294
            - 10.0
295
            number: 0.0
296
          number: 9.0
297
        - nested_dict_3:
298
            nested_list_3:
299
            - 10.0
300
            number: 0.0
301
          number: 9.0
302
        """) == top.__mapper__.text
303
304
305
def describe_aliases():
306
307
    @pytest.fixture
308
    def sample(tmpdir):
309
        cls = type('Sample', (), {})
310
        path = str(tmpdir.join("sample.yml"))
311
        attrs = dict(var4=NestedList3, var5=StatusDictionary)
312
        return yorm.sync(cls(), path, attrs)
313
314
    def _log_ref(name, var, ref):
315
        log("%s: %r", name, var)
316
        log("%s_ref: %r", name, ref)
317
        log("%s ID: %s", name, id(var))
318
        log("%s_ref ID: %s", name, id(ref))
319
        assert id(ref) == id(var)
320
        assert ref == var
321
322
    def test_alias_list(sample):
323
        var4_ref = sample.var4
324
        _log_ref('var4', sample.var4, var4_ref)
325
        assert [] == sample.var4
326
327
        log("Appending 42 to var4_ref...")
328
        var4_ref.append(42)
329
        _log_ref('var4', sample.var4, var4_ref)
330
        assert [42] == sample.var4
331
332
        log("Appending 2015 to var4_ref...")
333
        var4_ref.append(2015)
334
        assert [42, 2015] == sample.var4
335
336
    def test_alias_dict(sample):
337
        var5_ref = sample.var5
338
        _log_ref('var5', sample.var5, var5_ref)
339
        assert {'status': False, 'checked': 0} == sample.var5
340
341
        log("Setting status=True in var5_ref...")
342
        var5_ref['status'] = True
343
        _log_ref('var5', sample.var5, var5_ref)
344
        assert {'status': True, 'checked': 0} == sample.var5
345
346
        log("Setting status=False in var5_ref...")
347
        var5_ref['status'] = False
348
        _log_ref('var5', sample.var5, var5_ref)
349
        assert {'status': False, 'checked': 0} == sample.var5
350
351
    def test_alias_dict_in_list():
352
        top = Top()
353
        top.nested_list.append('foobar')
354
        ref1 = top.nested_list[0]
355
        ref2 = top.nested_list[0].nested_dict_3
356
        ref3 = top.nested_list[0].nested_dict_3.nested_list_3
357
        assert id(ref1) == id(top.nested_list[0])
358
        assert id(ref2) == id(top.nested_list[0].nested_dict_3)
359
        assert id(ref3) == id(top.nested_list[0].nested_dict_3.nested_list_3)
360
361
    def test_alias_list_in_dict():
362
        top = Top()
363
        log("Updating nested attribute...")
364
        top.nested_dict.number = 1
365
        log("Grabbing refs...")
366
        ref1 = top.nested_dict
367
        ref2 = top.nested_dict.nested_list_2
368
        assert id(ref1) == id(top.nested_dict)
369
        assert id(ref2) == id(top.nested_dict.nested_list_2)
370
371
    def test_custom_init_is_invoked(sample):
372
        sample.__mapper__.text = "var5:\n  checked: 42"
373
        with expect.raises(RuntimeError):
374
            print(sample.var5)
375