ref: b24a5a737f897466dbf6ff9b3684e9e4d657e658
dir: /mbld/test.myr/
use std
use "build"
use "clean"
use "deps"
use "opts"
use "parse"
use "types"
use "util"
use "syssel"
use "subtest"
use "config"
pkg bld =
const test : (b : build# -> bool)
;;
const test = {b
var tests : (byte[:][:], byte[:])[:]
var failed, p, ok
var bincmd
/* build with the test tag */
addsysattrs(b, ["test"][:])
/* no implicit tests to run */
tests = [][:]
buildall(b)
setdir(b, "")
for tn in b.all
match gettarg(b.targs, tn)
| `Bin bt: std.sljoin(&tests, buildtests(b, bt))
| `Lib lt: std.sljoin(&tests, buildtests(b, lt))
| _: /* nothing */
;;
;;
for tn in b.all
match gettarg(b.targs, tn)
| `Bin t:
if !t.istest
continue
;;
if t.incpath.len == 0 || !std.sleq(t.incpath[0], ".")
std.slput(&t.incpath, 0, std.sldup("."))
;;
buildbin(b, t, false)
bincmd = std.sldup([std.strcat("./", t.name)][:])
std.slpush(&tests, (bincmd, std.sldup(t.dir)))
| `Cmd t:
if !t.istest
continue
;;
std.slpush(&tests, (dupcmd(t.cmd), std.sldup(t.dir)))
| _:
/* skip */
;;
;;
ok = true
failed = [][:]
for (c, dir) in tests
setdir(b, dir)
if !runtest(b, c)
ok = false
p = std.pathcat(b.curdir, c[0])
std.slpush(&failed, p)
;;
;;
for (bin, dir) in tests
freecmd(bin)
std.slfree(dir)
;;
std.slfree(tests)
if tests.len == 0
-> true
;;
printfailed(failed)
for f in failed
std.slfree(f)
;;
std.slfree(failed)
if ok
std.put("TESTS PASSED\n")
else
std.put("TESTS FAILED\n")
;;
-> ok
}
const printfailed : (f : byte[:][:] -> void) = {failed
if failed.len > 10
std.put("\t{} tests failed\n", failed.len)
elif failed.len > 0
std.put("FAILURES:\n")
for t in failed
std.put("\t{}\n", t)
;;
;;
}
const dupcmd = {cmd
var ret
ret = [][:]
for c in cmd
std.slpush(&ret, std.sldup(c))
;;
-> ret
}
const freecmd = {cmd
for c in cmd
std.slfree(c)
;;
std.slfree(cmd)
}
const buildtests = {b, targ
var tt, bin, tests, incpath, libdeps
var cmd
tests = [][:]
setdir(b, targ.dir)
for s in targ.inputs
match testpath(s)
| `std.None: /* nothing to do */
| `std.Some path:
bin = srcswapsuffix(path, "")
incpath = std.sldup(targ.incpath)
libdeps = std.sldup(targ.libdeps)
std.sljoin(&libdeps, targ.tstdeps)
tt = [
.name = bin,
.dir = targ.dir,
.inputs = [path][:],
.install = false,
.libdeps = libdeps,
.incpath = std.slput(&incpath, 0, "."),
]
buildbin(b, &tt, true)
cmd = std.sldup([std.strcat("./", bin)][:])
std.slpush(&tests, (cmd, std.sldup(targ.dir)))
std.slfree(tt.libdeps)
std.slfree(tt.incpath)
std.slfree(path)
;;
;;
-> tests
}
const runtest = {b, cmd
var res, log, logfd, p
var sub
std.put("run")
for c in cmd
p = std.pathcat(b.curdir, c)
std.put(" {}", p)
std.slfree(p)
;;
std.put(":\t")
match std.spork(cmd)
| `std.Err m:
std.fatal("\nunable to run test: {}\n", m)
| `std.Ok (pid, infd, outfd):
log = std.strcat(cmd[0], ".log")
logfd = std.try(std.openmode(log, std.Owronly | std.Ocreat, 0o644))
sub = showsub(outfd, logfd)
std.slfree(log)
std.close(infd)
std.close(outfd)
res = false
match std.wait(pid)
| `std.Wfailure: std.put("FAIL\n")
| `std.Wsignalled: std.put("CRASH\n")
| `std.Wsuccess:
res = true
/* if we have subtests, we've already printed the output */
match sub
| `std.Some r: res = r
| `std.None: std.put("PASS\n")
;;
| `std.Waiterror: std.put("failed waiting for pid {}\n", pid)
;;
;;
-> res
}
const testpath = {s
var path, file
path = std.pathcat("./test", s)
if std.fexists(path)
-> `std.Some path
;;
match std.strfind(s, "+")
| `std.None:
| `std.Some idx:
file = std.strcat(s[:idx], ".myr")
path = std.pathcat("./test", file)
std.slfree(file)
if std.fexists(path)
-> `std.Some path
;;
;;
-> `std.None
}