1""" 2Test lldb Python API for file handles. 3""" 4 5 6import os 7import io 8import re 9import sys 10from contextlib import contextmanager 11 12import lldb 13from lldbsuite.test import lldbtest 14from lldbsuite.test.decorators import * 15 16class OhNoe(Exception): 17 pass 18 19class BadIO(io.TextIOBase): 20 @property 21 def closed(self): 22 return False 23 def writable(self): 24 return True 25 def readable(self): 26 return True 27 def write(self, s): 28 raise OhNoe('OH NOE') 29 def read(self, n): 30 raise OhNoe("OH NOE") 31 def flush(self): 32 raise OhNoe('OH NOE') 33 34# This class will raise an exception while it's being 35# converted into a C++ object by swig 36class ReallyBadIO(io.TextIOBase): 37 def fileno(self): 38 return 999 39 def writable(self): 40 raise OhNoe("OH NOE!!!") 41 42class MutableBool(): 43 def __init__(self, value): 44 self.value = value 45 def set(self, value): 46 self.value = bool(value) 47 def __bool__(self): 48 return self.value 49 50class FlushTestIO(io.StringIO): 51 def __init__(self, mutable_flushed, mutable_closed): 52 super(FlushTestIO, self).__init__() 53 self.mut_flushed = mutable_flushed 54 self.mut_closed = mutable_closed 55 def close(self): 56 self.mut_closed.set(True) 57 return super(FlushTestIO, self).close() 58 def flush(self): 59 self.mut_flushed.set(True) 60 return super(FlushTestIO, self).flush() 61 62@contextmanager 63def replace_stdout(new): 64 old = sys.stdout 65 sys.stdout = new 66 try: 67 yield 68 finally: 69 sys.stdout = old 70 71def readStrippedLines(f): 72 def i(): 73 for line in f: 74 line = line.strip() 75 if line: 76 yield line 77 return list(i()) 78 79 80class FileHandleTestCase(lldbtest.TestBase): 81 82 NO_DEBUG_INFO_TESTCASE = True 83 mydir = lldbtest.Base.compute_mydir(__file__) 84 85 # The way normal tests evaluate debugger commands is 86 # by using a SBCommandInterpreter directly, which captures 87 # the output in a result object. For many of tests tests 88 # we want the debugger to write the output directly to 89 # its I/O streams like it would have done interactively. 90 # 91 # For this reason we also define handleCmd() here, even though 92 # it is similar to runCmd(). 93 94 def setUp(self): 95 super(FileHandleTestCase, self).setUp() 96 self.out_filename = self.getBuildArtifact('output') 97 self.in_filename = self.getBuildArtifact('input') 98 99 def tearDown(self): 100 super(FileHandleTestCase, self).tearDown() 101 for name in (self.out_filename, self.in_filename): 102 if os.path.exists(name): 103 os.unlink(name) 104 105 # Similar to runCmd(), but letting the debugger just print the results 106 # instead of collecting them. 107 def handleCmd(self, cmd, check=True, collect_result=True): 108 assert not check or collect_result 109 ret = lldb.SBCommandReturnObject() 110 if collect_result: 111 interpreter = self.dbg.GetCommandInterpreter() 112 interpreter.HandleCommand(cmd, ret) 113 else: 114 self.dbg.HandleCommand(cmd) 115 self.dbg.GetOutputFile().Flush() 116 self.dbg.GetErrorFile().Flush() 117 if collect_result and check: 118 self.assertTrue(ret.Succeeded()) 119 return ret.GetOutput() 120 121 122 def test_legacy_file_out_script(self): 123 with open(self.out_filename, 'w') as f: 124 self.dbg.SetOutputFileHandle(f, False) 125 # scripts print to output even if you capture the results 126 # I'm not sure I love that behavior, but that's the way 127 # it's been for a long time. That's why this test works 128 # even with collect_result=True. 129 self.handleCmd('script 1+1') 130 self.dbg.GetOutputFileHandle().write('FOO\n') 131 self.dbg.GetOutputFileHandle().flush() 132 with open(self.out_filename, 'r') as f: 133 self.assertEqual(readStrippedLines(f), ['2', 'FOO']) 134 135 136 def test_legacy_file_out(self): 137 with open(self.out_filename, 'w') as f: 138 self.dbg.SetOutputFileHandle(f, False) 139 self.handleCmd('p/x 3735928559', collect_result=False, check=False) 140 with open(self.out_filename, 'r') as f: 141 self.assertIn('deadbeef', f.read()) 142 143 def test_legacy_file_err_with_get(self): 144 with open(self.out_filename, 'w') as f: 145 self.dbg.SetErrorFileHandle(f, False) 146 self.handleCmd('lolwut', check=False, collect_result=False) 147 f2 = self.dbg.GetErrorFileHandle() 148 f2.write('FOOBAR\n') 149 f2.flush() 150 with open(self.out_filename, 'r') as f: 151 errors = f.read() 152 self.assertTrue(re.search(r'error:.*lolwut', errors)) 153 self.assertTrue(re.search(r'FOOBAR', errors)) 154 155 156 def test_legacy_file_err(self): 157 with open(self.out_filename, 'w') as f: 158 self.dbg.SetErrorFileHandle(f, False) 159 self.handleCmd('lol', check=False, collect_result=False) 160 with open(self.out_filename, 'r') as f: 161 self.assertIn("is not a valid command", f.read()) 162 163 164 def test_legacy_file_error(self): 165 with open(self.out_filename, 'w') as f: 166 self.dbg.SetErrorFileHandle(f, False) 167 self.handleCmd('lolwut', check=False, collect_result=False) 168 with open(self.out_filename, 'r') as f: 169 errors = f.read() 170 self.assertTrue(re.search(r'error:.*lolwut', errors)) 171 172 def test_sbfile_type_errors(self): 173 sbf = lldb.SBFile() 174 self.assertRaises(Exception, sbf.Write, None) 175 self.assertRaises(Exception, sbf.Read, None) 176 self.assertRaises(Exception, sbf.Read, b'this bytes is not mutable') 177 self.assertRaises(Exception, sbf.Write, u"ham sandwich") 178 self.assertRaises(Exception, sbf.Read, u"ham sandwich") 179 180 181 def test_sbfile_write_fileno(self): 182 with open(self.out_filename, 'w') as f: 183 sbf = lldb.SBFile(f.fileno(), "w", False) 184 self.assertTrue(sbf.IsValid()) 185 e, n = sbf.Write(b'FOO\nBAR') 186 self.assertSuccess(e) 187 self.assertEqual(n, 7) 188 sbf.Close() 189 self.assertFalse(sbf.IsValid()) 190 with open(self.out_filename, 'r') as f: 191 self.assertEqual(readStrippedLines(f), ['FOO', 'BAR']) 192 193 194 def test_sbfile_write(self): 195 with open(self.out_filename, 'w') as f: 196 sbf = lldb.SBFile(f) 197 e, n = sbf.Write(b'FOO\n') 198 self.assertSuccess(e) 199 self.assertEqual(n, 4) 200 sbf.Close() 201 self.assertTrue(f.closed) 202 with open(self.out_filename, 'r') as f: 203 self.assertEqual(f.read().strip(), 'FOO') 204 205 206 def test_sbfile_read_fileno(self): 207 with open(self.out_filename, 'w') as f: 208 f.write('FOO') 209 with open(self.out_filename, 'r') as f: 210 sbf = lldb.SBFile(f.fileno(), "r", False) 211 self.assertTrue(sbf.IsValid()) 212 buffer = bytearray(100) 213 e, n = sbf.Read(buffer) 214 self.assertSuccess(e) 215 self.assertEqual(buffer[:n], b'FOO') 216 217 218 def test_sbfile_read(self): 219 with open(self.out_filename, 'w') as f: 220 f.write('foo') 221 with open(self.out_filename, 'r') as f: 222 sbf = lldb.SBFile(f) 223 buf = bytearray(100) 224 e, n = sbf.Read(buf) 225 self.assertSuccess(e) 226 self.assertEqual(n, 3) 227 self.assertEqual(buf[:n], b'foo') 228 sbf.Close() 229 self.assertTrue(f.closed) 230 231 232 def test_fileno_out(self): 233 with open(self.out_filename, 'w') as f: 234 sbf = lldb.SBFile(f.fileno(), "w", False) 235 status = self.dbg.SetOutputFile(sbf) 236 self.assertSuccess(status) 237 self.handleCmd('script 1+2') 238 self.dbg.GetOutputFile().Write(b'quux') 239 self.dbg.GetOutputFile().Flush() 240 241 with open(self.out_filename, 'r') as f: 242 self.assertEqual(readStrippedLines(f), ['3', 'quux']) 243 244 245 def test_fileno_help(self): 246 with open(self.out_filename, 'w') as f: 247 sbf = lldb.SBFile(f.fileno(), "w", False) 248 status = self.dbg.SetOutputFile(sbf) 249 self.assertSuccess(status) 250 self.handleCmd("help help", collect_result=False, check=False) 251 with open(self.out_filename, 'r') as f: 252 self.assertTrue(re.search(r'Show a list of all debugger commands', f.read())) 253 254 255 def test_help(self): 256 with open(self.out_filename, 'w') as f: 257 status = self.dbg.SetOutputFile(lldb.SBFile(f)) 258 self.assertSuccess(status) 259 self.handleCmd("help help", check=False, collect_result=False) 260 with open(self.out_filename, 'r') as f: 261 self.assertIn('Show a list of all debugger commands', f.read()) 262 263 264 def test_immediate(self): 265 with open(self.out_filename, 'w') as f: 266 ret = lldb.SBCommandReturnObject() 267 ret.SetImmediateOutputFile(f) 268 interpreter = self.dbg.GetCommandInterpreter() 269 interpreter.HandleCommand("help help", ret) 270 # make sure the file wasn't closed early. 271 f.write("\nQUUX\n") 272 ret = None # call destructor and flush streams 273 with open(self.out_filename, 'r') as f: 274 output = f.read() 275 self.assertTrue(re.search(r'Show a list of all debugger commands', output)) 276 self.assertTrue(re.search(r'QUUX', output)) 277 278 279 def test_immediate_string(self): 280 f = io.StringIO() 281 ret = lldb.SBCommandReturnObject() 282 ret.SetImmediateOutputFile(f) 283 interpreter = self.dbg.GetCommandInterpreter() 284 interpreter.HandleCommand("help help", ret) 285 # make sure the file wasn't closed early. 286 f.write("\nQUUX\n") 287 ret = None # call destructor and flush streams 288 output = f.getvalue() 289 self.assertTrue(re.search(r'Show a list of all debugger commands', output)) 290 self.assertTrue(re.search(r'QUUX', output)) 291 292 293 def test_immediate_sbfile_string(self): 294 f = io.StringIO() 295 ret = lldb.SBCommandReturnObject() 296 ret.SetImmediateOutputFile(lldb.SBFile(f)) 297 interpreter = self.dbg.GetCommandInterpreter() 298 interpreter.HandleCommand("help help", ret) 299 output = f.getvalue() 300 ret = None # call destructor and flush streams 301 # sbfile default constructor doesn't borrow the file 302 self.assertTrue(f.closed) 303 self.assertTrue(re.search(r'Show a list of all debugger commands', output)) 304 305 306 def test_fileno_inout(self): 307 with open(self.in_filename, 'w') as f: 308 f.write("help help\n") 309 310 with open(self.out_filename, 'w') as outf, open(self.in_filename, 'r') as inf: 311 312 outsbf = lldb.SBFile(outf.fileno(), "w", False) 313 status = self.dbg.SetOutputFile(outsbf) 314 self.assertSuccess(status) 315 316 insbf = lldb.SBFile(inf.fileno(), "r", False) 317 status = self.dbg.SetInputFile(insbf) 318 self.assertSuccess(status) 319 320 opts = lldb.SBCommandInterpreterRunOptions() 321 self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) 322 self.dbg.GetOutputFile().Flush() 323 324 with open(self.out_filename, 'r') as f: 325 self.assertTrue(re.search(r'Show a list of all debugger commands', f.read())) 326 327 328 def test_inout(self): 329 with open(self.in_filename, 'w') as f: 330 f.write("help help\n") 331 with open(self.out_filename, 'w') as outf, \ 332 open(self.in_filename, 'r') as inf: 333 status = self.dbg.SetOutputFile(lldb.SBFile(outf)) 334 self.assertSuccess(status) 335 status = self.dbg.SetInputFile(lldb.SBFile(inf)) 336 self.assertSuccess(status) 337 opts = lldb.SBCommandInterpreterRunOptions() 338 self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) 339 self.dbg.GetOutputFile().Flush() 340 with open(self.out_filename, 'r') as f: 341 output = f.read() 342 self.assertIn('Show a list of all debugger commands', output) 343 344 345 def test_binary_inout(self): 346 with open(self.in_filename, 'w') as f: 347 f.write("help help\n") 348 with open(self.out_filename, 'wb') as outf, \ 349 open(self.in_filename, 'rb') as inf: 350 status = self.dbg.SetOutputFile(lldb.SBFile(outf)) 351 self.assertSuccess(status) 352 status = self.dbg.SetInputFile(lldb.SBFile(inf)) 353 self.assertSuccess(status) 354 opts = lldb.SBCommandInterpreterRunOptions() 355 self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) 356 self.dbg.GetOutputFile().Flush() 357 with open(self.out_filename, 'r') as f: 358 output = f.read() 359 self.assertIn('Show a list of all debugger commands', output) 360 361 362 def test_string_inout(self): 363 inf = io.StringIO("help help\np/x ~0\n") 364 outf = io.StringIO() 365 status = self.dbg.SetOutputFile(lldb.SBFile(outf)) 366 self.assertSuccess(status) 367 status = self.dbg.SetInputFile(lldb.SBFile(inf)) 368 self.assertSuccess(status) 369 opts = lldb.SBCommandInterpreterRunOptions() 370 self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) 371 self.dbg.GetOutputFile().Flush() 372 output = outf.getvalue() 373 self.assertIn('Show a list of all debugger commands', output) 374 self.assertIn('0xfff', output) 375 376 377 def test_bytes_inout(self): 378 inf = io.BytesIO(b"help help\nhelp b\n") 379 outf = io.BytesIO() 380 status = self.dbg.SetOutputFile(lldb.SBFile(outf)) 381 self.assertSuccess(status) 382 status = self.dbg.SetInputFile(lldb.SBFile(inf)) 383 self.assertSuccess(status) 384 opts = lldb.SBCommandInterpreterRunOptions() 385 self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) 386 self.dbg.GetOutputFile().Flush() 387 output = outf.getvalue() 388 self.assertIn(b'Show a list of all debugger commands', output) 389 self.assertIn(b'Set a breakpoint', output) 390 391 392 def test_fileno_error(self): 393 with open(self.out_filename, 'w') as f: 394 395 sbf = lldb.SBFile(f.fileno(), 'w', False) 396 status = self.dbg.SetErrorFile(sbf) 397 self.assertSuccess(status) 398 399 self.handleCmd('lolwut', check=False, collect_result=False) 400 401 self.dbg.GetErrorFile().Write(b'\nzork\n') 402 403 with open(self.out_filename, 'r') as f: 404 errors = f.read() 405 self.assertTrue(re.search(r'error:.*lolwut', errors)) 406 self.assertTrue(re.search(r'zork', errors)) 407 408 409 def test_replace_stdout(self): 410 f = io.StringIO() 411 with replace_stdout(f): 412 self.assertEqual(sys.stdout, f) 413 self.handleCmd('script sys.stdout.write("lol")', 414 collect_result=False, check=False) 415 self.assertEqual(sys.stdout, f) 416 417 418 def test_replace_stdout_with_nonfile(self): 419 f = io.StringIO() 420 with replace_stdout(f): 421 class Nothing(): 422 pass 423 with replace_stdout(Nothing): 424 self.assertEqual(sys.stdout, Nothing) 425 self.handleCmd('script sys.stdout.write("lol")', 426 check=False, collect_result=False) 427 self.assertEqual(sys.stdout, Nothing) 428 sys.stdout.write(u"FOO") 429 self.assertEqual(f.getvalue(), "FOO") 430 431 432 def test_sbfile_write_borrowed(self): 433 with open(self.out_filename, 'w') as f: 434 sbf = lldb.SBFile.Create(f, borrow=True) 435 e, n = sbf.Write(b'FOO') 436 self.assertSuccess(e) 437 self.assertEqual(n, 3) 438 sbf.Close() 439 self.assertFalse(f.closed) 440 f.write('BAR\n') 441 with open(self.out_filename, 'r') as f: 442 self.assertEqual(f.read().strip(), 'FOOBAR') 443 444 445 446 def test_sbfile_write_forced(self): 447 with open(self.out_filename, 'w') as f: 448 written = MutableBool(False) 449 orig_write = f.write 450 def mywrite(x): 451 written.set(True) 452 return orig_write(x) 453 f.write = mywrite 454 sbf = lldb.SBFile.Create(f, force_io_methods=True) 455 e, n = sbf.Write(b'FOO') 456 self.assertTrue(written) 457 self.assertSuccess(e) 458 self.assertEqual(n, 3) 459 sbf.Close() 460 self.assertTrue(f.closed) 461 with open(self.out_filename, 'r') as f: 462 self.assertEqual(f.read().strip(), 'FOO') 463 464 465 def test_sbfile_write_forced_borrowed(self): 466 with open(self.out_filename, 'w') as f: 467 written = MutableBool(False) 468 orig_write = f.write 469 def mywrite(x): 470 written.set(True) 471 return orig_write(x) 472 f.write = mywrite 473 sbf = lldb.SBFile.Create(f, borrow=True, force_io_methods=True) 474 e, n = sbf.Write(b'FOO') 475 self.assertTrue(written) 476 self.assertSuccess(e) 477 self.assertEqual(n, 3) 478 sbf.Close() 479 self.assertFalse(f.closed) 480 with open(self.out_filename, 'r') as f: 481 self.assertEqual(f.read().strip(), 'FOO') 482 483 484 def test_sbfile_write_string(self): 485 f = io.StringIO() 486 sbf = lldb.SBFile(f) 487 e, n = sbf.Write(b'FOO') 488 self.assertEqual(f.getvalue().strip(), "FOO") 489 self.assertSuccess(e) 490 self.assertEqual(n, 3) 491 sbf.Close() 492 self.assertTrue(f.closed) 493 494 495 def test_string_out(self): 496 f = io.StringIO() 497 status = self.dbg.SetOutputFile(f) 498 self.assertSuccess(status) 499 self.handleCmd("script 'foobar'") 500 self.assertEqual(f.getvalue().strip(), "'foobar'") 501 502 503 def test_string_error(self): 504 f = io.StringIO() 505 status = self.dbg.SetErrorFile(f) 506 self.assertSuccess(status) 507 self.handleCmd('lolwut', check=False, collect_result=False) 508 errors = f.getvalue() 509 self.assertTrue(re.search(r'error:.*lolwut', errors)) 510 511 512 def test_sbfile_write_bytes(self): 513 f = io.BytesIO() 514 sbf = lldb.SBFile(f) 515 e, n = sbf.Write(b'FOO') 516 self.assertEqual(f.getvalue().strip(), b"FOO") 517 self.assertSuccess(e) 518 self.assertEqual(n, 3) 519 sbf.Close() 520 self.assertTrue(f.closed) 521 522 def test_sbfile_read_string(self): 523 f = io.StringIO('zork') 524 sbf = lldb.SBFile(f) 525 buf = bytearray(100) 526 e, n = sbf.Read(buf) 527 self.assertSuccess(e) 528 self.assertEqual(buf[:n], b'zork') 529 530 531 def test_sbfile_read_string_one_byte(self): 532 f = io.StringIO('z') 533 sbf = lldb.SBFile(f) 534 buf = bytearray(1) 535 e, n = sbf.Read(buf) 536 self.assertTrue(e.Fail()) 537 self.assertEqual(n, 0) 538 self.assertEqual(e.GetCString(), "can't read less than 6 bytes from a utf8 text stream") 539 540 541 def test_sbfile_read_bytes(self): 542 f = io.BytesIO(b'zork') 543 sbf = lldb.SBFile(f) 544 buf = bytearray(100) 545 e, n = sbf.Read(buf) 546 self.assertSuccess(e) 547 self.assertEqual(buf[:n], b'zork') 548 549 550 def test_sbfile_out(self): 551 with open(self.out_filename, 'w') as f: 552 sbf = lldb.SBFile(f) 553 status = self.dbg.SetOutputFile(sbf) 554 self.assertSuccess(status) 555 self.handleCmd('script 2+2') 556 with open(self.out_filename, 'r') as f: 557 self.assertEqual(f.read().strip(), '4') 558 559 560 def test_file_out(self): 561 with open(self.out_filename, 'w') as f: 562 status = self.dbg.SetOutputFile(f) 563 self.assertSuccess(status) 564 self.handleCmd('script 2+2') 565 with open(self.out_filename, 'r') as f: 566 self.assertEqual(f.read().strip(), '4') 567 568 569 def test_sbfile_error(self): 570 with open(self.out_filename, 'w') as f: 571 sbf = lldb.SBFile(f) 572 status = self.dbg.SetErrorFile(sbf) 573 self.assertSuccess(status) 574 self.handleCmd('lolwut', check=False, collect_result=False) 575 with open(self.out_filename, 'r') as f: 576 errors = f.read() 577 self.assertTrue(re.search(r'error:.*lolwut', errors)) 578 579 580 def test_file_error(self): 581 with open(self.out_filename, 'w') as f: 582 status = self.dbg.SetErrorFile(f) 583 self.assertSuccess(status) 584 self.handleCmd('lolwut', check=False, collect_result=False) 585 with open(self.out_filename, 'r') as f: 586 errors = f.read() 587 self.assertTrue(re.search(r'error:.*lolwut', errors)) 588 589 590 def test_exceptions(self): 591 self.assertRaises(Exception, lldb.SBFile, None) 592 self.assertRaises(Exception, lldb.SBFile, "ham sandwich") 593 self.assertRaises(OhNoe, lldb.SBFile, ReallyBadIO()) 594 error, n = lldb.SBFile(BadIO()).Write(b"FOO") 595 self.assertEqual(n, 0) 596 self.assertTrue(error.Fail()) 597 self.assertIn('OH NOE', error.GetCString()) 598 error, n = lldb.SBFile(BadIO()).Read(bytearray(100)) 599 self.assertEqual(n, 0) 600 self.assertTrue(error.Fail()) 601 self.assertIn('OH NOE', error.GetCString()) 602 603 604 def test_exceptions_logged(self): 605 messages = list() 606 self.dbg.SetLoggingCallback(messages.append) 607 self.handleCmd('log enable lldb script') 608 self.dbg.SetOutputFile(lldb.SBFile(BadIO())) 609 self.handleCmd('script 1+1') 610 self.assertTrue(any('OH NOE' in msg for msg in messages)) 611 612 613 def test_flush(self): 614 flushed = MutableBool(False) 615 closed = MutableBool(False) 616 f = FlushTestIO(flushed, closed) 617 self.assertFalse(flushed) 618 self.assertFalse(closed) 619 sbf = lldb.SBFile(f) 620 self.assertFalse(flushed) 621 self.assertFalse(closed) 622 sbf = None 623 self.assertFalse(flushed) 624 self.assertTrue(closed) 625 self.assertTrue(f.closed) 626 627 flushed = MutableBool(False) 628 closed = MutableBool(False) 629 f = FlushTestIO(flushed, closed) 630 self.assertFalse(flushed) 631 self.assertFalse(closed) 632 sbf = lldb.SBFile.Create(f, borrow=True) 633 self.assertFalse(flushed) 634 self.assertFalse(closed) 635 sbf = None 636 self.assertTrue(flushed) 637 self.assertFalse(closed) 638 self.assertFalse(f.closed) 639 640 641 def test_fileno_flush(self): 642 with open(self.out_filename, 'w') as f: 643 f.write("foo") 644 sbf = lldb.SBFile(f) 645 sbf.Write(b'bar') 646 sbf = None 647 self.assertTrue(f.closed) 648 with open(self.out_filename, 'r') as f: 649 self.assertEqual(f.read(), 'foobar') 650 651 with open(self.out_filename, 'w+') as f: 652 f.write("foo") 653 sbf = lldb.SBFile.Create(f, borrow=True) 654 sbf.Write(b'bar') 655 sbf = None 656 self.assertFalse(f.closed) 657 f.seek(0) 658 self.assertEqual(f.read(), 'foobar') 659 660 661 def test_close(self): 662 with open(self.out_filename, 'w') as f: 663 status = self.dbg.SetOutputFile(f) 664 self.assertSuccess(status) 665 self.handleCmd("help help", check=False, collect_result=False) 666 # make sure the file wasn't closed early. 667 f.write("\nZAP\n") 668 lldb.SBDebugger.Destroy(self.dbg) 669 # check that output file was closed when debugger was destroyed. 670 with self.assertRaises(ValueError): 671 f.write("\nQUUX\n") 672 with open(self.out_filename, 'r') as f: 673 output = f.read() 674 self.assertTrue(re.search(r'Show a list of all debugger commands', output)) 675 self.assertTrue(re.search(r'ZAP', output)) 676 677 678 def test_stdout(self): 679 f = io.StringIO() 680 status = self.dbg.SetOutputFile(f) 681 self.assertSuccess(status) 682 self.handleCmd(r"script sys.stdout.write('foobar\n')") 683 self.assertEqual(f.getvalue().strip().split(), ["foobar", "7"]) 684 685 686 def test_stdout_file(self): 687 with open(self.out_filename, 'w') as f: 688 status = self.dbg.SetOutputFile(f) 689 self.assertSuccess(status) 690 self.handleCmd(r"script sys.stdout.write('foobar\n')") 691 with open(self.out_filename, 'r') as f: 692 # In python2 sys.stdout.write() returns None, which 693 # the REPL will ignore, but in python3 it will 694 # return the number of bytes written, which the REPL 695 # will print out. 696 lines = [x for x in f.read().strip().split() if x != "7"] 697 self.assertEqual(lines, ["foobar"]) 698 699 700 def test_identity(self): 701 f = io.StringIO() 702 sbf = lldb.SBFile(f) 703 self.assertTrue(f is sbf.GetFile()) 704 sbf.Close() 705 self.assertTrue(f.closed) 706 707 f = io.StringIO() 708 sbf = lldb.SBFile.Create(f, borrow=True) 709 self.assertTrue(f is sbf.GetFile()) 710 sbf.Close() 711 self.assertFalse(f.closed) 712 713 with open(self.out_filename, 'w') as f: 714 sbf = lldb.SBFile(f) 715 self.assertTrue(f is sbf.GetFile()) 716 sbf.Close() 717 self.assertTrue(f.closed) 718 719 with open(self.out_filename, 'w') as f: 720 sbf = lldb.SBFile.Create(f, borrow=True) 721 self.assertFalse(f is sbf.GetFile()) 722 sbf.Write(b"foobar\n") 723 self.assertEqual(f.fileno(), sbf.GetFile().fileno()) 724 sbf.Close() 725 self.assertFalse(f.closed) 726 727 with open(self.out_filename, 'r') as f: 728 self.assertEqual("foobar", f.read().strip()) 729 730 with open(self.out_filename, 'wb') as f: 731 sbf = lldb.SBFile.Create(f, borrow=True, force_io_methods=True) 732 self.assertTrue(f is sbf.GetFile()) 733 sbf.Write(b"foobar\n") 734 self.assertEqual(f.fileno(), sbf.GetFile().fileno()) 735 sbf.Close() 736 self.assertFalse(f.closed) 737 738 with open(self.out_filename, 'r') as f: 739 self.assertEqual("foobar", f.read().strip()) 740 741 with open(self.out_filename, 'wb') as f: 742 sbf = lldb.SBFile.Create(f, force_io_methods=True) 743 self.assertTrue(f is sbf.GetFile()) 744 sbf.Write(b"foobar\n") 745 self.assertEqual(f.fileno(), sbf.GetFile().fileno()) 746 sbf.Close() 747 self.assertTrue(f.closed) 748 749 with open(self.out_filename, 'r') as f: 750 self.assertEqual("foobar", f.read().strip()) 751 752 753 def test_back_and_forth(self): 754 with open(self.out_filename, 'w') as f: 755 # at each step here we're borrowing the file, so we have to keep 756 # them all alive until the end. 757 sbf = lldb.SBFile.Create(f, borrow=True) 758 def i(sbf): 759 for i in range(10): 760 f = sbf.GetFile() 761 self.assertEqual(f.mode, "w") 762 yield f 763 sbf = lldb.SBFile.Create(f, borrow=True) 764 yield sbf 765 sbf.Write(str(i).encode('ascii') + b"\n") 766 files = list(i(sbf)) 767 with open(self.out_filename, 'r') as f: 768 self.assertEqual(list(range(10)), list(map(int, f.read().strip().split()))) 769 770 771 def test_set_filehandle_none(self): 772 self.assertRaises(Exception, self.dbg.SetOutputFile, None) 773 self.assertRaises(Exception, self.dbg.SetOutputFile, "ham sandwich") 774 self.assertRaises(Exception, self.dbg.SetOutputFileHandle, "ham sandwich") 775 self.assertRaises(Exception, self.dbg.SetInputFile, None) 776 self.assertRaises(Exception, self.dbg.SetInputFile, "ham sandwich") 777 self.assertRaises(Exception, self.dbg.SetInputFileHandle, "ham sandwich") 778 self.assertRaises(Exception, self.dbg.SetErrorFile, None) 779 self.assertRaises(Exception, self.dbg.SetErrorFile, "ham sandwich") 780 self.assertRaises(Exception, self.dbg.SetErrorFileHandle, "ham sandwich") 781 782 with open(self.out_filename, 'w') as f: 783 status = self.dbg.SetOutputFile(f) 784 self.assertSuccess(status) 785 status = self.dbg.SetErrorFile(f) 786 self.assertSuccess(status) 787 self.dbg.SetOutputFileHandle(None, False) 788 self.dbg.SetErrorFileHandle(None, False) 789 sbf = self.dbg.GetOutputFile() 790 self.assertEqual(sbf.GetFile().fileno(), 1) 791 sbf = self.dbg.GetErrorFile() 792 self.assertEqual(sbf.GetFile().fileno(), 2) 793 with open(self.out_filename, 'r') as f: 794 status = self.dbg.SetInputFile(f) 795 self.assertSuccess(status) 796 self.dbg.SetInputFileHandle(None, False) 797 sbf = self.dbg.GetInputFile() 798 self.assertEqual(sbf.GetFile().fileno(), 0) 799 800 801 def test_sbstream(self): 802 803 with open(self.out_filename, 'w') as f: 804 stream = lldb.SBStream() 805 stream.RedirectToFile(f) 806 stream.Print("zork") 807 with open(self.out_filename, 'r') as f: 808 self.assertEqual(f.read().strip(), "zork") 809 810 with open(self.out_filename, 'w') as f: 811 stream = lldb.SBStream() 812 stream.RedirectToFileHandle(f, True) 813 stream.Print("Yendor") 814 with open(self.out_filename, 'r') as f: 815 self.assertEqual(f.read().strip(), "Yendor") 816 817 stream = lldb.SBStream() 818 f = open(self.out_filename, 'w') 819 stream.RedirectToFile(lldb.SBFile.Create(f, borrow=False)) 820 stream.Print("Frobozz") 821 stream = None 822 self.assertTrue(f.closed) 823 with open(self.out_filename, 'r') as f: 824 self.assertEqual(f.read().strip(), "Frobozz") 825 826 def test_set_sbstream(self): 827 with open(self.out_filename, 'w') as outf: 828 outsbf = lldb.SBFile(outf.fileno(), "w", False) 829 status = self.dbg.SetOutputFile(outsbf) 830 self.assertSuccess(status) 831 self.dbg.SetInputString("help apropos\nhelp help\n") 832 833 opts = lldb.SBCommandInterpreterRunOptions() 834 self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) 835 self.dbg.GetOutputFile().Flush() 836 837 with open(self.out_filename, 'r') as f: 838 output = f.read() 839 self.assertIn('Show a list of all debugger commands', output) 840 self.assertIn('List debugger commands related to a word', output) 841