1--- Test runner for async tests.
2--
3-- @script async.run_test
4-- @copyright 2017 Aidan Holm <aidanholm@gmail.com>
5
6-- Adjust paths to work when running with DEVELOPMENT_PATHS=0
7dofile("tests/async/wrangle_paths.lua")
8require_web_module("tests/async/wrangle_paths")
9
10local shared_lib = {}
11local priv = require "tests.priv"
12local test = require("tests.lib")
13test.init(shared_lib)
14
15--- Launched as the init script of a luakit instance
16--
17-- Loads test_file and runs all tests in it in order
18local function do_test_file(test_file)
19    local wait_timer = timer()
20
21    -- Load test table, or abort
22    print("__load__ ")
23    local T, err = priv.load_test_file(test_file)
24    if not T then
25        print("__fail__ " .. test_file)
26        print(err)
27        luakit.quit(0)
28    end
29
30    -- Convert functions to coroutines
31    for test_name, func in pairs(T) do
32        if type(func) == "function" then
33            T[test_name] = coroutine.create(func)
34        end
35    end
36
37    local current_test
38    local waiting_signal
39
40    --- Runs a test untit it passes, fails, or waits for a signal
41    -- Additional arguments: parameters to signal handler
42    -- @treturn string Status of the test; one of "pass", "wait", "fail"
43    local function begin_or_continue_test(func, ...)
44        assert(type(func) == "thread")
45
46        shared_lib.current_coroutine = func
47
48        -- Run test until it finishes, pauses, or fails
49        local ok, ret = coroutine.resume(func, ...)
50        local state = coroutine.status(func)
51
52        if not ok then
53            print("__fail__ " .. current_test)
54            print(tostring(ret))
55            print(debug.traceback(func))
56            return "fail"
57        elseif state == "suspended" then
58            print("__wait__ " .. current_test)
59
60            -- Start timer
61            wait_timer.interval = ret.timeout
62            wait_timer:start()
63
64            -- wait_for_signal
65            if #ret == 2 then
66                -- Add signal handlers to resume running test
67                local obj, sig = ret[1], ret[2]
68                local function wrapper(...)
69                    obj:remove_signal(sig, wrapper)
70                    shared_lib.resume_suspended_test(...)
71                end
72                obj:add_signal(sig, wrapper)
73                waiting_signal = sig
74            end
75
76            -- Return to luakit
77            return "wait"
78        else
79            print("__pass__ " .. current_test)
80            return "pass"
81        end
82    end
83
84    --- Finds the next test to run and starts it, or quits
85    local function do_next_test()
86        repeat
87            local test_name, func = next(T, current_test)
88            if not test_name then
89                -- Quit if all tests have been run
90                luakit.quit()
91                return
92            end
93            current_test = test_name
94            print("__run__ " .. current_test)
95            local test_status = begin_or_continue_test(func)
96        until test_status == "wait"
97    end
98
99    --- Resumes a waiting test when a signal occurs
100    shared_lib.resume_suspended_test = function (...)
101        local func = shared_lib.current_coroutine
102        assert(type(func) == "thread")
103        -- Stop the timeout timer
104        wait_timer:stop()
105        waiting_signal = nil
106        -- Continue the test
107        print("__cont__ " .. current_test)
108        local test_status = begin_or_continue_test(func, ...)
109        -- If the test finished, do the next one
110        if test_status ~= "wait" then
111            luakit.idle_add(do_next_test)
112        end
113    end
114
115    wait_timer:add_signal("timeout", function ()
116        wait_timer:stop()
117        print("__fail__ " .. current_test)
118        if waiting_signal then
119            print("Timed out while waiting for signal '" .. waiting_signal .. "'")
120        else
121            print("Timed out while waiting")
122        end
123        print("  interval was " .. tostring(wait_timer.interval) .. "msec")
124        print("  " .. shared_lib.traceback)
125        do_next_test()
126    end)
127
128    do_next_test()
129
130    -- If the test hasn't opened any windows, open one to keep luakit happy
131    if #luakit.windows == 0 then
132        local win = widget{type="window"}
133        win:show()
134    end
135end
136
137io.stdout:setvbuf("line")
138
139local test_file = uris[1]
140assert(type(test_file) == "string")
141
142-- Setup luakit-test:// URI scheme
143luakit.register_scheme("luakit-test")
144widget.add_signal("create", function (w)
145    if w.type == "webview" then
146        w:add_signal("scheme-request::luakit-test", function (_, uri, request)
147            local path = uri:gsub("^luakit%-test://", "tests/html/")
148            local f = assert(io.open(path, "rb"))
149            local contents = f:read("*a") or ""
150            f:close()
151
152            local mime = "text/plain"
153            if path:match("%.html$") then mime = "text/html" end
154            if path:match("%.png$") then mime = "image/png" end
155            if path:match("%.jpg$") then mime = "image/jpeg" end
156
157            request:finish(contents, mime)
158        end)
159    end
160end)
161
162require('unique_instance')
163local lousy = require('lousy')
164-- Some lib files assume that a theme has been loaded
165lousy.theme.init(lousy.util.find_config("theme.lua"))
166
167do_test_file(test_file)
168
169-- vim: et:sw=4:ts=8:sts=4:tw=80
170