test: port the ww-test sep observer to ww; retire 989_septest

septest_test.ww keeps all five rows (pass/fail run-exits, the
userman + badsig @test rejects, the collide_run user-fn-run coexist)
plus the full-sepwork .s/.wwi byte-id sweep and the -T synth
TEXT-main / CALL-test.run presence needles, both driver stages. The
pass/fail run-exit rows overlap package_test ownership but stay:
retiring them would drop audit-listed assertions from this gate. The
attest_* data fixtures remain in test/wcc/data (also consumed by the
911_attest_* carriers).
This commit is contained in:
2026-08-08 14:08:24 +09:00
parent cd408195fa
commit 92d5f1cb56
3 changed files with 157 additions and 320 deletions

155
test/sep/septest_test.ww Normal file
View File

@@ -0,0 +1,155 @@
package septest_test;
// `ww test` sep-driver gate (M4 E1, #79-B). Port of the retired native
// carrier test/wcc/989_septest_run.c; every assertion preserved.
//
// Rows (each drives `<drv> test -o` on BOTH stages):
// pass — two passing inline @tests -> run-exit 0; the byte-id
// + synth anchor.
// fail — one failing inline @test -> run-exit 1: proves the
// @tests genuinely RUN under sep (non-vacuity teeth).
// userman — explicit user `main` collides with the -T synth
// entry -> reject (exit != 0; exact code is a driver
// detail, deliberately unasserted).
// badsig — non-`fn() void` @test signature -> reject.
// collide_run — user `fn run` coexists with lib/test's bound runner
// (distinct units: main.run in __root.s, test.run in
// test.s) -> exit 0; a regressed collision re-mangles
// to duplicate test.run -> w6l dup-symbol -> non-zero.
//
// byteid rows (pass, collide_run): EVERY .s/.wwi in the cs sepwork
// byte-equals the wwstage same-named file, with seen>0 (an empty
// sepwork fails loudly); __root.s carries "TEXT main" AND
// "CALL\ttest.run(SB)" — the qualified -T synth path fired under sep.
//
// The three on-disk attest fixtures stay in test/wcc/data/ (also
// consumed by the 911_attest_* carriers).
import os;
import os.exec;
import strings;
import testenv;
import time;
fn fail(label: str, why: str) void = {
let m: str = strings.concat("septest FAIL: ", label, " -- ", why,
"\n");
os.write(2, m.ptr, m.len: u64);
assert(false);
};
fn tmo() time.duration = {
return (180i64 * (time.second: i64)): time.duration;
};
fn passsrc() str = {
return strings.concat(
"package septest;\n",
"@test fn t_arith() void = {\n",
" let a: i32 = 2;\n",
" if (a + 3 != 5) { abort(); };\n",
"};\n",
"@test fn t_again() void = {\n",
" let s: str = \"ok\";\n",
" if (len(s) != 2) { abort(); };\n",
"};\n");
};
fn failsrc() str = {
return strings.concat(
"package septest;\n",
"@test fn t_bad() void = {\n",
" if (1 + 1 == 2) { abort(); };\n",
"};\n");
};
// -1 encodes an abnormal (non-EXIT) termination, never a valid code.
fn teststage(td: str, label: str, drv: str, tag: str, fixture: str) i32 = {
let prog: str = strings.concat(td, "/", label, ".", tag, ".bin");
let av: []str = [testenv.driver(drv), "test", "-o", prog, fixture];
let co: testenv.commandout;
testenv.runcommand(td, td, strings.concat(label, "_", tag), av,
tmo(), &co);
if (co.termination != exec.termination.EXIT) { return -1; };
return co.code;
};
fn cmpsepwork(label: str, csdir: str, wwdir: str) void = {
if (!testenv.isdir(csdir)) { fail(label, "no cs sepwork"); };
let names: []str = testenv.listdir(csdir);
let seen: i32 = 0;
let i: i32 = 0;
for (i < names.len) {
if (strings.hassuffix(names[i], ".s")
|| strings.hassuffix(names[i], ".wwi")) {
seen += 1;
if (!testenv.same(
testenv.readfile(strings.concat(csdir, "/", names[i])),
testenv.readfile(strings.concat(wwdir, "/", names[i])))) {
fail(label, strings.concat("cs!=ww for ", names[i],
" (rule 10)"));
};
};
i += 1;
};
// an existing-but-empty sepwork would pass the loop vacuously
if (seen == 0) { fail(label, "no .s/.wwi in cs sepwork"); };
};
fn runrow(label: str, src: str, path: str, expect: i32, byteid: bool,
reject: bool) void = {
let td: str = testenv.fresh();
let fixture: str = "";
if (path.len != 0) {
fixture = strings.concat(testenv.repo(), "/", path);
} else {
fixture = strings.concat(td, "/", label, ".ww");
testenv.writefile(fixture, src);
};
let cs: i32 = teststage(td, label, "ww", "cs", fixture);
let ws: i32 = teststage(td, label, "ww_ww", "ww", fixture);
if (reject) {
if (cs == 0 || ws == 0) {
fail(label, "accepted (expected reject on both stages)");
};
} else {
if (cs != expect || ws != expect) {
fail(label, "run-exit differs from expected on a stage");
};
};
if (byteid) {
let csdir: str = strings.concat(td, "/", label, ".cs.bin.sepwork");
let wwdir: str = strings.concat(td, "/", label, ".ww.bin.sepwork");
cmpsepwork(label, csdir, wwdir);
let rs: str = testenv.readfile(strings.concat(csdir, "/__root.s"));
if (!testenv.has(rs, "TEXT main")) {
fail(label, "__root.s lacks `TEXT main` (synth -T main missing)");
};
if (!testenv.has(rs, "CALL\ttest.run(SB)")) {
fail(label, strings.concat("__root.s lacks `CALL test.run(SB)` ",
"(qualified synth call missing)"));
};
};
testenv.clean(td);
};
@test fn pass() void = {
runrow("pass", passsrc(), "", 0, true, false);
};
@test fn failing() void = {
runrow("fail", failsrc(), "", 1, false, false);
};
@test fn userman() void = {
runrow("userman", "", "test/wcc/data/attest_userman.ww", 0, false, true);
};
@test fn badsig() void = {
runrow("badsig", "", "test/wcc/data/attest_badsig.ww", 0, false, true);
};
@test fn colliderun() void = {
runrow("collide_run", "", "test/wcc/data/attest_userrun.ww", 0, true,
false);
};