1 | """Integration tests for file IO.""" |
||
2 | |||
3 | # pylint: disable=missing-docstring,no-self-use,no-member,misplaced-comparison-constant |
||
4 | |||
5 | import pytest |
||
0 ignored issues
–
show
introduced
by
![]() |
|||
6 | |||
7 | import yorm |
||
8 | from yorm.types import Integer, String, Float, Boolean, Dictionary, List |
||
9 | |||
10 | from . import refresh_file_modification_times, log |
||
11 | |||
12 | |||
13 | # CLASSES ##################################################################### |
||
14 | |||
15 | |||
16 | class EmptyDictionary(Dictionary): |
||
17 | """Sample dictionary container.""" |
||
18 | |||
19 | |||
20 | @yorm.attr(all=Integer) |
||
21 | class IntegerList(List): |
||
22 | """Sample list container.""" |
||
23 | |||
24 | |||
25 | View Code Duplication | @yorm.attr(array=IntegerList) |
|
0 ignored issues
–
show
|
|||
26 | @yorm.attr(false=Boolean) |
||
27 | @yorm.attr(number_int=Integer) |
||
28 | @yorm.attr(number_real=Float) |
||
29 | @yorm.attr(object=EmptyDictionary) |
||
30 | @yorm.attr(string=String) |
||
31 | @yorm.attr(true=Boolean) |
||
32 | @yorm.sync("tmp/path/to/{self.category}/{self.name}.yml") |
||
33 | class SampleStandardDecorated: |
||
34 | """Sample class using standard attribute types.""" |
||
35 | |||
36 | def __init__(self, name, category='default'): |
||
37 | # pylint: disable=duplicate-code |
||
38 | self.name = name |
||
39 | self.category = category |
||
40 | # https://docs.python.org/3.4/library/json.html#json.JSONDecoder |
||
41 | self.object = {} |
||
42 | self.array = [] |
||
43 | # pylint: disable=duplicate-code |
||
44 | self.string = "" |
||
45 | self.number_int = 0 |
||
46 | self.number_real = 0.0 |
||
47 | # pylint: disable=duplicate-code |
||
48 | self.true = True |
||
49 | self.false = False |
||
50 | self.null = None |
||
51 | |||
52 | def __repr__(self): |
||
53 | return "<decorated {}>".format(id(self)) |
||
54 | |||
55 | |||
56 | # TESTS ####################################################################### |
||
57 | |||
58 | |||
59 | class TestCreate: |
||
60 | """Integration tests for creating mapped classes.""" |
||
61 | |||
62 | def test_load_from_existing(self, tmpdir): |
||
63 | """Verify attributes are updated from an existing file.""" |
||
64 | tmpdir.chdir() |
||
65 | sample = SampleStandardDecorated('sample') |
||
66 | sample2 = SampleStandardDecorated('sample') |
||
67 | assert sample2.__mapper__.path == sample.__mapper__.path |
||
68 | |||
69 | refresh_file_modification_times() |
||
70 | |||
71 | log("Changing values in object 1...") |
||
72 | sample.array = [0, 1, 2] |
||
73 | sample.string = "Hello, world!" |
||
74 | sample.number_int = 42 |
||
75 | sample.number_real = 4.2 |
||
76 | sample.true = True |
||
77 | sample.false = False |
||
78 | |||
79 | log("Reading changed values in object 2...") |
||
80 | assert [0, 1, 2] == sample2.array |
||
81 | assert "Hello, world!" == sample2.string |
||
82 | assert 42 == sample2.number_int |
||
83 | assert 4.2 == sample2.number_real |
||
84 | assert True is sample2.true |
||
85 | assert False is sample2.false |
||
86 | |||
87 | |||
88 | class TestDelete: |
||
89 | """Integration tests for deleting files.""" |
||
90 | |||
91 | def test_read(self, tmpdir): |
||
92 | """Verify a deleted file cannot be read from.""" |
||
93 | tmpdir.chdir() |
||
94 | sample = SampleStandardDecorated('sample') |
||
95 | sample.__mapper__.delete() |
||
96 | |||
97 | with pytest.raises(FileNotFoundError): |
||
98 | print(sample.string) |
||
99 | |||
100 | with pytest.raises(FileNotFoundError): |
||
101 | sample.string = "def456" |
||
102 | |||
103 | def test_write(self, tmpdir): |
||
104 | """Verify a deleted file cannot be written to.""" |
||
105 | tmpdir.chdir() |
||
106 | sample = SampleStandardDecorated('sample') |
||
107 | sample.__mapper__.delete() |
||
108 | |||
109 | with pytest.raises(FileNotFoundError): |
||
110 | sample.string = "def456" |
||
111 | |||
112 | def test_multiple(self, tmpdir): |
||
113 | """Verify a deleted file can be deleted again.""" |
||
114 | tmpdir.chdir() |
||
115 | sample = SampleStandardDecorated('sample') |
||
116 | sample.__mapper__.delete() |
||
117 | sample.__mapper__.delete() |
||
118 | |||
119 | |||
120 | class TestUpdate: |
||
121 | """Integration tests for updating files/object.""" |
||
122 | |||
123 | def test_automatic_save_after_first_modification(self, tmpdir): |
||
124 | tmpdir.chdir() |
||
125 | sample = SampleStandardDecorated('sample') |
||
126 | assert "number_int: 0\n" in sample.__mapper__.text |
||
127 | |||
128 | sample.number_int = 42 |
||
129 | assert "number_int: 42\n" in sample.__mapper__.text |
||
130 | |||
131 | sample.__mapper__.text = "number_int: true\n" |
||
132 | assert 1 is sample.number_int |
||
133 | assert "number_int: 1\n" in sample.__mapper__.text |
||
134 | |||
135 | def test_automatic_save_after_first_modification_on_list(self, tmpdir): |
||
136 | tmpdir.chdir() |
||
137 | sample = SampleStandardDecorated('sample') |
||
138 | assert "array:\n-\n" in sample.__mapper__.text |
||
139 | |||
140 | sample.array.append(42) |
||
141 | assert "array:\n- 42\n" in sample.__mapper__.text |
||
142 | |||
143 | sample.__mapper__.text = "array: [true]\n" |
||
144 | iter(sample.array) |
||
145 | assert "array:\n- 1\n" in sample.__mapper__.text |
||
146 |