local Path = require "plenary.path" local Job = require "plenary.job" local f = require "plenary.functional" local log = require "plenary.log" local win_float = require "plenary.window.float" local headless = require("plenary.nvim_meta").is_headless local harness = {} local print_output = vim.schedule_wrap(function(_, ...) for _, v in ipairs { ... } do io.stdout:write(tostring(v)) io.stdout:write "\n" end vim.cmd [[mode]] end) local get_nvim_output = function(job_id) return vim.schedule_wrap(function(bufnr, ...) if not vim.api.nvim_buf_is_valid(bufnr) then return end for _, v in ipairs { ... } do vim.api.nvim_chan_send(job_id, v .. "\r\n") end end) end function harness.test_directory_command(command) local split_string = vim.split(command, " ") local directory = table.remove(split_string, 1) local opts = assert(loadstring("return " .. table.concat(split_string, " ")))() return harness.test_directory(directory, opts) end function harness.test_directory(directory, opts) print "Starting..." opts = vim.tbl_deep_extend("force", { winopts = { winblend = 3 }, sequential = false, keep_going = true, timeout = 50000, }, opts or {}) local res = {} if not headless then res = win_float.percentage_range_window(0.95, 0.70, opts.winopts) res.job_id = vim.api.nvim_open_term(res.bufnr, {}) vim.api.nvim_buf_set_keymap(res.bufnr, "n", "q", ":q", {}) vim.api.nvim_win_set_option(res.win_id, "winhl", "Normal:Normal") vim.api.nvim_win_set_option(res.win_id, "conceallevel", 3) vim.api.nvim_win_set_option(res.win_id, "concealcursor", "n") if res.border_win_id then vim.api.nvim_win_set_option(res.border_win_id, "winhl", "Normal:Normal") end if res.bufnr then vim.api.nvim_buf_set_option(res.bufnr, "filetype", "PlenaryTestPopup") end vim.cmd "mode" end local outputter = headless and print_output or get_nvim_output(res.job_id) local paths = harness._find_files_to_run(directory) local path_len = #paths local failure = false local jobs = vim.tbl_map(function(p) local args = { "--headless", "-c", string.format('lua require("plenary.busted").run("%s")', p:absolute()), } if opts.minimal ~= nil then table.insert(args, "--noplugin") elseif opts.minimal_init ~= nil then table.insert(args, "--noplugin") table.insert(args, "-u") table.insert(args, opts.minimal_init) end local job = Job:new { command = vim.v.progpath, args = args, -- Can be turned on to debug on_stdout = function(_, data) if path_len == 1 then outputter(res.bufnr, data) end end, on_stderr = function(_, data) if path_len == 1 then outputter(res.bufnr, data) end end, on_exit = vim.schedule_wrap(function(j_self, _, _) if path_len ~= 1 then outputter(res.bufnr, unpack(j_self:stderr_result())) outputter(res.bufnr, unpack(j_self:result())) end vim.cmd "mode" end), } job.nvim_busted_path = p.filename return job end, paths) log.debug "Running..." for i, j in ipairs(jobs) do outputter(res.bufnr, "Scheduling: " .. j.nvim_busted_path) j:start() if opts.sequential then log.debug("... Sequential wait for job number", i) Job.join(j, opts.timeout) log.debug("... Completed job number", i) if j.code ~= 0 then failure = true if not opts.keep_going then break end end end end -- TODO: Probably want to let people know when we've completed everything. if not headless then return end if not opts.sequential then table.insert(jobs, opts.timeout) log.debug "... Parallel wait" Job.join(unpack(jobs)) log.debug "... Completed jobs" table.remove(jobs, table.getn(jobs)) failure = f.any(function(_, v) return v.code ~= 0 end, jobs) end vim.wait(100) if headless then if failure then return vim.cmd "1cq" end return vim.cmd "0cq" end end function harness._find_files_to_run(directory) local finder = Job:new { command = "find", args = { directory, "-type", "f", "-name", "*_spec.lua" }, } return vim.tbl_map(Path.new, finder:sync()) end function harness._run_path(test_type, directory) local paths = harness._find_files_to_run(directory) local bufnr = 0 local win_id = 0 for _, p in pairs(paths) do print " " print("Loading Tests For: ", p:absolute(), "\n") local ok, _ = pcall(function() dofile(p:absolute()) end) if not ok then print "Failed to load file" end end harness:run(test_type, bufnr, win_id) vim.cmd "qa!" return paths end return harness