ww test: fork-isolated record-and-continue harness (lib/test, both stages)
lib/test/run.ww: fork+wait4 runner; each @test runs in its own child, abort/SEGV/FPE decoded from wait-status, failures recorded and the run continues; exit = fail count. Tests are hermetic: module globals do not persist test-to-test (fresh fork image; sanctioned divergence from harec's shared-process __test_main, no setjmp/signal layer needed). -T synth (both stages) emits a module-global (str,*fn() void) table + return run(table) instead of straight-line calls. Driver twins bundle lib/test under test mode and gain ww test -c/-o (go test -c) so the byte-id gates diff the same artifact the real path builds. Gates 989/910/997 rewired onto it; new 911 pins record-and-continue across all three fault classes; 949 +3 rows. (#17-team commit-2)
This commit is contained in:
@@ -3724,6 +3724,19 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, objstem: *u8, inc
|
||||
c.out = cf;
|
||||
c.dirs = searchpath.ptr;
|
||||
c.visit = nil;
|
||||
// #17 auto-bundle lib/test: the -T synth's main calls lib/test's
|
||||
// run(), but @test files don't `import test;`. Pull it like an
|
||||
// implicit import through the same locate+expand path (the visit
|
||||
// set dedupes a fixture that imports it explicitly). cstage twin
|
||||
// in cmd/ww/main.c buildone.
|
||||
if (istest != 0) {
|
||||
let td: i32 = 0;
|
||||
let tp: *u8 = locateimport(searchpath.ptr, "test".ptr, "test".len: u64, &td);
|
||||
if (tp != nil) {
|
||||
if (td != 0) { expanddir(&c, tp); }
|
||||
else { expand(&c, tp); };
|
||||
};
|
||||
};
|
||||
if (entryisdir != 0) { expanddir(&c, srcd.ptr); }
|
||||
else { expand(&c, src); };
|
||||
};
|
||||
@@ -4267,20 +4280,31 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
// directory: open the dir, getdents64, build+run each *_test.ww,
|
||||
// report ok/FAIL per file, return 0 iff all pass.
|
||||
|
||||
fn runsingletest(selfdir: *u8, src: *u8, incs: *u8) i32 = {
|
||||
fn runsingletest(selfdir: *u8, src: *u8, incs: *u8, compileonly: i32, outstem: *u8) i32 = {
|
||||
let tmp: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
tmp.len = os.PATH_MAX;
|
||||
makeruntmp(tmp.ptr);
|
||||
if (buildone(selfdir, src, 0, tmp.ptr, nil, incs, nil, 1i32) != 0) {
|
||||
os.remove(pathstr(tmp.ptr));
|
||||
// -o redirects the binary + its combined (objstem, T3) to <stem>; the
|
||||
// default temp keeps the combined next to the source as before.
|
||||
let outp: *u8 = nil;
|
||||
let objstem: *u8 = nil;
|
||||
if (outstem != nil) {
|
||||
outp = outstem;
|
||||
objstem = outstem;
|
||||
} else {
|
||||
makeruntmp(tmp.ptr);
|
||||
outp = tmp.ptr;
|
||||
};
|
||||
if (buildone(selfdir, src, 0, outp, objstem, incs, nil, 1i32) != 0) {
|
||||
if (outstem == nil) { os.remove(pathstr(outp)); };
|
||||
return 1;
|
||||
};
|
||||
if (compileonly != 0) { return 0; };
|
||||
let execargv: []*u8 = alloc([], 2u64)!;
|
||||
execargv.len = 2;
|
||||
execargv[0] = tmp.ptr;
|
||||
execargv[0] = outp;
|
||||
execargv[1] = nil;
|
||||
let rc: i32 = procrun(tmp.ptr, execargv.ptr);
|
||||
os.remove(pathstr(tmp.ptr));
|
||||
let rc: i32 = procrun(outp, execargv.ptr);
|
||||
if (outstem == nil) { os.remove(pathstr(outp)); };
|
||||
return rc;
|
||||
};
|
||||
|
||||
@@ -4371,6 +4395,11 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
let incoff: u64 = 0u64;
|
||||
cstrseal(incs.ptr, 0u64);
|
||||
|
||||
// -c (compile-only) + -o <stem>: build the test binary + its lib/test-
|
||||
// inclusive combined WITHOUT running it, for the byte-id gates. cstage
|
||||
// twin: cmd/ww/main.c do_test (error wording identical).
|
||||
let compileonly: i32 = 0;
|
||||
let outstem: *u8 = nil;
|
||||
let i: i32 = start;
|
||||
for (i < argc) {
|
||||
let p: *u8 = argv[i];
|
||||
@@ -4393,10 +4422,23 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
};
|
||||
incoff = cstrinto(incs.ptr, incoff, dir);
|
||||
cstrseal(incs.ptr, incoff);
|
||||
} else { if (p[1u64] == 99u8 && p[2u64] == 0u8) { // "-c"
|
||||
compileonly = 1;
|
||||
} else { if (p[1u64] == 111u8) { // '-o'
|
||||
if (p[2u64] != 0u8) {
|
||||
outstem = p + 2u64;
|
||||
} else {
|
||||
if (i + 1 >= argc) {
|
||||
cerr("ww test: -o needs an argument\n");
|
||||
return 2;
|
||||
};
|
||||
i += 1;
|
||||
outstem = argv[i];
|
||||
};
|
||||
} else {
|
||||
cerr("ww test: unknown flag\n");
|
||||
return 2;
|
||||
};
|
||||
}; }; };
|
||||
} else {
|
||||
if (target == nil) { target = p; };
|
||||
};
|
||||
@@ -4410,10 +4452,14 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
// single-file mode: literal *.ww that exists
|
||||
if (cstrendswithlit(target, ".ww")) {
|
||||
if (os.access(pathstr(target), 0i32) == 0) {
|
||||
return runsingletest(selfdir, target, incs.ptr);
|
||||
return runsingletest(selfdir, target, incs.ptr, compileonly, outstem);
|
||||
};
|
||||
};
|
||||
|
||||
if (compileonly != 0 || outstem != nil) {
|
||||
cerr("ww test: -c/-o need a single test file\n");
|
||||
return 2;
|
||||
};
|
||||
// otherwise treat target as a directory; enumerate *_test.ww
|
||||
return rundirtests(selfdir, target);
|
||||
};
|
||||
|
||||
@@ -938,6 +938,19 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, objstem: *u8, inc
|
||||
c.out = cf;
|
||||
c.dirs = searchpath.ptr;
|
||||
c.visit = nil;
|
||||
// #17 auto-bundle lib/test: the -T synth's main calls lib/test's
|
||||
// run(), but @test files don't `import test;`. Pull it like an
|
||||
// implicit import through the same locate+expand path (the visit
|
||||
// set dedupes a fixture that imports it explicitly). cstage twin
|
||||
// in cmd/ww/main.c buildone.
|
||||
if (istest != 0) {
|
||||
let td: i32 = 0;
|
||||
let tp: *u8 = locateimport(searchpath.ptr, "test".ptr, "test".len: u64, &td);
|
||||
if (tp != nil) {
|
||||
if (td != 0) { expanddir(&c, tp); }
|
||||
else { expand(&c, tp); };
|
||||
};
|
||||
};
|
||||
if (entryisdir != 0) { expanddir(&c, srcd.ptr); }
|
||||
else { expand(&c, src); };
|
||||
};
|
||||
@@ -1481,20 +1494,31 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
// directory: open the dir, getdents64, build+run each *_test.ww,
|
||||
// report ok/FAIL per file, return 0 iff all pass.
|
||||
|
||||
fn runsingletest(selfdir: *u8, src: *u8, incs: *u8) i32 = {
|
||||
fn runsingletest(selfdir: *u8, src: *u8, incs: *u8, compileonly: i32, outstem: *u8) i32 = {
|
||||
let tmp: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
tmp.len = os.PATH_MAX;
|
||||
makeruntmp(tmp.ptr);
|
||||
if (buildone(selfdir, src, 0, tmp.ptr, nil, incs, nil, 1i32) != 0) {
|
||||
os.remove(pathstr(tmp.ptr));
|
||||
// -o redirects the binary + its combined (objstem, T3) to <stem>; the
|
||||
// default temp keeps the combined next to the source as before.
|
||||
let outp: *u8 = nil;
|
||||
let objstem: *u8 = nil;
|
||||
if (outstem != nil) {
|
||||
outp = outstem;
|
||||
objstem = outstem;
|
||||
} else {
|
||||
makeruntmp(tmp.ptr);
|
||||
outp = tmp.ptr;
|
||||
};
|
||||
if (buildone(selfdir, src, 0, outp, objstem, incs, nil, 1i32) != 0) {
|
||||
if (outstem == nil) { os.remove(pathstr(outp)); };
|
||||
return 1;
|
||||
};
|
||||
if (compileonly != 0) { return 0; };
|
||||
let execargv: []*u8 = alloc([], 2u64)!;
|
||||
execargv.len = 2;
|
||||
execargv[0] = tmp.ptr;
|
||||
execargv[0] = outp;
|
||||
execargv[1] = nil;
|
||||
let rc: i32 = procrun(tmp.ptr, execargv.ptr);
|
||||
os.remove(pathstr(tmp.ptr));
|
||||
let rc: i32 = procrun(outp, execargv.ptr);
|
||||
if (outstem == nil) { os.remove(pathstr(outp)); };
|
||||
return rc;
|
||||
};
|
||||
|
||||
@@ -1585,6 +1609,11 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
let incoff: u64 = 0u64;
|
||||
cstrseal(incs.ptr, 0u64);
|
||||
|
||||
// -c (compile-only) + -o <stem>: build the test binary + its lib/test-
|
||||
// inclusive combined WITHOUT running it, for the byte-id gates. cstage
|
||||
// twin: cmd/ww/main.c do_test (error wording identical).
|
||||
let compileonly: i32 = 0;
|
||||
let outstem: *u8 = nil;
|
||||
let i: i32 = start;
|
||||
for (i < argc) {
|
||||
let p: *u8 = argv[i];
|
||||
@@ -1607,10 +1636,23 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
};
|
||||
incoff = cstrinto(incs.ptr, incoff, dir);
|
||||
cstrseal(incs.ptr, incoff);
|
||||
} else { if (p[1u64] == 99u8 && p[2u64] == 0u8) { // "-c"
|
||||
compileonly = 1;
|
||||
} else { if (p[1u64] == 111u8) { // '-o'
|
||||
if (p[2u64] != 0u8) {
|
||||
outstem = p + 2u64;
|
||||
} else {
|
||||
if (i + 1 >= argc) {
|
||||
cerr("ww test: -o needs an argument\n");
|
||||
return 2;
|
||||
};
|
||||
i += 1;
|
||||
outstem = argv[i];
|
||||
};
|
||||
} else {
|
||||
cerr("ww test: unknown flag\n");
|
||||
return 2;
|
||||
};
|
||||
}; }; };
|
||||
} else {
|
||||
if (target == nil) { target = p; };
|
||||
};
|
||||
@@ -1624,10 +1666,14 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
// single-file mode: literal *.ww that exists
|
||||
if (cstrendswithlit(target, ".ww")) {
|
||||
if (os.access(pathstr(target), 0i32) == 0) {
|
||||
return runsingletest(selfdir, target, incs.ptr);
|
||||
return runsingletest(selfdir, target, incs.ptr, compileonly, outstem);
|
||||
};
|
||||
};
|
||||
|
||||
if (compileonly != 0 || outstem != nil) {
|
||||
cerr("ww test: -c/-o need a single test file\n");
|
||||
return 2;
|
||||
};
|
||||
// otherwise treat target as a directory; enumerate *_test.ww
|
||||
return rundirtests(selfdir, target);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user