| """ | |
| Test lldb Python API for file handles. | |
| """ | |
| import os | |
| import io | |
| import re | |
| import sys | |
| from contextlib import contextmanager | |
| import lldb | |
| from lldbsuite.test import lldbtest | |
| from lldbsuite.test.decorators import * | |
| class OhNoe(Exception): | |
| pass | |
| class BadIO(io.TextIOBase): | |
| @property | |
| def closed(self): | |
| return False | |
| def writable(self): | |
| return True | |
| def readable(self): | |
| return True | |
| def write(self, s): | |
| raise OhNoe("OH NOE") | |
| def read(self, n): | |
| raise OhNoe("OH NOE") | |
| def flush(self): | |
| raise OhNoe("OH NOE") | |
| # This class will raise an exception while it's being | |
| # converted into a C++ object by swig | |
| class ReallyBadIO(io.TextIOBase): | |
| def fileno(self): | |
| return 999 | |
| def writable(self): | |
| raise OhNoe("OH NOE!!!") | |
| class MutableBool: | |
| def __init__(self, value): | |
| self.value = value | |
| def set(self, value): | |
| self.value = bool(value) | |
| def __bool__(self): | |
| return self.value | |
| class FlushTestIO(io.StringIO): | |
| def __init__(self, mutable_flushed, mutable_closed): | |
| super(FlushTestIO, self).__init__() | |
| self.mut_flushed = mutable_flushed | |
| self.mut_closed = mutable_closed | |
| def close(self): | |
| self.mut_closed.set(True) | |
| return super(FlushTestIO, self).close() | |
| def flush(self): | |
| self.mut_flushed.set(True) | |
| return super(FlushTestIO, self).flush() | |
| @contextmanager | |
| def replace_stdout(new): | |
| old = sys.stdout | |
| sys.stdout = new | |
| try: | |
| yield | |
| finally: | |
| sys.stdout = old | |
| def readStrippedLines(f): | |
| def i(): | |
| for line in f: | |
| line = line.strip() | |
| if line: | |
| yield line | |
| return list(i()) | |
| class FileHandleTestCase(lldbtest.TestBase): | |
| NO_DEBUG_INFO_TESTCASE = True | |
| # The way normal tests evaluate debugger commands is | |
| # by using a SBCommandInterpreter directly, which captures | |
| # the output in a result object. For many of tests tests | |
| # we want the debugger to write the output directly to | |
| # its I/O streams like it would have done interactively. | |
| # | |
| # For this reason we also define handleCmd() here, even though | |
| # it is similar to runCmd(). | |
| def setUp(self): | |
| super(FileHandleTestCase, self).setUp() | |
| self.out_filename = self.getBuildArtifact("output") | |
| self.in_filename = self.getBuildArtifact("input") | |
| self.err_filename = self.getBuildArtifact("error") | |
| def tearDown(self): | |
| super(FileHandleTestCase, self).tearDown() | |
| for name in (self.out_filename, self.in_filename, self.err_filename): | |
| if os.path.exists(name): | |
| os.unlink(name) | |
| # Similar to runCmd(), but letting the debugger just print the results | |
| # instead of collecting them. | |
| def handleCmd(self, cmd, check=True, collect_result=True): | |
| assert not check or collect_result | |
| ret = lldb.SBCommandReturnObject() | |
| if collect_result: | |
| interpreter = self.dbg.GetCommandInterpreter() | |
| interpreter.HandleCommand(cmd, ret) | |
| else: | |
| self.dbg.HandleCommand(cmd) | |
| self.dbg.GetOutputFile().Flush() | |
| self.dbg.GetErrorFile().Flush() | |
| if collect_result and check: | |
| self.assertTrue(ret.Succeeded()) | |
| return ret.GetOutput() | |
| def test_legacy_file_out_script(self): | |
| with open(self.out_filename, "w") as f: | |
| self.dbg.SetOutputFileHandle(f, False) | |
| # scripts print to output even if you capture the results | |
| # I'm not sure I love that behavior, but that's the way | |
| # it's been for a long time. That's why this test works | |
| # even with collect_result=True. | |
| self.handleCmd("script 1+1") | |
| self.dbg.GetOutputFileHandle().write("FOO\n") | |
| self.dbg.GetOutputFileHandle().flush() | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual(readStrippedLines(f), ["2", "FOO"]) | |
| def test_legacy_file_out(self): | |
| with open(self.out_filename, "w") as f: | |
| self.dbg.SetOutputFileHandle(f, False) | |
| self.handleCmd("expression/x 3735928559", collect_result=False, check=False) | |
| with open(self.out_filename, "r") as f: | |
| self.assertIn("deadbeef", f.read()) | |
| def test_legacy_file_err_with_get(self): | |
| with open(self.out_filename, "w") as f: | |
| self.dbg.SetErrorFileHandle(f, False) | |
| self.handleCmd("lolwut", check=False, collect_result=False) | |
| f2 = self.dbg.GetErrorFileHandle() | |
| f2.write("FOOBAR\n") | |
| f2.flush() | |
| with open(self.out_filename, "r") as f: | |
| errors = f.read() | |
| self.assertTrue(re.search(r"error:.*lolwut", errors)) | |
| self.assertTrue(re.search(r"FOOBAR", errors)) | |
| def test_legacy_file_err(self): | |
| with open(self.out_filename, "w") as f: | |
| self.dbg.SetErrorFileHandle(f, False) | |
| self.handleCmd("lol", check=False, collect_result=False) | |
| with open(self.out_filename, "r") as f: | |
| self.assertIn("is not a valid command", f.read()) | |
| def test_legacy_file_error(self): | |
| with open(self.out_filename, "w") as f: | |
| self.dbg.SetErrorFileHandle(f, False) | |
| self.handleCmd("lolwut", check=False, collect_result=False) | |
| with open(self.out_filename, "r") as f: | |
| errors = f.read() | |
| self.assertTrue(re.search(r"error:.*lolwut", errors)) | |
| def test_sbfile_type_errors(self): | |
| sbf = lldb.SBFile() | |
| self.assertRaises(Exception, sbf.Write, None) | |
| self.assertRaises(Exception, sbf.Read, None) | |
| self.assertRaises(Exception, sbf.Read, b"this bytes is not mutable") | |
| self.assertRaises(Exception, sbf.Write, "ham sandwich") | |
| self.assertRaises(Exception, sbf.Read, "ham sandwich") | |
| def test_sbfile_write_fileno(self): | |
| with open(self.out_filename, "w") as f: | |
| sbf = lldb.SBFile(f.fileno(), "w", False) | |
| self.assertTrue(sbf.IsValid()) | |
| e, n = sbf.Write(b"FOO\nBAR") | |
| self.assertSuccess(e) | |
| self.assertEqual(n, 7) | |
| sbf.Close() | |
| self.assertFalse(sbf.IsValid()) | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual(readStrippedLines(f), ["FOO", "BAR"]) | |
| def test_sbfile_write(self): | |
| with open(self.out_filename, "w") as f: | |
| sbf = lldb.SBFile(f) | |
| e, n = sbf.Write(b"FOO\n") | |
| self.assertSuccess(e) | |
| self.assertEqual(n, 4) | |
| sbf.Close() | |
| self.assertTrue(f.closed) | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual(f.read().strip(), "FOO") | |
| def test_sbfile_read_fileno(self): | |
| with open(self.out_filename, "w") as f: | |
| f.write("FOO") | |
| with open(self.out_filename, "r") as f: | |
| sbf = lldb.SBFile(f.fileno(), "r", False) | |
| self.assertTrue(sbf.IsValid()) | |
| buffer = bytearray(100) | |
| e, n = sbf.Read(buffer) | |
| self.assertSuccess(e) | |
| self.assertEqual(buffer[:n], b"FOO") | |
| def test_sbfile_read(self): | |
| with open(self.out_filename, "w") as f: | |
| f.write("foo") | |
| with open(self.out_filename, "r") as f: | |
| sbf = lldb.SBFile(f) | |
| buf = bytearray(100) | |
| e, n = sbf.Read(buf) | |
| self.assertSuccess(e) | |
| self.assertEqual(n, 3) | |
| self.assertEqual(buf[:n], b"foo") | |
| sbf.Close() | |
| self.assertTrue(f.closed) | |
| def test_fileno_out(self): | |
| with open(self.out_filename, "w") as f: | |
| sbf = lldb.SBFile(f.fileno(), "w", False) | |
| status = self.dbg.SetOutputFile(sbf) | |
| self.assertSuccess(status) | |
| self.handleCmd("script 1+2") | |
| self.dbg.GetOutputFile().Write(b"quux") | |
| self.dbg.GetOutputFile().Flush() | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual(readStrippedLines(f), ["3", "quux"]) | |
| def test_fileno_help(self): | |
| with open(self.out_filename, "w") as f: | |
| sbf = lldb.SBFile(f.fileno(), "w", False) | |
| status = self.dbg.SetOutputFile(sbf) | |
| self.assertSuccess(status) | |
| self.handleCmd("help help", collect_result=False, check=False) | |
| with open(self.out_filename, "r") as f: | |
| self.assertTrue( | |
| re.search(r"Show a list of all debugger commands", f.read()) | |
| ) | |
| def test_help(self): | |
| with open(self.out_filename, "w") as f: | |
| status = self.dbg.SetOutputFile(lldb.SBFile(f)) | |
| self.assertSuccess(status) | |
| self.handleCmd("help help", check=False, collect_result=False) | |
| with open(self.out_filename, "r") as f: | |
| self.assertIn("Show a list of all debugger commands", f.read()) | |
| def test_immediate(self): | |
| with open(self.out_filename, "w") as f: | |
| ret = lldb.SBCommandReturnObject() | |
| ret.SetImmediateOutputFile(f) | |
| interpreter = self.dbg.GetCommandInterpreter() | |
| interpreter.HandleCommand("help help", ret) | |
| # make sure the file wasn't closed early. | |
| f.write("\nQUUX\n") | |
| ret = None # call destructor and flush streams | |
| with open(self.out_filename, "r") as f: | |
| output = f.read() | |
| self.assertTrue(re.search(r"Show a list of all debugger commands", output)) | |
| self.assertTrue(re.search(r"QUUX", output)) | |
| def test_immediate_string(self): | |
| f = io.StringIO() | |
| ret = lldb.SBCommandReturnObject() | |
| ret.SetImmediateOutputFile(f) | |
| interpreter = self.dbg.GetCommandInterpreter() | |
| interpreter.HandleCommand("help help", ret) | |
| # make sure the file wasn't closed early. | |
| f.write("\nQUUX\n") | |
| ret = None # call destructor and flush streams | |
| output = f.getvalue() | |
| self.assertTrue(re.search(r"Show a list of all debugger commands", output)) | |
| self.assertTrue(re.search(r"QUUX", output)) | |
| def test_immediate_sbfile_string(self): | |
| f = io.StringIO() | |
| ret = lldb.SBCommandReturnObject() | |
| ret.SetImmediateOutputFile(lldb.SBFile(f)) | |
| interpreter = self.dbg.GetCommandInterpreter() | |
| interpreter.HandleCommand("help help", ret) | |
| output = f.getvalue() | |
| ret = None # call destructor and flush streams | |
| # sbfile default constructor doesn't borrow the file | |
| self.assertTrue(f.closed) | |
| self.assertTrue(re.search(r"Show a list of all debugger commands", output)) | |
| def test_fileno_inout(self): | |
| with open(self.in_filename, "w") as f: | |
| f.write("help help\n") | |
| with open(self.out_filename, "w") as outf, open(self.in_filename, "r") as inf: | |
| outsbf = lldb.SBFile(outf.fileno(), "w", False) | |
| status = self.dbg.SetOutputFile(outsbf) | |
| self.assertSuccess(status) | |
| insbf = lldb.SBFile(inf.fileno(), "r", False) | |
| status = self.dbg.SetInputFile(insbf) | |
| self.assertSuccess(status) | |
| opts = lldb.SBCommandInterpreterRunOptions() | |
| self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) | |
| self.dbg.GetOutputFile().Flush() | |
| with open(self.out_filename, "r") as f: | |
| self.assertTrue( | |
| re.search(r"Show a list of all debugger commands", f.read()) | |
| ) | |
| def test_inout(self): | |
| with open(self.in_filename, "w") as f: | |
| f.write("help help\n") | |
| with open(self.out_filename, "w") as outf, open(self.in_filename, "r") as inf: | |
| status = self.dbg.SetOutputFile(lldb.SBFile(outf)) | |
| self.assertSuccess(status) | |
| status = self.dbg.SetInputFile(lldb.SBFile(inf)) | |
| self.assertSuccess(status) | |
| opts = lldb.SBCommandInterpreterRunOptions() | |
| self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) | |
| self.dbg.GetOutputFile().Flush() | |
| with open(self.out_filename, "r") as f: | |
| output = f.read() | |
| self.assertIn("Show a list of all debugger commands", output) | |
| def test_binary_inout(self): | |
| with open(self.in_filename, "w") as f: | |
| f.write("help help\n") | |
| with open(self.out_filename, "wb") as outf, open(self.in_filename, "rb") as inf: | |
| status = self.dbg.SetOutputFile(lldb.SBFile(outf)) | |
| self.assertSuccess(status) | |
| status = self.dbg.SetInputFile(lldb.SBFile(inf)) | |
| self.assertSuccess(status) | |
| opts = lldb.SBCommandInterpreterRunOptions() | |
| self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) | |
| self.dbg.GetOutputFile().Flush() | |
| with open(self.out_filename, "r") as f: | |
| output = f.read() | |
| self.assertIn("Show a list of all debugger commands", output) | |
| def test_string_inout(self): | |
| inf = io.StringIO("help help\nexpression/x ~0\n") | |
| outf = io.StringIO() | |
| status = self.dbg.SetOutputFile(lldb.SBFile(outf)) | |
| self.assertSuccess(status) | |
| status = self.dbg.SetInputFile(lldb.SBFile(inf)) | |
| self.assertSuccess(status) | |
| opts = lldb.SBCommandInterpreterRunOptions() | |
| self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) | |
| self.dbg.GetOutputFile().Flush() | |
| output = outf.getvalue() | |
| self.assertIn("Show a list of all debugger commands", output) | |
| self.assertIn("0xfff", output) | |
| def test_bytes_inout(self): | |
| inf = io.BytesIO(b"help help\nhelp b\n") | |
| outf = io.BytesIO() | |
| status = self.dbg.SetOutputFile(lldb.SBFile(outf)) | |
| self.assertSuccess(status) | |
| status = self.dbg.SetInputFile(lldb.SBFile(inf)) | |
| self.assertSuccess(status) | |
| opts = lldb.SBCommandInterpreterRunOptions() | |
| self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) | |
| self.dbg.GetOutputFile().Flush() | |
| output = outf.getvalue() | |
| self.assertIn(b"Show a list of all debugger commands", output) | |
| self.assertIn(b"Set a breakpoint", output) | |
| def test_fileno_error(self): | |
| with open(self.out_filename, "w") as f: | |
| sbf = lldb.SBFile(f.fileno(), "w", False) | |
| status = self.dbg.SetErrorFile(sbf) | |
| self.assertSuccess(status) | |
| self.handleCmd("lolwut", check=False, collect_result=False) | |
| self.dbg.GetErrorFile().Write(b"\nzork\n") | |
| with open(self.out_filename, "r") as f: | |
| errors = f.read() | |
| self.assertTrue(re.search(r"error:.*lolwut", errors)) | |
| self.assertTrue(re.search(r"zork", errors)) | |
| def test_replace_stdout(self): | |
| f = io.StringIO() | |
| with replace_stdout(f): | |
| self.assertEqual(sys.stdout, f) | |
| self.handleCmd( | |
| 'script sys.stdout.write("lol")', collect_result=False, check=False | |
| ) | |
| self.assertEqual(sys.stdout, f) | |
| def test_replace_stdout_with_nonfile(self): | |
| f = io.StringIO() | |
| with replace_stdout(f): | |
| class Nothing: | |
| pass | |
| with replace_stdout(Nothing): | |
| self.assertEqual(sys.stdout, Nothing) | |
| self.handleCmd( | |
| 'script sys.stdout.write("lol")', check=False, collect_result=False | |
| ) | |
| self.assertEqual(sys.stdout, Nothing) | |
| sys.stdout.write("FOO") | |
| self.assertEqual(f.getvalue(), "FOO") | |
| def test_sbfile_write_borrowed(self): | |
| with open(self.out_filename, "w") as f: | |
| sbf = lldb.SBFile.Create(f, borrow=True) | |
| e, n = sbf.Write(b"FOO") | |
| self.assertSuccess(e) | |
| self.assertEqual(n, 3) | |
| sbf.Close() | |
| self.assertFalse(f.closed) | |
| f.write("BAR\n") | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual(f.read().strip(), "FOOBAR") | |
| def test_sbfile_write_forced(self): | |
| with open(self.out_filename, "w") as f: | |
| written = MutableBool(False) | |
| orig_write = f.write | |
| def mywrite(x): | |
| written.set(True) | |
| return orig_write(x) | |
| f.write = mywrite | |
| sbf = lldb.SBFile.Create(f, force_io_methods=True) | |
| e, n = sbf.Write(b"FOO") | |
| self.assertTrue(written) | |
| self.assertSuccess(e) | |
| self.assertEqual(n, 3) | |
| sbf.Close() | |
| self.assertTrue(f.closed) | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual(f.read().strip(), "FOO") | |
| def test_sbfile_write_forced_borrowed(self): | |
| with open(self.out_filename, "w") as f: | |
| written = MutableBool(False) | |
| orig_write = f.write | |
| def mywrite(x): | |
| written.set(True) | |
| return orig_write(x) | |
| f.write = mywrite | |
| sbf = lldb.SBFile.Create(f, borrow=True, force_io_methods=True) | |
| e, n = sbf.Write(b"FOO") | |
| self.assertTrue(written) | |
| self.assertSuccess(e) | |
| self.assertEqual(n, 3) | |
| sbf.Close() | |
| self.assertFalse(f.closed) | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual(f.read().strip(), "FOO") | |
| def test_sbfile_write_string(self): | |
| f = io.StringIO() | |
| sbf = lldb.SBFile(f) | |
| e, n = sbf.Write(b"FOO") | |
| self.assertEqual(f.getvalue().strip(), "FOO") | |
| self.assertSuccess(e) | |
| self.assertEqual(n, 3) | |
| sbf.Close() | |
| self.assertTrue(f.closed) | |
| def test_string_out(self): | |
| f = io.StringIO() | |
| status = self.dbg.SetOutputFile(f) | |
| self.assertSuccess(status) | |
| self.handleCmd("script 'foobar'") | |
| self.assertEqual(f.getvalue().strip(), "'foobar'") | |
| def test_string_error(self): | |
| f = io.StringIO() | |
| status = self.dbg.SetErrorFile(f) | |
| self.assertSuccess(status) | |
| self.handleCmd("lolwut", check=False, collect_result=False) | |
| errors = f.getvalue() | |
| self.assertTrue(re.search(r"error:.*lolwut", errors)) | |
| def test_sbfile_write_bytes(self): | |
| f = io.BytesIO() | |
| sbf = lldb.SBFile(f) | |
| e, n = sbf.Write(b"FOO") | |
| self.assertEqual(f.getvalue().strip(), b"FOO") | |
| self.assertSuccess(e) | |
| self.assertEqual(n, 3) | |
| sbf.Close() | |
| self.assertTrue(f.closed) | |
| def test_sbfile_read_string(self): | |
| f = io.StringIO("zork") | |
| sbf = lldb.SBFile(f) | |
| buf = bytearray(100) | |
| e, n = sbf.Read(buf) | |
| self.assertSuccess(e) | |
| self.assertEqual(buf[:n], b"zork") | |
| def test_sbfile_read_string_one_byte(self): | |
| f = io.StringIO("z") | |
| sbf = lldb.SBFile(f) | |
| buf = bytearray(1) | |
| e, n = sbf.Read(buf) | |
| self.assertTrue(e.Fail()) | |
| self.assertEqual(n, 0) | |
| self.assertEqual( | |
| e.GetCString(), "can't read less than 6 bytes from a utf8 text stream" | |
| ) | |
| def test_sbfile_read_bytes(self): | |
| f = io.BytesIO(b"zork") | |
| sbf = lldb.SBFile(f) | |
| buf = bytearray(100) | |
| e, n = sbf.Read(buf) | |
| self.assertSuccess(e) | |
| self.assertEqual(buf[:n], b"zork") | |
| def test_sbfile_out(self): | |
| with open(self.out_filename, "w") as f: | |
| sbf = lldb.SBFile(f) | |
| status = self.dbg.SetOutputFile(sbf) | |
| self.assertSuccess(status) | |
| self.handleCmd("script 2+2") | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual(f.read().strip(), "4") | |
| def test_file_out(self): | |
| with open(self.out_filename, "w") as f: | |
| status = self.dbg.SetOutputFile(f) | |
| self.assertSuccess(status) | |
| self.handleCmd("script 2+2") | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual(f.read().strip(), "4") | |
| def test_sbfile_error(self): | |
| with open(self.out_filename, "w") as f: | |
| sbf = lldb.SBFile(f) | |
| status = self.dbg.SetErrorFile(sbf) | |
| self.assertSuccess(status) | |
| self.handleCmd("lolwut", check=False, collect_result=False) | |
| with open(self.out_filename, "r") as f: | |
| errors = f.read() | |
| self.assertTrue(re.search(r"error:.*lolwut", errors)) | |
| def test_file_error(self): | |
| with open(self.out_filename, "w") as f: | |
| status = self.dbg.SetErrorFile(f) | |
| self.assertSuccess(status) | |
| self.handleCmd("lolwut", check=False, collect_result=False) | |
| with open(self.out_filename, "r") as f: | |
| errors = f.read() | |
| self.assertTrue(re.search(r"error:.*lolwut", errors)) | |
| def test_exceptions(self): | |
| self.assertRaises(Exception, lldb.SBFile, None) | |
| self.assertRaises(Exception, lldb.SBFile, "ham sandwich") | |
| self.assertRaises(OhNoe, lldb.SBFile, ReallyBadIO()) | |
| error, n = lldb.SBFile(BadIO()).Write(b"FOO") | |
| self.assertEqual(n, 0) | |
| self.assertTrue(error.Fail()) | |
| self.assertIn("OH NOE", error.GetCString()) | |
| error, n = lldb.SBFile(BadIO()).Read(bytearray(100)) | |
| self.assertEqual(n, 0) | |
| self.assertTrue(error.Fail()) | |
| self.assertIn("OH NOE", error.GetCString()) | |
| def test_exceptions_logged(self): | |
| messages = list() | |
| self.dbg.SetLoggingCallback(messages.append) | |
| self.handleCmd("log enable lldb script") | |
| self.dbg.SetOutputFile(lldb.SBFile(BadIO())) | |
| self.handleCmd("script 1+1") | |
| self.assertTrue(any("OH NOE" in msg for msg in messages)) | |
| def test_flush(self): | |
| flushed = MutableBool(False) | |
| closed = MutableBool(False) | |
| f = FlushTestIO(flushed, closed) | |
| self.assertFalse(flushed) | |
| self.assertFalse(closed) | |
| sbf = lldb.SBFile(f) | |
| self.assertFalse(flushed) | |
| self.assertFalse(closed) | |
| sbf = None | |
| self.assertFalse(flushed) | |
| self.assertTrue(closed) | |
| self.assertTrue(f.closed) | |
| flushed = MutableBool(False) | |
| closed = MutableBool(False) | |
| f = FlushTestIO(flushed, closed) | |
| self.assertFalse(flushed) | |
| self.assertFalse(closed) | |
| sbf = lldb.SBFile.Create(f, borrow=True) | |
| self.assertFalse(flushed) | |
| self.assertFalse(closed) | |
| sbf = None | |
| self.assertTrue(flushed) | |
| self.assertFalse(closed) | |
| self.assertFalse(f.closed) | |
| def test_fileno_flush(self): | |
| with open(self.out_filename, "w") as f: | |
| f.write("foo") | |
| sbf = lldb.SBFile(f) | |
| sbf.Write(b"bar") | |
| sbf = None | |
| self.assertTrue(f.closed) | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual(f.read(), "foobar") | |
| with open(self.out_filename, "w+") as f: | |
| f.write("foo") | |
| sbf = lldb.SBFile.Create(f, borrow=True) | |
| sbf.Write(b"bar") | |
| sbf = None | |
| self.assertFalse(f.closed) | |
| f.seek(0) | |
| self.assertEqual(f.read(), "foobar") | |
| def test_close(self): | |
| with open(self.out_filename, "w") as f: | |
| status = self.dbg.SetOutputFile(f) | |
| self.assertSuccess(status) | |
| self.handleCmd("help help", check=False, collect_result=False) | |
| # make sure the file wasn't closed early. | |
| f.write("\nZAP\n") | |
| lldb.SBDebugger.Destroy(self.dbg) | |
| # check that output file was closed when debugger was destroyed. | |
| with self.assertRaises(ValueError): | |
| f.write("\nQUUX\n") | |
| with open(self.out_filename, "r") as f: | |
| output = f.read() | |
| self.assertTrue(re.search(r"Show a list of all debugger commands", output)) | |
| self.assertTrue(re.search(r"ZAP", output)) | |
| def test_stdout(self): | |
| f = io.StringIO() | |
| status = self.dbg.SetOutputFile(f) | |
| self.assertSuccess(status) | |
| self.handleCmd(r"script sys.stdout.write('foobar\n')") | |
| self.assertEqual(f.getvalue().strip().split(), ["foobar", "7"]) | |
| def test_stdout_file(self): | |
| with open(self.out_filename, "w") as f: | |
| status = self.dbg.SetOutputFile(f) | |
| self.assertSuccess(status) | |
| self.handleCmd(r"script sys.stdout.write('foobar\n')") | |
| with open(self.out_filename, "r") as f: | |
| # In python2 sys.stdout.write() returns None, which | |
| # the REPL will ignore, but in python3 it will | |
| # return the number of bytes written, which the REPL | |
| # will print out. | |
| lines = [x for x in f.read().strip().split() if x != "7"] | |
| self.assertEqual(lines, ["foobar"]) | |
| @skipIf(hostoslist=["windows"]) | |
| def test_stdout_file_interactive(self): | |
| """Ensure when we read stdin from a file, outputs from python goes to the right I/O stream.""" | |
| with open(self.in_filename, "w") as f: | |
| f.write( | |
| """script --language python -- | |
| import sys | |
| variable = 250 + 5 | |
| print(variable) | |
| print("wrote to", "stderr", file=sys.stderr) | |
| quit | |
| """ | |
| ) | |
| with open(self.out_filename, "w") as outf, open( | |
| self.in_filename, "r" | |
| ) as inf, open(self.err_filename, "w") as errf: | |
| status = self.dbg.SetOutputFile(lldb.SBFile(outf)) | |
| self.assertSuccess(status) | |
| status = self.dbg.SetErrorFile(lldb.SBFile(errf)) | |
| self.assertSuccess(status) | |
| status = self.dbg.SetInputFile(lldb.SBFile(inf)) | |
| self.assertSuccess(status) | |
| auto_handle_events = True | |
| spawn_thread = False | |
| num_errs = 0 | |
| quit_requested = False | |
| stopped_for_crash = False | |
| opts = lldb.SBCommandInterpreterRunOptions() | |
| self.dbg.RunCommandInterpreter( | |
| auto_handle_events, | |
| spawn_thread, | |
| opts, | |
| num_errs, | |
| quit_requested, | |
| stopped_for_crash, | |
| ) | |
| self.dbg.GetOutputFile().Flush() | |
| expected_out_text = "255" | |
| expected_err_text = "wrote to stderr" | |
| # check stdout | |
| with open(self.out_filename, "r") as f: | |
| out_text = f.read() | |
| self.assertIn(expected_out_text, out_text) | |
| self.assertNotIn(expected_err_text, out_text) | |
| # check stderr | |
| with open(self.err_filename, "r") as f: | |
| err_text = f.read() | |
| self.assertIn(expected_err_text, err_text) | |
| self.assertNotIn(expected_out_text, err_text) | |
| def test_identity(self): | |
| f = io.StringIO() | |
| sbf = lldb.SBFile(f) | |
| self.assertIs(f, sbf.GetFile()) | |
| sbf.Close() | |
| self.assertTrue(f.closed) | |
| f = io.StringIO() | |
| sbf = lldb.SBFile.Create(f, borrow=True) | |
| self.assertIs(f, sbf.GetFile()) | |
| sbf.Close() | |
| self.assertFalse(f.closed) | |
| with open(self.out_filename, "w") as f: | |
| sbf = lldb.SBFile(f) | |
| self.assertIs(f, sbf.GetFile()) | |
| sbf.Close() | |
| self.assertTrue(f.closed) | |
| with open(self.out_filename, "w") as f: | |
| sbf = lldb.SBFile.Create(f, borrow=True) | |
| self.assertIsNot(f, sbf.GetFile()) | |
| sbf.Write(b"foobar\n") | |
| self.assertEqual(f.fileno(), sbf.GetFile().fileno()) | |
| sbf.Close() | |
| self.assertFalse(f.closed) | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual("foobar", f.read().strip()) | |
| with open(self.out_filename, "wb") as f: | |
| sbf = lldb.SBFile.Create(f, borrow=True, force_io_methods=True) | |
| self.assertIs(f, sbf.GetFile()) | |
| sbf.Write(b"foobar\n") | |
| self.assertEqual(f.fileno(), sbf.GetFile().fileno()) | |
| sbf.Close() | |
| self.assertFalse(f.closed) | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual("foobar", f.read().strip()) | |
| with open(self.out_filename, "wb") as f: | |
| sbf = lldb.SBFile.Create(f, force_io_methods=True) | |
| self.assertIs(f, sbf.GetFile()) | |
| sbf.Write(b"foobar\n") | |
| self.assertEqual(f.fileno(), sbf.GetFile().fileno()) | |
| sbf.Close() | |
| self.assertTrue(f.closed) | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual("foobar", f.read().strip()) | |
| def test_back_and_forth(self): | |
| with open(self.out_filename, "w") as f: | |
| # at each step here we're borrowing the file, so we have to keep | |
| # them all alive until the end. | |
| sbf = lldb.SBFile.Create(f, borrow=True) | |
| def i(sbf): | |
| for i in range(10): | |
| f = sbf.GetFile() | |
| self.assertEqual(f.mode, "w") | |
| yield f | |
| sbf = lldb.SBFile.Create(f, borrow=True) | |
| yield sbf | |
| sbf.Write(str(i).encode("ascii") + b"\n") | |
| files = list(i(sbf)) | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual(list(range(10)), list(map(int, f.read().strip().split()))) | |
| def test_set_filehandle_none(self): | |
| self.assertRaises(Exception, self.dbg.SetOutputFile, None) | |
| self.assertRaises(Exception, self.dbg.SetOutputFile, "ham sandwich") | |
| self.assertRaises(Exception, self.dbg.SetOutputFileHandle, "ham sandwich") | |
| self.assertRaises(Exception, self.dbg.SetInputFile, None) | |
| self.assertRaises(Exception, self.dbg.SetInputFile, "ham sandwich") | |
| self.assertRaises(Exception, self.dbg.SetInputFileHandle, "ham sandwich") | |
| self.assertRaises(Exception, self.dbg.SetErrorFile, None) | |
| self.assertRaises(Exception, self.dbg.SetErrorFile, "ham sandwich") | |
| self.assertRaises(Exception, self.dbg.SetErrorFileHandle, "ham sandwich") | |
| with open(self.out_filename, "w") as f: | |
| status = self.dbg.SetOutputFile(f) | |
| self.assertSuccess(status) | |
| status = self.dbg.SetErrorFile(f) | |
| self.assertSuccess(status) | |
| self.dbg.SetOutputFileHandle(None, False) | |
| self.dbg.SetErrorFileHandle(None, False) | |
| sbf = self.dbg.GetOutputFile() | |
| self.assertEqual(sbf.GetFile().fileno(), 1) | |
| sbf = self.dbg.GetErrorFile() | |
| self.assertEqual(sbf.GetFile().fileno(), 2) | |
| with open(self.out_filename, "r") as f: | |
| status = self.dbg.SetInputFile(f) | |
| self.assertSuccess(status) | |
| self.dbg.SetInputFileHandle(None, False) | |
| sbf = self.dbg.GetInputFile() | |
| self.assertEqual(sbf.GetFile().fileno(), 0) | |
| def test_sbstream(self): | |
| with open(self.out_filename, "w") as f: | |
| stream = lldb.SBStream() | |
| stream.RedirectToFile(f) | |
| stream.Print("zork") | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual(f.read().strip(), "zork") | |
| with open(self.out_filename, "w") as f: | |
| stream = lldb.SBStream() | |
| stream.RedirectToFileHandle(f, True) | |
| stream.Print("Yendor") | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual(f.read().strip(), "Yendor") | |
| stream = lldb.SBStream() | |
| f = open(self.out_filename, "w") | |
| stream.RedirectToFile(lldb.SBFile.Create(f, borrow=False)) | |
| stream.Print("Frobozz") | |
| stream = None | |
| self.assertTrue(f.closed) | |
| with open(self.out_filename, "r") as f: | |
| self.assertEqual(f.read().strip(), "Frobozz") | |
| def test_set_sbstream(self): | |
| with open(self.out_filename, "w") as outf: | |
| outsbf = lldb.SBFile(outf.fileno(), "w", False) | |
| status = self.dbg.SetOutputFile(outsbf) | |
| self.assertSuccess(status) | |
| self.dbg.SetInputString("help apropos\nhelp help\n") | |
| opts = lldb.SBCommandInterpreterRunOptions() | |
| self.dbg.RunCommandInterpreter(True, False, opts, 0, False, False) | |
| self.dbg.GetOutputFile().Flush() | |
| with open(self.out_filename, "r") as f: | |
| output = f.read() | |
| self.assertIn("Show a list of all debugger commands", output) | |
| self.assertIn("List debugger commands related to a word", output) |