Skip to content

Instantly share code, notes, and snippets.

@RadicalTeapot
Created April 27, 2024 22:57
Show Gist options
  • Save RadicalTeapot/71f91f3e4acbc64b0c24eb550bea0709 to your computer and use it in GitHub Desktop.
Save RadicalTeapot/71f91f3e4acbc64b0c24eb550bea0709 to your computer and use it in GitHub Desktop.
Quick and dirty Neovim unit-test runner
local M = {
buf_nr = nil,
suites = {},
window_title = "Results: ",
buffer_namespace = { name = "ResultWindowNS", id = nil },
}
M.clear_internal_buffer = function()
if M.buf_nr ~= nil and vim.fn.bufexists(M.buf_nr) then
vim.api.nvim_buf_delete(M.buf_nr, { force = true })
M.buf_nr = nil
end
end
M.setup_buffer = function()
M.clear_internal_buffer()
M.buf_nr = vim.api.nvim_create_buf(false, true)
vim.bo[M.buf_nr].bufhidden = "wipe"
M.buffer_namespace.id = vim.api.nvim_create_namespace(M.buffer_namespace.name) -- Won't be recreated if it already exists
vim.api.nvim_buf_clear_namespace(M.buf_nr, M.buffer_namespace.id, 0, -1)
-- Key mappings for closing the window (tied to the scratch buffer only)
local map_opts = { noremap = true, silent = true }
vim.api.nvim_buf_set_keymap(M.buf_nr, "n", "q", "<cmd>bd!<CR>", map_opts)
vim.api.nvim_buf_set_keymap(M.buf_nr, "n", "<Esc>", "<cmd>bd!<CR>", map_opts)
vim.api.nvim_create_autocmd({ "BufDelete", "BufWipeout" }, {
group = vim.api.nvim_create_augroup("ResultWindowGroup", { clear = true }),
callback = function()
M.buf_nr = nil
end,
})
end
M.open_floating_window = function()
assert(M.buf_nr, "Buffer should have been initialized before opening window")
-- Define the floating window size and position
local width = math.floor(vim.api.nvim_get_option("columns") / 2)
local height = math.floor(vim.api.nvim_get_option("lines") / 2)
-- Set window options (defined here :h nvim_open_win)
local opts = {
relative = "editor",
width = width,
height = height,
col = math.floor(vim.api.nvim_get_option("columns") / 4),
row = math.floor(vim.api.nvim_get_option("lines") / 4),
style = "minimal",
border = "rounded",
title = " Results ",
title_pos = "left",
}
-- Create the floating window
local win = vim.api.nvim_open_win(M.buf_nr, true, opts)
vim.wo[win].wrap = true
-- Set custom highlight (see :h api-floatwin)
vim.api.nvim_set_option_value("winhl", "FloatTitle:PmenuSel", { win = win })
end
-- TODO Move to utils
M.error_callback = function(err)
return err
end
M.test_runner = function(name, func)
local result, ret = xpcall(func, M.error_callback)
if result then
return true, name
end
return false, name .. ", reason: " .. ret
end
M.suite_runner = function(func)
local run_results = {}
local function it(test_name, test_func)
local result, msg = M.test_runner(test_name, test_func)
table.insert(run_results, { status = result, message = msg })
end
local result, ret = xpcall(func, M.error_callback, it)
return result, run_results, ret
end
M.describe = function(suite_name, suite_func)
M.suites[suite_name] = function()
return M.suite_runner(suite_func)
end
end
-- TODO Cleanup this function
M.run = function()
M.setup_buffer()
M.open_floating_window()
local print_index = 0
for name, runner in pairs(M.suites) do
local result, run_results, msg = runner()
if not result then
local message = "Suite " .. name .. " failed: " .. msg
vim.api.nvim_buf_set_lines(M.buf_nr, print_index, -1, false, { message, "" })
print_index = -1
else
local passed = vim.tbl_filter(function(r)
return r.status
end, run_results)
local message = "Suite " .. name .. " results"
vim.api.nvim_buf_set_lines(M.buf_nr, print_index, -1, false, { message })
local virt_text = {}
if #passed > 0 then
table.insert(virt_text, { "Passed: " .. #passed, "DiagnosticSignOk" })
table.insert(virt_text, { " " })
end
if #passed < #run_results then
table.insert(virt_text, { "Failed: " .. (#run_results - #passed), "DiagnosticSignError" })
end
vim.api.nvim_buf_set_extmark(
M.buf_nr,
M.buffer_namespace.id,
vim.api.nvim_buf_line_count(M.buf_nr) - 1,
0,
{ virt_text = virt_text }
)
print_index = -1
for i, v in ipairs(run_results) do
vim.api.nvim_buf_set_lines(
M.buf_nr,
-1,
-1,
false,
{ "[" .. i .. "/" .. #run_results .. "] " .. v.message }
)
local hl_grp_name = v.status and "DiagnosticSignOk" or "DiagnosticSignError"
local text = v.status and "Passed" or "Failed"
vim.api.nvim_buf_set_extmark(
M.buf_nr,
M.buffer_namespace.id,
vim.api.nvim_buf_line_count(M.buf_nr) - 1,
0,
{ virt_text = { { text, hl_grp_name } } }
)
end
vim.api.nvim_buf_set_lines(M.buf_nr, print_index, -1, false, { "" })
end
end
end
return M
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment