Completed
Push — develop ( b4a21c...b1df34 )
by Jace
02:37
created

TestStandard.test_function_to_json()   F

Complexity

Conditions 11

Size

Total Lines 51

Duplication

Lines 51
Ratio 100 %
Metric Value
dl 51
loc 51
rs 3.6
cc 11

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like TestStandard.test_function_to_json() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""Integration tests for the package."""
2
# pylint: disable=missing-docstring,no-self-use,no-member,misplaced-comparison-constant,attribute-defined-outside-init
0 ignored issues
show
introduced by
Bad option value 'misplaced-comparison-constant'
Loading history...
3
4
import logging
5
6
import yorm
7
from yorm.types import Object, String, Integer, Float, Boolean
8
from yorm.types import Markdown, Dictionary, List
9
10
from . import strip, refresh_file_modification_times
11
12
log = logging.getLogger(__name__)
13
14
15
# CLASSES ######################################################################
16
17
18
class EmptyDictionary(Dictionary):
19
    """Sample dictionary container."""
20
21
22
@yorm.attr(all=Integer)
23
class IntegerList(List):
24
    """Sample list container."""
25
26
27
class SampleStandard:
28
    """Sample class using standard attribute types."""
29
30
    def __init__(self):
31
        # https://docs.python.org/3.4/library/json.html#json.JSONDecoder
32
        self.object = {}
33
        self.array = []
34
        self.string = ""
35
        self.number_int = 0
36
        self.number_real = 0.0
37
        self.truthy = True
38
        self.falsey = False
39
        self.null = None
40
41
    def __repr__(self):
42
        return "<standard {}>".format(id(self))
43
44
45 View Code Duplication
@yorm.attr(array=IntegerList)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
46
@yorm.attr(falsey=Boolean)
47
@yorm.attr(number_int=Integer)
48
@yorm.attr(number_real=Float)
49
@yorm.attr(object=EmptyDictionary)
50
@yorm.attr(string=String)
51
@yorm.attr(truthy=Boolean)
52
@yorm.sync("path/to/{self.category}/{self.name}.yml")
53
class SampleStandardDecorated:
54
    """Sample class using standard attribute types."""
55
56
    def __init__(self, name, category='default'):
57
        self.name = name
58
        self.category = category
59
        # https://docs.python.org/3.4/library/json.html#json.JSONDecoder
60
        self.object = {}
61
        self.array = []
62
        self.string = ""
63
        self.number_int = 0
64
        self.number_real = 0.0
65
        self.truthy = True
66
        self.falsey = False
67
        self.null = None
68
69
    def __repr__(self):
70
        return "<decorated {}>".format(id(self))
71
72
73
@yorm.attr(label=String)
74
@yorm.attr(status=Boolean)
75
class StatusDictionary(Dictionary):
76
    """Sample dictionary container."""
77
78
79
@yorm.attr(all=StatusDictionary)
80
class StatusDictionaryList(List):
81
    """Sample list container."""
82
83
84
class Level(String):
85
    """Sample custom attribute."""
86
87
    @classmethod
88
    def to_data(cls, obj):
89
        value = cls.to_value(obj)
90
        count = value.split('.')
91
        if count == 0:
92
            return int(value)
93
        elif count == 1:
94
            return float(value)
95
        else:
96
            return value
97
98
99
@yorm.sync("path/to/directory/{UUID}.yml", attrs={'level': Level})
100
class SampleCustomDecorated:
101
    """Sample class using custom attribute types."""
102
103
    def __init__(self, name):
104
        self.name = name
105
        self.level = '1.0'
106
107
    def __repr__(self):
108
        return "<custom {}>".format(id(self))
109
110
111
@yorm.attr(string=String)
112
@yorm.sync("sample.yml", auto=False)
113
class SampleDecoratedAutoOff:
114
    """Sample class with automatic storage turned off."""
115
116
    def __init__(self):
117
        self.string = ""
118
119
    def __repr__(self):
120
        return "<auto off {}>".format(id(self))
121
122
123
@yorm.sync("sample.yml", strict=False)
124
class SampleEmptyDecorated:
125
    """Sample class using standard attribute types."""
126
127
    def __repr__(self):
128
        return "<empty {}>".format(id(self))
129
130
131
class SampleExtended:
132
    """Sample class using extended attribute types."""
133
134
    def __init__(self):
135
        self.text = ""
136
137
    def __repr__(self):
138
        return "<extended {}>".format(id(self))
139
140
141
class SampleNested:
142
    """Sample class using nested attribute types."""
143
144
    def __init__(self):
145
        self.count = 0
146
        self.results = []
147
148
    def __repr__(self):
149
        return "<nested {}>".format(id(self))
150
151
# TESTS ########################################################################
152
153
154
class TestStandard:
155
    """Integration tests for standard attribute types."""
156
157
    @yorm.attr(status=yorm.types.Boolean)
158
    class StatusDictionary(Dictionary):
159
        pass
160
161
    def test_decorator(self, tmpdir):
162
        """Verify standard attribute types dump/load correctly (decorator)."""
163
        tmpdir.chdir()
164
        sample = SampleStandardDecorated('sample')
165
        assert "path/to/default/sample.yml" == sample.__mapper__.path
166
167
        log.info("Checking object default values...")
168
        assert {} == sample.object
169
        assert [] == sample.array
170
        assert "" == sample.string
171
        assert 0 == sample.number_int
172
        assert 0.0 == sample.number_real
173
        assert True is sample.truthy
174
        assert False is sample.falsey
175
        assert None is sample.null
176
177
        log.info("Changing object values...")
178
        sample.object = {'key2': 'value'}
179
        sample.array = [0, 1, 2]
180
        sample.string = "Hello, world!"
181
        sample.number_int = 42
182
        sample.number_real = 4.2
183
        sample.truthy = False
184
        sample.falsey = True
185
186
        log.info("Checking file contents...")
187
        assert strip("""
