1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
|
--- Testing interface.
--
-- This module provides useful functions for use in luakit tests.
--
-- @module tests.lib
-- @copyright 2017 Aidan Holm <aidanholm@gmail.com>
local find_files = require "build-utils.find_files"
local _M = {}
local shared_lib = nil
function _M.init(arg)
_M.init = nil
shared_lib = arg
end
--- Pause test execution until a webview widget finishes loading.
--
-- @tparam widget view The webview widget to wait on.
function _M.wait_for_view(view)
assert(type(view) == "widget" and view.type == "webview")
shared_lib.traceback = debug.traceback("",2)
repeat
local _, status, uri, err = _M.wait_for_signal(view, "load-status", 5000)
if status == "failed" then
local fmt = "tests.wait_for_view() failed loading '%s': %s"
local msg = fmt:format(uri, err)
assert(false, msg)
end
until status == "finished"
end
--- Pause test execution for a short time.
--
-- @tparam[opt] number timeout The time to delay, in milliseconds.
-- Defaults to 5 milliseconds.
function _M.delay(timeout)
assert(not timeout or type(timeout) == "number", "Expected number")
timeout = timeout or 5 -- "Sensible default" of 5ms
local t = timer{interval = timeout}
t:start()
-- timeout+1000 ensures we don't fail the test while waiting
_M.wait_for_signal(t, "timeout", timeout+1000)
end
--- Pause test execution until a predicate returns `true`.
--
-- Suspends test execution, polling the provided predicate function at an
-- interval, until the predicate returns a truthy value. If the predicate does
-- not return a truthy value within a certain time period, the running test fails.
--
-- @tparam function func The predicate function.
-- @tparam[opt] number poll_time The interval at which to poll the predicate, in
-- milliseconds. Defaults to 5 milliseconds.
-- @tparam[opt] number timeout Maximum time to wait before failing the running test,
-- in milliseconds. Defaults to 200 milliseconds.
function _M.wait_until(func, poll_time, timeout)
assert(type(func) == "function", "Expected a function")
assert(not poll_time or type(poll_time) == "number", "Expected number")
assert(not timeout or type(timeout) == "number", "Expected number")
shared_lib.traceback = debug.traceback("",2)
poll_time = poll_time or 5
timeout = timeout or 200
local t = 0
repeat
_M.delay(poll_time)
t = t + poll_time
assert(t < timeout, "Timed out")
until func()
end
--- Pause test execution until a particular signal is emitted on an object.
--
-- Suspends test execution until `signal` is emitted on `object`. If no such
-- signal is emitted on `object` within `timeout` milliseconds, the running test
-- fails.
--
-- @param object The object to wait for `signal` on.
-- @tparam string signal The signal to wait for.
-- @tparam[opt] number timeout Maximum time to wait before failing the running test,
-- in milliseconds. Defaults to 200 milliseconds.
function _M.wait_for_signal(object, signal, timeout)
assert(shared_lib.current_coroutine, "Not currently running a test!")
assert(coroutine.running() == shared_lib.current_coroutine, "Not currently running in the test coroutine!")
assert(type(signal) == "string", "Expected string")
assert(not timeout or type(timeout) == "number", "Expected number")
shared_lib.traceback = debug.traceback("",2)
timeout = timeout or 200
return coroutine.yield({object, signal, timeout=timeout})
end
local waiting = false
--- Pause test execution indefinitely.
--
-- The running test is suspended until `continue()` is called. If `continue()`
-- is not called within `timeout` milliseconds, the running test fails.
--
-- @tparam[opt] number timeout Maximum time to wait before failing the running test,
-- in milliseconds. Defaults to 200 milliseconds.
-- @return All parameters to `continue()`.
function _M.wait(timeout)
assert(shared_lib.current_coroutine, "Not currently running a test!")
assert(coroutine.running() == shared_lib.current_coroutine, "Not currently running in the test coroutine!")
assert(not timeout or type(timeout) == "number", "Expected number")
assert(not waiting, "Already waiting")
shared_lib.traceback = debug.traceback("",2)
waiting = true
timeout = timeout or 200
return coroutine.yield({timeout=timeout})
end
--- Continue test execution.
--
-- The running test, currently suspended after a call to `wait()`, is resumed.
-- `wait()` must have been previously called.
--
-- All parameters to `continue()` are returned by `wait()`.
-- @param ... Values to return from `wait()`.
function _M.continue(...)
assert(shared_lib.current_coroutine, "Not currently running a test!")
assert(waiting and (coroutine.running() ~= shared_lib.current_coroutine), "Not waiting, cannot continue")
waiting = false
shared_lib.resume_suspended_test(...)
end
--- Get the URI prefix for the test HTTP server.
--
-- The port the test server listens on may not always be the same. This function
-- returns the current URI prefix, which looks like `http://127.0.0.1:8888/`.
--
-- Currently, however, there is no HTTP server; instead, the custom URI scheme
-- `luakit-test://` is used.
-- @treturn string The URI prefix for the test HTTP server.
function _M.http_server()
return "luakit-test://"
end
--- Retrieve a subset of files in the current directory.
--
-- This function searches the directory and then filters the result
-- according to the provided parameters and the `.gitignore` file. It
-- is mostly intended for use in code style tests. The returned list of
-- file paths includes all files that:
--
-- * are within at least one of the directories in `dirs`,
-- * match at least one of the Lua patterns in `patterns`, and
-- * do _not_ match any of the Lua patterns in `excludes`.
--
-- @function find_files
-- @tparam string|table dirs The directory prefix (or list of prefixes) in which
-- to look for files.
-- @tparam string|table patterns A Lua pattern (or list of patterns) with which
-- to filter file paths; non-matching files are removed.
-- @tparam[opt] table excludes A list of Lua patterns with which to filter file
-- paths; matching files are removed.
-- @treturn table A list of matching file paths.
_M.find_files = find_files.find_files
--- Helper function to format a list of file errors.
--
-- Aligns file names and file errors into two separate columns.
--
-- @tparam {entry} entries A list of file error entries.
--
-- # `entry` format
--
-- - file: The path of the file.
-- - err: The error string.
-- @treturn string The formatted output string.
function _M.format_file_errors(entries)
assert(type(entries) == "table")
local sep = " "
-- Find file alignment length
local align, luakit_files = 0, find_files.get_luakit_files()
for _, file in ipairs(luakit_files) do
align = math.max(align, file:len())
end
-- Build output
local lines = {}
local prev_file = nil
for _, entry in ipairs(entries) do
local file = entry.file ~= prev_file and entry.file or ""
prev_file = entry.file
local line = string.format("%-" .. tostring(align) .. "s%s%s", file, sep, entry.err)
table.insert(lines, line)
end
return table.concat(lines, "\n")
end
return _M
-- vim: et:sw=4:ts=8:sts=4:tw=80
|