nvimdotfiles/lua/myworkflow/go-tests.lua

178 lines
4.0 KiB
Lua

local M = {
results = {}
}
local ns = vim.api.nvim_create_namespace("live-tests")
local test_function_query_string = [[
(
(function_declaration
name: (identifier) @name
parameters:
(parameter_list
(parameter_declaration
name: (identifier)
type: (pointer_type
(qualified_type
package: (package_identifier) @_package_name
name: (type_identifier) @_type_name)))))
(#eq? @_package_name "testing")
(#eq? @_type_name "T")
(#eq? @name "%s")
)
]]
local find_test_line = function(go_bufnr, name)
local formatted = string.format(test_function_query_string, name)
local query = vim.treesitter.query.parse("go", formatted)
local parser = vim.treesitter.get_parser(go_bufnr, "go", {})
local tree = parser:parse()[1]
local root = tree:root()
for id, node in query:iter_captures(root, go_bufnr, 0, -1) do
if id == 1 then
local range = { node:range() }
return range[1]
end
end
end
local function clear(table)
for k in pairs(table) do
table[k] = nil
end
end
vim.api.nvim_create_user_command('GoTest', function()
M.goRunTests()
end, {})
vim.api.nvim_create_user_command('GoPrintResults', function()
print(vim.inspect(M.results))
end, {})
vim.api.nvim_create_user_command('GoSetTestMarks', function()
M.goSetAllMarks()
end, {})
vim.api.nvim_create_user_command('GoClearResults', function()
clear(M.results)
end, {})
vim.api.nvim_create_user_command('GoClearTestMarks', function()
local currbuf = vim.api.nvim_get_current_buf()
vim.api.nvim_buf_clear_namespace(currbuf, ns, 0, -1)
end, {})
local errored = false
function M.goRunTests()
-- TODO: replace jobstart/jobwait with system()
vim.fn.jobstart({ "go", "test", "./...", "-json" }, {
stdout_buffered = true,
on_stdout = function(_, data)
if errored == true then
errored = false
return
end
if not data then
return
end
clear(M.results)
local collected_messages = {}
for _, line in ipairs(data) do
if line == "" then goto continue end
local decoded = vim.json.decode(line)
if decoded.Test == nil then
goto continue
end
if decoded.Action == 'pass' or decoded.Action == 'fail' then
M.results[decoded.Test] = { Action = decoded.Action }
end
if decoded.Action == 'output' then
local testname = decoded.Test
local a = ""
if collected_messages[testname] == nil then
a = ""
else
a = collected_messages[testname]
end
collected_messages[decoded.Test] = a .. decoded.Output
end
::continue::
end
-- Merge collected messages into results
for test, _ in pairs(M.results) do
M.results[test].Message = collected_messages[test]
end
end,
on_stderr = function(_, data)
for _, value in pairs(data) do
if value and value ~= "" then
errored = true
print('Error while running tests: ', value)
end
end
end,
on_exit = function()
M.goSetAllMarks()
end
})
end
function M.goSetAllMarks()
local files = vim.fn.system({ "find", "-type", "f", "-name", "*_test.go" })
local sep = "\n"
local filetable = {}
for str in string.gmatch(files, "([^" .. sep .. "]+)") do
table.insert(filetable, str)
end
for _, file in ipairs(filetable) do
vim.fn.bufadd(file)
vim.fn.bufload(file)
local bufno = vim.fn.bufnr(file)
M.goSetMarks(bufno)
end
end
function M.goSetMarks(currbuf)
vim.api.nvim_buf_clear_namespace(currbuf, ns, 0, -1)
vim.diagnostic.set(ns, currbuf, {}, {})
local text = {}
local failed = {}
for test, val in pairs(M.results) do
local linenum = find_test_line(currbuf, test)
if linenum == nil then goto continue end
if val.Action == 'pass' then
text = { "" }
vim.api.nvim_buf_set_extmark(currbuf, ns, linenum, 0, {
virt_text = { text },
})
elseif val.Action == 'fail' then
table.insert(failed, {
bufnr = currbuf,
lnum = linenum,
col = 0,
severity = vim.diagnostic.severity.ERROR,
source = "go-test",
message = "Test Failed\n\n" .. val.Message,
user_data = {},
})
end
::continue::
end
vim.diagnostic.set(ns, currbuf, failed, {})
end
return M