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