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.assertTrue(e.Success()) 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.assertTrue(e.Success()) 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.assertTrue(e.Success()) 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.assertTrue(e.Success()) 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.assertTrue(status.Success()) 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.assertTrue(status.Success()) 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.assertTrue(status.Success()) 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 @skipIf(py_version=['<', (3,)]) 280 def test_immediate_string(self): 281 f = io.StringIO() 282 ret = lldb.SBCommandReturnObject() 283 ret.SetImmediateOutputFile(f) 284 interpreter = self.dbg.GetCommandInterpreter() 285 interpreter.HandleCommand("help help", ret) 286 # make sure the file wasn't closed early. 287 f.write("\nQUUX\n") 288 ret = None # call destructor and flush streams 289 output = f.getvalue() 290 self.assertTrue(re.search(r'Show a list of all debugger commands', output)) 291 self.assertTrue(re.search(r'QUUX', output)) 292 293 294 @skipIf(py_version=['<', (3,)]) 295 def test_immediate_sbfile_string(self): 296 f = io.StringIO() 297 ret = lldb.SBCommandReturnObject() 298 ret.SetImmediateOutputFile(lldb.SBFile(f)) 299 interpreter = self.dbg.GetCommandInterpreter() 300 interpreter.HandleCommand("help help", ret) 301 output = f.getvalue() 302 ret = None # call destructor and flush streams 303 # sbfile default constructor doesn't borrow the file 304 self.assertTrue(f.closed) 305 self.assertTrue(re.search(r'Show a list of all debugger commands', output)) 306 307 308 def test_fileno_inout(self): 309 with open(self.in_filename, 'w') as f: 310 f.write("help help\n") 311 312 with open(self.out_filename, 'w') as outf, open(self.in_filename, 'r') as inf: 313 314 outsbf = lldb.SBFile(outf.fileno(), "w", False) 315 status = self.dbg.SetOutputFile(outsbf) 316 self.assertTrue(status.Success()) 317 318 insbf = lldb.SBFile(inf.fileno(), "r", False) 319 status = self.dbg.SetInputFile(insbf) 320 self.assertTrue(status.Success()) 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(re.search(r'Show a list of all debugger commands', f.read())) 328 329 330 def test_inout(self): 331 with open(self.in_filename, 'w') as f: 332 f.write("help help\n") 333 with open(self.out_filename, 'w') as outf, \ 334 open(self.in_filename, 'r') as inf: 335 status = self.dbg.SetOutputFile(lldb.SBFile(outf)) 336 self.assertTrue(status.Success()) 337 status = self.dbg.SetInputFile(lldb.SBFile(inf)) 338 self.assertTrue(status.Success()) 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 347 def test_binary_inout(self): 348 with open(self.in_filename, 'w') as f: 349 f.write("help help\n") 350 with open(self.out_filename, 'wb') as outf, \ 351 open(self.in_filename, 'rb') as inf: 352 status = self.dbg.SetOutputFile(lldb.SBFile(outf)) 353 self.assertTrue(status.Success()) 354 status = self.dbg.SetInputFile(lldb.SBFile(inf)) 355 self.assertTrue(status.Success()) 356 opts = lldb.SBCommandInterpreterRunOptions() 357 self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) 358 self.dbg.GetOutputFile().Flush() 359 with open(self.out_filename, 'r') as f: 360 output = f.read() 361 self.assertIn('Show a list of all debugger commands', output) 362 363 364 @skipIf(py_version=['<', (3,)]) 365 def test_string_inout(self): 366 inf = io.StringIO("help help\np/x ~0\n") 367 outf = io.StringIO() 368 status = self.dbg.SetOutputFile(lldb.SBFile(outf)) 369 self.assertTrue(status.Success()) 370 status = self.dbg.SetInputFile(lldb.SBFile(inf)) 371 self.assertTrue(status.Success()) 372 opts = lldb.SBCommandInterpreterRunOptions() 373 self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) 374 self.dbg.GetOutputFile().Flush() 375 output = outf.getvalue() 376 self.assertIn('Show a list of all debugger commands', output) 377 self.assertIn('0xfff', output) 378 379 380 @skipIf(py_version=['<', (3,)]) 381 def test_bytes_inout(self): 382 inf = io.BytesIO(b"help help\nhelp b\n") 383 outf = io.BytesIO() 384 status = self.dbg.SetOutputFile(lldb.SBFile(outf)) 385 self.assertTrue(status.Success()) 386 status = self.dbg.SetInputFile(lldb.SBFile(inf)) 387 self.assertTrue(status.Success()) 388 opts = lldb.SBCommandInterpreterRunOptions() 389 self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) 390 self.dbg.GetOutputFile().Flush() 391 output = outf.getvalue() 392 self.assertIn(b'Show a list of all debugger commands', output) 393 self.assertIn(b'Set a breakpoint', output) 394 395 396 def test_fileno_error(self): 397 with open(self.out_filename, 'w') as f: 398 399 sbf = lldb.SBFile(f.fileno(), 'w', False) 400 status = self.dbg.SetErrorFile(sbf) 401 self.assertTrue(status.Success()) 402 403 self.handleCmd('lolwut', check=False, collect_result=False) 404 405 self.dbg.GetErrorFile().Write(b'\nzork\n') 406 407 with open(self.out_filename, 'r') as f: 408 errors = f.read() 409 self.assertTrue(re.search(r'error:.*lolwut', errors)) 410 self.assertTrue(re.search(r'zork', errors)) 411 412 413 def test_replace_stdout(self): 414 f = io.StringIO() 415 with replace_stdout(f): 416 self.assertEqual(sys.stdout, f) 417 self.handleCmd('script sys.stdout.write("lol")', 418 collect_result=False, check=False) 419 self.assertEqual(sys.stdout, f) 420 421 422 def test_replace_stdout_with_nonfile(self): 423 f = io.StringIO() 424 with replace_stdout(f): 425 class Nothing(): 426 pass 427 with replace_stdout(Nothing): 428 self.assertEqual(sys.stdout, Nothing) 429 self.handleCmd('script sys.stdout.write("lol")', 430 check=False, collect_result=False) 431 self.assertEqual(sys.stdout, Nothing) 432 sys.stdout.write(u"FOO") 433 self.assertEqual(f.getvalue(), "FOO") 434 435 436 def test_sbfile_write_borrowed(self): 437 with open(self.out_filename, 'w') as f: 438 sbf = lldb.SBFile.Create(f, borrow=True) 439 e, n = sbf.Write(b'FOO') 440 self.assertTrue(e.Success()) 441 self.assertEqual(n, 3) 442 sbf.Close() 443 self.assertFalse(f.closed) 444 f.write('BAR\n') 445 with open(self.out_filename, 'r') as f: 446 self.assertEqual(f.read().strip(), 'FOOBAR') 447 448 449 450 @skipIf(py_version=['<', (3,)]) 451 def test_sbfile_write_forced(self): 452 with open(self.out_filename, 'w') as f: 453 written = MutableBool(False) 454 orig_write = f.write 455 def mywrite(x): 456 written.set(True) 457 return orig_write(x) 458 f.write = mywrite 459 sbf = lldb.SBFile.Create(f, force_io_methods=True) 460 e, n = sbf.Write(b'FOO') 461 self.assertTrue(written) 462 self.assertTrue(e.Success()) 463 self.assertEqual(n, 3) 464 sbf.Close() 465 self.assertTrue(f.closed) 466 with open(self.out_filename, 'r') as f: 467 self.assertEqual(f.read().strip(), 'FOO') 468 469 470 @skipIf(py_version=['<', (3,)]) 471 def test_sbfile_write_forced_borrowed(self): 472 with open(self.out_filename, 'w') as f: 473 written = MutableBool(False) 474 orig_write = f.write 475 def mywrite(x): 476 written.set(True) 477 return orig_write(x) 478 f.write = mywrite 479 sbf = lldb.SBFile.Create(f, borrow=True, force_io_methods=True) 480 e, n = sbf.Write(b'FOO') 481 self.assertTrue(written) 482 self.assertTrue(e.Success()) 483 self.assertEqual(n, 3) 484 sbf.Close() 485 self.assertFalse(f.closed) 486 with open(self.out_filename, 'r') as f: 487 self.assertEqual(f.read().strip(), 'FOO') 488 489 490 @skipIf(py_version=['<', (3,)]) 491 def test_sbfile_write_string(self): 492 f = io.StringIO() 493 sbf = lldb.SBFile(f) 494 e, n = sbf.Write(b'FOO') 495 self.assertEqual(f.getvalue().strip(), "FOO") 496 self.assertTrue(e.Success()) 497 self.assertEqual(n, 3) 498 sbf.Close() 499 self.assertTrue(f.closed) 500 501 502 @skipIf(py_version=['<', (3,)]) 503 def test_string_out(self): 504 f = io.StringIO() 505 status = self.dbg.SetOutputFile(f) 506 self.assertTrue(status.Success()) 507 self.handleCmd("script 'foobar'") 508 self.assertEqual(f.getvalue().strip(), "'foobar'") 509 510 511 @skipIf(py_version=['<', (3,)]) 512 def test_string_error(self): 513 f = io.StringIO() 514 status = self.dbg.SetErrorFile(f) 515 self.assertTrue(status.Success()) 516 self.handleCmd('lolwut', check=False, collect_result=False) 517 errors = f.getvalue() 518 self.assertTrue(re.search(r'error:.*lolwut', errors)) 519 520 521 @skipIf(py_version=['<', (3,)]) 522 def test_sbfile_write_bytes(self): 523 f = io.BytesIO() 524 sbf = lldb.SBFile(f) 525 e, n = sbf.Write(b'FOO') 526 self.assertEqual(f.getvalue().strip(), b"FOO") 527 self.assertTrue(e.Success()) 528 self.assertEqual(n, 3) 529 sbf.Close() 530 self.assertTrue(f.closed) 531 532 @skipIf(py_version=['<', (3,)]) 533 def test_sbfile_read_string(self): 534 f = io.StringIO('zork') 535 sbf = lldb.SBFile(f) 536 buf = bytearray(100) 537 e, n = sbf.Read(buf) 538 self.assertTrue(e.Success()) 539 self.assertEqual(buf[:n], b'zork') 540 541 542 @skipIf(py_version=['<', (3,)]) 543 def test_sbfile_read_string_one_byte(self): 544 f = io.StringIO('z') 545 sbf = lldb.SBFile(f) 546 buf = bytearray(1) 547 e, n = sbf.Read(buf) 548 self.assertTrue(e.Fail()) 549 self.assertEqual(n, 0) 550 self.assertEqual(e.GetCString(), "can't read less than 6 bytes from a utf8 text stream") 551 552 553 @skipIf(py_version=['<', (3,)]) 554 def test_sbfile_read_bytes(self): 555 f = io.BytesIO(b'zork') 556 sbf = lldb.SBFile(f) 557 buf = bytearray(100) 558 e, n = sbf.Read(buf) 559 self.assertTrue(e.Success()) 560 self.assertEqual(buf[:n], b'zork') 561 562 563 @skipIf(py_version=['<', (3,)]) 564 def test_sbfile_out(self): 565 with open(self.out_filename, 'w') as f: 566 sbf = lldb.SBFile(f) 567 status = self.dbg.SetOutputFile(sbf) 568 self.assertTrue(status.Success()) 569 self.handleCmd('script 2+2') 570 with open(self.out_filename, 'r') as f: 571 self.assertEqual(f.read().strip(), '4') 572 573 574 @skipIf(py_version=['<', (3,)]) 575 def test_file_out(self): 576 with open(self.out_filename, 'w') as f: 577 status = self.dbg.SetOutputFile(f) 578 self.assertTrue(status.Success()) 579 self.handleCmd('script 2+2') 580 with open(self.out_filename, 'r') as f: 581 self.assertEqual(f.read().strip(), '4') 582 583 584 def test_sbfile_error(self): 585 with open(self.out_filename, 'w') as f: 586 sbf = lldb.SBFile(f) 587 status = self.dbg.SetErrorFile(sbf) 588 self.assertTrue(status.Success()) 589 self.handleCmd('lolwut', check=False, collect_result=False) 590 with open(self.out_filename, 'r') as f: 591 errors = f.read() 592 self.assertTrue(re.search(r'error:.*lolwut', errors)) 593 594 595 def test_file_error(self): 596 with open(self.out_filename, 'w') as f: 597 status = self.dbg.SetErrorFile(f) 598 self.assertTrue(status.Success()) 599 self.handleCmd('lolwut', check=False, collect_result=False) 600 with open(self.out_filename, 'r') as f: 601 errors = f.read() 602 self.assertTrue(re.search(r'error:.*lolwut', errors)) 603 604 605 def test_exceptions(self): 606 self.assertRaises(Exception, lldb.SBFile, None) 607 self.assertRaises(Exception, lldb.SBFile, "ham sandwich") 608 if sys.version_info[0] < 3: 609 self.assertRaises(Exception, lldb.SBFile, ReallyBadIO()) 610 else: 611 self.assertRaises(OhNoe, lldb.SBFile, ReallyBadIO()) 612 error, n = lldb.SBFile(BadIO()).Write(b"FOO") 613 self.assertEqual(n, 0) 614 self.assertTrue(error.Fail()) 615 self.assertIn('OH NOE', error.GetCString()) 616 error, n = lldb.SBFile(BadIO()).Read(bytearray(100)) 617 self.assertEqual(n, 0) 618 self.assertTrue(error.Fail()) 619 self.assertIn('OH NOE', error.GetCString()) 620 621 622 @skipIf(py_version=['<', (3,)]) 623 def test_exceptions_logged(self): 624 messages = list() 625 self.dbg.SetLoggingCallback(messages.append) 626 self.handleCmd('log enable lldb script') 627 self.dbg.SetOutputFile(lldb.SBFile(BadIO())) 628 self.handleCmd('script 1+1') 629 self.assertTrue(any('OH NOE' in msg for msg in messages)) 630 631 632 @skipIf(py_version=['<', (3,)]) 633 def test_flush(self): 634 flushed = MutableBool(False) 635 closed = MutableBool(False) 636 f = FlushTestIO(flushed, closed) 637 self.assertFalse(flushed) 638 self.assertFalse(closed) 639 sbf = lldb.SBFile(f) 640 self.assertFalse(flushed) 641 self.assertFalse(closed) 642 sbf = None 643 self.assertFalse(flushed) 644 self.assertTrue(closed) 645 self.assertTrue(f.closed) 646 647 flushed = MutableBool(False) 648 closed = MutableBool(False) 649 f = FlushTestIO(flushed, closed) 650 self.assertFalse(flushed) 651 self.assertFalse(closed) 652 sbf = lldb.SBFile.Create(f, borrow=True) 653 self.assertFalse(flushed) 654 self.assertFalse(closed) 655 sbf = None 656 self.assertTrue(flushed) 657 self.assertFalse(closed) 658 self.assertFalse(f.closed) 659 660 661 def test_fileno_flush(self): 662 with open(self.out_filename, 'w') as f: 663 f.write("foo") 664 sbf = lldb.SBFile(f) 665 sbf.Write(b'bar') 666 sbf = None 667 self.assertTrue(f.closed) 668 with open(self.out_filename, 'r') as f: 669 self.assertEqual(f.read(), 'foobar') 670 671 with open(self.out_filename, 'w+') as f: 672 f.write("foo") 673 sbf = lldb.SBFile.Create(f, borrow=True) 674 sbf.Write(b'bar') 675 sbf = None 676 self.assertFalse(f.closed) 677 f.seek(0) 678 self.assertEqual(f.read(), 'foobar') 679 680 681 def test_close(self): 682 with open(self.out_filename, 'w') as f: 683 status = self.dbg.SetOutputFile(f) 684 self.assertTrue(status.Success()) 685 self.handleCmd("help help", check=False, collect_result=False) 686 # make sure the file wasn't closed early. 687 f.write("\nZAP\n") 688 lldb.SBDebugger.Destroy(self.dbg) 689 # check that output file was closed when debugger was destroyed. 690 with self.assertRaises(ValueError): 691 f.write("\nQUUX\n") 692 with open(self.out_filename, 'r') as f: 693 output = f.read() 694 self.assertTrue(re.search(r'Show a list of all debugger commands', output)) 695 self.assertTrue(re.search(r'ZAP', output)) 696 697 698 @skipIf(py_version=['<', (3,)]) 699 def test_stdout(self): 700 f = io.StringIO() 701 status = self.dbg.SetOutputFile(f) 702 self.assertTrue(status.Success()) 703 self.handleCmd(r"script sys.stdout.write('foobar\n')") 704 self.assertEqual(f.getvalue().strip().split(), ["foobar", "7"]) 705 706 707 def test_stdout_file(self): 708 with open(self.out_filename, 'w') as f: 709 status = self.dbg.SetOutputFile(f) 710 self.assertTrue(status.Success()) 711 self.handleCmd(r"script sys.stdout.write('foobar\n')") 712 with open(self.out_filename, 'r') as f: 713 # In python2 sys.stdout.write() returns None, which 714 # the REPL will ignore, but in python3 it will 715 # return the number of bytes written, which the REPL 716 # will print out. 717 lines = [x for x in f.read().strip().split() if x != "7"] 718 self.assertEqual(lines, ["foobar"]) 719 720 721 @skipIf(py_version=['<', (3,)]) 722 def test_identity(self): 723 724 f = io.StringIO() 725 sbf = lldb.SBFile(f) 726 self.assertTrue(f is sbf.GetFile()) 727 sbf.Close() 728 self.assertTrue(f.closed) 729 730 f = io.StringIO() 731 sbf = lldb.SBFile.Create(f, borrow=True) 732 self.assertTrue(f is sbf.GetFile()) 733 sbf.Close() 734 self.assertFalse(f.closed) 735 736 with open(self.out_filename, 'w') as f: 737 sbf = lldb.SBFile(f) 738 self.assertTrue(f is sbf.GetFile()) 739 sbf.Close() 740 self.assertTrue(f.closed) 741 742 with open(self.out_filename, 'w') as f: 743 sbf = lldb.SBFile.Create(f, borrow=True) 744 self.assertFalse(f is sbf.GetFile()) 745 sbf.Write(b"foobar\n") 746 self.assertEqual(f.fileno(), sbf.GetFile().fileno()) 747 sbf.Close() 748 self.assertFalse(f.closed) 749 750 with open(self.out_filename, 'r') as f: 751 self.assertEqual("foobar", f.read().strip()) 752 753 with open(self.out_filename, 'wb') as f: 754 sbf = lldb.SBFile.Create(f, borrow=True, force_io_methods=True) 755 self.assertTrue(f is sbf.GetFile()) 756 sbf.Write(b"foobar\n") 757 self.assertEqual(f.fileno(), sbf.GetFile().fileno()) 758 sbf.Close() 759 self.assertFalse(f.closed) 760 761 with open(self.out_filename, 'r') as f: 762 self.assertEqual("foobar", f.read().strip()) 763 764 with open(self.out_filename, 'wb') as f: 765 sbf = lldb.SBFile.Create(f, force_io_methods=True) 766 self.assertTrue(f is sbf.GetFile()) 767 sbf.Write(b"foobar\n") 768 self.assertEqual(f.fileno(), sbf.GetFile().fileno()) 769 sbf.Close() 770 self.assertTrue(f.closed) 771 772 with open(self.out_filename, 'r') as f: 773 self.assertEqual("foobar", f.read().strip()) 774 775 776 def test_back_and_forth(self): 777 with open(self.out_filename, 'w') as f: 778 # at each step here we're borrowing the file, so we have to keep 779 # them all alive until the end. 780 sbf = lldb.SBFile.Create(f, borrow=True) 781 def i(sbf): 782 for i in range(10): 783 f = sbf.GetFile() 784 self.assertEqual(f.mode, "w") 785 yield f 786 sbf = lldb.SBFile.Create(f, borrow=True) 787 yield sbf 788 sbf.Write(str(i).encode('ascii') + b"\n") 789 files = list(i(sbf)) 790 with open(self.out_filename, 'r') as f: 791 self.assertEqual(list(range(10)), list(map(int, f.read().strip().split()))) 792 793 794 def test_set_filehandle_none(self): 795 self.assertRaises(Exception, self.dbg.SetOutputFile, None) 796 self.assertRaises(Exception, self.dbg.SetOutputFile, "ham sandwich") 797 self.assertRaises(Exception, self.dbg.SetOutputFileHandle, "ham sandwich") 798 self.assertRaises(Exception, self.dbg.SetInputFile, None) 799 self.assertRaises(Exception, self.dbg.SetInputFile, "ham sandwich") 800 self.assertRaises(Exception, self.dbg.SetInputFileHandle, "ham sandwich") 801 self.assertRaises(Exception, self.dbg.SetErrorFile, None) 802 self.assertRaises(Exception, self.dbg.SetErrorFile, "ham sandwich") 803 self.assertRaises(Exception, self.dbg.SetErrorFileHandle, "ham sandwich") 804 805 with open(self.out_filename, 'w') as f: 806 status = self.dbg.SetOutputFile(f) 807 self.assertTrue(status.Success()) 808 status = self.dbg.SetErrorFile(f) 809 self.assertTrue(status.Success()) 810 self.dbg.SetOutputFileHandle(None, False) 811 self.dbg.SetErrorFileHandle(None, False) 812 sbf = self.dbg.GetOutputFile() 813 if sys.version_info.major >= 3: 814 # python 2 lacks PyFile_FromFd, so GetFile() will 815 # have to duplicate the file descriptor and make a FILE* 816 # in order to convert a NativeFile it back to a python 817 # file. 818 self.assertEqual(sbf.GetFile().fileno(), 1) 819 sbf = self.dbg.GetErrorFile() 820 if sys.version_info.major >= 3: 821 self.assertEqual(sbf.GetFile().fileno(), 2) 822 with open(self.out_filename, 'r') as f: 823 status = self.dbg.SetInputFile(f) 824 self.assertTrue(status.Success()) 825 self.dbg.SetInputFileHandle(None, False) 826 sbf = self.dbg.GetInputFile() 827 if sys.version_info.major >= 3: 828 self.assertEqual(sbf.GetFile().fileno(), 0) 829 830 831 def test_sbstream(self): 832 833 with open(self.out_filename, 'w') as f: 834 stream = lldb.SBStream() 835 stream.RedirectToFile(f) 836 stream.Print("zork") 837 with open(self.out_filename, 'r') as f: 838 self.assertEqual(f.read().strip(), "zork") 839 840 with open(self.out_filename, 'w') as f: 841 stream = lldb.SBStream() 842 stream.RedirectToFileHandle(f, True) 843 stream.Print("Yendor") 844 with open(self.out_filename, 'r') as f: 845 self.assertEqual(f.read().strip(), "Yendor") 846 847 stream = lldb.SBStream() 848 f = open(self.out_filename, 'w') 849 stream.RedirectToFile(lldb.SBFile.Create(f, borrow=False)) 850 stream.Print("Frobozz") 851 stream = None 852 self.assertTrue(f.closed) 853 with open(self.out_filename, 'r') as f: 854 self.assertEqual(f.read().strip(), "Frobozz") 855 856 def test_set_sbstream(self): 857 with open(self.out_filename, 'w') as outf: 858 outsbf = lldb.SBFile(outf.fileno(), "w", False) 859 status = self.dbg.SetOutputFile(outsbf) 860 self.assertTrue(status.Success()) 861 self.dbg.SetInputString("help apropos\nhelp help\n") 862 863 opts = lldb.SBCommandInterpreterRunOptions() 864 self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) 865 self.dbg.GetOutputFile().Flush() 866 867 with open(self.out_filename, 'r') as f: 868 output = f.read() 869 self.assertIn('Show a list of all debugger commands', output) 870 self.assertIn('List debugger commands related to a word', output) 871