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