Completed
Push — develop ( b1df34...10b422 )
by Jace
8s
created

TestStandard.test_auto_off()   A

Complexity

Conditions 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 14
rs 9.4285
cc 3
1
"""Integration tests for the package."""
0 ignored issues
show
Duplication introduced by
Similar lines in 2 files
==tests.test_examples:51
==tests.test_files:33
@yorm.sync("path/to/self.category/self.name.yml")
class SampleStandardDecorated:
"""Sample class using standard attribute types."""

def __init__(self, name, category='default'):
self.name = name
self.category = category
# https://docs.python.org/3.4/library/json.html#json.JSONDecoder
self.object = {}
self.array = []
self.string = ""
self.number_int = 0
self.number_real = 0.0
Loading history...
Duplication introduced by
Similar lines in 2 files
==tests.test_examples:179
==tests.test_ordering:29
sample.string = "Hello, world!"
sample.number_int = 42
sample.number_real = 4.2
sample.truthy = False
sample.falsey = True
Loading history...
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_save=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 save off {}>".format(id(self))
121
122
123
@yorm.sync("sample.yml", auto_attr=True)
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 save off."""
323
        tmpdir.chdir()
324
        sample = SampleDecoratedAutoOff()
325
326
        sample.string = "hello"
327
        assert "" == sample.__mapper__.text
328
329
        sample.__mapper__.auto_store = True
330
        sample.string = "world"
331
332
        assert strip("""
333
        string: world
334
        """) == sample.__mapper__.text
335
336
337
class TestContainers:
338
    """Integration tests for attribute containers."""
339
340
    def test_nesting(self, tmpdir):
341
        """Verify standard attribute types can be nested."""
342
        tmpdir.chdir()
343
        _sample = SampleNested()
344
        attrs = {'count': Integer,
345
                 'results': StatusDictionaryList}
346
        sample = yorm.sync(_sample, "sample.yml", attrs, auto_attr=True)
347
348
        # check defaults
349
        assert 0 == sample.count
350
        assert [] == sample.results
351
352
        # change object values
353
        sample.count = 5
354
        sample.results = [{'status': False, 'label': "abc"},
355
                          {'status': None, 'label': None},
356
                          {'label': "def"},
357
                          {'status': True},
358
                          {}]
359
360
        # check file values
361
        assert strip("""
362
        count: 5
363
        results:
364
        - label: abc
365
          status: false
366
        - label: ''
367
          status: false
368
        - label: def
369
          status: false
370
        - label: ''
371
          status: true
372
        - label: ''
373
          status: false
374
        """) == sample.__mapper__.text
375
376
        # change file values
377
        refresh_file_modification_times()
378
        sample.__mapper__.text = strip("""
379
        count: 3
380
        other: 4.2
381
        results:
382
        - label: abc
383
        - label: null
384
          status: false
385
        - status: true
386
        """)
387
388
        # check object values
389
        assert 3 == sample.count
390
        assert 4.2 == sample.other
391
        assert [{'label': 'abc', 'status': False},
392
                {'label': '', 'status': False},
393
                {'label': '', 'status': True}] == sample.results
394
395
    def test_objects(self, tmpdir):
396
        """Verify containers are treated as objects when added."""
397
        tmpdir.chdir()
398
        sample = SampleEmptyDecorated()
399
400
        # change file values
401
        refresh_file_modification_times()
402
        sample.__mapper__.text = strip("""
403
        object: {'key': 'value'}
404
        array: [1, '2', '3.0']
405
        """)
406
407
        # (a mapped attribute must be read first to trigger retrieving)
408
        sample.__mapper__.fetch()
409
410
        # check object values
411
        assert {'key': 'value'} == sample.object
412
        assert [1, '2', '3.0'] == sample.array
413
414
        # check object types
415
        assert Object == sample.__mapper__.attrs['object']
416
        assert Object == sample.__mapper__.attrs['array']
417
418
419
class TestExtended:
420
    """Integration tests for extended attribute types."""
421
422
    def test_function(self, tmpdir):
423
        """Verify extended attribute types dump/load correctly."""
424
        tmpdir.chdir()
425
        _sample = SampleExtended()
426
        attrs = {'text': Markdown}
427
        sample = yorm.sync(_sample, "path/to/directory/sample.yml", attrs)
428
429
        # check defaults
430
        assert "" == sample.text
431
432
        # change object values
433
        refresh_file_modification_times()
434
        sample.text = strip("""
435
        This is the first sentence. This is the second sentence.
436
        This is the third sentence.
437
        """)
438
439
        # check file values
440
        assert strip("""
441
        text: |
442
          This is the first sentence.
443
          This is the second sentence.
444
          This is the third sentence.
445
        """) == sample.__mapper__.text
446
447
        # change file values
448
        refresh_file_modification_times()
449
        sample.__mapper__.text = strip("""
450
        text: |
451
          This is a
452
          sentence.
453
        """)
454
455
        # check object values
456
        assert "This is a sentence." == sample.text
457
458
459
class TestCustom:
460
    """Integration tests for custom attribute types."""
461
462
    def test_decorator(self, tmpdir):
463
        """Verify custom attribute types dump/load correctly."""
464
        tmpdir.chdir()
465
        sample = SampleCustomDecorated('sample')
466
467
        # check defaults
468
        assert '1.0' == sample.level
469
470
        # change values
471
        sample.level = '1.2.3'
472
473
        # check file values
474
        assert strip("""
475
        level: 1.2.3
476
        """) == sample.__mapper__.text
477
478
        # change file values
479
        refresh_file_modification_times()
480
        sample.__mapper__.text = strip("""
481
        level: 1
482
        """)
483
484
        # check object values
485
        assert '1' == sample.level
486