ref: d1c72c34e6fd566250e4e8c750d89c3631bf9668
parent: aff5b4b72e11a8d31e45a0a99d6a02bf1b2f2ed1
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Feb 14 07:36:37 EST 2015
Add initial support for implicit tests.
--- a/Makefile
+++ b/Makefile
@@ -12,6 +12,7 @@
parse.myr \
subdir.myr \
util.myr \
+ test.myr \
types.myr
include config.mk
--- a/bldfile
+++ b/bldfile
@@ -11,6 +11,7 @@
opts.myr
parse.myr
subdir.myr
+ test.myr
types.myr
util.myr
;;
--- a/build.myr
+++ b/build.myr
@@ -11,9 +11,8 @@
pkg bld =
const buildall : (p : parser# -> bool)
const genall : (p : parser# -> bool)
- const test : (p : parser# -> bool)
const build : (p : parser#, target : byte[:] -> bool)
- const buildbin : (p : parser#, bt : myrtarg# -> void)
+ const buildbin : (p : parser#, bt : myrtarg#, addsrc : bool -> void)
const buildlib : (p : parser#, lt : myrtarg# -> void)
;;
@@ -21,7 +20,7 @@
for t in p.targs
match t
| `Bin bt:
- buildbin(p, bt)
+ buildbin(p, bt, false)
| `Lib lt:
buildlib(p, lt)
| `Gen gt:
@@ -46,11 +45,6 @@
-> true
}
-const test = {p
- std.fatal(1, "testing not yet supported\n")
- -> false
-}
-
const build = {p, targ
var found
@@ -59,7 +53,7 @@
match t
| `Bin bt:
if std.sleq(bt.name, targ)
- buildbin(p, bt)
+ buildbin(p, bt, false)
;;
| `Lib lt:
if std.sleq(lt.name, targ)
@@ -86,8 +80,8 @@
-> found
}
-const buildbin = {p, targ
- var dg
+const buildbin = {p, targ, addsrc
+ var dg, src
if targ.built
->
@@ -101,7 +95,7 @@
;;
;;
std.put("%s...\n", targ.name)
- if !myrdeps(p, targ, false, false, &dg)
+ if !myrdeps(p, targ, false, false, addsrc, &dg)
std.fatal(1, "Could not load dependencies for %s\n", targ.name)
;;
if !std.hthas(dg.deps, targ.name)
@@ -108,7 +102,9 @@
std.fatal(1, "no input files for %s\n", targ.name)
;;
if builddep(p, &dg, targ.name, targ.incpath) || !freshlibs(targ, dg.libs)
- linkbin(&dg, targ.name, targ.inputs, targ.ldscript, targ.runtime, targ.incpath, targ.libdeps)
+ src = std.htkeys(dg.sources)
+ linkbin(&dg, targ.name, src, targ.ldscript, targ.runtime, targ.incpath, targ.libdeps)
+ std.slfree(src)
;;
targ.built = true
}
@@ -126,7 +122,7 @@
var archive
var u, l
var dg
- var lib
+ var lib, src
if targ.built
->
@@ -134,7 +130,7 @@
lib = targ.name
std.put("lib%s.a...\n", lib)
archive = std.fmt("lib%s.a", lib)
- if !myrdeps(p, targ, true, false, &dg)
+ if !myrdeps(p, targ, true, false, false, &dg)
std.fatal(1, "Could not load dependencies for %s\n", lib)
;;
if !std.hthas(dg.deps, lib)
@@ -143,8 +139,10 @@
u = builddep(p, &dg, targ.name, targ.incpath)
l = builddep(p, &dg, archive, targ.incpath)
if u || l || !freshlibs(targ, dg.libs)
- mergeuse(&dg, lib, targ.inputs, targ.incpath)
- archivelib(&dg, lib, targ.inputs, targ.incpath)
+ src = std.htkeys(dg.sources)
+ mergeuse(&dg, lib, src, targ.incpath)
+ archivelib(&dg, lib, src, targ.incpath)
+ std.slfree(src)
;;
std.slfree(archive)
targ.built = true
@@ -187,7 +185,7 @@
| `std.None:
;;
- match std.htget(dg.sources, out)
+ match std.htget(dg.input, out)
| `std.Some src:
if stale
compile(src, incs)
--- a/clean.myr
+++ b/clean.myr
@@ -58,7 +58,11 @@
var keys
var dg
- if !myrdeps(p, targ, islib, true, &dg)
+ /*
+ we want to automatically add 'clean' sources since otherwise,
+ mbld won't be able to clean code after changing a build file.
+ */
+ if !myrdeps(p, targ, islib, true, true, &dg)
std.fatal(1, "Could not load dependencies for %s\n", targ.name)
;;
mchammer_files = std.mkht(std.strhash, std.streq)
--- a/deps.myr
+++ b/deps.myr
@@ -8,7 +8,7 @@
use "util.use"
pkg bld =
- const myrdeps : (p : parser#, mt : myrtarg#, islib : bool, isclean : bool, dg : depgraph# -> bool)
+ const myrdeps : (p : parser#, mt : myrtarg#, islib : bool, isclean : bool, addsrc : bool, dg : depgraph# -> bool)
/* a bit ugly: initialized from main() */
var usepat : regex.regex#
@@ -21,7 +21,7 @@
`Lib byte[:]
;;
-const myrdeps = {p, mt, islib, isclean, dg
+const myrdeps = {p, mt, islib, isclean, addsrc, dg
var objs, uses, srcs, incs
var seentab, donetab
var out, useout
@@ -29,10 +29,12 @@
dg.deps = std.mkht(std.strhash, std.streq)
dg.libs = std.mkht(std.strhash, std.streq)
+ dg.input = std.mkht(std.strhash, std.streq)
dg.sources = std.mkht(std.strhash, std.streq)
dg.updated = std.mkht(std.strhash, std.streq)
seentab = std.mkht(std.strhash, std.streq)
donetab = std.mkht(std.strhash, std.streq)
+
/* direct dependencies of binary */
if islib
out = std.fmt("lib%s.a", mt.name)
@@ -41,18 +43,21 @@
out = std.sldup(mt.name)
useout = ""
;;
+
srcs = mt.inputs
incs = mt.incpath
objs = swapall(srcs, config.Objsuffix)
uses = swapall(srcs, ".use")
for i = 0; i < srcs.len; i++
- std.htput(dg.sources, objs[i], srcs[i])
+ std.htput(dg.input, objs[i], srcs[i])
+ std.htput(dg.sources, srcs[i], true)
pushdep(dg, srcs[i], objs[i])
if std.hassuffix(srcs[i], ".myr")
- std.htput(dg.sources, uses[i], srcs[i])
+ std.htput(dg.input, uses[i], srcs[i])
pushdep(dg, srcs[i], uses[i])
;;
;;
+
for i = 0; i < srcs.len; i++
pushdep(dg, objs[i], out)
if islib && std.hassuffix(srcs[i], ".myr")
@@ -59,8 +64,9 @@
pushdep(dg, uses[i], useout)
;;
;;
+
for i = 0; i < srcs.len; i++
- srcdeps(p, dg, seentab, donetab, srcs[i], objs[i], uses[i], incs, isclean)
+ srcdeps(p, dg, seentab, donetab, srcs[i], objs[i], uses[i], incs, isclean, addsrc)
;;
dumpgraph(dg)
std.htfree(seentab)
@@ -94,7 +100,7 @@
std.put("}\n")
}
-const srcdeps = {p, g, seen, done, path, obj, usefile, incs, isclean
+const srcdeps = {p, g, seen, done, path, obj, usefile, incs, isclean, addsrc
var deps
if std.hthas(done, path)
@@ -125,7 +131,7 @@
if usefile.len != 0
pushdep(g, l, usefile)
;;
- addusedep(p, g, seen, done, l, incs, isclean)
+ addusedep(p, g, seen, done, l, incs, isclean, addsrc)
;;
;;
std.htput(seen, path, false)
@@ -132,7 +138,7 @@
std.htput(done, path, true)
}
-const addusedep = {p, g, seen, done, usefile, incs, isclean
+const addusedep = {p, g, seen, done, usefile, incs, isclean, addsrc
var src
if std.hthas(done, usefile)
@@ -141,15 +147,20 @@
;;
->
;;
- match std.htget(g.sources, usefile)
+ match std.htget(g.input, usefile)
| `std.Some path:
src = std.sldup(path)
| `std.None:
src = swapsuffix(usefile, ".use", ".myr")
+ if addsrc
+ std.htput(g.sources, src, true)
+ elif !std.hthas(g.input, src)
+ std.fatal(1, "source file %s not listed in bldfile\n", src)
+ ;;
;;
pushdep(g, src, usefile)
- std.htput(g.sources, usefile, src)
- srcdeps(p, g, seen, done, src, "", usefile, incs, isclean)
+ std.htput(g.input, usefile, src)
+ srcdeps(p, g, seen, done, src, "", usefile, incs, isclean, addsrc)
std.htput(done, usefile, true)
}
--- a/main.myr
+++ b/main.myr
@@ -8,6 +8,7 @@
use "install.use"
use "opts.use"
use "parse.use"
+use "test.use"
use "types.use"
const main = {args : byte[:][:]
@@ -66,7 +67,7 @@
]
p = mkparser("cli")
if bintarg
- bld.buildbin(p, &mt)
+ bld.buildbin(p, &mt, true)
else
bld.buildlib(p, &mt)
;;
--- /dev/null
+++ b/test.myr
@@ -1,0 +1,118 @@
+use std
+
+use "build.use"
+use "clean.use"
+use "deps.use"
+use "opts.use"
+use "parse.use"
+use "types.use"
+use "util.use"
+use "subdir.use"
+
+use "config.use"
+
+pkg bld =
+ const test : (p : parser# -> bool)
+;;
+
+const test = {p
+ var hasdir, ok
+
+ /* no implicit tests to run */
+ ok = true
+ hasdir = std.fexists("test")
+ if hasdir
+ for it in p.targs
+ match it
+ | `Bin bt: ok = dotest(p, bt, ok)
+ | `Lib lt: ok = dotest(p, lt, ok)
+ | _: /* ignore */
+ ;;
+ ;;
+ ;;
+ -> true
+}
+
+const dotest = {p, targ, ok
+ var tt, bin ,path, tests
+
+ tests = [][:]
+ for s in targ.inputs
+ path = std.pathcat("test", s)
+ if std.fexists(path)
+ bin = srcswapsuffix(path, "")
+ tt = [
+ .name = bin,
+ .inputs = [path, s][:],
+ .install = false,
+ .libdeps = targ.libdeps,
+ .incpath = targ.incpath,
+ .built = false,
+ ]
+
+ cleantest(p, path)
+ buildbin(p, &tt, true)
+ tests = std.slpush(tests, bin)
+ ;;
+ std.slfree(path)
+ ;;
+
+ ok = true
+ for t in tests
+ if !runtest(t)
+ ok = false
+ ;;
+ std.slfree(t)
+ ;;
+ std.slfree(tests)
+ -> ok
+}
+
+const cleantest = {p, src
+ var obj, bin, log, usef
+
+ obj = srcswapsuffix(src, config.Objsuffix)
+ log = srcswapsuffix(src, ".log")
+ usef = srcswapsuffix(src, ".use")
+ bin = srcswapsuffix(src, "")
+
+ std.remove(obj)
+ std.remove(usef)
+ std.remove(log)
+ std.remove(bin)
+
+ std.slfree(obj)
+ std.slfree(usef)
+ std.slfree(log)
+ std.slfree(bin)
+}
+
+const runtest = {bin
+ var r, log
+
+ std.put("run %s:\t", bin)
+ log = std.strcat(bin, ".log")
+ match std.spork([bin][:])
+ | `std.Fail m:
+ std.fatal(1, "unable to run test: %s\n", m)
+ | `std.Ok (pid, infd, outfd):
+ match std.fslurp(outfd)
+ | `std.Ok buf:
+ std.blat(log, buf)
+ | `std.Fail m:
+ ;;
+ std.slfree(log)
+
+ r = false
+ match std.wait(pid)
+ | `std.Wfailure: std.put("FAIL\n")
+ | `std.Wsignalled: std.put("CRASH\n")
+ | `std.Wsuccess:
+ std.put("PASS\n")
+ r = true
+ | _: std.put("???\n")
+ ;;
+ ;;
+ -> r
+}
+
--- a/types.myr
+++ b/types.myr
@@ -21,7 +21,8 @@
roots : byte[:][:]
deps : std.htab(byte[:], byte[:][:])#
libs : std.htab(byte[:], byte[:][:])#
- sources : std.htab(byte[:], byte[:])#
+ input : std.htab(byte[:], byte[:])#
+ sources : std.htab(byte[:], bool)#
updated : std.htab(byte[:], bool)#
;;