blob: 999bf74b0373499b8ce147272ec1ddcd037cbb85 [file] [log] [blame]
Nikita Putikhin9aa3bc62023-05-19 20:39:51 +00001#
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
Nikita Putikhin9aa3bc62023-05-19 20:39:51 +000017import copy
18import json
Nikita Putikhin7da179e2023-07-03 07:37:58 +000019import textwrap
20import unittest
Nikita Putikhin9aa3bc62023-05-19 20:39:51 +000021from typing import Any
22
Nikita Putikhin7da179e2023-07-03 07:37:58 +000023import gdbclient
24
25
Nikita Putikhin9aa3bc62023-05-19 20:39:51 +000026class 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
Nikita Putikhin7da179e2023-07-03 07:37:58 +0000166class 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
Nikita Putikhin9aa3bc62023-05-19 20:39:51 +0000382if __name__ == '__main__':
383 unittest.main(verbosity=2)