-
-
Notifications
You must be signed in to change notification settings - Fork 331
Expand file tree
/
Copy pathtest_harness.lua
More file actions
255 lines (205 loc) · 6.54 KB
/
test_harness.lua
File metadata and controls
255 lines (205 loc) · 6.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
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 plenary_dir = vim.fn.fnamemodify(debug.getinfo(1).source:match "@?(.*[/\\])", ":p:h:h:h")
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_file_command(command)
local split_string = vim.split(command, " ")
local file = vim.fn.expand(table.remove(split_string, 1))
local opts = assert(loadstring("return " .. table.concat(split_string, " ")))()
return harness.test_file(file, opts)
end
function harness.test_directory_command(command)
local split_string = vim.split(command, " ")
local directory = vim.fn.expand(table.remove(split_string, 1))
local opts = assert(loadstring("return " .. table.concat(split_string, " ")))()
return harness.test_directory(directory, opts)
end
local function test_paths(paths, opts)
local minimal = not opts or not opts.init or opts.minimal or opts.minimal_init
opts = vim.tbl_deep_extend("force", {
nvim_cmd = vim.v.progpath,
winopts = { winblend = 3 },
sequential = false,
keep_going = true,
timeout = 50000,
}, opts or {})
vim.env.PLENARY_TEST_TIMEOUT = opts.timeout
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<CR>", {})
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 path_len = #paths
local failure = false
local jobs = vim.tbl_map(function(p)
local args = {
"--headless",
"-c",
"set rtp+=.," .. vim.fn.escape(plenary_dir, " ") .. " | runtime plugin/plenary.vim",
}
if minimal then
table.insert(args, "--noplugin")
if opts.minimal_init then
table.insert(args, "-u")
table.insert(args, opts.minimal_init)
end
elseif opts.init ~= nil then
table.insert(args, "-u")
table.insert(args, opts.init)
end
table.insert(args, "-c")
table.insert(args, string.format('lua require("plenary.busted").run("%s")', p:absolute():gsub("\\", "\\\\")))
local job = Job:new {
command = opts.nvim_cmd,
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)
if not Job.join(j, opts.timeout) then
log.debug("... Timed out job number", i)
failure = true
pcall(function()
j.handle:kill(15) -- SIGTERM
end)
else
log.debug("... Completed job number", i, j.code, j.signal)
failure = failure or j.code ~= 0 or j.signal ~= 0
end
if failure and not opts.keep_going then
break
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.test_directory(directory, opts)
print "Starting..."
directory = directory:gsub("\\", "/")
local paths = harness._find_files_to_run(directory)
-- Paths work strangely on Windows, so lets have abs paths
if vim.fn.has "win32" == 1 or vim.fn.has "win64" == 1 then
paths = vim.tbl_map(function(p)
return Path:new(directory, p.filename)
end, paths)
end
test_paths(paths, opts)
end
function harness.test_file(filepath, opts)
test_paths({ Path:new(filepath) }, opts)
end
function harness._find_files_to_run(directory)
local finder
if vim.fn.has "win32" == 1 or vim.fn.has "win64" == 1 then
-- On windows use powershell Get-ChildItem instead
local cmd = vim.fn.executable "pwsh.exe" == 1 and "pwsh" or "powershell"
finder = Job:new {
command = cmd,
args = { "-NoProfile", "-Command", [[Get-ChildItem -Recurse -n -Filter "*_spec.lua"]] },
cwd = directory,
}
else
-- everywhere else use find
finder = Job:new {
command = "find",
args = { directory, "-type", "f", "-name", "*_spec.lua" },
}
end
return vim.tbl_map(Path.new, finder:sync(vim.env.PLENARY_TEST_TIMEOUT))
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