1-- Make lldb available in global 2lldb = require('lldb') 3 4-- Global assertion functions 5function assertTrue(x) 6 if not x then error('assertTrue failure') end 7end 8 9function assertFalse(x) 10 if x then error('assertNotNil failure') end 11end 12 13function assertNotNil(x) 14 if x == nil then error('assertNotNil failure') end 15end 16 17function assertEqual(x, y) 18 if type(x) == 'table' and type(y) == 'table' then 19 for k, _ in pairs(x) do 20 assertEqual(x[k], y[k]) 21 end 22 elseif type(x) ~= type(y) then 23 error('assertEqual failure') 24 elseif x ~= y then 25 error('assertEqual failure') 26 end 27end 28 29function assertStrContains(x, y) 30 if not string.find(x, y, 1, true) then 31 error('assertStrContains failure') 32 end 33end 34 35-- Global helper functions 36function read_file_non_empty_lines(f) 37 local lines = {} 38 while true do 39 local line = f:read('*l') 40 if not line then break end 41 if line ~= '\n' then table.insert(lines, line) end 42 end 43 return lines 44end 45 46function split_lines(str) 47 local lines = {} 48 for line in str:gmatch("[^\r\n]+") do 49 table.insert(lines, line) 50 end 51 return lines 52end 53 54function get_stopped_threads(process, reason) 55 local threads = {} 56 for i = 0, process:GetNumThreads() - 1 do 57 local t = process:GetThreadAtIndex(i) 58 if t:IsValid() and t:GetStopReason() == reason then 59 table.insert(threads, t) 60 end 61 end 62 return threads 63end 64 65function get_stopped_thread(process, reason) 66 local threads = get_stopped_threads(process, reason) 67 if #threads ~= 0 then return threads[1] 68 else return nil end 69end 70 71-- Test helper 72 73local _M = {} 74local _m = {} 75 76local _mt = { __index = _m } 77 78function _M.create_test(name, exe, output, input) 79 print('[lldb/lua] Create test ' .. name) 80 exe = exe or os.getenv('TEST_EXE') 81 output = output or os.getenv('TEST_OUTPUT') 82 input = input or os.getenv('TEST_INPUT') 83 lldb.SBDebugger.Initialize() 84 local debugger = lldb.SBDebugger.Create() 85 -- Ensure that debugger is created 86 assertNotNil(debugger) 87 assertTrue(debugger:IsValid()) 88 89 debugger:SetAsync(false) 90 91 local lua_language = debugger:GetScriptingLanguage('lua') 92 assertNotNil(lua_language) 93 debugger:SetScriptLanguage(lua_language) 94 95 local test = setmetatable({ 96 output = output, 97 input = input, 98 name = name, 99 exe = exe, 100 debugger = debugger 101 }, _mt) 102 _G[name] = test 103 return test 104end 105 106function _m:create_target(exe) 107 local target 108 if not exe then exe = self.exe end 109 target = self.debugger:CreateTarget(exe) 110 -- Ensure that target is created 111 assertNotNil(target) 112 assertTrue(target:IsValid()) 113 return target 114end 115 116function _m:handle_command(command, collect) 117 if collect == nil then collect = true end 118 if collect then 119 local ret = lldb.SBCommandReturnObject() 120 local interpreter = self.debugger:GetCommandInterpreter() 121 assertTrue(interpreter:IsValid()) 122 interpreter:HandleCommand(command, ret) 123 self.debugger:GetOutputFile():Flush() 124 self.debugger:GetErrorFile():Flush() 125 assertTrue(ret:Succeeded()) 126 return ret:GetOutput() 127 else 128 self.debugger:HandleCommand(command) 129 self.debugger:GetOutputFile():Flush() 130 self.debugger:GetErrorFile():Flush() 131 end 132end 133 134function _m:run() 135 local tests = {} 136 for k, v in pairs(self) do 137 if string.sub(k, 1, 4) == 'Test' then 138 table.insert(tests, k) 139 end 140 end 141 table.sort(tests) 142 for _, t in ipairs(tests) do 143 print('[lldb/lua] Doing test ' .. self.name .. ' - ' .. t) 144 local success = xpcall(self[t], function(e) 145 print(debug.traceback()) 146 end, self) 147 if not success then 148 print('[lldb/lua] Failure in test ' .. self.name .. ' - ' .. t) 149 return 1 150 end 151 end 152 return 0 153end 154 155return _M 156