Completed
Push — develop ( 0ce159...3bb0e5 )
by Jace
02:41
created

it_can_be_applied_multiple_times()   A

Complexity

Conditions 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
rs 9.4285
cc 1
1
# pylint: disable=unused-variable,expression-not-assigned
2
# pylint: disable=missing-docstring,no-self-use,no-member,misplaced-comparison-constant
0 ignored issues
show
introduced by
Bad option value 'misplaced-comparison-constant'
Loading history...
3
4
import logging
5
from unittest.mock import patch, Mock
6
7
import pytest
8
from expecter import expect
0 ignored issues
show
Configuration introduced by
The import expecter could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
9
10
from yorm import decorators
11
from yorm.bases import Converter
12
13
log = logging.getLogger(__name__)
14
15
16
class MockConverter(Converter):
17
    """Sample converter class."""
18
19
    @classmethod
20
    def create_default(cls):
21
        return None
22
23
    @classmethod
24
    def to_value(cls, *_):
25
        return None
26
27
    @classmethod
28
    def to_data(cls, _):
29
        return None
30
31
32
@patch('yorm.diskutils.write', Mock())
33
@patch('yorm.diskutils.stamp', Mock())
34
@patch('yorm.diskutils.read', Mock(return_value=""))
35
class TestSyncObject:
36
    """Unit tests for the `sync_object` function."""
37
38
    class Sample:
39
        """Sample class."""
40
41
    def test_no_attrs(self):
42
        """Verify mapping can be enabled with no attributes."""
43
        sample = decorators.sync(self.Sample(), "sample.yml")
44
        assert "sample.yml" == sample.__mapper__.path
45
        assert {} == sample.__mapper__.attrs
46
47
    def test_with_attrs(self):
48
        """Verify mapping can be enabled with with attributes."""
49
        attrs = {'var1': MockConverter}
50
        sample = decorators.sync(self.Sample(), "sample.yml", attrs)
51
        assert "sample.yml" == sample.__mapper__.path
52
        assert {'var1': MockConverter} == sample.__mapper__.attrs
53
54
    def test_multiple(self):
55
        """Verify mapping cannot be enabled twice."""
56
        sample = decorators.sync(self.Sample(), "sample.yml")
57
        with pytest.raises(TypeError):
58
            decorators.sync(sample, "sample.yml")
59
60
    @patch('yorm.diskutils.exists', Mock(return_value=True))
61
    def test_init_existing(self):
62
        """Verify an existing file is read."""
63
        with patch('yorm.diskutils.read', Mock(return_value="abc: 123")):
64
            sample = decorators.sync(self.Sample(), "s.yml", auto_track=True)
65
        assert 123 == sample.abc
66
67
68
@patch('yorm.diskutils.write', Mock())
69
@patch('yorm.diskutils.stamp', Mock())
70
@patch('yorm.diskutils.read', Mock(return_value=""))
71
class TestSyncInstances:
72
    """Unit tests for the `sync_instances` decorator."""
73
74
    @decorators.sync("sample.yml", auto_track=True)
75
    class SampleDecorated:
76
        """Sample decorated class using a single path."""
77
78
        def __repr__(self):
79
            return "<decorated {}>".format(id(self))
80
81
    @decorators.sync("{UUID}.yml")
82
    class SampleDecoratedIdentifiers:
83
        """Sample decorated class using UUIDs for paths."""
84
85
        def __repr__(self):
86
            return "<decorated w/ UUID {}>".format(id(self))
87
88
    @decorators.sync("path/to/{n}.yml", {'n': 'name'})
89
    class SampleDecoratedAttributes:
90
        """Sample decorated class using an attribute value for paths."""
91
92
        def __init__(self, name):
93
            self.name = name
94
95
        def __repr__(self):
96
            return "<decorated w/ specified attributes {}>".format(id(self))
97
98
    @decorators.sync("path/to/{self.name}.yml")
99
    class SampleDecoratedAttributesAutomatic:
100
        """Sample decorated class using an attribute value for paths."""
101
102
        def __init__(self, name):
103
            self.name = name
104
105
        def __repr__(self):
106
            return "<decorated w/ automatic attributes {}>".format(id(self))
107
108
    @decorators.sync("{self.a}/{self.b}/{c}.yml", {'self.b': 'b', 'c': 'c'})
109
    class SampleDecoratedAttributesCombination:
110
        """Sample decorated class using an attribute value for paths."""
111
112
        def __init__(self, a, b, c):
113
            self.a = a
114
            self.b = b
115
            self.c = c
116
117
        def __repr__(self):
118
            return "<decorated w/ attributes {}>".format(id(self))
119
120
    @decorators.sync("sample.yml", attrs={'var1': MockConverter})
121
    class SampleDecoratedWithAttributes:
122
        """Sample decorated class using a single path."""
123
124
    def test_no_attrs(self):
125
        """Verify mapping can be enabled with no attributes."""
