mirror of
https://github.com/Reuh/anselme.git
synced 2025-10-28 00:59:31 +00:00
Add interactive mode for test runner
This commit is contained in:
parent
12c32bb8a2
commit
93dadb3b5d
1 changed files with 76 additions and 55 deletions
131
test/run.lua
131
test/run.lua
|
|
@ -7,6 +7,8 @@ local anselme = require("anselme")
|
||||||
local persistent_manager = require("anselme.state.persistent_manager")
|
local persistent_manager = require("anselme.state.persistent_manager")
|
||||||
local ast = require("anselme.ast")
|
local ast = require("anselme.ast")
|
||||||
|
|
||||||
|
io.stdout:setvbuf("no")
|
||||||
|
|
||||||
-- simple random to get the same result across lua versions
|
-- simple random to get the same result across lua versions
|
||||||
local prev = 0
|
local prev = 0
|
||||||
local function badrandom(a, b)
|
local function badrandom(a, b)
|
||||||
|
|
@ -26,36 +28,50 @@ function math.random(a, b)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function run_loop(run_state, out)
|
-- handle anselme run loop
|
||||||
|
local function run_loop(run_state, write_output, interactive)
|
||||||
while run_state:active() do
|
while run_state:active() do
|
||||||
local e, data = run_state:step()
|
local e, data = run_state:step()
|
||||||
table.insert(out, "--- "..e.." ---")
|
write_output("--- "..e.." ---")
|
||||||
if e == "text" then
|
if e == "text" then
|
||||||
for _, l in ipairs(data) do
|
for _, l in ipairs(data) do
|
||||||
table.insert(out, l:format(run_state))
|
write_output(l:format(run_state))
|
||||||
end
|
end
|
||||||
elseif e == "choice" then
|
elseif e == "choice" then
|
||||||
local choice = assert(run_state:eval_local("choice"), "no choice selected"):to_lua()
|
local choice
|
||||||
for i, l in ipairs(data) do
|
if interactive then
|
||||||
if i == choice then
|
for i, l in ipairs(data) do
|
||||||
table.insert(out, "=> "..l:format(run_state))
|
write_output(("%s> %s"):format(i, l:format(run_state)))
|
||||||
else
|
end
|
||||||
table.insert(out, " > "..l:format(run_state))
|
io.write(("Select choice (1-%s): "):format(#data))
|
||||||
|
choice = tonumber(io.read("l"))
|
||||||
|
else
|
||||||
|
choice = assert(run_state:eval_local("choice"), "no choice selected"):to_lua()
|
||||||
|
for i, l in ipairs(data) do
|
||||||
|
if i == choice then
|
||||||
|
write_output(("=> %s"):format(l:format(run_state)))
|
||||||
|
else
|
||||||
|
write_output((" > %s"):format(l:format(run_state)))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
data:choose(choice)
|
data:choose(choice)
|
||||||
elseif e == "return" then
|
elseif e == "return" then
|
||||||
table.insert(out, data:format(run_state))
|
write_output(data:format(run_state))
|
||||||
run_state:merge()
|
run_state:merge()
|
||||||
else
|
else
|
||||||
table.insert(out, tostring(data))
|
write_output(tostring(data))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- run a test file and return the result
|
-- run a test file and return the result
|
||||||
local function run(path)
|
local function run(path, interactive)
|
||||||
local out = { "--# run #--" }
|
local out = { "--# run #--" }
|
||||||
|
local write_output
|
||||||
|
if interactive then write_output = print
|
||||||
|
else write_output = function(str) table.insert(out, str) end
|
||||||
|
end
|
||||||
math.randomseed()
|
math.randomseed()
|
||||||
|
|
||||||
local state = anselme:new()
|
local state = anselme:new()
|
||||||
|
|
@ -67,74 +83,76 @@ local function run(path)
|
||||||
state:define("wait", "(duration::number)", function(duration) coroutine.yield("wait", duration) end)
|
state:define("wait", "(duration::number)", function(duration) coroutine.yield("wait", duration) end)
|
||||||
state:define("run in new branch", "(code)", function(code)
|
state:define("run in new branch", "(code)", function(code)
|
||||||
local parallel_state = state:branch()
|
local parallel_state = state:branch()
|
||||||
table.insert(out, "--# parallel script #--")
|
write_output("--# parallel script #--")
|
||||||
parallel_state:run(code, "parallel")
|
parallel_state:run(code, "parallel")
|
||||||
run_loop(parallel_state, out)
|
run_loop(parallel_state, write_output, interactive)
|
||||||
table.insert(out, "--# main script #--")
|
write_output("--# main script #--")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local run_state = state:branch()
|
local run_state = state:branch()
|
||||||
|
|
||||||
local f = assert(io.open(path, "r"))
|
local f = assert(io.open(path, "r"))
|
||||||
local s, block = pcall(anselme.parse, f:read("*a"), path)
|
local s, block = pcall(anselme.parse, f:read("a"), path)
|
||||||
f:close()
|
f:close()
|
||||||
|
|
||||||
if not s then
|
if not s then
|
||||||
return "--# parse error #--\n"..tostring(block)
|
write_output("--# parse error #--")
|
||||||
|
write_output(tostring(block))
|
||||||
|
return table.concat(out, "\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
run_state:run(block)
|
run_state:run(block)
|
||||||
|
|
||||||
run_loop(run_state, out)
|
run_loop(run_state, write_output, interactive)
|
||||||
|
|
||||||
if state:defined("post run check") then
|
if state:defined("post run check") then
|
||||||
local post_run_state = state:branch()
|
local post_run_state = state:branch()
|
||||||
post_run_state:run("post run check!")
|
post_run_state:run("post run check!")
|
||||||
|
|
||||||
table.insert(out, "--# post run check #--")
|
write_output("--# post run check #--")
|
||||||
run_loop(post_run_state, out)
|
run_loop(post_run_state, write_output, interactive)
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(out, "--# saved #--")
|
write_output("--# saved #--")
|
||||||
table.insert(out, persistent_manager:capture(state):format(state))
|
write_output(persistent_manager:get_struct(state):format(state))
|
||||||
|
|
||||||
return table.concat(out, "\n")
|
return table.concat(out, "\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- display an animated loading indicator
|
|
||||||
io.stdout:setvbuf("no")
|
|
||||||
local loading = {
|
|
||||||
loop = { "⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷" },
|
|
||||||
loop_pos = 1,
|
|
||||||
erase_code = "",
|
|
||||||
|
|
||||||
write = function(self, message)
|
|
||||||
self:clear()
|
|
||||||
local str = self.loop[self.loop_pos].." "..message
|
|
||||||
self.erase_code = ("\b \b"):rep(#str)
|
|
||||||
io.write(str)
|
|
||||||
end,
|
|
||||||
clear = function(self)
|
|
||||||
io.write(self.erase_code)
|
|
||||||
end,
|
|
||||||
update = function(self)
|
|
||||||
self.loop_pos = self.loop_pos + 1
|
|
||||||
if self.loop_pos > #self.loop then self.loop_pos = 1 end
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
-- list tests
|
|
||||||
local tests = {}
|
|
||||||
for test in lfs.dir("test/tests/") do
|
|
||||||
if test:match("%.ans$") then
|
|
||||||
table.insert(tests, "test/tests/"..test)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- run!
|
-- run!
|
||||||
if not arg[1] or arg[1] == "update" then
|
if not arg[1] or arg[1] == "update" then
|
||||||
|
-- display an animated loading indicator
|
||||||
|
local loading = {
|
||||||
|
loop = { "⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷" },
|
||||||
|
loop_pos = 1,
|
||||||
|
erase_code = "",
|
||||||
|
|
||||||
|
write = function(self, message)
|
||||||
|
self:clear()
|
||||||
|
local str = self.loop[self.loop_pos].." "..message
|
||||||
|
self.erase_code = ("\b \b"):rep(#str)
|
||||||
|
io.write(str)
|
||||||
|
end,
|
||||||
|
clear = function(self)
|
||||||
|
io.write(self.erase_code)
|
||||||
|
end,
|
||||||
|
update = function(self)
|
||||||
|
self.loop_pos = self.loop_pos + 1
|
||||||
|
if self.loop_pos > #self.loop then self.loop_pos = 1 end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
-- list tests
|
||||||
|
local tests = {}
|
||||||
|
for test in lfs.dir("test/tests/") do
|
||||||
|
if test:match("%.ans$") then
|
||||||
|
table.insert(tests, "test/tests/"..test)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local total, failure, errored, notfound = #tests, 0, 0, 0
|
local total, failure, errored, notfound = #tests, 0, 0, 0
|
||||||
|
|
||||||
|
-- run tests
|
||||||
for i, test in ipairs(tests) do
|
for i, test in ipairs(tests) do
|
||||||
-- status
|
-- status
|
||||||
loading:write(("%s/%s tests ran; running %s"):format(i, #tests, test))
|
loading:write(("%s/%s tests ran; running %s"):format(i, #tests, test))
|
||||||
|
|
@ -147,7 +165,7 @@ if not arg[1] or arg[1] == "update" then
|
||||||
local f = io.open(test:gsub("^test/tests/", "test/results/"), "r")
|
local f = io.open(test:gsub("^test/tests/", "test/results/"), "r")
|
||||||
local expected
|
local expected
|
||||||
if f then
|
if f then
|
||||||
expected = f:read("*a")
|
expected = f:read("a")
|
||||||
f:close()
|
f:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -161,7 +179,7 @@ if not arg[1] or arg[1] == "update" then
|
||||||
end
|
end
|
||||||
if arg[1] == "update" then
|
if arg[1] == "update" then
|
||||||
local c = assert(io.open(test, "r"))
|
local c = assert(io.open(test, "r"))
|
||||||
local code = c:read("*a")
|
local code = c:read("a")
|
||||||
c:close()
|
c:close()
|
||||||
print(" Code:")
|
print(" Code:")
|
||||||
print(" "..code:gsub("\n", "\n "))
|
print(" "..code:gsub("\n", "\n "))
|
||||||
|
|
@ -180,7 +198,7 @@ if not arg[1] or arg[1] == "update" then
|
||||||
else
|
else
|
||||||
io.write("Write this result? (y/N/e) ")
|
io.write("Write this result? (y/N/e) ")
|
||||||
end
|
end
|
||||||
r = io.read("*l"):lower()
|
r = io.read("l"):lower()
|
||||||
until r == "y" or r == "n" or r == "e" or r == ""
|
until r == "y" or r == "n" or r == "e" or r == ""
|
||||||
if r == "y" then
|
if r == "y" then
|
||||||
local o = assert(io.open(test:gsub("^test/tests/", "test/results/"), "w"))
|
local o = assert(io.open(test:gsub("^test/tests/", "test/results/"), "w"))
|
||||||
|
|
@ -207,9 +225,12 @@ if not arg[1] or arg[1] == "update" then
|
||||||
local successes = total-failure-notfound-errored
|
local successes = total-failure-notfound-errored
|
||||||
print(("%s successes, %s failures, %s errors, %s missing result files, out of %s tests"):format(successes, failure, errored, notfound, total))
|
print(("%s successes, %s failures, %s errors, %s missing result files, out of %s tests"):format(successes, failure, errored, notfound, total))
|
||||||
if successes < total then os.exit(1) end
|
if successes < total then os.exit(1) end
|
||||||
|
elseif arg[1] == "interactive" and arg[2] then
|
||||||
|
run(tostring(arg[2]), true)
|
||||||
else
|
else
|
||||||
print("usage:")
|
print("usage:")
|
||||||
print("lua test/run.lua: run all the tests")
|
print("lua test/run.lua: run all the tests")
|
||||||
print("lua test/run.lua update: run all tests, optionally updating incorrect or missing results")
|
print("lua test/run.lua update: run all tests, optionally updating incorrect or missing results")
|
||||||
|
print("lua test/run.lua interactive <script>: run the file <script> in interactive mode")
|
||||||
print("lua test/run.lua help: display this message")
|
print("lua test/run.lua help: display this message")
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue