Skip to content

Commit

Permalink
refactor: use sed
Browse files Browse the repository at this point in the history
  • Loading branch information
fredrikaverpil committed Jul 4, 2024
1 parent 7960fcc commit e844b8f
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 100 deletions.
80 changes: 34 additions & 46 deletions lua/neotest-golang/cmd.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

local async = require("neotest.async")

local convert = require("neotest-golang.convert")
local options = require("neotest-golang.options")
local json = require("neotest-golang.json")

Expand All @@ -21,59 +20,44 @@ function M.golist_data(cwd)
return json.process_golist_output(output)
end

function M.gotest_list_data(go_mod_folderpath, module_name)
local cmd = { "go", "test", "-v", "-json", "-list", "^Test", module_name }
local output = vim.fn.system(
"cd " .. go_mod_folderpath .. " && " .. table.concat(cmd, " ")
)

-- FIXME: weird... would've expected to call process_gotest_output
local json_output = json.process_golist_output(output)

--- @type string[]
local test_names = {}
for _, v in ipairs(json_output) do
if v.Action == "output" then
--- @type string
local test_name = string.gsub(v.Output, "\n", "")
if string.match(test_name, "^Test") then
test_names = vim.list_extend(
test_names,
{ convert.to_gotest_regex_pattern(test_name) }
)
end
end
function M.sed_regexp(filepath)
if M.system_has("sed") == false then
return nil
end

return test_names
local sed_command =
string.format("sed -n '/func Test/p' %s", vim.fn.shellescape(filepath))
local handle = io.popen(sed_command)
local result = nil
if handle ~= nil then
result = handle:read("*a")
handle:close()
end
local lines = {}
for line in string.gmatch(result, "([^\n]*)\n") do
line = string.gsub(line, "func ", "")
line = string.gsub(line, "%(.*", "")
table.insert(lines, line)
end
local regexp = "^(" .. table.concat(lines, "|") .. ")$"
return regexp
end

function M.test_command_for_dir(module_name)
local go_test_required_args = { module_name }
function M.test_command_in_package(package_or_path)
local go_test_required_args = { package_or_path }
local cmd, json_filepath = M.test_command(go_test_required_args)
return cmd, json_filepath
end

function M.test_command_for_file(module_name, test_names_regexp)
local go_test_required_args = { "-run", test_names_regexp, module_name }
local cmd, json_filepath = M.test_command(go_test_required_args)

return cmd, json_filepath
end

function M.test_command_for_individual_test(
test_folder_absolute_path,
test_name
)
local go_test_required_args = { test_folder_absolute_path, "-run", test_name }
function M.test_command_in_package_with_regexp(package_or_path, regexp)
local go_test_required_args = { package_or_path, "-run", regexp }
local cmd, json_filepath = M.test_command(go_test_required_args)
return cmd, json_filepath
end

function M.test_command(go_test_required_args)
--- The runner to use for running tests.
--- @type string
local runner = M.fallback_to_go_test(options.get().runner)
local runner = M.runner_fallback(options.get().runner)

--- The filepath to write test output JSON to, if using `gotestsum`.
--- @type string | nil
Expand Down Expand Up @@ -109,16 +93,20 @@ function M.gotestsum(go_test_required_args, json_filepath)
return cmd
end

function M.fallback_to_go_test(executable)
if vim.fn.executable(executable) == 0 then
vim.notify(
"Runner " .. executable .. " not found. Falling back to 'go'.",
vim.log.levels.WARN
)
function M.runner_fallback(executable)
if M.system_has(executable) == false then
options.set({ runner = "go" })
return options.get().runner
end
return options.get().runner
end

function M.system_has(executable)
if vim.fn.executable(executable) == 0 then
vim.notify("Executable not found: " .. executable, vim.log.levels.WARN)
return false
end
return true
end

return M
12 changes: 2 additions & 10 deletions lua/neotest-golang/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ function M.Adapter.build_spec(args)

--- The position object, describing the current directory, file or test.
--- @type neotest.Position
local pos = args.tree:data()
local pos = args.tree:data() -- NOTE: causes <file> is not accessible by the current user!

if not tree then
vim.notify(
Expand Down Expand Up @@ -100,11 +100,6 @@ function M.Adapter.build_spec(args)
-- The idea here is not to have such fallbacks take place in the future, but
-- while this adapter is being developed, it can be useful to have such
-- functionality.
--
-- NOTE: Right now the adapter is not yet complete, and cannot
-- handle the 'file' position type. The goal is to try to support this,
-- as it is not efficient to run all tests in a file individually, when you
-- might want to run all tests in the file using one 'go test' command.

if pos.type == "dir" and pos.path == vim.fn.getcwd() then
-- A runspec is to be created, based on running all tests in the given
Expand All @@ -126,7 +121,7 @@ function M.Adapter.build_spec(args)
end

vim.notify(
"Unknown Neotest test position type, "
"Unknown Neotest position type, "
.. "cannot build runspec with position type: "
.. pos.type,
vim.log.levels.ERROR
Expand All @@ -135,9 +130,6 @@ end

--- Process the test command output and result. Populate test outcome into the
--- Neotest internal tree structure.
---
--- TODO: implement parsing of 'file' position type results.
---
--- @async
--- @param spec neotest.RunSpec
--- @param result neotest.StrategyResult
Expand Down
9 changes: 1 addition & 8 deletions lua/neotest-golang/parse.lua
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,7 @@ function M.test_results(spec, result, tree)
--- Test command (e.g. 'go test') status.
--- @type neotest.ResultStatus
local test_command_status = "skipped"
if context.dummy_test == true then
test_command_status = "skipped"
elseif result.code == 0 then
if result.code == 0 then
test_command_status = "passed"
else
test_command_status = "failed"
Expand All @@ -115,11 +113,6 @@ function M.test_results(spec, result, tree)
output = test_command_output_path,
}

-- if the test execution was skipped, return early
if context.dummy_test == true then
return neotest_result
end

--- Internal data structure to store test result data.
--- @type table<string, TestData>
local res = M.aggregate_data(tree, gotest_output, golist_output)
Expand Down
12 changes: 6 additions & 6 deletions lua/neotest-golang/runspec_dir.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--- Helpers to build the command and context around running all tests of
--- a Go module.
--- a Go package.

local cmd = require("neotest-golang.cmd")

Expand All @@ -24,16 +24,16 @@ function M.build(pos)
local go_mod_folderpath = vim.fn.fnamemodify(go_mod_filepath, ":h")
local golist_data = cmd.golist_data(go_mod_folderpath)

-- find the go module that corresponds to the go_mod_folderpath
local module_name = "./..." -- if no go module, run all tests at the $CWD
-- find the go package that corresponds to the go_mod_folderpath
local package_name = "./..."
for _, golist_item in ipairs(golist_data) do
if pos.path == golist_item.Dir then
module_name = golist_item.ImportPath
package_name = golist_item.ImportPath
break
end
end

local test_cmd, json_filepath = cmd.test_command_for_dir(module_name)
local test_cmd, json_filepath = cmd.test_command_in_package(package_name)

--- @type RunspecContext
local context = {
Expand All @@ -56,7 +56,7 @@ end

function M.fail_fast(pos)
local msg = "The selected folder must contain a go.mod file "
.. "or be a subdirectory of a Go module."
.. "or be a subdirectory of a Go package."
vim.notify(msg, vim.log.levels.ERROR)

--- @type RunspecContext
Expand Down
52 changes: 24 additions & 28 deletions lua/neotest-golang/runspec_file.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ local M = {}
--- @return neotest.RunSpec | neotest.RunSpec[] | nil
function M.build(pos, tree)
if vim.tbl_isempty(tree:children()) then
M.fail_fast(pos)
return M.fail_fast(pos)
end

local go_mod_filepath = runspec_dir.find_file_upwards("go.mod", pos.path)
Expand All @@ -24,13 +24,29 @@ function M.build(pos, tree)
local go_mod_folderpath = vim.fn.fnamemodify(go_mod_filepath, ":h")
local golist_data = cmd.golist_data(go_mod_folderpath)

-- find the go module that corresponds to the go_mod_folderpath
local module_name = "./..." -- if no go module, run all tests at the $CWD
-- find the go package that corresponds to the pos.path
local package_name = "./..."
local pos_path_filename = vim.fn.fnamemodify(pos.path, ":t")
for _, golist_item in ipairs(golist_data) do
if golist_item.TestGoFiles ~= nil then
if vim.tbl_contains(golist_item.TestGoFiles, pos_path_filename) then
package_name = golist_item.ImportPath
break
end
end
end

local test_names_regexp =
M.find_tests_in_file(pos, golist_data, go_mod_folderpath, module_name)
local test_cmd, json_filepath =
cmd.test_command_for_file(module_name, test_names_regexp)
-- use sed to find all top-level tests in pos.path
local test_cmd = nil
local json_filepath = nil
local regexp = cmd.sed_regexp(pos.path)
if regexp ~= nil then
test_cmd, json_filepath =
cmd.test_command_in_package_with_regexp(package_name, regexp)
else
-- fallback: run all tests in the package
test_cmd, json_filepath = cmd.test_command_in_package(package_name)
end

--- @type RunspecContext
local context = {
Expand All @@ -57,8 +73,7 @@ function M.fail_fast(pos)
pos_id = pos.id,
pos_type = "file",
golist_data = {}, -- no golist output
parse_test_results = true,
dummy_test = true,
parse_test_results = false,
}

--- Runspec designed for files that contain no tests.
Expand All @@ -70,23 +85,4 @@ function M.fail_fast(pos)
return run_spec
end

function M.find_tests_in_file(pos, golist_data, go_mod_folderpath, module_name)
local pos_path_filename = vim.fn.fnamemodify(pos.path, ":t")

for _, golist_item in ipairs(golist_data) do
if golist_item.TestGoFiles ~= nil then
if vim.tbl_contains(golist_item.TestGoFiles, pos_path_filename) then
module_name = golist_item.ImportPath
break
end
end
end

-- FIXME: this grabs all test files from the package. We only want the one in the file.
local test_names = cmd.gotest_list_data(go_mod_folderpath, module_name)
local test_names_regexp = "^(" .. table.concat(test_names, "|") .. ")$"

return test_names_regexp
end

return M
6 changes: 4 additions & 2 deletions lua/neotest-golang/runspec_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ function M.build(pos, strategy)
local test_name = convert.to_gotest_test_name(pos.id)
test_name = convert.to_gotest_regex_pattern(test_name)

local test_cmd, json_filepath =
cmd.test_command_for_individual_test(test_folder_absolute_path, test_name)
local test_cmd, json_filepath = cmd.test_command_in_package_with_regexp(
test_folder_absolute_path,
test_name
)

local runspec_strategy = nil
if strategy == "dap" then
Expand Down

0 comments on commit e844b8f

Please sign in to comment.