• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#
2# Copyright (C) 2023 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17import copy
18import json
19import textwrap
20import unittest
21from typing import Any
22
23import gdbclient
24
25
26class LaunchConfigMergeTest(unittest.TestCase):
27    def merge_compare(self, base: dict[str, Any], to_add: dict[str, Any] | None, expected: dict[str, Any]) -> None:
28        actual = copy.deepcopy(base)
29        gdbclient.merge_launch_dict(actual, to_add)
30        self.assertEqual(actual, expected, f'base={base}, to_add={to_add}')
31
32    def test_add_none(self) -> None:
33        base = { 'foo' : 1 }
34        to_add = None
35        expected = { 'foo' : 1 }
36        self.merge_compare(base, to_add, expected)
37
38    def test_add_val(self) -> None:
39        base = { 'foo' : 1 }
40        to_add = { 'bar' : 2}
41        expected = { 'foo' : 1, 'bar' : 2 }
42        self.merge_compare(base, to_add, expected)
43
44    def test_overwrite_val(self) -> None:
45        base = { 'foo' : 1 }
46        to_add = { 'foo' : 2}
47        expected = { 'foo' : 2 }
48        self.merge_compare(base, to_add, expected)
49
50    def test_lists_get_appended(self) -> None:
51        base = { 'foo' : [1, 2] }
52        to_add = { 'foo' : [3, 4]}
53        expected = { 'foo' : [1, 2, 3, 4] }
54        self.merge_compare(base, to_add, expected)
55
56    def test_add_elem_to_dict(self) -> None:
57        base = { 'foo' : { 'bar' : 1 } }
58        to_add = { 'foo' : { 'baz' : 2 } }
59        expected = { 'foo' : { 'bar' :  1, 'baz' : 2 } }
60        self.merge_compare(base, to_add, expected)
61
62    def test_overwrite_elem_in_dict(self) -> None:
63        base = { 'foo' : { 'bar' : 1 } }
64        to_add = { 'foo' : { 'bar' : 2 } }
65        expected = { 'foo' : { 'bar' : 2 } }
66        self.merge_compare(base, to_add, expected)
67
68    def test_merging_dict_and_value_raises(self) -> None:
69        base = { 'foo' : { 'bar' : 1 } }
70        to_add = { 'foo' : 2 }
71        with self.assertRaises(ValueError):
72            gdbclient.merge_launch_dict(base, to_add)
73
74    def test_merging_value_and_dict_raises(self) -> None:
75        base = { 'foo' : 2 }
76        to_add = { 'foo' : { 'bar' : 1 } }
77        with self.assertRaises(ValueError):
78            gdbclient.merge_launch_dict(base, to_add)
79
80    def test_merging_dict_and_list_raises(self) -> None:
81        base = { 'foo' : { 'bar' : 1 } }
82        to_add = { 'foo' : [1] }
83        with self.assertRaises(ValueError):
84            gdbclient.merge_launch_dict(base, to_add)
85
86    def test_merging_list_and_dict_raises(self) -> None:
87        base = { 'foo' : [1] }
88        to_add = { 'foo' : { 'bar' : 1 } }
89        with self.assertRaises(ValueError):
90            gdbclient.merge_launch_dict(base, to_add)
91
92    def test_adding_elem_to_list_raises(self) -> None:
93        base = { 'foo' : [1] }
94        to_add = { 'foo' : 2}
95        with self.assertRaises(ValueError):
96            gdbclient.merge_launch_dict(base, to_add)
97
98    def test_adding_list_to_elem_raises(self) -> None:
99        base = { 'foo' : 1 }
100        to_add = { 'foo' : [2]}
101        with self.assertRaises(ValueError):
102            gdbclient.merge_launch_dict(base, to_add)
103
104
105class VsCodeLaunchGeneratorTest(unittest.TestCase):
106    def setUp(self) -> None:
107        # These tests can generate long diffs, so we remove the limit
108        self.maxDiff = None
109
110    def test_generate_script(self) -> None:
111        self.assertEqual(json.loads(gdbclient.generate_vscode_lldb_script(root='/root',
112                                                            sysroot='/sysroot',
113                                                            binary_name='test',
114                                                            port=123,
115                                                            solib_search_path=['/path1',
116                                                                               '/path2'],
117                                                            extra_props=None)),
118        {
119             'name': '(lldbclient.py) Attach test (port: 123)',
120             'type': 'lldb',
121             'request': 'custom',
122             'relativePathBase': '/root',
123             'sourceMap': { '/b/f/w' : '/root', '': '/root', '.': '/root' },
124             'initCommands': ['settings append target.exec-search-paths /path1 /path2'],
125             'targetCreateCommands': ['target create test',
126                                      'target modules search-paths add / /sysroot/'],
127             'processCreateCommands': ['gdb-remote 123']
128         })
129
130    def test_generate_script_with_extra_props(self) -> None:
131        extra_props = {
132            'initCommands' : ['settings append target.exec-search-paths /path3'],
133            'processCreateCommands' : ['break main', 'continue'],
134            'sourceMap' : { '/test/' : '/root/test'},
135            'preLaunchTask' : 'Build'
136        }
137        self.assertEqual(json.loads(gdbclient.generate_vscode_lldb_script(root='/root',
138                                                            sysroot='/sysroot',
139                                                            binary_name='test',
140                                                            port=123,
141                                                            solib_search_path=['/path1',
142                                                                               '/path2'],
143                                                            extra_props=extra_props)),
144        {
145             'name': '(lldbclient.py) Attach test (port: 123)',
146             'type': 'lldb',
147             'request': 'custom',
148             'relativePathBase': '/root',
149             'sourceMap': { '/b/f/w' : '/root',
150                           '': '/root',
151                           '.': '/root',
152                           '/test/' : '/root/test' },
153             'initCommands': [
154                 'settings append target.exec-search-paths /path1 /path2',
155                 'settings append target.exec-search-paths /path3',
156             ],
157             'targetCreateCommands': ['target create test',
158                                      'target modules search-paths add / /sysroot/'],
159             'processCreateCommands': ['gdb-remote 123',
160                                       'break main',
161                                       'continue'],
162             'preLaunchTask' : 'Build'
163         })
164
165
166class LaunchConfigInsertTest(unittest.TestCase):
167    def setUp(self) -> None:
168        # These tests can generate long diffs, so we remove the limit
169        self.maxDiff = None
170
171    def test_insert_config(self) -> None:
172        dst = textwrap.dedent("""\
173            // #lldbclient-generated-begin
174            // #lldbclient-generated-end""")
175        to_insert = textwrap.dedent("""\
176                                    foo
177                                    bar""")
178        self.assertEqual(gdbclient.insert_commands_into_vscode_config(dst,
179                                                                      to_insert),
180                         textwrap.dedent("""\
181                            // #lldbclient-generated-begin
182                            foo
183                            bar
184                            // #lldbclient-generated-end"""))
185
186    def test_insert_into_start(self) -> None:
187        dst = textwrap.dedent("""\
188            // #lldbclient-generated-begin
189            // #lldbclient-generated-end
190            more content""")
191        to_insert = textwrap.dedent("""\
192            foo
193            bar""")
194        self.assertEqual(gdbclient.insert_commands_into_vscode_config(dst,
195                                                                      to_insert),
196                         textwrap.dedent("""\
197                            // #lldbclient-generated-begin
198                            foo
199                            bar
200                            // #lldbclient-generated-end
201                            more content"""))
202
203    def test_insert_into_mid(self) -> None:
204        dst = textwrap.dedent("""\
205            start content
206            // #lldbclient-generated-begin
207            // #lldbclient-generated-end
208            more content""")
209        to_insert = textwrap.dedent("""\
210            foo
211            bar""")
212        self.assertEqual(gdbclient.insert_commands_into_vscode_config(dst,
213                                                                      to_insert),
214                         textwrap.dedent("""\
215                            start content
216                            // #lldbclient-generated-begin
217                            foo
218                            bar
219                            // #lldbclient-generated-end
220                            more content"""))
221
222    def test_insert_into_end(self) -> None:
223        dst = textwrap.dedent("""\
224            start content
225            // #lldbclient-generated-begin
226            // #lldbclient-generated-end""")
227        to_insert = textwrap.dedent("""\
228            foo
229            bar""")
230        self.assertEqual(gdbclient.insert_commands_into_vscode_config(dst,
231                                                                      to_insert),
232                         textwrap.dedent("""\
233                            start content
234                            // #lldbclient-generated-begin
235                            foo
236                            bar
237                            // #lldbclient-generated-end"""))
238
239    def test_insert_twice(self) -> None:
240        dst = textwrap.dedent("""\
241            // #lldbclient-generated-begin
242            // #lldbclient-generated-end
243            // #lldbclient-generated-begin
244            // #lldbclient-generated-end
245            """)
246        to_insert = 'foo'
247        self.assertEqual(gdbclient.insert_commands_into_vscode_config(dst,
248                                                                      to_insert),
249                         textwrap.dedent("""\
250                            // #lldbclient-generated-begin
251                            foo
252                            // #lldbclient-generated-end
253                            // #lldbclient-generated-begin
254                            foo
255                            // #lldbclient-generated-end
256                         """))
257
258    def test_preserve_space_indent(self) -> None:
259        dst = textwrap.dedent("""\
260            {
261              "version": "0.2.0",
262              "configurations": [
263                // #lldbclient-generated-begin
264                // #lldbclient-generated-end
265              ]
266            }
267        """)
268        to_insert = textwrap.dedent("""\
269            {
270                "name": "(lldbclient.py) Attach test",
271                "type": "lldb",
272                "processCreateCommands": [
273                    "gdb-remote 123",
274                    "test"
275                ]
276            }""")
277        self.assertEqual(gdbclient.insert_commands_into_vscode_config(dst,
278                                                                      to_insert),
279                         textwrap.dedent("""\
280                             {
281                               "version": "0.2.0",
282                               "configurations": [
283                                 // #lldbclient-generated-begin
284                                 {
285                                     "name": "(lldbclient.py) Attach test",
286                                     "type": "lldb",
287                                     "processCreateCommands": [
288                                         "gdb-remote 123",
289                                         "test"
290                                     ]
291                                 }
292                                 // #lldbclient-generated-end
293                               ]
294                             }
295                         """))
296
297    def test_preserve_tab_indent(self) -> None:
298        dst = textwrap.dedent("""\
299            {
300            \t"version": "0.2.0",
301            \t"configurations": [
302            \t\t// #lldbclient-generated-begin
303            \t\t// #lldbclient-generated-end
304            \t]
305            }
306        """)
307        to_insert = textwrap.dedent("""\
308            {
309            \t"name": "(lldbclient.py) Attach test",
310            \t"type": "lldb",
311            \t"processCreateCommands": [
312            \t\t"gdb-remote 123",
313            \t\t"test"
314            \t]
315            }""")
316        self.assertEqual(gdbclient.insert_commands_into_vscode_config(dst,
317                                                                      to_insert),
318                         textwrap.dedent("""\
319                            {
320                            \t"version": "0.2.0",
321                            \t"configurations": [
322                            \t\t// #lldbclient-generated-begin
323                            \t\t{
324                            \t\t\t"name": "(lldbclient.py) Attach test",
325                            \t\t\t"type": "lldb",
326                            \t\t\t"processCreateCommands": [
327                            \t\t\t\t"gdb-remote 123",
328                            \t\t\t\t"test"
329                            \t\t\t]
330                            \t\t}
331                            \t\t// #lldbclient-generated-end
332                            \t]
333                            }
334                         """))
335
336    def test_preserve_trailing_whitespace(self) -> None:
337        dst = textwrap.dedent("""\
338            // #lldbclient-generated-begin \t
339            // #lldbclient-generated-end\t """)
340        to_insert = 'foo'
341        self.assertEqual(gdbclient.insert_commands_into_vscode_config(dst,
342                                                                      to_insert),
343                         textwrap.dedent("""\
344                            // #lldbclient-generated-begin \t
345                            foo
346                            // #lldbclient-generated-end\t """))
347
348    def test_fail_if_no_begin(self) -> None:
349        dst = textwrap.dedent("""\
350            // #lldbclient-generated-end""")
351        with self.assertRaisesRegex(ValueError, 'Did not find begin marker line'):
352            gdbclient.insert_commands_into_vscode_config(dst, 'foo')
353
354    def test_fail_if_no_end(self) -> None:
355        dst = textwrap.dedent("""\
356            // #lldbclient-generated-begin""")
357        with self.assertRaisesRegex(ValueError, 'Unterminated begin marker at line 1'):
358            gdbclient.insert_commands_into_vscode_config(dst, 'foo')
359
360    def test_fail_if_begin_has_extra_text(self) -> None:
361        dst = textwrap.dedent("""\
362            // #lldbclient-generated-begin text
363            // #lldbclient-generated-end""")
364        with self.assertRaisesRegex(ValueError, 'Did not find begin marker line'):
365            gdbclient.insert_commands_into_vscode_config(dst, 'foo')
366
367    def test_fail_if_end_has_extra_text(self) -> None:
368        dst = textwrap.dedent("""\
369            // #lldbclient-generated-begin
370            // #lldbclient-generated-end text""")
371        with self.assertRaisesRegex(ValueError, 'Unterminated begin marker at line 1'):
372            gdbclient.insert_commands_into_vscode_config(dst, 'foo')
373
374    def test_fail_if_begin_end_swapped(self) -> None:
375        dst = textwrap.dedent("""\
376            // #lldbclient-generated-end
377            // #lldbclient-generated-begin""")
378        with self.assertRaisesRegex(ValueError, 'Unterminated begin marker at line 2'):
379            gdbclient.insert_commands_into_vscode_config(dst, 'foo')
380
381
382if __name__ == '__main__':
383    unittest.main(verbosity=2)
384