ref: f6aa1954f1076821fe2cd8f34df9fceaf1f5c53a
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 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) tt = [ .name = bin, .dir = targ.dir, .inputs = [path][:], .install = false, .libdeps = std.sldup(targ.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.Fail m: std.fatal("\nunable to run test: {}\n", m) | `std.Ok (pid, infd, outfd): log = std.strcat(cmd[0], ".log") logfd = std.try(std.open(log, std.Owronly | std.Ocreat)) 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 }