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