Skip to content

Commit

Permalink
feat: show build error in test output
Browse files Browse the repository at this point in the history
  • Loading branch information
fredrikaverpil committed Nov 22, 2024
1 parent cdb0eb0 commit ba733ea
Showing 1 changed file with 87 additions and 11 deletions.
98 changes: 87 additions & 11 deletions lua/neotest-golang/process.lua
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,27 @@ function M.test_results(spec, result, tree)

--- The raw output from the test command.
--- @type table
local raw_output = {}
local runner_output = {}
if runner == "go" then
raw_output = async.fn.readfile(result.output)
runner_output = async.fn.readfile(result.output)
elseif runner == "gotestsum" then
raw_output = async.fn.readfile(context.test_output_json_filepath)
runner_output = async.fn.readfile(context.test_output_json_filepath)
end
logger.debug({ "Raw 'go test' output: ", raw_output })
logger.debug({ "Raw 'go test' output: ", runner_output })

--- The 'go list -json' output, converted into a lua table.
local golist_output = context.golist_data

--- Go test output.
--- @type table
local gotest_output = lib.json.decode_from_table(raw_output, true)
local gotest_output = lib.json.decode_from_table(runner_output, true)

-- detect build error
local build_failed, build_failure_output =
M.detect_build_errors(result, gotest_output)
if build_failed then
M.build_failure_to_lookup(build_failure_output, golist_output)
end

--- Internal data structure to store test result data.
--- @type table<string, TestData>
Expand All @@ -101,7 +108,12 @@ function M.test_results(spec, result, tree)
--- Test command (e.g. 'go test') status.
--- @type neotest.ResultStatus
local result_status = nil
if neotest_result[pos.id] and neotest_result[pos.id].status == "skipped" then
if build_failed then
-- mark as failed if the build failed.
result_status = "failed"
elseif
neotest_result[pos.id] and neotest_result[pos.id].status == "skipped"
then
-- keep the status if it was already decided to be skipped.
result_status = "skipped"
elseif context.errors ~= nil and #context.errors > 0 then
Expand All @@ -122,14 +134,19 @@ function M.test_results(spec, result, tree)

-- override the position which was executed with the full
-- command execution output.
local cmd_output = M.filter_gotest_output(gotest_output)
cmd_output = vim.list_extend(context.errors or {}, cmd_output)
if #cmd_output == 0 and result.code ~= 0 and runner == "gotestsum" then
-- special case; gotestsum does not capture compilation errors from stderr.
cmd_output = { "Failed to run 'go test'. Compilation error?" }
local cmd_output
if build_failed then
cmd_output = M.filter_gotest_output(build_failure_output)
else
cmd_output = M.filter_gotest_output(gotest_output)
end
cmd_output = vim.list_extend(context.errors or {}, cmd_output)

-- write output to final file.
local cmd_output_path = vim.fs.normalize(async.fn.tempname())
async.fn.writefile(cmd_output, cmd_output_path)

-- construct final result for the position.
if neotest_result[pos.id] == nil then
-- set status and output as none of them have yet to be set.
neotest_result[pos.id] = {
Expand Down Expand Up @@ -163,6 +180,65 @@ function M.filter_gotest_output(gotest_output)
return o
end

--- Detect build errors

function M.detect_build_errors(result, gotest_output)
if result.code ~= 0 and #gotest_output > 0 then
-- TODO: can be optimized, where 'go' runner does not have to re-read this file.
local original_output = async.fn.readfile(result.output)
local original_output_json =
lib.json.decode_from_table(original_output, true)

-- FIXME: sometimes, there is no gotest_output or original output...
-- like for example when running a sub-test that currently gets skipped due to failure.

for _, value in pairs(original_output_json) do
if value.Action == "output" then
if string.find(value.Output, "build failed", 1, true) then
return true, original_output_json
elseif string.find(value.Output, "setup failed", 1, true) then
return true, original_output_json
elseif string.find(value.Output, "#", 1, true) then
return true, original_output_json
end
end
end
end
return false, {}
end

function M.build_failure_to_lookup(build_failed_output, golist_output)
local failed_packages = {}
for _, value in pairs(build_failed_output) do
-- if the output starts with '#'
if value.Action == "output" and string.find(value.Output, "#", 1, true) then
local failed_package = vim.split(value.Output, " ")[2]
if not vim.tbl_contains(failed_packages, failed_package) then
table.insert(failed_packages, failed_package)
end
end
end

--- @type table<string, string[]>
local failed_package_lookup = {}
for _, data in ipairs(golist_output) do
for _, pkg in ipairs(failed_packages) do
if data.ImportPath == pkg then
vim.notify("Match: " .. data.ImportPath .. " == " .. pkg)
if failed_package_lookup[data.ImportPath] == nil then
failed_package_lookup[data.ImportPath] = {}
end

table.insert(failed_package_lookup[data.ImportPath], data.Dir)
end
end
end

vim.notify(vim.inspect(failed_package_lookup))

return failed_package_lookup
end

--- Aggregate neotest data and 'go test' output data.
--- @param tree neotest.Tree
--- @param gotest_output table
Expand Down

0 comments on commit ba733ea

Please sign in to comment.