• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2022 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Tests for pw_ide.editors"""
15
16from collections import OrderedDict
17from enum import Enum
18import unittest
19
20from pw_ide.editors import (
21    dict_deep_merge,
22    EditorSettingsFile,
23    EditorSettingsManager,
24    JsonFileFormat,
25)
26
27from test_cases import PwIdeTestCase
28
29
30class TestDictDeepMerge(unittest.TestCase):
31    """Tests dict_deep_merge"""
32
33    def test_invariants_with_dict_success(self):
34        # pylint: disable=unnecessary-lambda
35        dict_a = {'hello': 'world'}
36        dict_b = {'foo': 'bar'}
37
38        expected = {
39            'hello': 'world',
40            'foo': 'bar',
41        }
42
43        result = dict_deep_merge(dict_b, dict_a, lambda: dict())
44        self.assertEqual(result, expected)
45
46    def test_invariants_with_dict_implicit_ctor_success(self):
47        # pylint: disable=unnecessary-lambda
48        dict_a = {'hello': 'world'}
49        dict_b = {'foo': 'bar'}
50
51        expected = {
52            'hello': 'world',
53            'foo': 'bar',
54        }
55
56        result = dict_deep_merge(dict_b, dict_a)
57        self.assertEqual(result, expected)
58
59    def test_invariants_with_dict_fails_wrong_ctor_type(self):
60        # pylint: disable=unnecessary-lambda
61        dict_a = {'hello': 'world'}
62        dict_b = {'foo': 'bar'}
63
64        with self.assertRaises(TypeError):
65            dict_deep_merge(dict_b, dict_a, lambda: OrderedDict())
66
67    def test_invariants_with_ordered_dict_success(self):
68        # pylint: disable=unnecessary-lambda
69        dict_a = OrderedDict({'hello': 'world'})
70        dict_b = OrderedDict({'foo': 'bar'})
71
72        expected = OrderedDict(
73            {
74                'hello': 'world',
75                'foo': 'bar',
76            }
77        )
78
79        result = dict_deep_merge(dict_b, dict_a, lambda: OrderedDict())
80        self.assertEqual(result, expected)
81
82    def test_invariants_with_ordered_dict_implicit_ctor_success(self):
83        # pylint: disable=unnecessary-lambda
84        dict_a = OrderedDict({'hello': 'world'})
85        dict_b = OrderedDict({'foo': 'bar'})
86
87        expected = OrderedDict(
88            {
89                'hello': 'world',
90                'foo': 'bar',
91            }
92        )
93
94        result = dict_deep_merge(dict_b, dict_a)
95        self.assertEqual(result, expected)
96
97    def test_invariants_with_ordered_dict_fails_wrong_ctor_type(self):
98        # pylint: disable=unnecessary-lambda
99        dict_a = OrderedDict({'hello': 'world'})
100        dict_b = OrderedDict({'foo': 'bar'})
101
102        with self.assertRaises(TypeError):
103            dict_deep_merge(dict_b, dict_a, lambda: dict())
104
105
106class TestEditorSettingsFile(PwIdeTestCase):
107    """Tests EditorSettingsFile"""
108
109    def test_open_new_file_and_write(self):
110        name = 'settings'
111        json_fmt = JsonFileFormat()
112        settings_file = EditorSettingsFile(self.temp_dir_path, name, json_fmt)
113
114        with settings_file.modify() as settings:
115            settings['hello'] = 'world'
116
117        with open(self.temp_dir_path / f'{name}.{json_fmt.ext}') as file:
118            settings_dict = json_fmt.load(file)
119
120        self.assertEqual(settings_dict['hello'], 'world')
121
122    def test_open_new_file_and_get(self):
123        name = 'settings'
124        json_fmt = JsonFileFormat()
125        settings_file = EditorSettingsFile(self.temp_dir_path, name, json_fmt)
126
127        with settings_file.modify() as settings:
128            settings['hello'] = 'world'
129
130        settings_dict = settings_file.get()
131        self.assertEqual(settings_dict['hello'], 'world')
132
133    def test_open_new_file_no_backup(self):
134        name = 'settings'
135        json_fmt = JsonFileFormat()
136        settings_file = EditorSettingsFile(self.temp_dir_path, name, json_fmt)
137
138        with settings_file.modify() as settings:
139            settings['hello'] = 'world'
140
141        backup_files = [
142            path
143            for path in self.temp_dir_path.iterdir()
144            if path.name != f'{name}.{json_fmt.ext}'
145        ]
146
147        self.assertEqual(len(backup_files), 0)
148
149    def test_open_existing_file_and_backup(self):
150        name = 'settings'
151        json_fmt = JsonFileFormat()
152        settings_file = EditorSettingsFile(self.temp_dir_path, name, json_fmt)
153
154        with settings_file.modify() as settings:
155            settings['hello'] = 'world'
156
157        with settings_file.modify() as settings:
158            settings['hello'] = 'mundo'
159
160        settings_dict = settings_file.get()
161        self.assertEqual(settings_dict['hello'], 'mundo')
162
163        backup_files = [
164            path
165            for path in self.temp_dir_path.iterdir()
166            if path.name != f'{name}.{json_fmt.ext}'
167        ]
168
169        self.assertEqual(len(backup_files), 1)
170
171        with open(backup_files[0]) as file:
172            settings_dict = json_fmt.load(file)
173
174        self.assertEqual(settings_dict['hello'], 'world')
175
176    def test_open_existing_file_with_reinit_and_backup(self):
177        name = 'settings'
178        json_fmt = JsonFileFormat()
179        settings_file = EditorSettingsFile(self.temp_dir_path, name, json_fmt)
180
181        with settings_file.modify() as settings:
182            settings['hello'] = 'world'
183
184        with settings_file.modify(reinit=True) as settings:
185            settings['hello'] = 'mundo'
186
187        settings_dict = settings_file.get()
188        self.assertEqual(settings_dict['hello'], 'mundo')
189
190        backup_files = [
191            path
192            for path in self.temp_dir_path.iterdir()
193            if path.name != f'{name}.{json_fmt.ext}'
194        ]
195
196        self.assertEqual(len(backup_files), 1)
197
198        with open(backup_files[0]) as file:
199            settings_dict = json_fmt.load(file)
200
201        self.assertEqual(settings_dict['hello'], 'world')
202
203    def open_existing_file_no_change_no_backup(self):
204        name = 'settings'
205        json_fmt = JsonFileFormat()
206        settings_file = EditorSettingsFile(self.temp_dir_path, name, json_fmt)
207
208        with settings_file.modify() as settings:
209            settings['hello'] = 'world'
210
211        with settings_file.modify() as settings:
212            settings['hello'] = 'world'
213
214        settings_dict = settings_file.get()
215        self.assertEqual(settings_dict['hello'], 'world')
216
217        backup_files = [
218            path
219            for path in self.temp_dir_path.iterdir()
220            if path.name != f'{name}.{json_fmt.ext}'
221        ]
222
223        self.assertEqual(len(backup_files), 0)
224
225        with open(backup_files[0]) as file:
226            settings_dict = json_fmt.load(file)
227
228        self.assertEqual(settings_dict['hello'], 'world')
229
230    def test_write_bad_file_restore_backup(self):
231        name = 'settings'
232        json_fmt = JsonFileFormat()
233        settings_file = EditorSettingsFile(self.temp_dir_path, name, json_fmt)
234
235        with settings_file.modify() as settings:
236            settings['hello'] = 'world'
237
238        with self.assertRaises(TypeError):
239            with settings_file.modify() as settings:
240                settings['hello'] = object()
241
242        settings_dict = settings_file.get()
243        self.assertEqual(settings_dict['hello'], 'world')
244
245        backup_files = [
246            path
247            for path in self.temp_dir_path.iterdir()
248            if path.name != f'{name}.{json_fmt.ext}'
249        ]
250
251        self.assertEqual(len(backup_files), 0)
252
253
254class EditorSettingsTestType(Enum):
255    SETTINGS = 'settings'
256
257
258class TestEditorSettingsManager(PwIdeTestCase):
259    """Tests EditorSettingsManager"""
260
261    def test_settings_merge(self):
262        """Test that settings merge as expected in isolation."""
263        default_settings = OrderedDict(
264            {
265                'foo': 'bar',
266                'baz': 'qux',
267                'lorem': OrderedDict(
268                    {
269                        'ipsum': 'dolor',
270                    }
271                ),
272            }
273        )
274
275        types_with_defaults = {
276            EditorSettingsTestType.SETTINGS: lambda _: default_settings
277        }
278
279        ide_settings = self.make_ide_settings()
280        json_fmt = JsonFileFormat()
281        manager = EditorSettingsManager(
282            ide_settings, self.temp_dir_path, json_fmt, types_with_defaults
283        )
284
285        project_settings = OrderedDict(
286            {
287                'alpha': 'beta',
288                'baz': 'xuq',
289                'foo': 'rab',
290            }
291        )
292
293        with manager.project(
294            EditorSettingsTestType.SETTINGS
295        ).modify() as settings:
296            dict_deep_merge(project_settings, settings)
297
298        user_settings = OrderedDict(
299            {
300                'baz': 'xqu',
301                'lorem': OrderedDict(
302                    {
303                        'ipsum': 'sit amet',
304                        'consectetur': 'adipiscing',
305                    }
306                ),
307            }
308        )
309
310        with manager.user(EditorSettingsTestType.SETTINGS).modify() as settings:
311            dict_deep_merge(user_settings, settings)
312
313        expected = {
314            'alpha': 'beta',
315            'foo': 'rab',
316            'baz': 'xqu',
317            'lorem': {
318                'ipsum': 'sit amet',
319                'consectetur': 'adipiscing',
320            },
321        }
322
323        with manager.active(
324            EditorSettingsTestType.SETTINGS
325        ).modify() as active_settings:
326            manager.default(EditorSettingsTestType.SETTINGS).sync_to(
327                active_settings
328            )
329            manager.project(EditorSettingsTestType.SETTINGS).sync_to(
330                active_settings
331            )
332            manager.user(EditorSettingsTestType.SETTINGS).sync_to(
333                active_settings
334            )
335
336        self.assertCountEqual(
337            manager.active(EditorSettingsTestType.SETTINGS).get(), expected
338        )
339
340
341if __name__ == '__main__':
342    unittest.main()
343