go.nvim/lua/go/gotest.lua

570 lines
14 KiB
Lua
Raw Normal View History

-- run `go test`
2021-07-08 16:16:22 +00:00
local M = {}
local utils = require("go.utils")
2021-11-23 23:13:40 +00:00
local log = utils.log
2022-07-07 11:23:18 +00:00
local trace = utils.trace
local empty = utils.empty
2021-11-23 23:13:40 +00:00
local ginkgo = require("go.ginkgo")
local getopt = require("go.alt_getopt")
2022-07-07 11:23:18 +00:00
local install = require("go.install").install
2022-06-01 11:29:13 +00:00
local vfn = vim.fn
local long_opts = {
verbose = "v",
compile = "c",
2022-06-05 22:24:55 +00:00
coverage = "C",
2022-07-07 11:23:18 +00:00
count = "n",
tags = "t",
2022-03-14 23:16:29 +00:00
bench = "b",
2022-08-05 00:48:08 +00:00
metric = "m",
2022-05-24 09:17:26 +00:00
select = "s",
2022-05-13 10:54:47 +00:00
floaterm = "F",
}
local sep = require("go.utils").sep()
2022-08-05 00:48:08 +00:00
local short_opts = "vcC:t:bsFmn:"
local bench_opts = { "-benchmem", "-cpuprofile", "profile.out" }
2021-07-08 16:16:22 +00:00
M.efm = function()
2022-06-01 11:29:13 +00:00
-- local indent = [[%\\%( %\\)]]
local efm = [[%-G=== RUN %.%#]]
efm = efm .. [[,%-G" .. indent .. "%#--- PASS: %.%#]]
efm = efm .. [[,%G--- FAIL: %\\%(Example%\\)%\\@=%m (%.%#)]]
efm = efm .. [[,%G" .. indent .. "%#--- FAIL: %m (%.%#)]]
efm = efm .. [[,%A" .. indent .. "%\\+%[%^:]%\\+: %f:%l: %m]]
efm = efm .. [[,%+Gpanic: test timed out after %.%\\+]]
efm = efm .. ",%+Afatal error: %.%# [recovered]"
efm = efm .. [[,%+Afatal error: %.%#]]
efm = efm .. [[,%+Apanic: %.%#]]
-- exit
efm = efm .. ",%-Cexit status %[0-9]%\\+"
efm = efm .. ",exit status %[0-9]%\\+"
-- failed lines
efm = efm .. ",%-CFAIL%\\t%.%#"
2022-07-07 11:23:18 +00:00
efm = efm .. ",FAIL%\\t%.%#"
-- compiling error
efm = efm .. ",%A%f:%l:%c: %m"
efm = efm .. ",%A%f:%l: %m"
2022-07-07 11:23:18 +00:00
efm = efm .. ",%G%\\t%m"
efm = efm .. ",%-C%.%#"
efm = efm .. ",%-G%.%#"
efm = string.gsub(efm, " ", [[\ ]])
log(efm)
return efm
end
2022-05-30 14:04:52 +00:00
-- return "-tags=tag1,tag2"
M.get_build_tags = function(args)
2021-12-16 07:15:21 +00:00
-- local tags = "-tags"
2022-06-18 05:43:07 +00:00
args = args or {}
2022-05-30 14:04:52 +00:00
local tags = {}
2021-11-23 23:13:40 +00:00
if _GO_NVIM_CFG.build_tags ~= "" then
2022-05-30 14:04:52 +00:00
tags = { _GO_NVIM_CFG.build_tags }
end
2022-06-01 11:29:13 +00:00
local optarg, _, reminder = getopt.get_opts(args, short_opts, long_opts)
if optarg["t"] then
2022-05-30 14:04:52 +00:00
table.insert(tags, optarg["t"])
2021-11-23 23:13:40 +00:00
end
local rt = utils.get_build_tags()
if not utils.empty(rt) then
vim.list_extend(tags, rt)
end
if #tags > 0 then
2022-05-30 14:04:52 +00:00
return "-tags=" .. table.concat(tags, ","), reminder
end
2021-11-23 23:13:40 +00:00
end
2022-05-30 14:04:52 +00:00
local function richgo(cmd)
if cmd[1] == "go" and vfn.executable("richgo") == 1 then
2022-05-30 14:04:52 +00:00
cmd[1] = "richgo"
end
return cmd
end
2021-11-23 23:13:40 +00:00
local function get_test_filebufnr()
2022-06-01 11:29:13 +00:00
local fn = vfn.expand("%")
2022-07-07 11:23:18 +00:00
trace(fn)
local bufnr = vim.api.nvim_get_current_buf()
if not fn:find("test%.go$") then
fn = require("go.alternate").alternate()
2022-06-01 11:29:13 +00:00
fn = vfn.fnamemodify(fn, ":p") -- expand to full path
local uri = vim.uri_from_fname(fn)
bufnr = vim.uri_to_bufnr(uri)
log(fn, bufnr, uri)
if vfn.filereadable(vim.uri_to_fname(uri)) == 0 then
-- no test file existed
return 0, "no test file"
end
if not vim.api.nvim_buf_is_loaded(bufnr) then
2022-06-01 11:29:13 +00:00
vfn.bufload(bufnr)
end
end
return bufnr
end
2022-05-30 14:04:52 +00:00
-- {-c: compile, -v: verbose, -t: tags, -b: bench, -s: select}
local function run_test(path, args)
2021-11-23 23:13:40 +00:00
log(args)
local compile = false
local bench = false
2022-06-01 11:29:13 +00:00
local optarg, _, reminder = getopt.get_opts(args, short_opts, long_opts)
2022-07-07 11:23:18 +00:00
trace(optarg)
if optarg["c"] then
2022-06-01 11:29:13 +00:00
path = utils.rel_path(true) -- vfn.expand("%:p:h") can not resolve releative path
compile = true
end
if optarg["b"] then
bench = true
end
if next(reminder) then
path = reminder[1]
end
2022-01-10 10:26:41 +00:00
local test_runner = _GO_NVIM_CFG.go
if _GO_NVIM_CFG.test_runner ~= test_runner then
2021-11-23 23:13:40 +00:00
test_runner = _GO_NVIM_CFG.test_runner
if not install(test_runner) then
test_runner = "go"
end
end
2022-05-30 14:04:52 +00:00
local tags = M.get_build_tags(args)
2021-12-16 07:15:21 +00:00
log(tags)
local cmd = {}
local run_in_floaterm = optarg["F"] or _GO_NVIM_CFG.run_in_floaterm
if run_in_floaterm then
table.insert(cmd, test_runner or "go")
table.insert(cmd, "test")
end
if _GO_NVIM_CFG.verbose_tests then
table.insert(cmd, "-v")
2021-12-16 07:15:21 +00:00
end
if not empty(tags) then
cmd = vim.list_extend(cmd, { tags })
2021-12-16 07:15:21 +00:00
end
2022-06-05 22:24:55 +00:00
if optarg["C"] then
table.insert(cmd, "-coverprofile=" .. optarg["C"])
end
2022-07-07 11:23:18 +00:00
if optarg["n"] then
table.insert(cmd, "-count=" .. optarg["n"] or "1")
end
if not empty(reminder) then
cmd = vim.list_extend(cmd, reminder)
end
2021-11-23 23:13:40 +00:00
if compile == true then
if path ~= "" then
2022-05-30 14:04:52 +00:00
table.insert(cmd, "-c")
table.insert(cmd, path)
end
elseif bench == true then
if path ~= "" then
table.insert(cmd, "-bench=" .. path)
else
table.insert(cmd, "-bench=.")
end
vim.list_extend(cmd, bench_opts)
else
if path ~= "" then
table.insert(cmd, path)
else
local argsstr = "." .. utils.sep() .. "..."
2022-05-30 14:04:52 +00:00
table.insert(cmd, argsstr)
end
2021-12-16 07:15:21 +00:00
end
utils.log(cmd, args)
if run_in_floaterm then
2022-07-07 11:23:18 +00:00
install("richgo")
local term = require("go.term").run
2022-05-30 14:04:52 +00:00
cmd = richgo(cmd)
log(cmd)
term({ cmd = cmd, autoclose = false })
2022-05-24 07:54:52 +00:00
return cmd
2021-11-23 23:13:40 +00:00
end
2022-01-10 10:26:41 +00:00
vim.cmd([[setl makeprg=]] .. _GO_NVIM_CFG.go .. [[\ test]])
2021-11-23 23:13:40 +00:00
utils.log("test cmd", cmd)
2022-05-24 07:54:52 +00:00
return require("go.asyncmake").make(unpack(cmd))
2021-11-23 23:13:40 +00:00
end
M.test = function(...)
local args = { ... }
2021-11-23 23:13:40 +00:00
log(args)
2022-05-30 14:04:52 +00:00
local test_opts = {
verbose = "v",
compile = "c",
2022-06-05 22:24:55 +00:00
coverage = "C",
2022-05-30 14:04:52 +00:00
tags = "t",
bench = "b",
2022-08-05 00:48:08 +00:00
metrics = "m",
2022-05-30 14:04:52 +00:00
floaterm = "F",
nearest = "n",
file = "f",
package = "p",
}
2022-08-05 00:48:08 +00:00
local test_short_opts = "vcC:t:bsfmnpF"
2022-06-01 11:29:13 +00:00
local optarg, _, reminder = getopt.get_opts(args, test_short_opts, test_opts)
2022-05-30 14:04:52 +00:00
2022-06-01 11:29:13 +00:00
vfn.setqflist({})
2022-05-30 14:04:52 +00:00
if optarg["n"] then --nearest
optarg["n"] = nil
local opts = getopt.rebuid_args(optarg, reminder) or {}
return M.test_func(unpack(opts))
end
if optarg["f"] then -- currentfile
optarg["f"] = nil
local opts = getopt.rebuid_args(optarg, reminder) or {}
return M.test_file(unpack(opts))
end
if optarg["p"] then -- current package
optarg["p"] = nil
local opts = getopt.rebuid_args(optarg, reminder) or {}
return M.test_package(unpack(opts))
end
2021-12-16 07:15:21 +00:00
local workfolder = utils.work_path()
2021-11-23 23:13:40 +00:00
if workfolder == nil then
workfolder = "."
end
2022-05-30 14:04:52 +00:00
local fpath = workfolder .. utils.sep() .. "..."
2022-05-30 14:04:52 +00:00
if #reminder > 0 then
fpath = reminder[1]
end
utils.log("fpath :" .. fpath)
run_test(fpath, args)
2021-11-23 23:13:40 +00:00
end
M.test_suit = function(...)
local args = { ... }
2021-11-23 23:13:40 +00:00
log(args)
2021-12-16 07:15:21 +00:00
local workfolder = utils.work_path()
2021-11-23 23:13:40 +00:00
utils.log(args)
local fpath = workfolder .. utils.sep() .. "..."
2021-12-16 01:34:06 +00:00
2021-11-23 23:13:40 +00:00
utils.log("fpath" .. fpath)
run_test(fpath, args)
end
M.test_package = function(...)
local args = { ... }
2021-11-23 23:13:40 +00:00
log(args)
2022-06-01 11:29:13 +00:00
local fpath = "." .. sep .. vfn.fnamemodify(vfn.expand("%:h"), ":.") .. sep .. "..."
2021-12-16 07:15:21 +00:00
utils.log("fpath: " .. fpath)
2022-05-24 07:54:52 +00:00
return run_test(fpath, args)
end
M.get_test_func_name = function()
local row, col = unpack(vim.api.nvim_win_get_cursor(0))
row, col = row, col + 1
local ns = require("go.ts.go").get_func_method_node_at_pos()
if empty(ns) then
return nil
end
2022-06-01 11:29:13 +00:00
if ns == nil or ns.name == nil then
return nil
end
if not string.find(ns.name, "[T|t]est") then
-- not in a test function
local fns = M.get_testfunc()
for _, fn in ipairs(fns) do
log(fn, ns.name)
if string.find(fn:lower(), ns.name:lower()) then
ns = { name = fn }
return ns
end
end
end
return ns
end
2022-05-30 14:04:52 +00:00
--options {s:select, F: floaterm}
M.test_func = function(...)
local args = { ... }
2021-11-23 23:13:40 +00:00
log(args)
2021-07-08 16:16:22 +00:00
2022-06-01 11:29:13 +00:00
local ns = M.get_test_func_name()
if empty(ns) then
2022-05-24 09:17:26 +00:00
return M.select_tests()
2021-07-08 16:16:22 +00:00
end
2022-06-01 11:29:13 +00:00
local optarg, _, reminder = getopt.get_opts(args, short_opts, long_opts)
local tags = M.get_build_tags(args, get_test_filebufnr())
2021-07-08 16:16:22 +00:00
utils.log("parnode" .. vim.inspect(ns))
2021-11-23 23:13:40 +00:00
2022-01-10 10:26:41 +00:00
local test_runner = _GO_NVIM_CFG.go
2021-12-16 07:15:21 +00:00
if _GO_NVIM_CFG.test_runner ~= "go" then
2021-11-23 23:13:40 +00:00
test_runner = _GO_NVIM_CFG.test_runner
if not install(test_runner) then
test_runner = "go"
end
if test_runner == "ginkgo" then
ginkgo.test_func(...)
2021-11-23 23:13:40 +00:00
end
end
2022-05-30 14:04:52 +00:00
local run_flags = "-run"
local cmd = {}
local run_in_floaterm = optarg["F"] or _GO_NVIM_CFG.run_in_floaterm
if run_in_floaterm then
table.insert(cmd, test_runner)
table.insert(cmd, "test")
end
2022-05-24 09:17:26 +00:00
if optarg["s"] then
return M.select_tests()
end
if _GO_NVIM_CFG.verbose_tests and _GO_NVIM_CFG.test_runner == "go" then
table.insert(cmd, "-v")
2021-12-16 07:15:21 +00:00
end
2022-05-30 14:04:52 +00:00
if tags and tags ~= "" then
table.insert(cmd, tags)
2021-12-16 07:15:21 +00:00
end
2022-06-01 11:29:13 +00:00
if ns == nil or ns.name == nil then
return
end
2021-11-23 23:13:40 +00:00
2022-07-07 11:23:18 +00:00
if optarg["n"] then
table.insert(cmd, "-count=" .. optarg["n"] or "1")
end
2021-12-16 07:15:21 +00:00
if ns.name:find("Bench") then
local bench = "-bench=" .. ns.name
table.insert(cmd, bench)
vim.list_extend(cmd, bench_opts)
else
2022-05-30 14:04:52 +00:00
table.insert(cmd, run_flags)
2022-06-29 05:01:17 +00:00
table.insert(cmd, [['^]] .. ns.name .. [[$']])
2021-12-16 07:15:21 +00:00
end
2022-06-01 11:29:13 +00:00
local fpath = "." .. sep .. vfn.fnamemodify(vfn.expand("%:h"), ":.")
2021-12-16 07:15:21 +00:00
table.insert(cmd, fpath)
2021-11-23 23:13:40 +00:00
if test_runner == "dlv" then
cmd = { "dlv", "test", fpath, "--", "-test.run", "^" .. ns.name }
local term = require("go.term").run
term({ cmd = cmd, autoclose = false })
return
end
if run_in_floaterm then
2021-11-23 23:13:40 +00:00
utils.log(cmd)
2022-07-07 11:23:18 +00:00
install("richgo")
local term = require("go.term").run
2022-05-30 14:04:52 +00:00
cmd = richgo(cmd)
term({ cmd = cmd, autoclose = false })
2021-11-23 23:13:40 +00:00
return
end
2022-05-24 09:17:26 +00:00
vim.list_extend(cmd, reminder)
2021-11-23 23:13:40 +00:00
2021-12-16 07:15:21 +00:00
vim.cmd([[setl makeprg=]] .. test_runner .. [[\ test]])
-- set_efm()
2021-07-08 16:16:22 +00:00
utils.log("test cmd", cmd)
2022-05-24 07:23:53 +00:00
return require("go.asyncmake").make(unpack(cmd))
2021-07-08 16:16:22 +00:00
end
2021-11-23 23:13:40 +00:00
M.test_file = function(...)
local args = { ... }
2021-11-23 23:13:40 +00:00
log(args)
-- require sed
-- local testcases = [[sed -n 's/func.*\(Test.*\)(.*/\1/p' | xargs | sed 's/ /\\\|/g']]
2022-06-01 11:29:13 +00:00
-- local fpath = vfn.expand("%:p")
2022-06-01 11:29:13 +00:00
local fpath = "." .. sep .. vfn.fnamemodify(vfn.expand("%:p"), ":.")
2021-12-16 07:15:21 +00:00
-- utils.log(args)
local cmd = [[cat ]] .. fpath .. [[| sed -n 's/func.*\(Test.*\)(.*/\1/p' | xargs | sed 's/ /\\|/g']]
2021-11-23 23:13:40 +00:00
-- TODO maybe with treesitter or lsp list all functions in current file and regex with Test
2022-06-01 11:29:13 +00:00
if vfn.executable("sed") == 0 then
M.test_package(...)
return
end
2022-06-01 11:29:13 +00:00
local optarg, _, reminder = getopt.get_opts(args, short_opts, long_opts)
local run_in_floaterm = optarg["F"] or _GO_NVIM_CFG.run_in_floaterm
2022-06-01 11:29:13 +00:00
local tests = vfn.systemlist(cmd)
if vim.v.shell_error ~= 0 then
utils.warn("iferr failed" .. vim.inspect(tests))
return
end
2021-12-16 07:15:21 +00:00
utils.log(cmd, tests)
tests = tests[1]
2022-06-01 11:29:13 +00:00
if vfn.empty(tests) == 1 then
vim.notify("no test found fallback to package test", vim.lsp.log_levels.DEBUG)
M.test_package(...)
return
2021-11-24 09:05:02 +00:00
end
2021-11-23 23:13:40 +00:00
2022-05-30 14:04:52 +00:00
local tags = M.get_build_tags(args)
2021-11-23 23:13:40 +00:00
2022-01-10 10:26:41 +00:00
local test_runner = _GO_NVIM_CFG.go
if _GO_NVIM_CFG.test_runner ~= "go" then
2021-11-23 23:13:40 +00:00
test_runner = _GO_NVIM_CFG.test_runner
if not install(test_runner) then
test_runner = "go"
end
if test_runner == "ginkgo" then
ginkgo.test_func(...)
2021-11-23 23:13:40 +00:00
end
end
local relpath = utils.rel_path(true)
log(relpath)
2021-11-23 23:13:40 +00:00
local cmd_args = {}
if run_in_floaterm then
table.insert(cmd_args, test_runner)
table.insert(cmd_args, "test")
2021-12-16 07:15:21 +00:00
end
if _GO_NVIM_CFG.verbose_tests then
table.insert(cmd_args, "-v")
end
2022-05-30 14:04:52 +00:00
if tags ~= nil then
table.insert(cmd_args, tags)
2021-12-16 07:15:21 +00:00
end
2022-05-30 14:04:52 +00:00
if next(reminder) then
vim.list_extend(cmd_args, reminder)
2021-12-16 07:15:21 +00:00
end
table.insert(cmd_args, "-run")
2022-05-30 14:04:52 +00:00
2022-07-07 11:23:18 +00:00
if optarg["n"] then
table.insert(cmd_args, "-count=" .. optarg["n"] or "1")
end
2022-06-16 01:38:37 +00:00
local sh = vim.o.shell
2022-06-29 05:01:17 +00:00
if sh:find("fish") then
tests = "'" .. tests .. "'"
2022-06-16 01:38:37 +00:00
end
table.insert(cmd_args, tests) -- shell script | is a pipe
2021-12-16 07:15:21 +00:00
table.insert(cmd_args, relpath)
2021-12-16 01:34:06 +00:00
if run_in_floaterm then
2022-07-07 11:23:18 +00:00
install("richgo")
local term = require("go.term").run
2022-05-30 14:04:52 +00:00
cmd_args = richgo(cmd_args)
cmd_args = table.concat(cmd_args, " ")
log(cmd_args)
2021-12-16 07:15:21 +00:00
term({ cmd = cmd_args, autoclose = false })
return cmd_args
2021-11-23 23:13:40 +00:00
end
if _GO_NVIM_CFG.test_runner == "dlv" then
cmd_args = { "dlv", "test", relpath, "--", "-test.run", tests }
cmd_args = table.concat(cmd_args, " ")
local term = require("go.term").run
term({ cmd = cmd_args, autoclose = false })
return cmd_args
end
2022-01-10 10:26:41 +00:00
vim.cmd([[setl makeprg=]] .. _GO_NVIM_CFG.go .. [[\ test]])
log(cmd_args)
2022-05-24 07:54:52 +00:00
local cmdret = require("go.asyncmake").make(unpack(cmd_args))
2022-05-30 14:04:52 +00:00
utils.log("test cmd: ", cmdret, " finished")
2022-05-24 07:54:52 +00:00
return cmdret
2021-08-31 11:19:14 +00:00
end
2022-04-18 12:31:17 +00:00
-- TS based run func
-- https://github.com/rentziass/dotfiles/blob/master/vim/.config/nvim/lua/rentziass/lsp/go_tests.lua
M.run_file = function()
local bufnr = vim.api.nvim_get_current_buf()
local tree = vim.treesitter.get_parser(bufnr):parse()[1]
local query = vim.treesitter.parse_query("go", require("go.ts.textobjects").query_test_func)
local test_names = {}
for id, node in query:iter_captures(tree:root(), bufnr, 0, -1) do
2022-04-18 12:31:17 +00:00
local name = query.captures[id] -- name of the capture in the query
if name == "test_name" then
2022-04-18 14:22:08 +00:00
table.insert(test_names, vim.treesitter.query.get_node_text(node, bufnr))
2022-04-18 12:31:17 +00:00
end
end
vim.schedule(function()
vim.lsp.buf.execute_command({
command = "gopls.run_tests",
arguments = { { URI = vim.uri_from_bufnr(0), Tests = test_names } },
})
end)
end
M.get_testfunc = function()
local bufnr = get_test_filebufnr()
local parser = vim.treesitter.get_parser(bufnr)
local tree = parser:parse()
tree = tree[1]
2022-05-24 09:17:26 +00:00
local query = vim.treesitter.parse_query("go", require("go.ts.go").query_test_func)
2022-04-18 12:31:17 +00:00
local test_names = {}
2022-06-01 11:29:13 +00:00
for id, node in query:iter_captures(tree:root(), bufnr, 0, -1) do
2022-04-18 12:31:17 +00:00
local name = query.captures[id] -- name of the capture in the query
if name == "test_name" then
2022-04-18 14:22:08 +00:00
table.insert(test_names, vim.treesitter.query.get_node_text(node, bufnr))
2022-04-18 12:31:17 +00:00
end
end
return test_names
end
-- GUI to select test?
M.select_tests = function()
2022-04-18 12:31:17 +00:00
local guihua = utils.load_plugin("guihua.lua", "guihua.gui")
local original_select = vim.ui.select
if guihua then
vim.ui.select = require("guihua.gui").select
end
2022-05-24 09:17:26 +00:00
vim.defer_fn(function()
vim.ui.select = original_select
end, 500)
local function onselect(item, idx)
if not item then
return
end
local uri = vim.uri_from_bufnr(0)
log(uri, item, idx)
vim.schedule(function()
vim.lsp.buf.execute_command({
command = "gopls.run_tests",
arguments = { { URI = uri, Tests = { item } } },
})
end)
end
local test_names = M.get_testfunc()
2022-05-24 09:17:26 +00:00
vim.ui.select(test_names, {
prompt = "select test to run:",
kind = "codelensaction",
}, onselect)
return test_names
2022-04-18 12:31:17 +00:00
end
2021-07-08 16:16:22 +00:00
return M