-- 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