Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(busted): Compact test output format #488

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.PHONY: test generate_filetypes lint luarocks_upload test_luarocks_install
.PHONY: test generate_filetypes lint

test:
nvim --headless --noplugin -u scripts/minimal.vim -c "PlenaryBustedDirectory tests/plenary/ {minimal_init = 'tests/minimal_init.vim'}"

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ The second argument is a Lua option table with the following fields:
- `keep_going`: if `sequential`, whether to continue on test failure (default true)
- `timeout`: controls the maximum time allotted to each job in parallel or
sequential operation (defaults to 50,000 milliseconds)
- `output_format`: configure output format, possible values are `'default'` and `'compact'`

The exit code is 0 when success and 1 when fail, so you can use it easily in a `Makefile`!

Expand Down
248 changes: 190 additions & 58 deletions lua/plenary/busted.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,58 @@
local opts = {}
local is_headless = require("plenary.nvim_meta").is_headless
local output_compact = false
local generic_marker = "▪"
local pass_marker = generic_marker or "●"
local fail_marker = generic_marker or "●"
local pending_marker = generic_marker or "●"

local mod = {}

local results = {}
local current_prints = {}
local current_description = {}
local current_before_each = {}
local current_after_each = {}

local color_table = {
magenta = 35,
blue = 34,
yellow = 33,
green = 32,
red = 31,
}

