8000 mini.nvim/lua/mini/test.lua at main · connectednode/mini.nvim · GitHub
[go: up one dir, main page]

Skip to content

Latest commit

 

History

History
2321 lines (2009 loc) · 85.7 KB

test.lua

File metadata and controls

2321 lines (2009 loc) · 85.7 KB
local reference = H.screenshot_read(path)
-- Compare
local are_same, cause = H.screenshot_compare(reference, screenshot, opts)
if are_same then return true end
local subject = 'screenshot equality to reference at ' .. vim.inspect(path)
local context = string.format('%s\nReference:\n%s\n\nObserved:\n%s', cause, tostring(reference), tostring(screenshot))
H.error_expect(subject, context)
end
--- Create new expectation function
---
--- Helper for writing custom functions with behavior similar to other methods
--- of |MiniTest.expect|.
---
---@param subject string|function|table Subject of expectation. If callable,
--- called with expectation input arguments to produce string value.
---@param predicate function|table Predicate callable. Called with expectation
--- input arguments. Output `false` or `nil` means failed expectation.
---@param fail_context string|function|table Information about fail. If callable,
--- called with expectation input arguments to produce string value.
---
---@return function Expectation function.
---
---@usage >
--- local expect_truthy = MiniTest.new_expectation(
--- 'truthy',
--- function(x) return x end,
--- function(x) return 'Object: ' .. vim.inspect(x) end
--- )
MiniTest.new_expectation = function(subject, predicate, fail_context)
return function(...)
if predicate(...) then return true end
local cur_subject = vim.is_callable(subject) and subject(...) or subject
local cur_context = vim.is_callable(fail_context) and fail_context(...) or fail_context
H.error_expect(cur_subject, cur_context)
end
end
-- Reporters ------------------------------------------------------------------
--- Table with pre-configured report generators
---
--- Each element is a function which returns reporter - table with callable
--- `start`, `update`, and `finish` fields.
MiniTest.gen_reporter = {}
--- Generate buffer reporter
---
--- This is a default choice for interactive (not headless) usage. Opens a window
--- with dedicated non-terminal buffer and updates it with throttled redraws.
---
--- Opened buffer has the following helpful Normal mode mappings:
--- - `<Esc>` - stop test execution if executing (see |MiniTest.is_executing()|
--- and |MiniTest.stop()|). Close window otherwise.
--- - `q` - same as `<Esc>` for convenience and compatibility.
---
--- General idea:
--- - Group cases by concatenating first `opts.group_depth` elements of case
--- description (`desc` field). Groups by collected files if using default values.
--- - In `start()` show some stats to know how much is scheduled to be executed.
--- - In `update()` show symbolic overview of current group and state of current
--- case. Each symbol represents one case and its state:
--- - `?` - case didn't finish executing.
--- - `o` - pass.
--- - `O` - pass with notes.
--- - `x` - fail.
--- - `X` - fail with notes.
--- - In `finish()` show all fails and notes ordered by case.
---
---@param opts table|nil Table with options. Used fields:
--- - <group_depth> - number of first elements of case description (can be zero)
--- used for grouping. Higher values mean higher granularity of output.
--- Default: 1.
--- - <throttle_delay> - minimum number of milliseconds to wait between
--- redrawing. Reduces screen flickering but not amount of computations.
--- Default: 10.
--- - <window> - definition of window to open. Can take one of the forms:
--- - Callable. It is called expecting output to be target window id
--- (current window is used if output is `nil`). Use this to open in
--- "normal" window (like `function() vim.cmd('vsplit') end`).
--- - Table. Used as `config` argument in |nvim_open_win()|.
--- Default: table for centered floating window.
MiniTest.gen_reporter.buffer = function(opts)
-- NOTE: another choice of implementing this is to use terminal buffer
-- `vim.api.nvim_open_term()`.
-- Pros:
-- - Renders ANSI escape sequences (mostly) correctly, i.e. no need in
-- replacing them with Neovim range highlights.
-- - This reporter and `stdout` one can share more of a codebase.
-- Cons:
-- - Couldn't manage to implement "redraw on every update".
-- - Extra steps still are needed in order to have richer output information.
-- This involves ANSI sequences that move cursor, which have same issues as
-- in `stdout`, albeit easier to overcome:
-- - Handling of scroll.
-- - Hard wrapping of lines leading to need of using window width.
opts = vim.tbl_deep_extend(
'force',
{ group_depth = 1, throttle_delay = 10, window = H.buffer_reporter.default_window_opts() },
opts or {}
)
local buf_id, win_id
local is_valid_buf_win = function() return vim.api.nvim_buf_is_valid(buf_id) and vim.api.nvim_win_is_valid(win_id) end
-- Helpers
local set_cursor = function(line)
vim.api.nvim_win_set_cursor(win_id, { line or vim.api.nvim_buf_line_count(buf_id), 0 })
end
-- Define "write from cursor line" function with throttled redraw
local latest_draw_time = 0
local replace_last = function(n_replace, lines, force)
H.buffer_reporter.set_lines(buf_id, lines, -n_replace - 1, -1)
-- Throttle redraw to reduce flicker
local cur_time = vim.loop.hrtime()
local is_enough_time_passed = (cur_time - latest_draw_time) > opts.throttle_delay * 1000000
if is_enough_time_passed or force then
vim.cmd('redraw')
latest_draw_time = cur_time
end
end
-- Create reporter functions
local res = {}
local all_cases, all_groups, latest_group_name
res.start = function(cases)
-- Set up buffer and window
buf_id, win_id = H.buffer_reporter.setup_buf_and_win(opts.window)
-- Set up data (taking into account possible not first time run)
all_cases = cases
all_groups = H.overview_reporter.compute_groups(cases, opts.group_depth)
latest_group_name = nil
-- Write lines
local lines = H.overview_reporter.start_lines(all_cases, all_groups)
replace_last(1, lines)
set_cursor()
end
res.update = function(case_num)
if not is_valid_buf_win() then return end
local case, cur_group_name = all_cases[case_num], all_groups[case_num].name
-- Update symbol
local state = type(case.exec) == 'table' and case.exec.state or nil
all_groups[case_num].symbol = H.reporter_symbols[state]
local n_replace = H.buffer_reporter.update_step_n_replace(latest_group_name, cur_group_name)
local lines = H.buffer_reporter.update_step_lines(case_num, all_cases, all_groups)
replace_last(n_replace, lines)
set_cursor()
latest_group_name = cur_group_name
end
res.finish = function()
if not is_valid_buf_win() then return end
-- Cache final cursor position to overwrite 'Current case state' header
local start_line = vim.api.nvim_buf_line_count(buf_id) - 1
-- Force writing lines
local lines = H.overview_reporter.finish_lines(all_cases)
replace_last(2, lines, true)
set_cursor(start_line)
end
return res
end
--- Generate stdout reporter
---
--- This is a default choice for headless usage. Writes to `stdout`. Uses
--- coloring ANSI escape sequences to make pretty and informative output
--- (should work in most modern terminals and continuous integration providers).
---
--- It has same general idea as |MiniTest.gen_reporter.buffer()| with slightly
--- less output (it doesn't overwrite previous text) to overcome typical
--- terminal limitations.
---
---@param opts table|nil Table with options. Used fields:
--- - <group_depth> - number of first elements of case description (can be zero)
--- used for grouping. Higher values mean higher granularity of output.
--- Default: 1.
--- - <quit_on_finish> - whether to quit after finishing test execution.
--- Default: `true`.
MiniTest.gen_reporter.stdout = function(opts)
opts = vim.tbl_deep_extend('force', { group_depth = 1, quit_on_finish = true }, opts or {})
local write = function(text)
text = type(text) == 'table' and table.concat(text, '\n') or text
io.stdout:write(text)
io.flush()
end
local all_cases, all_groups, latest_group_name
local default_symbol = H.reporter_symbols[nil]
local res = {}
res.start = function(cases)
-- Set up data
all_cases = cases
all_groups = H.overview_reporter.compute_groups(cases, opts.group_depth)
-- Write lines
local lines = H.overview_reporter.start_lines(all_cases, all_groups)
write(lines)
end
res.update = function(case_num)
local cur_case = all_cases[case_num]
local cur_group_name = all_groups[case_num].name
-- Possibly start overview of new group
if cur_group_name ~= latest_group_name then
write('\n')
write(cur_group_name)
if cur_group_name ~= '' then write(': ') end
end
-- Possibly show new symbol
local state = type(cur_case.exec) == 'table' and cur_case.exec.state or nil
0