
This uses [teyit](https://pypi.org/project/teyit/) to modernize asserts, as recommended by the [unittest release notes](https://docs.python.org/3.12/whatsnew/3.12.html#id3). For example, `assertTrue(a == b)` is replaced with `assertEqual(a, b)`. This produces better error messages, e.g. `error: unexpectedly found 1 and 2 to be different` instead of `error: False`.
821 lines
30 KiB
Python
821 lines
30 KiB
Python
"""
|
|
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")
|
|
|
|
def tearDown(self):
|
|
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 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"])
|
|
|
|
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)
|