-- Make lldb available in global
lldb = require('lldb')
-- Global assertion functions
function assertTrue(x)
if not x then error('assertTrue failure') end
end
function assertFalse(x)
if x then error('assertNotNil failure') end
end
function assertNotNil(x)
if x == nil then error('assertNotNil failure') end
end
function assertEqual(x, y)
if type(x) == 'table' and type(y) == 'table' then
for k, _ in pairs(x) do
assertEqual(x[k], y[k])
end
elseif type(x) ~= type(y) then
error('assertEqual failure')
elseif x ~= y then
error('assertEqual failure')
end
end
function assertStrContains(x, y)
if not string.find(x, y, 1, true) then
error('assertStrContains failure')
end
end
-- Global helper functions
function read_file_non_empty_lines(f)
local lines = {}
while true do
local line = f:read('*l')
if not line then break end
if line ~= '\n' then table.insert(lines, line) end
end
return lines
end
function split_lines(str)
local lines = {}
for line in str:gmatch("[^\r\n]+") do
table.insert(lines, line)
end
return lines
end
function get_stopped_threads(process, reason)
local threads = {}
for i = 0, process:GetNumThreads() - 1 do
local t = process:GetThreadAtIndex(i)
if t:IsValid() and t:GetStopReason() == reason then
table.insert(threads, t)
end
end
return threads
end
function get_stopped_thread(process, reason)
local threads = get_stopped_threads(process, reason)
if #threads ~= 0 then return threads[1]
else return nil end
end
-- Test helper
local _M = {}
local _m = {}
local _mt = { __index = _m }
function _M.create_test(name, exe, output, input)
print('[lldb/lua] Create test ' .. name)
exe = exe or os.getenv('TEST_EXE')
output = output or os.getenv('TEST_OUTPUT')
input = input or os.getenv('TEST_INPUT')
lldb.SBDebugger.Initialize()
local debugger = lldb.SBDebugger.Create()
-- Ensure that debugger is created
assertNotNil(debugger)
assertTrue(debugger:IsValid())
debugger:SetAsync(false)
local lua_language = debugger:GetScriptingLanguage('lua')
assertNotNil(lua_language)
debugger:SetScriptLanguage(lua_language)
local test = setmetatable({
output = output,
input = input,
name = name,
exe = exe,
debugger = debugger
}, _mt)
_G[name] = test
return test
end
function _m:create_target(exe)
local target
if not exe then exe = self.exe end
target = self.debugger:CreateTarget(exe)
-- Ensure that target is created
assertNotNil(target)
assertTrue(target:IsValid())
return target
end
function _m:handle_command(command, collect)
if collect == nil then collect = true end
if collect then
local ret = lldb.SBCommandReturnObject()
local interpreter = self.debugger:GetCommandInterpreter()
assertTrue(interpreter:IsValid())
interpreter:HandleCommand(command, ret)
self.debugger:GetOutputFile():Flush()
self.debugger:GetErrorFile():Flush()
assertTrue(ret:Succeeded())
return ret:GetOutput()
else
self.debugger:HandleCommand(command)
self.debugger:GetOutputFile():Flush()
self.debugger:GetErrorFile():Flush()
end
end
function _m:run()
local tests = {}
for k, v in pairs(self) do
if string.sub(k, 1, 4) == 'Test' then
table.insert(tests, k)
end
end
table.sort(tests)
for _, t in ipairs(tests) do
print('[lldb/lua] Doing test ' .. self.name .. ' - ' .. t)
local success = xpcall(self[t], function(e)
print(debug.traceback())
end, self)
if not success then
print('[lldb/lua] Failure in test ' .. self.name .. ' - ' .. t)
return 1
end
end
return 0
end
return _M