126
        sample = self.SampleDecorated()
127
        assert "sample.yml" == sample.__mapper__.path
128
        assert {} == sample.__mapper__.attrs
129
130
    def test_with_attrs(self):
131
        """Verify mapping can be enabled with with attributes."""
132
        sample = self.SampleDecoratedWithAttributes()
133
        assert "sample.yml" == sample.__mapper__.path
134
        assert ['var1'] == list(sample.__mapper__.attrs.keys())
135
136
    @patch('yorm.diskutils.exists', Mock(return_value=True))
137
    def test_init_existing(self):
138
        """Verify an existing file is read."""
139
        with patch('yorm.diskutils.read', Mock(return_value="abc: 123")):
140
            sample = self.SampleDecorated()
141
        assert 123 == sample.abc
142
143
    @patch('uuid.uuid4', Mock(return_value=Mock(hex='abc123')))
144
    def test_filename_uuid(self):
145
        """Verify UUIDs can be used for filename."""
146
        sample = self.SampleDecoratedIdentifiers()
147
        assert "abc123.yml" == sample.__mapper__.path
148
        assert {} == sample.__mapper__.attrs
149
150
    def test_filename_attributes(self):
151
        """Verify attributes can be used to determine filename."""
152
        sample1 = self.SampleDecoratedAttributes('one')
153
        sample2 = self.SampleDecoratedAttributes('two')
154
        assert "path/to/one.yml" == sample1.__mapper__.path
155
        assert "path/to/two.yml" == sample2.__mapper__.path
156
157
    def test_filename_attributes_automatic(self):
158
        """Verify attributes can be used to determine filename (auto save)."""
159
        sample1 = self.SampleDecoratedAttributesAutomatic('one')
160
        sample2 = self.SampleDecoratedAttributesAutomatic('two')
161
        assert "path/to/one.yml" == sample1.__mapper__.path
162
        assert "path/to/two.yml" == sample2.__mapper__.path
163
164
    def test_filename_attributes_combination(self):
165
        """Verify attributes can be used to determine filename (combo)."""
166
        log.info("Creating first object...")
167
        sample1 = self.SampleDecoratedAttributesCombination('A', 'B', 'C')
168
        log.info("Creating second object...")
169
        sample2 = self.SampleDecoratedAttributesCombination(1, 2, 3)
170
        assert "A/B/C.yml" == sample1.__mapper__.path
171
        assert "1/2/3.yml" == sample2.__mapper__.path
172
173
174
def describe_attr():
175
176
    class MockConverter1(MockConverter):
177
        """Sample converter class."""
178
179
    class MockConverter2(MockConverter):
180
        """Sample converter class."""
181
182
    @pytest.fixture
183
    def path(tmpdir):
184
        tmpdir.chdir()
185
        return "mock/path"
186
187
    def it_accepts_one_argument(path):
188
189
        @decorators.attr(var1=MockConverter1)
190
        @decorators.sync(path)
191
        class SampleDecoratedSingle:
192
            """Class using single `attr` decorator."""
193
194
        sample = SampleDecoratedSingle()
195
        expect(sample.__mapper__.attrs) == {'var1': MockConverter1}
196
197
    def it_rejects_zero_arguments():
198
        with expect.raises(ValueError):
199
            decorators.attr()
200
201
    def it_rejects_more_than_one_argument():
202
        with expect.raises(ValueError):
203
            decorators.attr(foo=1, bar=2)
204
205
    def it_can_be_applied_multiple_times(path):
206
207
        @decorators.attr(var1=MockConverter1)
208
        @decorators.attr(var2=MockConverter2)
209
        @decorators.sync(path)
210
        class SampleDecoratedMultiple:
211
            """Class using multiple `attr` decorators."""
212
213
        sample = SampleDecoratedMultiple()
214
        expect(sample.__mapper__.attrs) == {'var1': MockConverter1,
215
                                            'var2': MockConverter2}
216
217
    def it_can_be_applied_before_sync(path):
218
219
        @decorators.attr(var2=MockConverter2)
220
        @decorators.sync(path, attrs={'var1': MockConverter1})
221
        class SampleDecoratedCombo:
222
            """Class using `attr` decorator and providing a mapping."""
223
224
        sample = SampleDecoratedCombo()
225
        expect(sample.__mapper__.attrs) == {'var1': MockConverter1,
226
                                            'var2': MockConverter2}
227
228
    def it_can_be_applied_after_sync(path):
229
230
        @decorators.sync(path, attrs={'var1': MockConverter1})
231
        @decorators.attr(var2=MockConverter2)
232
        class SampleDecoratedBackwards:
233
            """Class using `attr` decorator after `sync` decorator."""
234
235
        sample = SampleDecoratedBackwards()
236
        expect(sample.__mapper__.attrs) == {'var1': MockConverter1,
237
                                            'var2': MockConverter2}
238