tests.test_examples.TestStandard.test_function()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 47
Code Lines 29

Duplication

Lines 47
Ratio 100 %

Importance

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