Commit | Line | Data |
---|---|---|
d31714a0 SA |
1 | # The software in this package is distributed under the GNU General |
2 | # Public License version 2 (with a special exception described below). | |
3 | # | |
4 | # A copy of GNU General Public License (GPL) is included in this distribution, | |
5 | # in the file COPYING.GPL. | |
6 | # | |
7 | # As a special exception, if other files instantiate templates or use macros | |
8 | # or inline functions from this file, or you compile this file and link it | |
9 | # with other works to produce a work based on this file, this file | |
10 | # does not by itself cause the resulting work to be covered | |
11 | # by the GNU General Public License. | |
12 | # | |
13 | # However the source code for this file must still be made available | |
14 | # in accordance with section (3) of the GNU General Public License. | |
15 | # | |
16 | # This exception does not invalidate any other reasons why a work based | |
17 | # on this file might be covered by the GNU General Public License. | |
18 | # | |
19 | # Copyright (c) 2016-2022 Intra2net AG <info@intra2net.com> | |
20 | ||
21 | """ | |
22 | test_model.py: unit tests for cnfvar/model.py. | |
23 | ||
24 | Tests classes and functions in cnfvar/model.py | |
25 | ||
26 | For help see :py:mod:`unittest` | |
27 | """ | |
28 | ||
29 | import unittest | |
30 | import json | |
31 | from textwrap import dedent | |
32 | from tempfile import NamedTemporaryFile | |
b621d44e | 33 | from copy import deepcopy |
d31714a0 | 34 | |
b621d44e | 35 | from src.cnfvar import CnfList, CnfDiff |
d31714a0 SA |
36 | |
37 | CNF_TEST_DATA = dedent("""\ | |
38 | 1 USER,1: "jake" | |
39 | 2 (1) USER_DISABLED,0: "0" | |
40 | 3 (1) USER_FULLNAME,0: "Jake" | |
41 | 4 (1) USER_GROUPWARE_FOLDER_DRAFTS,0: "INBOX/Entwürfe" | |
42 | 5 (1) USER_GROUPWARE_FOLDER_OUTBOX,0: "INBOX/Gesendete Objekte" | |
43 | 6 (1) USER_GROUPWARE_FOLDER_TRASH,0: "INBOX/Gelöschte Elemente" | |
44 | 7 (1) USER_GROUP_MEMBER_REF,0: "100" | |
45 | 8 (1) USER_GROUP_MEMBER_REF,1: "2" | |
46 | 9 (1) USER_PASSWORD,0: "test1234" | |
47 | 11 USER,2: "jill" | |
48 | 12 (11) USER_DISABLED,0: "0" | |
49 | 13 (11) USER_FULLNAME,0: "Jill" | |
50 | 14 (11) USER_GROUPWARE_FOLDER_DRAFTS,0: "INBOX/Entwürfe" | |
51 | 15 (11) USER_GROUPWARE_FOLDER_OUTBOX,0: "INBOX/Gesendete Objekte" | |
52 | 16 (11) USER_GROUPWARE_FOLDER_TRASH,0: "INBOX/Gelöschte Elemente" | |
53 | 17 (11) USER_GROUP_MEMBER_REF,0: "100" | |
54 | 18 (11) USER_GROUP_MEMBER_REF,1: "2" | |
55 | 19 (11) USER_PASSWORD,0: "test1234" | |
56 | 74 EMAILFILTER_BAN_FILTERLIST,0: "Vordefiniert: Alles verboten" | |
57 | 75 (74) EMAILFILTER_BAN_FILTERLIST_ENCRYPTED,0: "BLOCK" | |
58 | 76 (74) EMAILFILTER_BAN_FILTERLIST_EXTENSIONS,0: "" | |
59 | 77 (74) EMAILFILTER_BAN_FILTERLIST_FILTER_OFFICE_FILES,0: "BY_FILTERLIST" | |
60 | 78 (74) EMAILFILTER_BAN_FILTERLIST_MIMETYPES,0: "" | |
61 | 79 (78) EMAILFILTER_BAN_FILTERLIST_MIMETYPES_NAME,0: "text/plain" | |
62 | 80 (78) EMAILFILTER_BAN_FILTERLIST_MIMETYPES_NAME,1: "text/html" | |
63 | 81 (74) EMAILFILTER_BAN_FILTERLIST_MODE,0: "ALLOW" | |
64 | 82 (74) EMAILFILTER_BAN_FILTERLIST_PREDEFINED_ID,0: "1" | |
65 | 1196 UPDATE_EXPIRED,0: "0" | |
66 | 1197 UPDATE_URL_BASE,0: "https://update.intra2net.com/" | |
67 | 1198 UPDATE_VALIDATION_GROUP,0: "normal" | |
68 | 1199 UPS_LOCAL_KILLPOWER_ENABLE,0: "1" | |
69 | """) | |
70 | ||
71 | ||
72 | EXPECTED_CNF_DATA = dedent("""\ | |
73 | 1 USER,1: "jake" | |
74 | 2 (1) USER_DISABLED,0: "0" | |
75 | 3 (1) USER_FULLNAME,0: "Jake" | |
76 | 4 (1) USER_GROUPWARE_FOLDER_DRAFTS,0: "INBOX/Entwürfe" | |
77 | 5 (1) USER_GROUPWARE_FOLDER_OUTBOX,0: "INBOX/Gesendete Objekte" | |
78 | 6 (1) USER_GROUPWARE_FOLDER_TRASH,0: "INBOX/Gelöschte Elemente" | |
79 | 7 (1) USER_GROUP_MEMBER_REF,0: "100" | |
80 | 8 (1) USER_GROUP_MEMBER_REF,1: "2" | |
81 | 9 (1) USER_PASSWORD,0: "test1234" | |
82 | 10 USER,2: "jane" | |
83 | 11 (10) USER_DISABLED,0: "0" | |
84 | 12 (10) USER_FULLNAME,0: "Jane" | |
85 | 13 (10) USER_GROUPWARE_FOLDER_DRAFTS,0: "INBOX/Entwürfe" | |
86 | 14 (10) USER_GROUPWARE_FOLDER_OUTBOX,0: "INBOX/Gesendete Objekte" | |
87 | 15 (10) USER_GROUPWARE_FOLDER_TRASH,0: "INBOX/Gelöschte Elemente" | |
88 | 16 (10) USER_GROUP_MEMBER_REF,0: "200" | |
89 | 17 (10) USER_GROUP_MEMBER_REF,1: "2" | |
90 | 18 (10) USER_PASSWORD,0: "test1234" | |
91 | 19 (10) USER_GROUP_MEMBER_REF,2: "5" | |
92 | 20 EMAILFILTER_BAN_FILTERLIST,0: "Vordefiniert: Alles verboten" | |
93 | 21 (20) EMAILFILTER_BAN_FILTERLIST_ENCRYPTED,0: "BLOCK" | |
94 | 22 (20) EMAILFILTER_BAN_FILTERLIST_EXTENSIONS,0: "" | |
95 | 23 (20) EMAILFILTER_BAN_FILTERLIST_FILTER_OFFICE_FILES,0: "BY_FILTERLIST" | |
96 | 24 (20) EMAILFILTER_BAN_FILTERLIST_MIMETYPES,0: "" # hey this is a comment | |
97 | 25 (24) EMAILFILTER_BAN_FILTERLIST_MIMETYPES_NAME,0: "text/plain" | |
98 | 26 (24) EMAILFILTER_BAN_FILTERLIST_MIMETYPES_NAME,1: "text/html" | |
99 | 27 (20) EMAILFILTER_BAN_FILTERLIST_MODE,0: "ALLOW" | |
100 | 28 (20) EMAILFILTER_BAN_FILTERLIST_PREDEFINED_ID,0: "1" | |
101 | 29 UPDATE_EXPIRED,0: "1" | |
102 | 30 UPDATE_URL_BASE,0: "https://update.intra2net.com/" | |
103 | 31 UPDATE_VALIDATION_GROUP,0: "normal" | |
104 | 32 UPS_LOCAL_KILLPOWER_ENABLE,0: "1" | |
105 | """) | |
106 | ||
107 | ||
108 | class TestModel(unittest.TestCase): | |
109 | """Test the multiple capabilities of the CNF modules.""" | |
110 | ||
111 | def test_querying_and_serialization(self): | |
112 | """Test deserializing, querying and serializing a CnfList.""" | |
113 | cnfs = CnfList.from_cnf_string(CNF_TEST_DATA) | |
114 | ||
115 | self._modify(cnfs) | |
116 | ||
117 | with NamedTemporaryFile() as tmpfile: | |
118 | cnfs.to_cnf_file(tmpfile.name) | |
119 | ||
120 | with open(tmpfile.name, "r", encoding="latin1") as f: | |
121 | contents = f.read() | |
122 | ||
123 | self.assertEqual(contents.splitlines(), EXPECTED_CNF_DATA.splitlines()) | |
124 | ||
125 | # make sure the result can be parsed again | |
126 | CnfList.from_cnf_string(str(contents)) | |
127 | ||
128 | def test_querying_and_serialization_json(self): | |
129 | """Test deserializing, querying and serializing a CnfList as JSON.""" | |
130 | # first serialize to JSON without renumbering to keep the structure | |
131 | cnfs = CnfList.from_cnf_string(CNF_TEST_DATA) | |
132 | ||
133 | with NamedTemporaryFile() as tmpfile: | |
134 | cnfs.to_json_file(tmpfile.name, renumber=False) | |
135 | ||
136 | with open(tmpfile.name, "r") as f: | |
137 | contents = f.read() | |
138 | ||
139 | # make sure the JSON structure is sane | |
140 | json.loads(contents) | |
141 | ||
142 | # now asserts that reading from JSON works | |
143 | cnfs_2 = CnfList.from_json_string(contents) | |
144 | self._modify(cnfs_2) | |
145 | cnfs_2.renumber() | |
146 | ||
147 | self.assertEqual(str(cnfs_2).splitlines(), EXPECTED_CNF_DATA.splitlines()) | |
148 | ||
149 | # make sure the result can be parsed again | |
150 | CnfList.from_cnf_string(str(cnfs_2)) | |
151 | ||
152 | def _modify(self, cnfs): | |
153 | """ | |
154 | Make test modifications on the list. | |
155 | ||
156 | :param cnfs: list of cnfvars to modify | |
157 | :type cnfs: :py:class:`CnfList` | |
158 | ||
159 | .. note:: we unify this into a method so we can make sure that the test | |
160 | using cnfvar strings and the test using JSON do the exactly same modifications. | |
161 | """ | |
162 | self.assertFalse(cnfs.single_with_name("update_expired").is_enabled()) | |
163 | cnfs.single_with_name("update_expired") \ | |
164 | .enable() | |
165 | self.assertTrue(cnfs.single_with_name("update_expired").is_enabled()) | |
166 | ||
167 | user_cnf = cnfs.first_with_value("jill") | |
168 | user_cnf.value = "jane" | |
169 | user_cnf.children[1].value = "Jane" | |
170 | user_cnf.children.first_with_name("user_group_member_ref").value = "200" | |
c89cc126 | 171 | user_cnf.add_children(("USER_GROUP_MEMBER_REF", 5, -1)) |
d31714a0 SA |
172 | |
173 | # check correct types and equality | |
174 | self.assertEqual(user_cnf.instance, 2) | |
175 | self.assertEqual(user_cnf.lineno, 11) | |
176 | ||
177 | other_cnf = cnfs.single_with_value("Vordefiniert: Alles verboten") | |
178 | other_cnf.children \ | |
179 | .where(lambda c: c.name == "emailfilter_ban_filterlist_mimetypes") \ | |
180 | .single() \ | |
181 | .comment = "hey this is a comment" | |
182 | ||
183 | ||
b621d44e CH |
184 | class TestCompare(unittest.TestCase): |
185 | """Test compare() function of BaseCnfList.""" | |
186 | ||
187 | DATA_STR = dedent("""\ | |
188 | 01 FRANCHISE,0: "Star Trek" | |
189 | 02 (01) SERIES,0: "The Original Series" | |
190 | 03 (02) SHIP,0: "Enterprise (original)" | |
191 | 04 (03) CAPTAIN,0: "Pike" | |
192 | 05 (03) CAPTAIN,1: "Kirk" | |
193 | 06 (01) SERIES,1: "The Animated Series" | |
194 | 07 (01) SERIES,1: "The Next Generation" | |
195 | 08 (07) SHIP,0: "Enterprise D" | |
196 | 09 (08) CAPTAIN,0: "Picard" | |
197 | 11 (08) CAPTAIN,1: "Riker" | |
198 | 12 (01) SERIES,2: "Deep Space Nine" | |
199 | 13 (01) SERIES,3: "Voyager" | |
200 | 14 (13) SHIP,0: "Voyager" | |
201 | 15 (01) SERIES,4: "Enterprise" | |
202 | 16 (15) SHIP,0: "Enterprise" | |
203 | 17 (16) CAPTAIN,0: "Archer" | |
204 | 18 FRANCHISE,1: "Star Wars" | |
205 | 19 (18) MOVIE,0: "A New Hope" | |
206 | 21 (19) EPISODE,0: "4" | |
207 | 22 (18) MOVIE,1: "The Empire Strikes Back" | |
208 | 23 (22) EPISODE,0: "5" | |
209 | 24 (18) MOVIE,2: "Return of the Jedi" | |
210 | 25 (24) EPISODE,0: "6" | |
211 | 26 (18) MOVIE,3: "The Phantom Menace" | |
212 | 27 (26) EPISODE,0: "1" | |
213 | 28 (18) MOVIE,4: "Attack of the Clones" | |
214 | 29 (28) EPISODE,0: "2" | |
215 | 31 (18) MOVIE,5: "Revenge of the Sith" | |
216 | 32 (31) EPISODE,0: "3" | |
217 | 33 FRANCHISE,2: "Battlestar Galactica" | |
218 | 34 FRANCHISE,3: "Firefly" | |
219 | 35 FRANCHISE,4: "Babylon 5" | |
220 | 36 FRANCHISE,5: "Star Gate" | |
221 | """) | |
222 | ||
223 | DATA: CnfList # initialized in setUpClass | |
224 | ||
225 | @classmethod | |
226 | def setUpClass(cls) -> None: | |
227 | """Called once before first test, converts above string to CnfList.""" | |
228 | cls.DATA = CnfList.from_cnf_string(cls.DATA_STR) | |
229 | ||
230 | def test_equal(self): | |
231 | """Compare data to itself.""" | |
232 | self.assertEqual(CnfDiff(), self.DATA.compare(self.DATA)) | |
233 | ||
234 | def test_remove(self): | |
235 | """Remove entry from data, check it is found.""" | |
236 | other = deepcopy(self.DATA) | |
237 | removed = other.single_with_value("Star Trek").children\ | |
238 | .single_with_value("The Original Series").children\ | |
239 | .single_with_value("Enterprise (original)").children \ | |
240 | .remove_where(lambda cnf: cnf.value == "Pike") | |
241 | self.assertEqual(1, len(removed)) | |
242 | diff = self.DATA.compare(other) | |
243 | self.assertEqual(1, len(diff)) | |
244 | diff_text = [] | |
245 | diff.print(output_func=lambda s: diff_text.append(s)) | |
246 | self.assertEqual(1, len(diff_text)) | |
247 | expect = "cnf diff: - captain (0) = 'Pike' " + \ | |
248 | "in franchise=Star Trek > series=The Original Series > ship=Enterprise (original)" | |
249 | self.assertEqual(expect, diff_text[0]) | |
250 | ||
251 | def test_add(self): | |
252 | """Add entry to data, check it is found.""" | |
253 | other = deepcopy(self.DATA) | |
254 | other.single_with_value("Star Wars").children.single_with_value("The Phantom Menace")\ | |
255 | .add_child("CHARACTER", "Jar Jar Binks") | |
256 | diff = self.DATA.compare(other) | |
257 | self.assertEqual(1, len(diff)) | |
258 | diff_text = [] | |
259 | diff.print(output_func=lambda s: diff_text.append(s)) | |
260 | self.assertEqual(1, len(diff_text)) | |
261 | expect = "cnf diff: + CHARACTER (0) = 'Jar Jar Binks' " + \ | |
262 | "in franchise=Star Wars > movie=The Phantom Menace" | |
263 | self.assertEqual(expect, diff_text[0]) | |
264 | ||
265 | def test_change(self): | |
266 | """Change entry in data, check it is found.""" | |
267 | other = deepcopy(self.DATA) | |
268 | other.single_with_value("Star Trek").children \ | |
269 | .single_with_value("The Next Generation").children \ | |
270 | .single_with_value("Enterprise D").children \ | |
271 | .single_with_value("Picard").value = "Jean-Luc" | |
272 | diff = self.DATA.compare(other) | |
273 | self.assertEqual(2, len(diff)) | |
274 | diff_text = [] | |
275 | diff.print(output_func=lambda s: diff_text.append(s)) | |
276 | self.assertEqual(2, len(diff_text)) | |
277 | expect = [ | |
278 | "cnf diff: - captain (0) = 'Picard' in franchise=Star Trek > " | |
279 | "series=The Next Generation > ship=Enterprise D", | |
280 | "cnf diff: + captain (0) = 'Jean-Luc' in franchise=Star Trek > " | |
281 | "series=The Next Generation > ship=Enterprise D", | |
282 | ] | |
283 | self.assertEqual(expect, diff_text) | |
284 | ||
285 | def test_ignore(self): | |
286 | """Check that changes on ignore_list are ignored.""" | |
287 | other = deepcopy(self.DATA) | |
288 | # same change as in test_change | |
289 | other.single_with_value("Star Trek").children \ | |
290 | .single_with_value("The Next Generation").children \ | |
291 | .single_with_value("Enterprise D").children \ | |
292 | .single_with_value("Picard").value = "Jean-Luc" | |
293 | diff = self.DATA.compare(other, ignore_list=["CAPTAIN",]) | |
294 | self.assertEqual(0, len(diff)) | |
295 | ||
296 | ||
d31714a0 SA |
297 | if __name__ == '__main__': |
298 | unittest.main() |