add test runner for lua plenary tests
This commit is contained in:
@@ -6,6 +6,7 @@ local defaults = {
|
|||||||
"test-samurai.runners.js-jest",
|
"test-samurai.runners.js-jest",
|
||||||
"test-samurai.runners.js-mocha",
|
"test-samurai.runners.js-mocha",
|
||||||
"test-samurai.runners.js-vitest",
|
"test-samurai.runners.js-vitest",
|
||||||
|
"test-samurai.runners.lua-plenary",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
240
lua/test-samurai/runners/lua-plenary.lua
Normal file
240
lua/test-samurai/runners/lua-plenary.lua
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
local util = require("test-samurai.util")
|
||||||
|
|
||||||
|
local runner = {
|
||||||
|
name = "lua-plenary",
|
||||||
|
framework = "plenary",
|
||||||
|
}
|
||||||
|
|
||||||
|
local function is_lua_test_path(path)
|
||||||
|
if not path or path == "" then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if not path:match("%.lua$") then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if path:match("_spec%.lua$") then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
if path:match("/tests/") then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function runner.is_test_file(bufnr)
|
||||||
|
local path = util.get_buf_path(bufnr)
|
||||||
|
return is_lua_test_path(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function find_repo_root(file)
|
||||||
|
local root = util.find_root(file, { ".git", "tests", "lua", "plugin" })
|
||||||
|
if not root or root == "" then
|
||||||
|
root = vim.loop.cwd()
|
||||||
|
end
|
||||||
|
return root
|
||||||
|
end
|
||||||
|
|
||||||
|
local function minimal_init_for(root)
|
||||||
|
return vim.fs.joinpath(root, "tests", "minimal_init.lua")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function escape_for_ex_double_quotes(s)
|
||||||
|
s = s or ""
|
||||||
|
s = s:gsub("\\", "\\\\")
|
||||||
|
s = s:gsub('"', '\\"')
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
local function count_keyword(line, kw)
|
||||||
|
local c = 0
|
||||||
|
local pat = "%f[%w]" .. kw .. "%f[%W]"
|
||||||
|
for _ in line:gmatch(pat) do
|
||||||
|
c = c + 1
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
local function find_end_lua_block(lines, start_idx)
|
||||||
|
local depth = 0
|
||||||
|
local started = false
|
||||||
|
for i = start_idx, #lines do
|
||||||
|
local line = lines[i]
|
||||||
|
local fnc = count_keyword(line, "function")
|
||||||
|
local endc = count_keyword(line, "end")
|
||||||
|
if fnc > 0 then
|
||||||
|
depth = depth + fnc
|
||||||
|
started = true
|
||||||
|
end
|
||||||
|
if started and endc > 0 then
|
||||||
|
depth = depth - endc
|
||||||
|
if depth <= 0 then
|
||||||
|
return i - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return #lines - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local function collect_lua_structs(lines)
|
||||||
|
local describes = {}
|
||||||
|
local tests = {}
|
||||||
|
|
||||||
|
for i, line in ipairs(lines) do
|
||||||
|
local dname = line:match("^%s*describe%s*%(%s*['\"`]([^'\"`]+)['\"`]")
|
||||||
|
if dname then
|
||||||
|
local start0 = i - 1
|
||||||
|
local end0 = find_end_lua_block(lines, i)
|
||||||
|
table.insert(describes, { kind = "describe", name = dname, start = start0, ["end"] = end0 })
|
||||||
|
else
|
||||||
|
local tname = line:match("^%s*it%s*%(%s*['\"`]([^'\"`]+)['\"`]")
|
||||||
|
if tname then
|
||||||
|
local start0 = i - 1
|
||||||
|
local end0 = find_end_lua_block(lines, i)
|
||||||
|
table.insert(tests, { kind = "it", name = tname, start = start0, ["end"] = end0 })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return describes, tests
|
||||||
|
end
|
||||||
|
|
||||||
|
local function build_full_name(lines, idx, leaf_name)
|
||||||
|
local parts = { leaf_name }
|
||||||
|
for i = idx - 1, 1, -1 do
|
||||||
|
local line = lines[i]
|
||||||
|
local dname = line:match("^%s*describe%s*%(%s*['\"`]([^'\"`]+)['\"`]")
|
||||||
|
if dname then
|
||||||
|
table.insert(parts, 1, dname)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return table.concat(parts, " ")
|
||||||
|
end
|
||||||
|
|
||||||
|
function runner.find_nearest(bufnr, row, _col)
|
||||||
|
if not runner.is_test_file(bufnr) then
|
||||||
|
return nil, "not a lua test file"
|
||||||
|
end
|
||||||
|
|
||||||
|
local lines = util.get_buf_lines(bufnr)
|
||||||
|
local describes, tests = collect_lua_structs(lines)
|
||||||
|
|
||||||
|
for _, t in ipairs(tests) do
|
||||||
|
if row >= t.start and row <= t["end"] then
|
||||||
|
local full = build_full_name(lines, t.start + 1, t.name)
|
||||||
|
local file = util.get_buf_path(bufnr)
|
||||||
|
local root = find_repo_root(file)
|
||||||
|
return { file = file, cwd = root, test_name = t.name, full_name = full, kind = "it" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local best_describe = nil
|
||||||
|
for _, d in ipairs(describes) do
|
||||||
|
if row >= d.start and row <= d["end"] then
|
||||||
|
if not best_describe or d.start >= best_describe.start then
|
||||||
|
best_describe = d
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if best_describe then
|
||||||
|
local full = build_full_name(lines, best_describe.start + 1, best_describe.name)
|
||||||
|
local file = util.get_buf_path(bufnr)
|
||||||
|
local root = find_repo_root(file)
|
||||||
|
return { file = file, cwd = root, test_name = best_describe.name, full_name = full, kind = "describe" }
|
||||||
|
end
|
||||||
|
|
||||||
|
local start = row + 1
|
||||||
|
if start > #lines then
|
||||||
|
start = #lines
|
||||||
|
elseif start < 1 then
|
||||||
|
start = 1
|
||||||
|
end
|
||||||
|
for i = start, 1, -1 do
|
||||||
|
local line = lines[i]
|
||||||
|
local tname = line:match("^%s*it%s*%(%s*['\"`]([^'\"`]+)['\"`]")
|
||||||
|
if tname then
|
||||||
|
local full = build_full_name(lines, i, tname)
|
||||||
|
local file = util.get_buf_path(bufnr)
|
||||||
|
local root = find_repo_root(file)
|
||||||
|
return { file = file, cwd = root, test_name = tname, full_name = full, kind = "it" }
|
||||||
|
end
|
||||||
|
local dname = line:match("^%s*describe%s*%(%s*['\"`]([^'\"`]+)['\"`]")
|
||||||
|
if dname then
|
||||||
|
local full = build_full_name(lines, i, dname)
|
||||||
|
local file = util.get_buf_path(bufnr)
|
||||||
|
local root = find_repo_root(file)
|
||||||
|
return { file = file, cwd = root, test_name = dname, full_name = full, kind = "describe" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil, "no test call found"
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ex_plenary_busted_file(file, filter_name)
|
||||||
|
local ex = "PlenaryBustedFile " .. vim.fn.fnameescape(file)
|
||||||
|
if filter_name and filter_name ~= "" then
|
||||||
|
local f = escape_for_ex_double_quotes(filter_name)
|
||||||
|
ex = ex .. ' { busted_args = { "--filter", "' .. f .. '" } }'
|
||||||
|
end
|
||||||
|
return ex
|
||||||
|
end
|
||||||
|
|
||||||
|
function runner.build_command(spec)
|
||||||
|
local root = spec and spec.cwd or vim.loop.cwd()
|
||||||
|
local minit = minimal_init_for(root)
|
||||||
|
|
||||||
|
local cmd = {
|
||||||
|
"nvim",
|
||||||
|
"--headless",
|
||||||
|
"-u",
|
||||||
|
minit,
|
||||||
|
"-c",
|
||||||
|
ex_plenary_busted_file(spec.file, spec.test_name),
|
||||||
|
"-c",
|
||||||
|
"qa",
|
||||||
|
}
|
||||||
|
|
||||||
|
return { cmd = cmd, cwd = root }
|
||||||
|
end
|
||||||
|
|
||||||
|
function runner.build_file_command(bufnr)
|
||||||
|
local file = util.get_buf_path(bufnr)
|
||||||
|
if not file or file == "" then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local root = find_repo_root(file)
|
||||||
|
local minit = minimal_init_for(root)
|
||||||
|
|
||||||
|
local cmd = {
|
||||||
|
"nvim",
|
||||||
|
"--headless",
|
||||||
|
"-u",
|
||||||
|
minit,
|
||||||
|
"-c",
|
||||||
|
ex_plenary_busted_file(file, nil),
|
||||||
|
"-c",
|
||||||
|
"qa",
|
||||||
|
}
|
||||||
|
|
||||||
|
return { cmd = cmd, cwd = root }
|
||||||
|
end
|
||||||
|
|
||||||
|
function runner.build_all_command(bufnr)
|
||||||
|
local file = util.get_buf_path(bufnr)
|
||||||
|
local root = find_repo_root(file)
|
||||||
|
local minit = minimal_init_for(root)
|
||||||
|
|
||||||
|
local cmd = {
|
||||||
|
"nvim",
|
||||||
|
"--headless",
|
||||||
|
"-u",
|
||||||
|
minit,
|
||||||
|
"-c",
|
||||||
|
"PlenaryBustedDirectory tests",
|
||||||
|
"-c",
|
||||||
|
"qa",
|
||||||
|
}
|
||||||
|
|
||||||
|
return { cmd = cmd, cwd = root }
|
||||||
|
end
|
||||||
|
|
||||||
|
return runner
|
||||||
97
session.vim
Normal file
97
session.vim
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
let SessionLoad = 1
|
||||||
|
let s:so_save = &g:so | let s:siso_save = &g:siso | setg so=0 siso=0 | setl so=-1 siso=-1
|
||||||
|
let v:this_session=expand("<sfile>:p")
|
||||||
|
silent only
|
||||||
|
silent tabonly
|
||||||
|
cd ~/Projekte/Neovim-Plugins/test-samurai
|
||||||
|
if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == ''
|
||||||
|
let s:wipebuf = bufnr('%')
|
||||||
|
endif
|
||||||
|
let s:shortmess_save = &shortmess
|
||||||
|
if &shortmess =~ 'A'
|
||||||
|
set shortmess=aoOA
|
||||||
|
else
|
||||||
|
set shortmess=aoO
|
||||||
|
endif
|
||||||
|
badd +17 tests/test_samurai_lua_spec.lua
|
||||||
|
badd +1 ~/Projekte/Neovim-Plugins/test-samurai/lua/test-samurai/runners/lua-plenary.lua
|
||||||
|
argglobal
|
||||||
|
%argdel
|
||||||
|
edit tests/test_samurai_lua_spec.lua
|
||||||
|
let s:save_splitbelow = &splitbelow
|
||||||
|
let s:save_splitright = &splitright
|
||||||
|
set splitbelow splitright
|
||||||
|
wincmd _ | wincmd |
|
||||||
|
vsplit
|
||||||
|
1wincmd h
|
||||||
|
wincmd w
|
||||||
|
let &splitbelow = s:save_splitbelow
|
||||||
|
let &splitright = s:save_splitright
|
||||||
|
wincmd t
|
||||||
|
let s:save_winminheight = &winminheight
|
||||||
|
let s:save_winminwidth = &winminwidth
|
||||||
|
set winminheight=0
|
||||||
|
set winheight=1
|
||||||
|
set winminwidth=0
|
||||||
|
set winwidth=1
|
||||||
|
exe 'vert 1resize ' . ((&columns * 119 + 119) / 239)
|
||||||
|
exe 'vert 2resize ' . ((&columns * 119 + 119) / 239)
|
||||||
|
argglobal
|
||||||
|
balt ~/Projekte/Neovim-Plugins/test-samurai/lua/test-samurai/runners/lua-plenary.lua
|
||||||
|
setlocal foldmethod=expr
|
||||||
|
setlocal foldexpr=v:lua.vim.treesitter.foldexpr()
|
||||||
|
setlocal foldmarker={{{,}}}
|
||||||
|
setlocal foldignore=#
|
||||||
|
setlocal foldlevel=99
|
||||||
|
setlocal foldminlines=1
|
||||||
|
setlocal foldnestmax=20
|
||||||
|
setlocal foldenable
|
||||||
|
let s:l = 17 - ((16 * winheight(0) + 27) / 54)
|
||||||
|
if s:l < 1 | let s:l = 1 | endif
|
||||||
|
keepjumps exe s:l
|
||||||
|
normal! zt
|
||||||
|
keepjumps 17
|
||||||
|
normal! 0
|
||||||
|
wincmd w
|
||||||
|
argglobal
|
||||||
|
if bufexists(fnamemodify("~/Projekte/Neovim-Plugins/test-samurai/lua/test-samurai/runners/lua-plenary.lua", ":p")) | buffer ~/Projekte/Neovim-Plugins/test-samurai/lua/test-samurai/runners/lua-plenary.lua | else | edit ~/Projekte/Neovim-Plugins/test-samurai/lua/test-samurai/runners/lua-plenary.lua | endif
|
||||||
|
if &buftype ==# 'terminal'
|
||||||
|
silent file ~/Projekte/Neovim-Plugins/test-samurai/lua/test-samurai/runners/lua-plenary.lua
|
||||||
|
endif
|
||||||
|
balt tests/test_samurai_lua_spec.lua
|
||||||
|
setlocal foldmethod=expr
|
||||||
|
setlocal foldexpr=v:lua.vim.treesitter.foldexpr()
|
||||||
|
setlocal foldmarker={{{,}}}
|
||||||
|
setlocal foldignore=#
|
||||||
|
setlocal foldlevel=99
|
||||||
|
setlocal foldminlines=1
|
||||||
|
setlocal foldnestmax=20
|
||||||
|
setlocal foldenable
|
||||||
|
let s:l = 1 - ((0 * winheight(0) + 27) / 54)
|
||||||
|
if s:l < 1 | let s:l = 1 | endif
|
||||||
|
keepjumps exe s:l
|
||||||
|
normal! zt
|
||||||
|
keepjumps 1
|
||||||
|
normal! 0
|
||||||
|
wincmd w
|
||||||
|
exe 'vert 1resize ' . ((&columns * 119 + 119) / 239)
|
||||||
|
exe 'vert 2resize ' . ((&columns * 119 + 119) / 239)
|
||||||
|
tabnext 1
|
||||||
|
if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0 && getbufvar(s:wipebuf, '&buftype') isnot# 'terminal'
|
||||||
|
silent exe 'bwipe ' . s:wipebuf
|
||||||
|
endif
|
||||||
|
unlet! s:wipebuf
|
||||||
|
set winheight=1 winwidth=20
|
||||||
|
let &shortmess = s:shortmess_save
|
||||||
|
let &winminheight = s:save_winminheight
|
||||||
|
let &winminwidth = s:save_winminwidth
|
||||||
|
let s:sx = expand("<sfile>:p:r")."x.vim"
|
||||||
|
if filereadable(s:sx)
|
||||||
|
exe "source " . fnameescape(s:sx)
|
||||||
|
endif
|
||||||
|
let &g:so = s:so_save | let &g:siso = s:siso_save
|
||||||
|
set hlsearch
|
||||||
|
nohlsearch
|
||||||
|
doautoall SessionLoadPost
|
||||||
|
unlet SessionLoad
|
||||||
|
" vim: set ft=vim :
|
||||||
130
tests/test_samurai_lua_spec.lua
Normal file
130
tests/test_samurai_lua_spec.lua
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
local test_samurai = require("test-samurai")
|
||||||
|
local lua_runner = require("test-samurai.runners.lua-plenary")
|
||||||
|
local util = require("test-samurai.util")
|
||||||
|
|
||||||
|
local function mkbuf(path, ft, lines)
|
||||||
|
local bufnr = vim.api.nvim_create_buf(false, true)
|
||||||
|
vim.api.nvim_buf_set_name(bufnr, path)
|
||||||
|
vim.bo[bufnr].filetype = ft
|
||||||
|
if lines then
|
||||||
|
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
|
||||||
|
end
|
||||||
|
return bufnr
|
||||||
|
end
|
||||||
|
|
||||||
|
describe("test-samurai lua runner (plenary)", function()
|
||||||
|
it("detects lua spec files by suffix", function()
|
||||||
|
local bufnr = mkbuf("/tmp/test_samurai_lua_spec_unique_1_spec.lua", "lua")
|
||||||
|
assert.is_true(lua_runner.is_test_file(bufnr))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("finds nearest it() when cursor is inside it block and builds filtered command", function()
|
||||||
|
local bufnr = mkbuf("/tmp/project/tests/test_samurai_lua_nearest_unique_2_spec.lua", "lua", {
|
||||||
|
"describe('outer', function()",
|
||||||
|
" it('inner 1', function()",
|
||||||
|
" local x = 1",
|
||||||
|
" end)",
|
||||||
|
"",
|
||||||
|
" it('inner 2', function()",
|
||||||
|
" local y = 2",
|
||||||
|
" end)",
|
||||||
|
"end)",
|
||||||
|
})
|
||||||
|
|
||||||
|
local orig_find_root = util.find_root
|
||||||
|
util.find_root = function()
|
||||||
|
return "/tmp/project"
|
||||||
|
end
|
||||||
|
|
||||||
|
local spec, err = lua_runner.find_nearest(bufnr, 6, 0)
|
||||||
|
|
||||||
|
util.find_root = orig_find_root
|
||||||
|
|
||||||
|
assert.is_nil(err)
|
||||||
|
assert.is_not_nil(spec)
|
||||||
|
assert.equals("inner 2", spec.test_name)
|
||||||
|
assert.equals("outer inner 2", spec.full_name)
|
||||||
|
assert.equals("/tmp/project", spec.cwd)
|
||||||
|
|
||||||
|
local cmd_spec = lua_runner.build_command(spec)
|
||||||
|
assert.equals("/tmp/project", cmd_spec.cwd)
|
||||||
|
assert.are.same({
|
||||||
|
"nvim",
|
||||||
|
"--headless",
|
||||||
|
"-u",
|
||||||
|
"/tmp/project/tests/minimal_init.lua",
|
||||||
|
"-c",
|
||||||
|
'PlenaryBustedFile ' .. spec.file .. ' { busted_args = { "--filter", "inner 2" } }',
|
||||||
|
"-c",
|
||||||
|
"qa",
|
||||||
|
}, cmd_spec.cmd)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("returns describe block when cursor is between it() calls", function()
|
||||||
|
local bufnr = mkbuf("/tmp/project/tests/test_samurai_lua_between_unique_3_spec.lua", "lua", {
|
||||||
|
"describe('outer', function()",
|
||||||
|
" it('inner 1', function()",
|
||||||
|
" local x = 1",
|
||||||
|
" end)",
|
||||||
|
"",
|
||||||
|
" it('inner 2', function()",
|
||||||
|
" local y = 2",
|
||||||
|
" end)",
|
||||||
|
"end)",
|
||||||
|
})
|
||||||
|
|
||||||
|
local orig_find_root = util.find_root
|
||||||
|
util.find_root = function()
|
||||||
|
return "/tmp/project"
|
||||||
|
end
|
||||||
|
|
||||||
|
local spec, err = lua_runner.find_nearest(bufnr, 4, 0)
|
||||||
|
|
||||||
|
util.find_root = orig_find_root
|
||||||
|
|
||||||
|
assert.is_nil(err)
|
||||||
|
assert.is_not_nil(spec)
|
||||||
|
assert.equals("outer", spec.test_name)
|
||||||
|
assert.equals("outer", spec.full_name)
|
||||||
|
assert.equals("describe", spec.kind)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("builds all command via PlenaryBustedDirectory", function()
|
||||||
|
local bufnr = mkbuf("/tmp/project/tests/test_samurai_core_spec_unique_4_spec.lua", "lua")
|
||||||
|
|
||||||
|
local orig_find_root = util.find_root
|
||||||
|
util.find_root = function()
|
||||||
|
return "/tmp/project"
|
||||||
|
end
|
||||||
|
|
||||||
|
local cmd_spec = lua_runner.build_all_command(bufnr)
|
||||||
|
|
||||||
|
util.find_root = orig_find_root
|
||||||
|
|
||||||
|
assert.are.same({
|
||||||
|
"nvim",
|
||||||
|
"--headless",
|
||||||
|
"-u",
|
||||||
|
"/tmp/project/tests/minimal_init.lua",
|
||||||
|
"-c",
|
||||||
|
"PlenaryBustedDirectory tests",
|
||||||
|
"-c",
|
||||||
|
"qa",
|
||||||
|
}, cmd_spec.cmd)
|
||||||
|
assert.equals("/tmp/project", cmd_spec.cwd)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("core selects lua runner for *_spec.lua buffers", function()
|
||||||
|
test_samurai.setup({
|
||||||
|
runner_modules = {
|
||||||
|
"test-samurai.runners.lua-plenary",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
local bufnr = mkbuf("/tmp/project/tests/test_samurai_core_spec_unique_5_spec.lua", "lua")
|
||||||
|
|
||||||
|
local runner = require("test-samurai.core").get_runner_for_buf(bufnr)
|
||||||
|
assert.is_not_nil(runner)
|
||||||
|
assert.equals("lua-plenary", runner.name)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
Reference in New Issue
Block a user