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