188
        array:
189
        - 0
190
        - 1
191
        - 2
192
        falsey: true
193
        number_int: 42
194
        number_real: 4.2
195
        object: {}
196
        string: Hello, world!
197
        truthy: false
198
        """) == sample.__mapper__.text
199
200
        log.info("Changing file contents...")
201
        refresh_file_modification_times()
202
        sample.__mapper__.text = strip("""
203
        array: [4, 5, 6]
204
        falsey: null
205
        number_int: 42
206
        number_real: '4.2'
207
        object: {'status': false}
208
        string: "abc"
209
        truthy: null
210
        """)
211
212
        log.info("Checking object values...")
213
        assert {'status': False} == sample.object
214
        assert [4, 5, 6] == sample.array
215
        assert "abc" == sample.string
216
        assert 42 == sample.number_int
217
        assert 4.2 == sample.number_real
218
        assert False is sample.truthy
219
        assert False is sample.falsey
220
221 View Code Duplication
    def test_function(self, tmpdir):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
222
        """Verify standard attribute types dump/load correctly (function)."""
223
        tmpdir.chdir()
224
        _sample = SampleStandard()
225
        attrs = {'object': self.StatusDictionary,
226
                 'array': IntegerList,
227
                 'string': String,
228
                 'number_int': Integer,
229
                 'number_real': Float,
230
                 'truthy': Boolean,
231
                 'falsey': Boolean}
232
        sample = yorm.sync(_sample, "path/to/directory/sample.yml", attrs)
233
        assert "path/to/directory/sample.yml" == sample.__mapper__.path
234
235
        # check defaults
236
        assert {'status': False} == sample.object
237
        assert [] == sample.array
238
        assert "" == sample.string
239
        assert 0 == sample.number_int
240
        assert 0.0 == sample.number_real
241
        assert True is sample.truthy
242
        assert False is sample.falsey
243
        assert None is sample.null
244
245
        # change object values
246
        sample.object = {'key': 'value'}
247
        sample.array = [1, 2, 3]
248
        sample.string = "Hello, world!"
249
        sample.number_int = 42
250
        sample.number_real = 4.2
251
        sample.truthy = None
252
        sample.falsey = 1
253
254
        # check file values
255
        assert strip("""
256
        array:
257
        - 1
258
        - 2
259
        - 3
260
        falsey: true
261
        number_int: 42
262
        number_real: 4.2
263
        object:
264
          status: false
265
        string: Hello, world!
266
        truthy: false
267
        """) == sample.__mapper__.text
268
269 View Code Duplication
    def test_function_to_json(self, tmpdir):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
270
        """Verify standard attribute types dump/load correctly (function)."""
271
        tmpdir.chdir()
272
        _sample = SampleStandard()
273
        attrs = {'object': self.StatusDictionary,
274
                 'array': IntegerList,
275
                 'string': String,
276
                 'number_int': Integer,
277
                 'number_real': Float,
278
                 'truthy': Boolean,
279
                 'falsey': Boolean}
280
        sample = yorm.sync(_sample, "path/to/directory/sample.json", attrs)
281
        assert "path/to/directory/sample.json" == sample.__mapper__.path
282
283
        # check defaults
284
        assert {'status': False} == sample.object
285
        assert [] == sample.array
286
        assert "" == sample.string
287
        assert 0 == sample.number_int
288
        assert 0.0 == sample.number_real
289
        assert True is sample.truthy
290
        assert False is sample.falsey
291
        assert None is sample.null
292
293
        # change object values
294
        sample.object = {'key': 'value'}
295
        sample.array = [1, 2, 3]
296
        sample.string = "Hello, world!"
297
        sample.number_int = 42
298
        sample.number_real = 4.2
299
        sample.truthy = None
300
        sample.falsey = 1
301
302
        # check file values
303
        assert strip("""
304
        {
305
            "array": [
306
                1,
307
                2,
308
                3
309
            ],
310
            "falsey": true,
311
            "number_int": 42,
312
            "number_real": 4.2,
313
            "object": {
314
                "status": false
315
            },
316
            "string": "Hello, world!",
317
            "truthy": false
318
        }
