1""" 2Test lldb-vscode setBreakpoints request 3""" 4 5 6import unittest2 7import vscode 8from lldbsuite.test.decorators import * 9from lldbsuite.test.lldbtest import * 10from lldbsuite.test import lldbutil 11import lldbvscode_testcase 12import time 13import os 14 15 16class TestVSCode_launch(lldbvscode_testcase.VSCodeTestCaseBase): 17 18 mydir = TestBase.compute_mydir(__file__) 19 20 @skipIfWindows 21 @skipIfDarwin # Flaky 22 @skipIfRemote 23 def test_default(self): 24 ''' 25 Tests the default launch of a simple program. No arguments, 26 environment, or anything else is specified. 27 ''' 28 program = self.getBuildArtifact("a.out") 29 self.build_and_launch(program) 30 self.continue_to_exit() 31 # Now get the STDOUT and verify our program argument is correct 32 output = self.get_stdout() 33 self.assertTrue(output and len(output) > 0, 34 "expect program output") 35 lines = output.splitlines() 36 self.assertTrue(program in lines[0], 37 "make sure program path is in first argument") 38 39 @skipIfWindows 40 @skipIfRemote 41 def test_termination(self): 42 ''' 43 Tests the correct termination of lldb-vscode upon a 'disconnect' 44 request. 45 ''' 46 self.create_debug_adaptor() 47 # The underlying lldb-vscode process must be alive 48 self.assertEqual(self.vscode.process.poll(), None) 49 50 # The lldb-vscode process should finish even though 51 # we didn't close the communication socket explicitly 52 self.vscode.request_disconnect() 53 54 # Wait until the underlying lldb-vscode process dies. 55 # We need to do this because the popen.wait function in python2.7 56 # doesn't have a timeout argument. 57 for _ in range(10): 58 time.sleep(1) 59 if self.vscode.process.poll() is not None: 60 break 61 # Check the return code 62 self.assertEqual(self.vscode.process.poll(), 0) 63 64 @skipIfWindows 65 @skipIfRemote 66 def test_stopOnEntry(self): 67 ''' 68 Tests the default launch of a simple program that stops at the 69 entry point instead of continuing. 70 ''' 71 program = self.getBuildArtifact("a.out") 72 self.build_and_launch(program, stopOnEntry=True) 73 self.set_function_breakpoints(['main']) 74 stopped_events = self.continue_to_next_stop() 75 for stopped_event in stopped_events: 76 if 'body' in stopped_event: 77 body = stopped_event['body'] 78 if 'reason' in body: 79 reason = body['reason'] 80 self.assertTrue( 81 reason != 'breakpoint', 82 'verify stop isn\'t "main" breakpoint') 83 84 @skipIfWindows 85 @skipIfRemote 86 def test_cwd(self): 87 ''' 88 Tests the default launch of a simple program with a current working 89 directory. 90 ''' 91 program = self.getBuildArtifact("a.out") 92 program_parent_dir = os.path.realpath( 93 os.path.dirname(os.path.dirname(program))) 94 self.build_and_launch(program, 95 cwd=program_parent_dir) 96 self.continue_to_exit() 97 # Now get the STDOUT and verify our program argument is correct 98 output = self.get_stdout() 99 self.assertTrue(output and len(output) > 0, 100 "expect program output") 101 lines = output.splitlines() 102 found = False 103 for line in lines: 104 if line.startswith('cwd = \"'): 105 quote_path = '"%s"' % (program_parent_dir) 106 found = True 107 self.assertTrue(quote_path in line, 108 "working directory '%s' not in '%s'" % ( 109 program_parent_dir, line)) 110 self.assertTrue(found, "verified program working directory") 111 112 @skipIfWindows 113 @skipIfRemote 114 def test_debuggerRoot(self): 115 ''' 116 Tests the "debuggerRoot" will change the working directory of 117 the lldb-vscode debug adaptor. 118 ''' 119 program = self.getBuildArtifact("a.out") 120 program_parent_dir = os.path.realpath( 121 os.path.dirname(os.path.dirname(program))) 122 commands = ['platform shell echo cwd = $PWD'] 123 self.build_and_launch(program, 124 debuggerRoot=program_parent_dir, 125 initCommands=commands) 126 output = self.get_console() 127 self.assertTrue(output and len(output) > 0, 128 "expect console output") 129 lines = output.splitlines() 130 prefix = 'cwd = ' 131 found = False 132 for line in lines: 133 if line.startswith(prefix): 134 found = True 135 self.assertEquals(program_parent_dir, line[len(prefix):], 136 "lldb-vscode working dir '%s' == '%s'" % ( 137 program_parent_dir, line[6:])) 138 self.assertTrue(found, "verified lldb-vscode working directory") 139 self.continue_to_exit() 140 141 @skipIfWindows 142 @skipIfRemote 143 def test_sourcePath(self): 144 ''' 145 Tests the "sourcePath" will set the target.source-map. 146 ''' 147 program = self.getBuildArtifact("a.out") 148 program_dir = os.path.dirname(program) 149 self.build_and_launch(program, 150 sourcePath=program_dir) 151 output = self.get_console() 152 self.assertTrue(output and len(output) > 0, 153 "expect console output") 154 lines = output.splitlines() 155 prefix = '(lldb) settings set target.source-map "." ' 156 found = False 157 for line in lines: 158 if line.startswith(prefix): 159 found = True 160 quoted_path = '"%s"' % (program_dir) 161 self.assertEquals(quoted_path, line[len(prefix):], 162 "lldb-vscode working dir %s == %s" % ( 163 quoted_path, line[6:])) 164 self.assertTrue(found, 'found "sourcePath" in console output') 165 self.continue_to_exit() 166 167 @skipIfWindows 168 @skipIfRemote 169 def test_disableSTDIO(self): 170 ''' 171 Tests the default launch of a simple program with STDIO disabled. 172 ''' 173 program = self.getBuildArtifact("a.out") 174 self.build_and_launch(program, 175 disableSTDIO=True) 176 self.continue_to_exit() 177 # Now get the STDOUT and verify our program argument is correct 178 output = self.get_stdout() 179 self.assertEquals(output, None, 180 "expect no program output") 181 182 @skipIfWindows 183 @skipIfLinux # shell argument expansion doesn't seem to work on Linux 184 @expectedFailureNetBSD 185 @skipIfRemote 186 def test_shellExpandArguments_enabled(self): 187 ''' 188 Tests the default launch of a simple program with shell expansion 189 enabled. 190 ''' 191 program = self.getBuildArtifact("a.out") 192 program_dir = os.path.dirname(program) 193 glob = os.path.join(program_dir, '*.out') 194 self.build_and_launch(program, args=[glob], shellExpandArguments=True) 195 self.continue_to_exit() 196 # Now get the STDOUT and verify our program argument is correct 197 output = self.get_stdout() 198 self.assertTrue(output and len(output) > 0, 199 "expect no program output") 200 lines = output.splitlines() 201 for line in lines: 202 quote_path = '"%s"' % (program) 203 if line.startswith("arg[1] ="): 204 self.assertTrue(quote_path in line, 205 'verify "%s" expanded to "%s"' % ( 206 glob, program)) 207 208 @skipIfWindows 209 @skipIfRemote 210 def test_shellExpandArguments_disabled(self): 211 ''' 212 Tests the default launch of a simple program with shell expansion 213 disabled. 214 ''' 215 program = self.getBuildArtifact("a.out") 216 program_dir = os.path.dirname(program) 217 glob = os.path.join(program_dir, '*.out') 218 self.build_and_launch(program, 219 args=[glob], 220 shellExpandArguments=False) 221 self.continue_to_exit() 222 # Now get the STDOUT and verify our program argument is correct 223 output = self.get_stdout() 224 self.assertTrue(output and len(output) > 0, 225 "expect no program output") 226 lines = output.splitlines() 227 for line in lines: 228 quote_path = '"%s"' % (glob) 229 if line.startswith("arg[1] ="): 230 self.assertTrue(quote_path in line, 231 'verify "%s" stayed to "%s"' % ( 232 glob, glob)) 233 234 @skipIfWindows 235 @skipIfRemote 236 def test_args(self): 237 ''' 238 Tests launch of a simple program with arguments 239 ''' 240 program = self.getBuildArtifact("a.out") 241 args = ["one", "with space", "'with single quotes'", 242 '"with double quotes"'] 243 self.build_and_launch(program, 244 args=args) 245 self.continue_to_exit() 246 247 # Now get the STDOUT and verify our arguments got passed correctly 248 output = self.get_stdout() 249 self.assertTrue(output and len(output) > 0, 250 "expect program output") 251 lines = output.splitlines() 252 # Skip the first argument that contains the program name 253 lines.pop(0) 254 # Make sure arguments we specified are correct 255 for (i, arg) in enumerate(args): 256 quoted_arg = '"%s"' % (arg) 257 self.assertTrue(quoted_arg in lines[i], 258 'arg[%i] "%s" not in "%s"' % (i+1, quoted_arg, lines[i])) 259 260 @skipIfWindows 261 @skipIfRemote 262 def test_environment(self): 263 ''' 264 Tests launch of a simple program with environment variables 265 ''' 266 program = self.getBuildArtifact("a.out") 267 env = ["NO_VALUE", "WITH_VALUE=BAR", "EMPTY_VALUE=", 268 "SPACE=Hello World"] 269 self.build_and_launch(program, 270 env=env) 271 self.continue_to_exit() 272 273 # Now get the STDOUT and verify our arguments got passed correctly 274 output = self.get_stdout() 275 self.assertTrue(output and len(output) > 0, 276 "expect program output") 277 lines = output.splitlines() 278 # Skip the all arguments so we have only environment vars left 279 while len(lines) and lines[0].startswith("arg["): 280 lines.pop(0) 281 # Make sure each environment variable in "env" is actually set in the 282 # program environment that was printed to STDOUT 283 for var in env: 284 found = False 285 for program_var in lines: 286 if var in program_var: 287 found = True 288 break 289 self.assertTrue(found, 290 '"%s" must exist in program environment (%s)' % ( 291 var, lines)) 292 293 @skipIfWindows 294 @skipIfRemote 295 def test_commands(self): 296 ''' 297 Tests the "initCommands", "preRunCommands", "stopCommands" and 298 "exitCommands" that can be passed during launch. 299 300 "initCommands" are a list of LLDB commands that get executed 301 before the targt is created. 302 "preRunCommands" are a list of LLDB commands that get executed 303 after the target has been created and before the launch. 304 "stopCommands" are a list of LLDB commands that get executed each 305 time the program stops. 306 "exitCommands" are a list of LLDB commands that get executed when 307 the process exits 308 ''' 309 program = self.getBuildArtifact("a.out") 310 initCommands = ['target list', 'platform list'] 311 preRunCommands = ['image list a.out', 'image dump sections a.out'] 312 stopCommands = ['frame variable', 'bt'] 313 exitCommands = ['expr 2+3', 'expr 3+4'] 314 self.build_and_launch(program, 315 initCommands=initCommands, 316 preRunCommands=preRunCommands, 317 stopCommands=stopCommands, 318 exitCommands=exitCommands) 319 320 # Get output from the console. This should contain both the 321 # "initCommands" and the "preRunCommands". 322 output = self.get_console() 323 # Verify all "initCommands" were found in console output 324 self.verify_commands('initCommands', output, initCommands) 325 # Verify all "preRunCommands" were found in console output 326 self.verify_commands('preRunCommands', output, preRunCommands) 327 328 source = 'main.c' 329 first_line = line_number(source, '// breakpoint 1') 330 second_line = line_number(source, '// breakpoint 2') 331 lines = [first_line, second_line] 332 333 # Set 2 breakoints so we can verify that "stopCommands" get run as the 334 # breakpoints get hit 335 breakpoint_ids = self.set_source_breakpoints(source, lines) 336 self.assertEquals(len(breakpoint_ids), len(lines), 337 "expect correct number of breakpoints") 338 339 # Continue after launch and hit the first breakpoint. 340 # Get output from the console. This should contain both the 341 # "stopCommands" that were run after the first breakpoint was hit 342 self.continue_to_breakpoints(breakpoint_ids) 343 output = self.get_console(timeout=1.0) 344 self.verify_commands('stopCommands', output, stopCommands) 345 346 # Continue again and hit the second breakpoint. 347 # Get output from the console. This should contain both the 348 # "stopCommands" that were run after the second breakpoint was hit 349 self.continue_to_breakpoints(breakpoint_ids) 350 output = self.get_console(timeout=1.0) 351 self.verify_commands('stopCommands', output, stopCommands) 352 353 # Continue until the program exits 354 self.continue_to_exit() 355 # Get output from the console. This should contain both the 356 # "exitCommands" that were run after the second breakpoint was hit 357 output = self.get_console(timeout=1.0) 358 self.verify_commands('exitCommands', output, exitCommands) 359 360 @skipIfWindows 361 @skipIfRemote 362 def test_extra_launch_commands(self): 363 ''' 364 Tests the "luanchCommands" with extra launching settings 365 ''' 366 self.build_and_create_debug_adaptor() 367 program = self.getBuildArtifact("a.out") 368 369 source = 'main.c' 370 first_line = line_number(source, '// breakpoint 1') 371 second_line = line_number(source, '// breakpoint 2') 372 # Set target binary and 2 breakoints 373 # then we can varify the "launchCommands" get run 374 # also we can verify that "stopCommands" get run as the 375 # breakpoints get hit 376 launchCommands = [ 377 'target create "%s"' % (program), 378 'br s -f main.c -l %d' % first_line, 379 'br s -f main.c -l %d' % second_line, 380 'process launch --stop-at-entry' 381 ] 382 383 initCommands = ['target list', 'platform list'] 384 preRunCommands = ['image list a.out', 'image dump sections a.out'] 385 stopCommands = ['frame variable', 'bt'] 386 exitCommands = ['expr 2+3', 'expr 3+4'] 387 self.launch(program, 388 initCommands=initCommands, 389 preRunCommands=preRunCommands, 390 stopCommands=stopCommands, 391 exitCommands=exitCommands, 392 launchCommands=launchCommands) 393 394 # Get output from the console. This should contain both the 395 # "initCommands" and the "preRunCommands". 396 output = self.get_console() 397 # Verify all "initCommands" were found in console output 398 self.verify_commands('initCommands', output, initCommands) 399 # Verify all "preRunCommands" were found in console output 400 self.verify_commands('preRunCommands', output, preRunCommands) 401 402 # Verify all "launchCommands" were founc in console output 403 # After execution, program should launch 404 self.verify_commands('launchCommands', output, launchCommands) 405 # Verify the "stopCommands" here 406 self.continue_to_next_stop() 407 output = self.get_console(timeout=1.0) 408 self.verify_commands('stopCommands', output, stopCommands) 409 410 # Continue and hit the second breakpoint. 411 # Get output from the console. This should contain both the 412 # "stopCommands" that were run after the first breakpoint was hit 413 self.continue_to_next_stop() 414 output = self.get_console(timeout=1.0) 415 self.verify_commands('stopCommands', output, stopCommands) 416 417 # Continue until the program exits 418 self.continue_to_exit() 419 # Get output from the console. This should contain both the 420 # "exitCommands" that were run after the second breakpoint was hit 421 output = self.get_console(timeout=1.0) 422 self.verify_commands('exitCommands', output, exitCommands) 423