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

SampleEmptyDecorated   A

Complexity

Total Complexity 1

Size/Duplication

Total Lines 6
Duplicated Lines 0 %
Metric Value
wmc 1
dl 0
loc 6
rs 10

1 Method

Rating   Name   Duplication   Size   Complexity  
A __repr__() 0 2 1
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