-- We are shadowing print so people can reliably print messages
print = function(...)
local container = current_prints[#current_prints]

if container then
container[#container + 1] = { ... }
else
for _, v in ipairs { ... } do
io.stdout:write(tostring(v))
io.stdout:write "\t"
end

io.stdout:write "\r\n"
end
end

print_append = function(...)
for _, v in ipairs { ... } do
io.stdout:write(tostring(v))
end
end

local indent = function(msg, spaces)
if spaces == nil then
spaces = 4
end

local prefix = string.rep(" ", spaces)
return prefix .. msg:gsub("\n", "\n" .. prefix)
end

local dirname = function(p)
return vim.fn.fnamemodify(p, ":h")
end
Expand All @@ -10,7 +65,7 @@ local function get_trace(element, level, msg)
end
level = level or 3

local thisdir = dirname(debug.getinfo(1, "Sl").source, ":h")
local thisdir = dirname(debug.getinfo(1, "Sl").source)
local info = debug.getinfo(level, "Sl")
while
info.what == "C"
Expand All @@ -29,25 +84,6 @@ local function get_trace(element, level, msg)
return file and file.getTrace(file.name, info) or trimTrace(info)
end

local is_headless = require("plenary.nvim_meta").is_headless

-- We are shadowing print so people can reliably print messages
print = function(...)
for _, v in ipairs { ... } do
io.stdout:write(tostring(v))
io.stdout:write "\t"
end

io.stdout:write "\r\n"
end

local mod = {}

local results = {}
local current_description = {}
local current_before_each = {}
local current_after_each = {}

local add_description = function(desc)
table.insert(current_description, desc)

Expand All @@ -68,27 +104,44 @@ local clear_last_each = function()
current_after_each[current_description[#current_description]] = nil
end

local call_inner = function(desc, func)
local push_print_capture = function(tbl)
current_prints[#current_prints + 1] = tbl
end

local pop_print_capture = function()
current_prints[#current_prints] = nil
end

local call_inner = function(desc, func, capture_prints)
local desc_stack = add_description(desc)
local prints = {}

if capture_prints then
push_print_capture(prints)
end

add_new_each()
local ok, msg = xpcall(func, function(msg)
-- debug.traceback
-- return vim.inspect(get_trace(nil, 3, msg))
local trace = get_trace(nil, 3, msg)
return trace.message .. "\n" .. trace.traceback
if output_compact then
return msg
else
local trace = get_trace(nil, 3, msg)
return trace.message .. "\n" .. trace.traceback
end
end)

if capture_prints then
pop_print_capture()
end

clear_last_each()
pop_description()

return ok, msg, desc_stack
return ok, msg, desc_stack, prints
end

local color_table = {
yellow = 33,
green = 32,
red = 31,
}

local color_string = function(color, str)
if not is_headless then
return str
Expand All @@ -104,17 +157,66 @@ local PENDING = color_string("yellow", "Pending")
local HEADER = string.rep("=", 40)

mod.format_results = function(res)
print ""
print(color_string("green", "Success: "), #res.pass)
print(color_string("red", "Failed : "), #res.fail)
print(color_string("red", "Errors : "), #res.errs)
print(HEADER)
if output_compact then
print(
string.format(
"\n%s: %d / %s: %d / %s: %d / %s: %d",
color_string("green", "pass"),
#res.pass,
color_string("magenta", "pending"),
#res.pending,
color_string("red", "fail"),
#res.fail,
color_string("yellow", "fatal"),
#res.errs
)
)

if #res.pending > 0 or #res.fail > 0 or #res.errs > 0 then
print ""
end

for _, pending in ipairs(res.pending) do
local path = table.concat(pending.descriptions, " » ")

print(string.format("%s: %s", color_string("magenta", "pending"), path))
end

for _, fail in ipairs(res.fail) do
local path = table.concat(fail.descriptions, " » ")

print ""
print(string.format("%s: %s", color_string("red", "fail"), path))
print(indent(fail.msg, 2))

for _, print_params in ipairs(fail.prints) do
print ""
print(string.format("%s:", color_string("blue", "print")))
print(indent(table.concat(print_params, "\t"), 2))
end
end

for _, error in ipairs(res.errs) do
local path = table.concat(error.descriptions, " » ")

print ""
print(string.format("%s: %s", color_string("yellow", "fatal"), path))
print(indent(error.msg, 2))
end
else
print ""
print(color_string("green", "Success: "), #res.pass)
print(color_string("red", "Failed : "), #res.fail)
print(color_string("red", "Errors : "), #res.errs)
print(HEADER)
end
end

mod.describe = function(desc, func)
results.pass = results.pass or {}
results.fail = results.fail or {}
results.errs = results.errs or {}
results.pending = results.pending or {}

describe = mod.inner_describe
local ok, msg, desc_stack = call_inner(desc, func)
Expand Down Expand Up @@ -151,15 +253,6 @@ mod.clear = function()
vim.api.nvim_buf_set_lines(0, 0, -1, false, {})
end

local indent = function(msg, spaces)
if spaces == nil then
spaces = 4
end

local prefix = string.rep(" ", spaces)
return prefix .. msg:gsub("\n", "\n" .. prefix)
end

local run_each = function(tbl)
for _, v in pairs(tbl) do
for _, w in ipairs(v) do
Expand All @@ -172,11 +265,12 @@ end

mod.it = function(desc, func)
run_each(current_before_each)
local ok, msg, desc_stack = call_inner(desc, func)
local ok, msg, desc_stack, prints = call_inner(desc, func, output_compact)
run_each(current_after_each)

local test_result = {
descriptions = desc_stack,
prints = prints,
msg = nil,
}

Expand All @@ -188,11 +282,19 @@ mod.it = function(desc, func)
to_insert = results.fail
test_result.msg = msg

print(FAIL, "||", table.concat(test_result.descriptions, " "))
print(indent(msg, 12))
if output_compact then
print_append(color_string("red", fail_marker))
else
print(FAIL, "||", table.concat(test_result.descriptions, " "))
print(indent(msg, 12))
end
else
to_insert = results.pass
print(SUCCESS, "||", table.concat(test_result.descriptions, " "))
if output_compact then
print_append(color_string("green", pass_marker))
else
print(SUCCESS, "||", table.concat(test_result.descriptions, " "))
end
end

table.insert(to_insert, test_result)
Expand All @@ -201,7 +303,13 @@ end
mod.pending = function(desc, func)
local curr_stack = vim.deepcopy(current_description)
table.insert(curr_stack, desc)
print(PENDING, "||", table.concat(curr_stack, " "))
table.insert(results.pending, { descriptions = curr_stack, msg = nil })

if output_compact then
print_append(color_string("magenta", pending_marker))
else
print(PENDING, "||", table.concat(curr_stack, " "))
end
end

_PlenaryBustedOldAssert = _PlenaryBustedOldAssert or assert
Expand All @@ -214,17 +322,36 @@ after_each = mod.after_each
clear = mod.clear
assert = require "luassert"

mod.run = function(file)
print("\n" .. HEADER)
print("Testing: ", file)
mod.run = function(input_file, input_opts_json)
local file = input_file

if type(input_opts_json) == "string" then
opts = vim.json.decode(input_opts_json)
output_compact = opts.output_format == "compact"
end

if output_compact then
local trimmed = vim.fn.fnamemodify(file, ":.")

print ""
print(string.format("%s: %s", color_string("blue", "test"), trimmed))
else
print("\n" .. HEADER)
print("Testing: ", file)
end

local loaded, msg = loadfile(file)

if not loaded then
print(HEADER)
print "FAILED TO LOAD FILE"
print(color_string("red", msg))
print(HEADER)
if output_compact then
print(string.format("%s: %s", color_string("red", "fatal"), msg))
else
print(HEADER)
print "FAILED TO LOAD FILE"
print(color_string("red", msg))
print(HEADER)
end

if is_headless then
return vim.cmd "2cq"
else
Expand All @@ -247,12 +374,17 @@ mod.run = function(file)
mod.format_results(results)

if #results.errs ~= 0 then
print("We had an unexpected error: ", vim.inspect(results.errs), vim.inspect(results))
if not output_compact then
print "\nFatal errors. Exit: 2"
end

if is_headless then
return vim.cmd "2cq"
end
elseif #results.fail > 0 then
print "Tests Failed. Exit: 1"
if not output_compact then
print "\nTests Failed. Exit: 1"
end

if is_headless then
return vim.cmd "1cq"
Expand Down
Loading