319
        """, tabs=2, end='') == sample.__mapper__.text
320
321
    def test_auto_off(self, tmpdir):
322
        """Verify file updates are disabled with auto off."""
323
        tmpdir.chdir()
324
        sample = SampleDecoratedAutoOff()
325
326
        # ensure the file does not exist
327
        assert False is sample.__mapper__.exists
328
        assert "" == sample.__mapper__.text
329
330
        # store value
331
        sample.string = "hello"
332
333
        # ensure the file still does not exist
334
        assert False is sample.__mapper__.exists
335
        assert "" == sample.__mapper__.text
336
337
        # enable auto and store value
338
        sample.__mapper__.auto = True
339
        sample.string = "world"
340
341
        # check for changed file values
342
        assert strip("""
343
        string: world
344
        """) == sample.__mapper__.text
345
346
347
class TestContainers:
348
    """Integration tests for attribute containers."""
349
350
    def test_nesting(self, tmpdir):
351
        """Verify standard attribute types can be nested."""
352
        tmpdir.chdir()
353
        _sample = SampleNested()
354
        attrs = {'count': Integer,
355
                 'results': StatusDictionaryList}
356
        sample = yorm.sync(_sample, "sample.yml", attrs, strict=False)
357
358
        # check defaults
359
        assert 0 == sample.count
360
        assert [] == sample.results
361
362
        # change object values
363
        sample.count = 5
364
        sample.results = [{'status': False, 'label': "abc"},
365
                          {'status': None, 'label': None},
366
                          {'label': "def"},
367
                          {'status': True},
368
                          {}]
369
370
        # check file values
371
        assert strip("""
372
        count: 5
373
        results:
374
        - label: abc
375
          status: false
376
        - label: ''
377
          status: false
378
        - label: def
379
          status: false
380
        - label: ''
381
          status: true
382
        - label: ''
383
          status: false
384
        """) == sample.__mapper__.text
385
386
        # change file values
387
        refresh_file_modification_times()
388
        sample.__mapper__.text = strip("""
389
        count: 3
390
        other: 4.2
391
        results:
392
        - label: abc
393
        - label: null
394
          status: false
395
        - status: true
396
        """)
397
398
        # check object values
399
        assert 3 == sample.count
400
        assert 4.2 == sample.other
401
        assert [{'label': 'abc', 'status': False},
402
                {'label': '', 'status': False},
403
                {'label': '', 'status': True}] == sample.results
404
405
    def test_objects(self, tmpdir):
406
        """Verify containers are treated as objects when added."""
407
        tmpdir.chdir()
408
        sample = SampleEmptyDecorated()
409
410
        # change file values
411
        refresh_file_modification_times()
412
        sample.__mapper__.text = strip("""
413
        object: {'key': 'value'}
414
        array: [1, '2', '3.0']
415
        """)
416
417
        # (a mapped attribute must be read first to trigger retrieving)
418
        sample.__mapper__.fetch()
419
420
        # check object values
421
        assert {'key': 'value'} == sample.object
422
        assert [1, '2', '3.0'] == sample.array
423
424
        # check object types
425
        assert Object == sample.__mapper__.attrs['object']
426
        assert Object == sample.__mapper__.attrs['array']
427
428
429
class TestExtended:
430
    """Integration tests for extended attribute types."""
431
432
    def test_function(self, tmpdir):
433
        """Verify extended attribute types dump/load correctly."""
434
        tmpdir.chdir()
435
        _sample = SampleExtended()
436
        attrs = {'text': Markdown}
437
        sample = yorm.sync(_sample, "path/to/directory/sample.yml", attrs)
438
439
        # check defaults
440
        assert "" == sample.text
441
442
        # change object values
443
        refresh_file_modification_times()
444
        sample.text = strip("""
445
        This is the first sentence. This is the second sentence.
446
        This is the third sentence.
447
        """)
448
449
        # check file values
450
        assert strip("""
451
        text: |
452
          This is the first sentence.
453
          This is the second sentence.
454
          This is the third sentence.
455
        """) == sample.__mapper__.text
456
457
        # change file values
458
        refresh_file_modification_times()
459
        sample.__mapper__.text = strip("""
460
        text: |
461
          This is a
462
          sentence.
463
        """)
464
465
        # check object values
466
        assert "This is a sentence." == sample.text
467
468
469
class TestCustom:
470
    """Integration tests for custom attribute types."""
471
472
    def test_decorator(self, tmpdir):
473
        """Verify custom attribute types dump/load correctly."""
474
        tmpdir.chdir()
475
        sample = SampleCustomDecorated('sample')
476
477
        # check defaults
478
        assert '1.0' == sample.level
479
480
        # change values
481
        sample.level = '1.2.3'
482
483
        # check file values
484
        assert strip("""
485
        level: 1.2.3
486
        """) == sample.__mapper__.text
487
488
        # change file values
489
        refresh_file_modification_times()
490
        sample.__mapper__.text = strip("""
491
        level: 1
492
        """)
493
494
        # check object values
495
        assert '1' == sample.level
496