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