shithub: mc

ref: e9b59bee4efb648e323dfb6269209b59c575806f
dir: /mbld/test.myr/

View raw version
use std

use "build"
use "opts"
use "types"
use "util"
use "subtest"

use "config"

pkg bld =
	const test	: (b : build#, targs : byte[:][:] -> bool)
	const bench	: (b : build#, targs : byte[:][:] -> bool)
;;

const test = {b, targs
	-> go(b, targs, "test", false)
}

const bench = {b, targs
	-> go(b, targs, "bench", true)
}

const go = {b, targs, kind, isbench
	var logdir, failed, ok
	var tests

	if !buildtarg(b, kind)
		std.exit(1)
	;;
	tests = std.htgetv(b.deps.targs, kind, [][:])
	ok = true
	failed = [][:]
	for t : tests
		logdir = std.fmt("{}/{}/{}", b.basedir, opt_objdir, t.wdir)
		std.mkpath(logdir)
		if !runtest(b, t, targs, logdir, isbench, &failed)
			ok = false
		;;
		std.slfree(logdir)
	;;
	std.chdir(b.basedir)

	if tests.len == 0
		-> true
	;;

	printfailed(failed)
	if ok
		mbldput("TESTS PASSED\n")
	else
		mbldput("TESTS FAILED\n")
	;;
	std.slfree(failed)
	-> ok
}

const printfailed = {failed
	if failed.len > 0
		mbldput("FAILURES: {}\n", failed.len)
		for t : failed
			mbldput("\t{}\n", t)
		;;
	;;
}

const runtest = {b, n, targs, logdir, isbench, failed
	var dir, res, log, logfd
	var sub, found

	if targs.len > 0
		found = false
		for t : targs
			found = found || matchtest(n.lbl, t)
		;;
		if !found
			-> true
		;;
	;;
	mbldput("run {}: ", n.lbl)
	dir = std.pathcat(b.basedir, n.wdir)
	std.chdir(dir)
	std.slfree(dir)

	if targs.len > 0
		match std.strfind(targs[0], ":")
		| `std.Some i:	std.setenv("MTEST_SUBSET", targs[0][i+1:])
		| `std.None:	/* ok */
		;;
	;;
	match std.spork(n.cmd)
	| `std.Err m:
		std.fatal("\nunable to run test: {}\n", m)
	| `std.Ok (pid, infd, outfd):
		if opt_verbosity >= 1
			log = ""
			logfd = std.try(std.dup(std.Out))
		else
			log = std.fmt("{}/{}.log", logdir, std.basename(n.lbl))
			logfd = std.try(std.openmode(log, std.Owrite | std.Ocreat, 0o644))
		;;
		sub = showsub(b, n.lbl, outfd, logfd, failed)
		std.slfree(log)
		std.close(infd)
		std.close(outfd)

		res = false
		match std.wait(pid)
		| `std.Waiterror:	mbldput("FUCK pid {}\n", pid)
		| `std.Wfailure:	mbldput("FAIL\n")
		| `std.Wsignalled:	mbldput("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:
				if isbench
					mbldput("MISSING TIMING\n")
					res = false
				else
					mbldput("PASS\n")
				;;
			;;
		;;
		if !res
			std.slpush(failed, std.fmt("{j= }", n.cmd))
		;;
		std.close(logfd)
	;;
	-> res
}

const matchtest = {name, pat
	match std.strfind(pat, ":")
	| `std.Some i:	-> std.strhas(name, pat[:i])
	| `std.None:	-> std.strhas(name, pat)
	;;
}