From a45d01a58427dca3b15fb776fce071778bec075e Mon Sep 17 00:00:00 2001 From: Fredrik Averpil Date: Fri, 6 Sep 2024 22:48:34 +0200 Subject: [PATCH] feat: show error from 'go test' and exit --- lua/neotest-golang/lib/json.lua | 10 ++-- lua/neotest-golang/process.lua | 87 +++++++++++++++++++++++---------- 2 files changed, 68 insertions(+), 29 deletions(-) diff --git a/lua/neotest-golang/lib/json.lua b/lua/neotest-golang/lib/json.lua index 2c0b909d..2fcd6e5a 100644 --- a/lua/neotest-golang/lib/json.lua +++ b/lua/neotest-golang/lib/json.lua @@ -6,8 +6,9 @@ local M = {} --- Decode JSON from a table of strings into a table of objects. --- @param tbl table +--- @param construct_invalid boolean --- @return table -function M.decode_from_table(tbl) +function M.decode_from_table(tbl, construct_invalid) local jsonlines = {} for _, line in ipairs(tbl) do if string.match(line, "^%s*{") then -- must start with the `{` character @@ -19,7 +20,10 @@ function M.decode_from_table(tbl) logger.warn("Failed to decode JSON line: " .. line) end else - -- vim.notify("Not valid JSON: " .. line, vim.log.levels.DEBUG) + logger.debug({ "Not valid JSON:", line }) + if construct_invalid then + table.insert(jsonlines, { Action = "output", Output = line }) + end end end return jsonlines @@ -40,7 +44,7 @@ function M.decode_from_string(str) current_object = current_object .. line end table.insert(tbl, current_object) - return M.decode_from_table(tbl) + return M.decode_from_table(tbl, false) end return M diff --git a/lua/neotest-golang/process.lua b/lua/neotest-golang/process.lua index 2d836be9..7eb040d6 100644 --- a/lua/neotest-golang/process.lua +++ b/lua/neotest-golang/process.lua @@ -16,7 +16,6 @@ local lib = require("neotest-golang.lib") --- @field golist_data table Filepath to 'go list' JSON data (lua table). -- TODO: rename to golist_data --- @field parse_test_results boolean If true, parsing of test output will occur. --- @field test_output_json_filepath? string Gotestsum JSON filepath. ---- @field dummy_test? boolean Temporary workaround before supporting position type 'test'. --- @class TestData --- @field status neotest.ResultStatus @@ -50,7 +49,7 @@ function M.test_results(spec, result, tree) ---@type neotest.ResultStatus status = "skipped", } - return results -- return early, fail fast + return results -- return early, used by e.g. debugging end --- The Neotest position tree node for this execution. @@ -70,7 +69,6 @@ function M.test_results(spec, result, tree) --- The runner to use for running tests. --- @type string local runner = options.get().runner - --- The raw output from the test command. --- @type table local raw_output = {} @@ -81,41 +79,65 @@ function M.test_results(spec, result, tree) end logger.debug({ "Raw 'go test' output: ", raw_output }) - local gotest_output = lib.json.decode_from_table(raw_output) - logger.debug({ "Parsed 'go test' output: ", gotest_output }) - - --- The 'go list -json' output, converted into a lua table. - local golist_output = context.golist_data - logger.debug({ "Parsed 'go list' output: ", golist_output }) - + --- Final Neotest results, the way Neotest wants it returned. --- @type table local neotest_result = {} - --- Test command (e.g. 'go test') status. --- @type neotest.ResultStatus local test_command_status = "skipped" + --- Go test output, + --- @type table + local gotest_output = {} + --- Test command output. + --- @type string + local test_command_output_path = vim.fs.normalize(async.fn.tempname()) + + -- decide what to do based on 'go test' command status code. if result.code == 0 then test_command_status = "passed" + -- parse raw output into a table. + gotest_output = lib.json.decode_from_table(raw_output, false) + logger.debug({ "Parsed 'go test' output: ", gotest_output }) + async.fn.writefile( + M.extract_gotest_output(gotest_output), + test_command_output_path + ) + -- register properties on the directory node that was run + neotest_result[pos.id] = { + status = test_command_status, + output = test_command_output_path, + } else test_command_status = "failed" - end - - --- Full 'go test' output (parsed from JSON). - --- @type table - local o = {} - local test_command_output_path = vim.fs.normalize(async.fn.tempname()) - for _, line in ipairs(gotest_output) do - if line.Action == "output" then - table.insert(o, line.Output) + if runner == "go" then + -- parse raw output into a table, include stderr output. + gotest_output = lib.json.decode_from_table(raw_output, true) + logger.debug({ "Parsed 'go test' output: ", gotest_output }) + async.fn.writefile( + M.extract_gotest_output(gotest_output), + test_command_output_path + ) + elseif runner == "gotestsum" then + -- gotestsum unfortunately does not write the stderr output into its JSON output. + async.fn.writefile( + { "Failed to run test. Compilation error?" }, + test_command_output_path + ) + else + logger.error({ "Unknown runner:", runner }) end + + -- register properties on the directory node that was run + neotest_result[pos.id] = { + status = test_command_status, + output = test_command_output_path, + } + return neotest_result -- return early, fail fast end - async.fn.writefile(o, test_command_output_path) - -- register properties on the directory node that was run - neotest_result[pos.id] = { - status = test_command_status, - output = test_command_output_path, - } + --- The 'go list -json' output, converted into a lua table. + local golist_output = context.golist_data + logger.debug({ "Parsed 'go list' output: ", golist_output }) --- Internal data structure to store test result data. --- @type table @@ -137,6 +159,19 @@ function M.test_results(spec, result, tree) return neotest_result end +--- Extract the Output-type parts of the 'go test' output. +--- @param gotest_output table +--- @return table +function M.extract_gotest_output(gotest_output) + local o = {} + for _, line in ipairs(gotest_output) do + if line.Action == "output" then + table.insert(o, line.Output) + end + end + return o +end + --- Aggregate neotest data and 'go test' output data. --- @param tree neotest.Tree --- @param gotest_output table