1""" 2Test lldb-vscode setBreakpoints request 3""" 4 5from __future__ import print_function 6 7import unittest2 8import vscode 9from lldbsuite.test.decorators import * 10from lldbsuite.test.lldbtest import * 11from lldbsuite.test import lldbutil 12import lldbvscode_testcase 13 14 15def make_buffer_verify_dict(start_idx, count, offset=0): 16 verify_dict = {} 17 for i in range(start_idx, start_idx + count): 18 verify_dict['[%i]' % (i)] = {'type': 'int', 'value': str(i+offset)} 19 return verify_dict 20 21 22class TestVSCode_variables(lldbvscode_testcase.VSCodeTestCaseBase): 23 24 mydir = TestBase.compute_mydir(__file__) 25 26 def verify_values(self, verify_dict, actual, varref_dict=None, expression=None): 27 if 'equals' in verify_dict: 28 verify = verify_dict['equals'] 29 for key in verify: 30 verify_value = verify[key] 31 actual_value = actual[key] 32 self.assertEqual(verify_value, actual_value, 33 '"%s" keys don\'t match (%s != %s)' % ( 34 key, actual_value, verify_value)) 35 if 'startswith' in verify_dict: 36 verify = verify_dict['startswith'] 37 for key in verify: 38 verify_value = verify[key] 39 actual_value = actual[key] 40 startswith = actual_value.startswith(verify_value) 41 self.assertTrue(startswith, 42 ('"%s" value "%s" doesn\'t start with' 43 ' "%s")') % ( 44 key, actual_value, 45 verify_value)) 46 hasVariablesReference = 'variablesReference' in actual 47 varRef = None 48 if hasVariablesReference: 49 # Remember variable references in case we want to test further 50 # by using the evaluate name. 51 varRef = actual["variablesReference"] 52 if varRef != 0 and varref_dict is not None: 53 if expression is None: 54 evaluateName = actual["evaluateName"] 55 else: 56 evaluateName = expression 57 varref_dict[evaluateName] = varRef 58 if ('hasVariablesReference' in verify_dict and 59 verify_dict['hasVariablesReference']): 60 self.assertTrue(hasVariablesReference, 61 "verify variable reference") 62 if 'children' in verify_dict: 63 self.assertTrue(hasVariablesReference and varRef is not None and 64 varRef != 0, 65 ("children verify values specified for " 66 "variable without children")) 67 68 response = self.vscode.request_variables(varRef) 69 self.verify_variables(verify_dict['children'], 70 response['body']['variables'], 71 varref_dict) 72 73 def verify_variables(self, verify_dict, variables, varref_dict=None): 74 for variable in variables: 75 name = variable['name'] 76 self.assertIn(name, verify_dict, 77 'variable "%s" in verify dictionary' % (name)) 78 self.verify_values(verify_dict[name], variable, varref_dict) 79 80 @skipIfWindows 81 @skipIfRemote 82 def test_scopes_variables_setVariable_evaluate(self): 83 ''' 84 Tests the "scopes", "variables", "setVariable", and "evaluate" 85 packets. 86 ''' 87 program = self.getBuildArtifact("a.out") 88 self.build_and_launch(program) 89 source = 'main.cpp' 90 breakpoint1_line = line_number(source, '// breakpoint 1') 91 lines = [breakpoint1_line] 92 # Set breakpoint in the thread function so we can step the threads 93 breakpoint_ids = self.set_source_breakpoints(source, lines) 94 self.assertEqual(len(breakpoint_ids), len(lines), 95 "expect correct number of breakpoints") 96 self.continue_to_breakpoints(breakpoint_ids) 97 locals = self.vscode.get_local_variables() 98 globals = self.vscode.get_global_variables() 99 buffer_children = make_buffer_verify_dict(0, 32) 100 verify_locals = { 101 'argc': { 102 'equals': {'type': 'int', 'value': '1'} 103 }, 104 'argv': { 105 'equals': {'type': 'const char **'}, 106 'startswith': {'value': '0x'}, 107 'hasVariablesReference': True 108 }, 109 'pt': { 110 'equals': {'type': 'PointType'}, 111 'hasVariablesReference': True, 112 'children': { 113 'x': {'equals': {'type': 'int', 'value': '11'}}, 114 'y': {'equals': {'type': 'int', 'value': '22'}}, 115 'buffer': {'children': buffer_children} 116 } 117 }, 118 'x': { 119 'equals': {'type': 'int'} 120 } 121 } 122 verify_globals = { 123 's_local': { 124 'equals': {'type': 'float', 'value': '2.25'} 125 }, 126 '::g_global': { 127 'equals': {'type': 'int', 'value': '123'} 128 }, 129 's_global': { 130 'equals': {'type': 'int', 'value': '234'} 131 }, 132 } 133 varref_dict = {} 134 self.verify_variables(verify_locals, locals, varref_dict) 135 self.verify_variables(verify_globals, globals, varref_dict) 136 # pprint.PrettyPrinter(indent=4).pprint(varref_dict) 137 # We need to test the functionality of the "variables" request as it 138 # has optional parameters like "start" and "count" to limit the number 139 # of variables that are fetched 140 varRef = varref_dict['pt.buffer'] 141 response = self.vscode.request_variables(varRef) 142 self.verify_variables(buffer_children, response['body']['variables']) 143 # Verify setting start=0 in the arguments still gets all children 144 response = self.vscode.request_variables(varRef, start=0) 145 self.verify_variables(buffer_children, response['body']['variables']) 146 # Verify setting count=0 in the arguments still gets all children. 147 # If count is zero, it means to get all children. 148 response = self.vscode.request_variables(varRef, count=0) 149 self.verify_variables(buffer_children, response['body']['variables']) 150 # Verify setting count to a value that is too large in the arguments 151 # still gets all children, and no more 152 response = self.vscode.request_variables(varRef, count=1000) 153 self.verify_variables(buffer_children, response['body']['variables']) 154 # Verify setting the start index and count gets only the children we 155 # want 156 response = self.vscode.request_variables(varRef, start=5, count=5) 157 self.verify_variables(make_buffer_verify_dict(5, 5), 158 response['body']['variables']) 159 # Verify setting the start index to a value that is out of range 160 # results in an empty list 161 response = self.vscode.request_variables(varRef, start=32, count=1) 162 self.assertEqual(len(response['body']['variables']), 0, 163 'verify we get no variable back for invalid start') 164 165 # Test evaluate 166 expressions = { 167 'pt.x': { 168 'equals': {'result': '11', 'type': 'int'}, 169 'hasVariablesReference': False 170 }, 171 'pt.buffer[2]': { 172 'equals': {'result': '2', 'type': 'int'}, 173 'hasVariablesReference': False 174 }, 175 'pt': { 176 'equals': {'type': 'PointType'}, 177 'startswith': {'result': 'PointType @ 0x'}, 178 'hasVariablesReference': True 179 }, 180 'pt.buffer': { 181 'equals': {'type': 'int[32]'}, 182 'startswith': {'result': 'int[32] @ 0x'}, 183 'hasVariablesReference': True 184 }, 185 'argv': { 186 'equals': {'type': 'const char **'}, 187 'startswith': {'result': '0x'}, 188 'hasVariablesReference': True 189 }, 190 'argv[0]': { 191 'equals': {'type': 'const char *'}, 192 'startswith': {'result': '0x'}, 193 'hasVariablesReference': True 194 }, 195 '2+3': { 196 'equals': {'result': '5', 'type': 'int'}, 197 'hasVariablesReference': False 198 }, 199 } 200 for expression in expressions: 201 response = self.vscode.request_evaluate(expression) 202 self.verify_values(expressions[expression], response['body']) 203 204 # Test setting variables 205 self.set_local('argc', 123) 206 argc = self.get_local_as_int('argc') 207 self.assertEqual(argc, 123, 208 'verify argc was set to 123 (123 != %i)' % (argc)) 209 210 self.set_local('argv', 0x1234) 211 argv = self.get_local_as_int('argv') 212 self.assertEqual(argv, 0x1234, 213 'verify argv was set to 0x1234 (0x1234 != %#x)' % ( 214 argv)) 215 216 # Set a variable value whose name is synthetic, like a variable index 217 # and verify the value by reading it 218 self.vscode.request_setVariable(varRef, "[0]", 100) 219 response = self.vscode.request_variables(varRef, start=0, count=1) 220 self.verify_variables(make_buffer_verify_dict(0, 1, 100), 221 response['body']['variables']) 222 223 # Set a variable value whose name is a real child value, like "pt.x" 224 # and verify the value by reading it 225 varRef = varref_dict['pt'] 226 self.vscode.request_setVariable(varRef, "x", 111) 227 response = self.vscode.request_variables(varRef, start=0, count=1) 228 value = response['body']['variables'][0]['value'] 229 self.assertEqual(value, '111', 230 'verify pt.x got set to 111 (111 != %s)' % (value)) 231 232 # We check shadowed variables and that a new get_local_variables request 233 # gets the right data 234 breakpoint2_line = line_number(source, '// breakpoint 2') 235 lines = [breakpoint2_line] 236 breakpoint_ids = self.set_source_breakpoints(source, lines) 237 self.assertEqual(len(breakpoint_ids), len(lines), 238 "expect correct number of breakpoints") 239 self.continue_to_breakpoints(breakpoint_ids) 240 241 verify_locals['argc']['equals']['value'] = '123' 242 verify_locals['pt']['children']['x']['equals']['value'] = '111' 243 verify_locals['x @ main.cpp:17'] = {'equals': {'type': 'int', 'value': '89'}} 244 verify_locals['x @ main.cpp:19'] = {'equals': {'type': 'int', 'value': '42'}} 245 verify_locals['x @ main.cpp:21'] = {'equals': {'type': 'int', 'value': '72'}} 246 247 self.verify_variables(verify_locals, self.vscode.get_local_variables()) 248 249 # Now we verify that we correctly change the name of a variable with and without differentiator suffix 250 self.assertFalse(self.vscode.request_setVariable(1, "x2", 9)['success']) 251 self.assertFalse(self.vscode.request_setVariable(1, "x @ main.cpp:0", 9)['success']) 252 253 self.assertTrue(self.vscode.request_setVariable(1, "x @ main.cpp:17", 17)['success']) 254 self.assertTrue(self.vscode.request_setVariable(1, "x @ main.cpp:19", 19)['success']) 255 self.assertTrue(self.vscode.request_setVariable(1, "x @ main.cpp:21", 21)['success']) 256 257 # The following should have no effect 258 self.assertFalse(self.vscode.request_setVariable(1, "x @ main.cpp:21", "invalid")['success']) 259 260 verify_locals['x @ main.cpp:17']['equals']['value'] = '17' 261 verify_locals['x @ main.cpp:19']['equals']['value'] = '19' 262 verify_locals['x @ main.cpp:21']['equals']['value'] = '21' 263 264 self.verify_variables(verify_locals, self.vscode.get_local_variables()) 265 266 # The plain x variable shold refer to the innermost x 267 self.assertTrue(self.vscode.request_setVariable(1, "x", 22)['success']) 268 verify_locals['x @ main.cpp:21']['equals']['value'] = '22' 269 270 self.verify_variables(verify_locals, self.vscode.get_local_variables()) 271 272 # In breakpoint 3, there should be no shadowed variables 273 breakpoint3_line = line_number(source, '// breakpoint 3') 274 lines = [breakpoint3_line] 275 breakpoint_ids = self.set_source_breakpoints(source, lines) 276 self.assertEqual(len(breakpoint_ids), len(lines), 277 "expect correct number of breakpoints") 278 self.continue_to_breakpoints(breakpoint_ids) 279 280 locals = self.vscode.get_local_variables() 281 names = [var['name'] for var in locals] 282 # The first shadowed x shouldn't have a suffix anymore 283 verify_locals['x'] = {'equals': {'type': 'int', 'value': '17'}} 284 self.assertNotIn('x @ main.cpp:17', names) 285 self.assertNotIn('x @ main.cpp:19', names) 286 self.assertNotIn('x @ main.cpp:21', names) 287 288 self.verify_variables(verify_locals, locals) 289 290 @skipIfWindows 291 @skipIfRemote 292 def test_scopes_and_evaluate_expansion(self): 293 """ 294 Tests the evaluated expression expands successfully after "scopes" packets 295 and permanent expressions persist. 296 """ 297 program = self.getBuildArtifact("a.out") 298 self.build_and_launch(program) 299 source = "main.cpp" 300 breakpoint1_line = line_number(source, "// breakpoint 1") 301 lines = [breakpoint1_line] 302 # Set breakpoint in the thread function so we can step the threads 303 breakpoint_ids = self.set_source_breakpoints(source, lines) 304 self.assertEqual( 305 len(breakpoint_ids), len(lines), "expect correct number of breakpoints" 306 ) 307 self.continue_to_breakpoints(breakpoint_ids) 308 309 # Verify locals 310 locals = self.vscode.get_local_variables() 311 buffer_children = make_buffer_verify_dict(0, 32) 312 verify_locals = { 313 "argc": {"equals": {"type": "int", "value": "1"}}, 314 "argv": { 315 "equals": {"type": "const char **"}, 316 "startswith": {"value": "0x"}, 317 "hasVariablesReference": True, 318 }, 319 "pt": { 320 "equals": {"type": "PointType"}, 321 "hasVariablesReference": True, 322 "children": { 323 "x": {"equals": {"type": "int", "value": "11"}}, 324 "y": {"equals": {"type": "int", "value": "22"}}, 325 "buffer": {"children": buffer_children}, 326 }, 327 }, 328 "x": {"equals": {"type": "int"}}, 329 } 330 self.verify_variables(verify_locals, locals) 331 332 # Evaluate expandable expression twice: once permanent (from repl) 333 # the other temporary (from other UI). 334 expandable_expression = { 335 "name": "pt", 336 "response": { 337 "equals": {"type": "PointType"}, 338 "startswith": {"result": "PointType @ 0x"}, 339 "hasVariablesReference": True, 340 }, 341 "children": { 342 "x": {"equals": {"type": "int", "value": "11"}}, 343 "y": {"equals": {"type": "int", "value": "22"}}, 344 "buffer": {"children": buffer_children}, 345 }, 346 } 347 348 # Evaluate from permanent UI. 349 permanent_expr_varref_dict = {} 350 response = self.vscode.request_evaluate( 351 expandable_expression["name"], frameIndex=0, threadId=None, context="repl" 352 ) 353 self.verify_values( 354 expandable_expression["response"], 355 response["body"], 356 permanent_expr_varref_dict, 357 expandable_expression["name"], 358 ) 359 360 # Evaluate from temporary UI. 361 temporary_expr_varref_dict = {} 362 response = self.vscode.request_evaluate(expandable_expression["name"]) 363 self.verify_values( 364 expandable_expression["response"], 365 response["body"], 366 temporary_expr_varref_dict, 367 expandable_expression["name"], 368 ) 369 370 # Evaluate locals again. 371 locals = self.vscode.get_local_variables() 372 self.verify_variables(verify_locals, locals) 373 374 # Verify the evaluated expressions before second locals evaluation 375 # can be expanded. 376 var_ref = temporary_expr_varref_dict[expandable_expression["name"]] 377 response = self.vscode.request_variables(var_ref) 378 self.verify_variables( 379 expandable_expression["children"], response["body"]["variables"] 380 ) 381 382 # Continue to breakpoint 3, permanent variable should still exist 383 # after resume. 384 breakpoint3_line = line_number(source, "// breakpoint 3") 385 lines = [breakpoint3_line] 386 breakpoint_ids = self.set_source_breakpoints(source, lines) 387 self.assertEqual( 388 len(breakpoint_ids), len(lines), "expect correct number of breakpoints" 389 ) 390 self.continue_to_breakpoints(breakpoint_ids) 391 392 var_ref = permanent_expr_varref_dict[expandable_expression["name"]] 393 response = self.vscode.request_variables(var_ref) 394 self.verify_variables( 395 expandable_expression["children"], response["body"]["variables"] 396 ) 397 398 # Test that frame scopes have corresponding presentation hints. 399 frame_id = self.vscode.get_stackFrame()["id"] 400 scopes = self.vscode.request_scopes(frame_id)["body"]["scopes"] 401 402 scope_names = [scope["name"] for scope in scopes] 403 self.assertIn("Locals", scope_names) 404 self.assertIn("Registers", scope_names) 405 406 for scope in scopes: 407 if scope["name"] == "Locals": 408 self.assertEquals(scope.get("presentationHint"), "locals") 409 if scope["name"] == "Registers": 410 self.assertEquals(scope.get("presentationHint"), "registers") 411