""" 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 mydir = lldbtest.Base.compute_mydir(__file__) # The way this class interacts with the debugger is different # than normal. Most of these test cases will mess with the # debugger I/O streams, so we want a fresh debugger for each # test so those mutations don't interfere with each other. # # Also, 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.debugger = lldb.SBDebugger.Create() self.out_filename = self.getBuildArtifact('output') self.in_filename = self.getBuildArtifact('input') def tearDown(self): lldb.SBDebugger.Destroy(self.debugger) super(FileHandleTestCase, self).tearDown() for name in (self.out_filename, self.in_filename): if os.path.exists(name): os.unlink(name) # Similar to runCmd(), but this uses the per-test debugger, and it # supports, 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.debugger.GetCommandInterpreter() interpreter.HandleCommand(cmd, ret) else: self.debugger.HandleCommand(cmd) self.debugger.GetOutputFile().Flush() self.debugger.GetErrorFile().Flush() if collect_result and check: self.assertTrue(ret.Succeeded()) return ret.GetOutput() @add_test_categories(['pyapi']) def test_legacy_file_out_script(self): with open(self.out_filename, 'w') as f: self.debugger.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.debugger.GetOutputFileHandle().write('FOO\n') lldb.SBDebugger.Destroy(self.debugger) with open(self.out_filename, 'r') as f: self.assertEqual(readStrippedLines(f), ['2', 'FOO']) @add_test_categories(['pyapi']) def test_legacy_file_out(self): with open(self.out_filename, 'w') as f: self.debugger.SetOutputFileHandle(f, False) self.handleCmd('p/x 3735928559', collect_result=False, check=False) lldb.SBDebugger.Destroy(self.debugger) with open(self.out_filename, 'r') as f: self.assertIn('deadbeef', f.read()) @add_test_categories(['pyapi']) def test_legacy_file_err_with_get(self): with open(self.out_filename, 'w') as f: self.debugger.SetErrorFileHandle(f, False) self.handleCmd('lolwut', check=False, collect_result=False) f2 = self.debugger.GetErrorFileHandle() f2.write('FOOBAR\n') f2.flush() lldb.SBDebugger.Destroy(self.debugger) 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)) @add_test_categories(['pyapi']) def test_legacy_file_err(self): with open(self.out_filename, 'w') as f: self.debugger.SetErrorFileHandle(f, False) self.handleCmd('lol', check=False, collect_result=False) lldb.SBDebugger.Destroy(self.debugger) with open(self.out_filename, 'r') as f: self.assertIn("is not a valid command", f.read()) @add_test_categories(['pyapi']) def test_legacy_file_error(self): debugger = self.debugger with open(self.out_filename, 'w') as f: debugger.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)) @add_test_categories(['pyapi']) 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, u"ham sandwich") self.assertRaises(Exception, sbf.Read, u"ham sandwich") @add_test_categories(['pyapi']) 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.assertTrue(e.Success()) self.assertEqual(n, 7) sbf.Close() self.assertFalse(sbf.IsValid()) with open(self.out_filename, 'r') as f: self.assertEqual(readStrippedLines(f), ['FOO', 'BAR']) @add_test_categories(['pyapi']) 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.assertTrue(e.Success()) self.assertEqual(n, 4) sbf.Close() self.assertTrue(f.closed) with open(self.out_filename, 'r') as f: self.assertEqual(f.read().strip(), 'FOO') @add_test_categories(['pyapi']) 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.assertTrue(e.Success()) self.assertEqual(buffer[:n], b'FOO') @add_test_categories(['pyapi']) 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.assertTrue(e.Success()) self.assertEqual(n, 3) self.assertEqual(buf[:n], b'foo') sbf.Close() self.assertTrue(f.closed) @add_test_categories(['pyapi']) def test_fileno_out(self): with open(self.out_filename, 'w') as f: sbf = lldb.SBFile(f.fileno(), "w", False) status = self.debugger.SetOutputFile(sbf) self.assertTrue(status.Success()) self.handleCmd('script 1+2') self.debugger.GetOutputFile().Write(b'quux') with open(self.out_filename, 'r') as f: self.assertEqual(readStrippedLines(f), ['3', 'quux']) @add_test_categories(['pyapi']) def test_fileno_help(self): with open(self.out_filename, 'w') as f: sbf = lldb.SBFile(f.fileno(), "w", False) status = self.debugger.SetOutputFile(sbf) self.assertTrue(status.Success()) 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())) @add_test_categories(['pyapi']) def test_help(self): debugger = self.debugger with open(self.out_filename, 'w') as f: status = debugger.SetOutputFile(lldb.SBFile(f)) self.assertTrue(status.Success()) 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()) @add_test_categories(['pyapi']) def test_immediate(self): with open(self.out_filename, 'w') as f: ret = lldb.SBCommandReturnObject() ret.SetImmediateOutputFile(f) interpreter = self.debugger.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)) @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) def test_immediate_string(self): f = io.StringIO() ret = lldb.SBCommandReturnObject() ret.SetImmediateOutputFile(f) interpreter = self.debugger.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)) @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) def test_immediate_sbfile_string(self): f = io.StringIO() ret = lldb.SBCommandReturnObject() ret.SetImmediateOutputFile(lldb.SBFile(f)) interpreter = self.debugger.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)) @add_test_categories(['pyapi']) 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.debugger.SetOutputFile(outsbf) self.assertTrue(status.Success()) insbf = lldb.SBFile(inf.fileno(), "r", False) status = self.debugger.SetInputFile(insbf) self.assertTrue(status.Success()) opts = lldb.SBCommandInterpreterRunOptions() self.debugger.RunCommandInterpreter(True, False, opts, 0, False, False) self.debugger.GetOutputFile().Flush() with open(self.out_filename, 'r') as f: self.assertTrue(re.search(r'Show a list of all debugger commands', f.read())) @add_test_categories(['pyapi']) 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.debugger.SetOutputFile(lldb.SBFile(outf)) self.assertTrue(status.Success()) status = self.debugger.SetInputFile(lldb.SBFile(inf)) self.assertTrue(status.Success()) opts = lldb.SBCommandInterpreterRunOptions() self.debugger.RunCommandInterpreter(True, False, opts, 0, False, False) self.debugger.GetOutputFile().Flush() with open(self.out_filename, 'r') as f: output = f.read() self.assertIn('Show a list of all debugger commands', output) @add_test_categories(['pyapi']) def test_binary_inout(self): debugger = self.debugger 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 = debugger.SetOutputFile(lldb.SBFile(outf)) self.assertTrue(status.Success()) status = debugger.SetInputFile(lldb.SBFile(inf)) self.assertTrue(status.Success()) opts = lldb.SBCommandInterpreterRunOptions() debugger.RunCommandInterpreter(True, False, opts, 0, False, False) debugger.GetOutputFile().Flush() with open(self.out_filename, 'r') as f: output = f.read() self.assertIn('Show a list of all debugger commands', output) @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) def test_string_inout(self): inf = io.StringIO("help help\np/x ~0\n") outf = io.StringIO() status = self.debugger.SetOutputFile(lldb.SBFile(outf)) self.assertTrue(status.Success()) status = self.debugger.SetInputFile(lldb.SBFile(inf)) self.assertTrue(status.Success()) opts = lldb.SBCommandInterpreterRunOptions() self.debugger.RunCommandInterpreter(True, False, opts, 0, False, False) self.debugger.GetOutputFile().Flush() output = outf.getvalue() self.assertIn('Show a list of all debugger commands', output) self.assertIn('0xfff', output) @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) def test_bytes_inout(self): inf = io.BytesIO(b"help help\nhelp b\n") outf = io.BytesIO() status = self.debugger.SetOutputFile(lldb.SBFile(outf)) self.assertTrue(status.Success()) status = self.debugger.SetInputFile(lldb.SBFile(inf)) self.assertTrue(status.Success()) opts = lldb.SBCommandInterpreterRunOptions() self.debugger.RunCommandInterpreter(True, False, opts, 0, False, False) self.debugger.GetOutputFile().Flush() output = outf.getvalue() self.assertIn(b'Show a list of all debugger commands', output) self.assertIn(b'Set a breakpoint', output) @add_test_categories(['pyapi']) def test_fileno_error(self): with open(self.out_filename, 'w') as f: sbf = lldb.SBFile(f.fileno(), 'w', False) status = self.debugger.SetErrorFile(sbf) self.assertTrue(status.Success()) self.handleCmd('lolwut', check=False, collect_result=False) self.debugger.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)) @add_test_categories(['pyapi']) 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) @add_test_categories(['pyapi']) def test_replace_stdout_with_nonfile(self): debugger = self.debugger 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(u"FOO") self.assertEqual(f.getvalue(), "FOO") @add_test_categories(['pyapi']) 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.assertTrue(e.Success()) 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') @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) 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.assertTrue(e.Success()) self.assertEqual(n, 3) sbf.Close() self.assertTrue(f.closed) with open(self.out_filename, 'r') as f: self.assertEqual(f.read().strip(), 'FOO') @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) 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.assertTrue(e.Success()) self.assertEqual(n, 3) sbf.Close() self.assertFalse(f.closed) with open(self.out_filename, 'r') as f: self.assertEqual(f.read().strip(), 'FOO') @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) 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.assertTrue(e.Success()) self.assertEqual(n, 3) sbf.Close() self.assertTrue(f.closed) @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) def test_string_out(self): f = io.StringIO() status = self.debugger.SetOutputFile(f) self.assertTrue(status.Success()) self.handleCmd("script 'foobar'") self.assertEqual(f.getvalue().strip(), "'foobar'") @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) def test_string_error(self): f = io.StringIO() debugger = self.debugger status = debugger.SetErrorFile(f) self.assertTrue(status.Success()) self.handleCmd('lolwut', check=False, collect_result=False) errors = f.getvalue() self.assertTrue(re.search(r'error:.*lolwut', errors)) @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) 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.assertTrue(e.Success()) self.assertEqual(n, 3) sbf.Close() self.assertTrue(f.closed) @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) def test_sbfile_read_string(self): f = io.StringIO('zork') sbf = lldb.SBFile(f) buf = bytearray(100) e, n = sbf.Read(buf) self.assertTrue(e.Success()) self.assertEqual(buf[:n], b'zork') @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) 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") @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) def test_sbfile_read_bytes(self): f = io.BytesIO(b'zork') sbf = lldb.SBFile(f) buf = bytearray(100) e, n = sbf.Read(buf) self.assertTrue(e.Success()) self.assertEqual(buf[:n], b'zork') @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) def test_sbfile_out(self): with open(self.out_filename, 'w') as f: sbf = lldb.SBFile(f) status = self.debugger.SetOutputFile(sbf) self.assertTrue(status.Success()) self.handleCmd('script 2+2') with open(self.out_filename, 'r') as f: self.assertEqual(f.read().strip(), '4') @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) def test_file_out(self): with open(self.out_filename, 'w') as f: status = self.debugger.SetOutputFile(f) self.assertTrue(status.Success()) self.handleCmd('script 2+2') with open(self.out_filename, 'r') as f: self.assertEqual(f.read().strip(), '4') @add_test_categories(['pyapi']) def test_sbfile_error(self): with open(self.out_filename, 'w') as f: sbf = lldb.SBFile(f) status = self.debugger.SetErrorFile(sbf) self.assertTrue(status.Success()) 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)) @add_test_categories(['pyapi']) def test_file_error(self): with open(self.out_filename, 'w') as f: status = self.debugger.SetErrorFile(f) self.assertTrue(status.Success()) 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)) @add_test_categories(['pyapi']) def test_exceptions(self): self.assertRaises(Exception, lldb.SBFile, None) self.assertRaises(Exception, lldb.SBFile, "ham sandwich") if sys.version_info[0] < 3: self.assertRaises(Exception, lldb.SBFile, ReallyBadIO()) else: 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()) @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) def test_exceptions_logged(self): messages = list() self.debugger.SetLoggingCallback(messages.append) self.handleCmd('log enable lldb script') self.debugger.SetOutputFile(lldb.SBFile(BadIO())) self.handleCmd('script 1+1') self.assertTrue(any('OH NOE' in msg for msg in messages)) @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) 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) @add_test_categories(['pyapi']) 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') @add_test_categories(['pyapi']) def test_close(self): debugger = self.debugger with open(self.out_filename, 'w') as f: status = debugger.SetOutputFile(f) self.assertTrue(status.Success()) self.handleCmd("help help", check=False, collect_result=False) # make sure the file wasn't closed early. f.write("\nZAP\n") lldb.SBDebugger.Destroy(debugger) # 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)) @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) def test_stdout(self): f = io.StringIO() status = self.debugger.SetOutputFile(f) self.assertTrue(status.Success()) self.handleCmd(r"script sys.stdout.write('foobar\n')") self.assertEqual(f.getvalue().strip().split(), ["foobar", "7"]) @add_test_categories(['pyapi']) def test_stdout_file(self): with open(self.out_filename, 'w') as f: status = self.debugger.SetOutputFile(f) self.assertTrue(status.Success()) 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"]) @add_test_categories(['pyapi']) @skipIf(py_version=['<', (3,)]) def test_identity(self): f = io.StringIO() sbf = lldb.SBFile(f) self.assertTrue(f is sbf.GetFile()) sbf.Close() self.assertTrue(f.closed) f = io.StringIO() sbf = lldb.SBFile.Create(f, borrow=True) self.assertTrue(f is sbf.GetFile()) sbf.Close() self.assertFalse(f.closed) with open(self.out_filename, 'w') as f: sbf = lldb.SBFile(f) self.assertTrue(f is sbf.GetFile()) sbf.Close() self.assertTrue(f.closed) with open(self.out_filename, 'w') as f: sbf = lldb.SBFile.Create(f, borrow=True) self.assertFalse(f is 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.assertTrue(f is 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.assertTrue(f is 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()) @add_test_categories(['pyapi']) 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()))) @add_test_categories(['pyapi']) def test_set_filehandle_none(self): self.assertRaises(Exception, self.debugger.SetOutputFile, None) self.assertRaises(Exception, self.debugger.SetOutputFile, "ham sandwich") self.assertRaises(Exception, self.debugger.SetOutputFileHandle, "ham sandwich") self.assertRaises(Exception, self.debugger.SetInputFile, None) self.assertRaises(Exception, self.debugger.SetInputFile, "ham sandwich") self.assertRaises(Exception, self.debugger.SetInputFileHandle, "ham sandwich") self.assertRaises(Exception, self.debugger.SetErrorFile, None) self.assertRaises(Exception, self.debugger.SetErrorFile, "ham sandwich") self.assertRaises(Exception, self.debugger.SetErrorFileHandle, "ham sandwich") with open(self.out_filename, 'w') as f: status = self.debugger.SetOutputFile(f) self.assertTrue(status.Success()) status = self.debugger.SetErrorFile(f) self.assertTrue(status.Success()) self.debugger.SetOutputFileHandle(None, False) self.debugger.SetErrorFileHandle(None, False) sbf = self.debugger.GetOutputFile() if sys.version_info.major >= 3: # python 2 lacks PyFile_FromFd, so GetFile() will # have to duplicate the file descriptor and make a FILE* # in order to convert a NativeFile it back to a python # file. self.assertEqual(sbf.GetFile().fileno(), 1) sbf = self.debugger.GetErrorFile() if sys.version_info.major >= 3: self.assertEqual(sbf.GetFile().fileno(), 2) with open(self.out_filename, 'r') as f: status = self.debugger.SetInputFile(f) self.assertTrue(status.Success()) self.debugger.SetInputFileHandle(None, False) sbf = self.debugger.GetInputFile() if sys.version_info.major >= 3: self.assertEqual(sbf.GetFile().fileno(), 0) @add_test_categories(['pyapi']) 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")