271 lines · python
1"""2Test lldb-dap completions request3"""4 5import lldbdap_testcase6import dap_server7from lldbsuite.test import lldbutil8from lldbsuite.test.decorators import *9from lldbsuite.test.lldbtest import *10 11session_completion = {12 "text": "session",13 "label": "session -- Commands controlling LLDB session.",14}15settings_completion = {16 "text": "settings",17 "label": "settings -- Commands for managing LLDB settings.",18}19memory_completion = {20 "text": "memory",21 "label": "memory -- Commands for operating on memory in the current target process.",22}23command_var_completion = {24 "text": "var",25 "label": "var -- Show variables for the current stack frame. Defaults to all arguments and local variables in scope. Names of argument, local, file static and file global variables can be specified.",26}27variable_var_completion = {28 "text": "var",29 "label": "var -- vector<baz> &",30}31variable_var1_completion = {"text": "var1", "label": "var1 -- int &"}32variable_var2_completion = {"text": "var2", "label": "var2 -- int &"}33 34 35# Older version of libcxx produce slightly different typename strings for36# templates like vector.37@skipIf(compiler="clang", compiler_version=["<", "16.0"])38class TestDAP_completions(lldbdap_testcase.DAPTestCaseBase):39 def verify_completions(self, actual_list, expected_list, not_expected_list=[]):40 for expected_item in expected_list:41 self.assertIn(expected_item, actual_list)42 43 for not_expected_item in not_expected_list:44 self.assertNotIn(not_expected_item, actual_list)45 46 def setup_debuggee(self):47 program = self.getBuildArtifact("a.out")48 source = "main.cpp"49 self.build_and_launch(program)50 self.set_source_breakpoints(51 source,52 [53 line_number(source, "// breakpoint 1"),54 line_number(source, "// breakpoint 2"),55 ],56 )57 58 def test_command_completions(self):59 """60 Tests completion requests for lldb commands, within "repl-mode=command"61 """62 self.setup_debuggee()63 self.continue_to_next_stop()64 65 res = self.dap_server.request_evaluate(66 "`lldb-dap repl-mode command", context="repl"67 )68 self.assertTrue(res["success"])69 70 # Provides completion for top-level commands71 self.verify_completions(72 self.dap_server.get_completions("se"),73 [session_completion, settings_completion],74 )75 76 # Provides completions for sub-commands77 self.verify_completions(78 self.dap_server.get_completions("memory "),79 [80 {81 "text": "read",82 "label": "read -- Read from the memory of the current target process.",83 },84 {85 "text": "region",86 "label": "region -- Get information on the memory region containing an address in the current target process.",87 },88 ],89 )90 91 # Provides completions for parameter values of commands92 self.verify_completions(93 self.dap_server.get_completions("`log enable "),94 [{"text": "gdb-remote", "label": "gdb-remote"}],95 )96 97 # Also works if the escape prefix is used98 self.verify_completions(99 self.dap_server.get_completions("`mem"), [memory_completion]100 )101 102 self.verify_completions(103 self.dap_server.get_completions("`"),104 [session_completion, settings_completion, memory_completion],105 )106 107 # Completes an incomplete quoted token108 self.verify_completions(109 self.dap_server.get_completions('setting "se'),110 [111 {112 "text": "set",113 "label": "set -- Set the value of the specified debugger setting.",114 }115 ],116 )117 118 # Completes an incomplete quoted token119 self.verify_completions(120 self.dap_server.get_completions("'mem"),121 [memory_completion],122 )123 124 # Completes expressions with quotes inside125 self.verify_completions(126 self.dap_server.get_completions('expr " "; typed'),127 [{"text": "typedef", "label": "typedef"}],128 )129 130 # Provides completions for commands, but not variables131 self.verify_completions(132 self.dap_server.get_completions("var"),133 [command_var_completion],134 [variable_var_completion],135 )136 137 def test_variable_completions(self):138 """139 Tests completion requests in "repl-mode=variable"140 """141 self.setup_debuggee()142 self.continue_to_next_stop()143 144 res = self.dap_server.request_evaluate(145 "`lldb-dap repl-mode variable", context="repl"146 )147 self.assertTrue(res["success"])148 149 # Provides completions for varibles, but not command150 self.verify_completions(151 self.dap_server.get_completions("var"),152 [variable_var_completion],153 [command_var_completion],154 )155 156 # We stopped inside `fun`, so we shouldn't see variables from main157 self.verify_completions(158 self.dap_server.get_completions("var"),159 [variable_var_completion],160 [161 variable_var1_completion,162 variable_var2_completion,163 ],164 )165 166 # We should see global keywords but not variables inside main167 self.verify_completions(168 self.dap_server.get_completions("str"),169 [{"text": "struct", "label": "struct"}],170 [{"text": "str1", "label": "str1 -- std::string &"}],171 )172 173 self.continue_to_next_stop()174 175 # We stopped in `main`, so we should see variables from main but176 # not from the other function177 self.verify_completions(178 self.dap_server.get_completions("var"),179 [180 variable_var1_completion,181 variable_var2_completion,182 ],183 [184 variable_var_completion,185 ],186 )187 188 self.verify_completions(189 self.dap_server.get_completions("str"),190 [191 {"text": "struct", "label": "struct"},192 {"text": "str1", "label": "str1 -- std::string &"},193 ],194 )195 196 # Completion also works for more complex expressions197 self.verify_completions(198 self.dap_server.get_completions("foo1.v"),199 [{"text": "var1", "label": "foo1.var1 -- int"}],200 )201 202 self.verify_completions(203 self.dap_server.get_completions("foo1.my_bar_object.v"),204 [{"text": "var1", "label": "foo1.my_bar_object.var1 -- int"}],205 )206 207 self.verify_completions(208 self.dap_server.get_completions("foo1.var1 + foo1.v"),209 [{"text": "var1", "label": "foo1.var1 -- int"}],210 )211 212 self.verify_completions(213 self.dap_server.get_completions("foo1.var1 + v"),214 [{"text": "var1", "label": "var1 -- int &"}],215 )216 217 # should correctly handle spaces between objects and member operators218 self.verify_completions(219 self.dap_server.get_completions("foo1 .v"),220 [{"text": "var1", "label": ".var1 -- int"}],221 [{"text": "var2", "label": ".var2 -- int"}],222 )223 224 self.verify_completions(225 self.dap_server.get_completions("foo1 . v"),226 [{"text": "var1", "label": "var1 -- int"}],227 [{"text": "var2", "label": "var2 -- int"}],228 )229 230 # Even in variable mode, we can still use the escape prefix231 self.verify_completions(232 self.dap_server.get_completions("`mem"), [memory_completion]233 )234 235 def test_auto_completions(self):236 """237 Tests completion requests in "repl-mode=auto"238 """239 self.setup_debuggee()240 241 res = self.dap_server.request_evaluate(242 "`lldb-dap repl-mode auto", context="repl"243 )244 self.assertTrue(res["success"])245 246 self.continue_to_next_stop()247 self.continue_to_next_stop()248 249 # We are stopped inside `main`. Variables `var1` and `var2` are in scope.250 # Make sure, we offer all completions251 self.verify_completions(252 self.dap_server.get_completions("va"),253 [254 command_var_completion,255 variable_var1_completion,256 variable_var2_completion,257 ],258 )259 260 # If we are using the escape prefix, only commands are suggested, but no variables261 self.verify_completions(262 self.dap_server.get_completions("`va"),263 [264 command_var_completion,265 ],266 [267 variable_var1_completion,268 variable_var2_completion,269 ],270 )271