test/wcc: carrier ownership repair and driver-contract adaptation

Every surviving carrier now owns its artifacts: checked mkdir/mkdtemp/
fopen acquisition, one all-exit cleanup funnel per carrier, ENOENT-
tolerant checked unlinks, exact-path deletion (rm -rf only for an
owned pid-keyed dir or a .sepwork beneath one), and cleanup failure
fails a passing carrier without overwriting its diagnostic. In the
same pass the carriers adapt to the driver contract this branch lands:
--sep and WW_PKGCACHE are gone, -S and the /tmp/ww_run_<pid> scratch
contract are asserted, and rows whose runtime or reject coverage moved
to test/wcc/data fixtures or test/lang @test owners are trimmed to the
byte/artifact/diagnostic observations only they can make.

Repair and adaptation ride together because most files interleave both
in the same hunks; splitting would manufacture intermediate carrier
states that never existed and cannot run against either driver.
This commit is contained in:
2026-08-07 23:02:47 +09:00
parent b2899dd8d3
commit a95a7a316b
132 changed files with 7573 additions and 6172 deletions

View File

@@ -10,7 +10,7 @@
* (task #21, FC0). This gate closes the class: each lib test fixture is
* sep-built through BOTH driver stages and the per-package asm compared.
*
* #94 sep layout: the gate drives `ww --sep` (cstage) and `ww_ww --sep`
* #94 sep layout: the gate drives `ww` (cstage) and `ww_ww`
* (wwstage) instead of feeding a single .combined.ww to raw w6c/w6c_ww.
* Under sep EACH package compiles to its OWN <stem>.sepwork/<pkg>.s — the
* lib body lands in <pkg>.s, NOT in __root.s (which holds only the test
@@ -27,7 +27,7 @@
* the concatenated asm must still DIFFER: when a fix lands,
* the entry fails loudly demanding graduation to ID rather
* than silently widening or narrowing coverage.
* WWREJECT — cstage --sep compiles, wwstage --sep errors (front-end
* WWREJECT — cstage compiles, wwstage errors (front-end
* gap, task #59). Graduation is pinned the same way.
*
* Modules with no test fixture and no embedding (sort/path/endian/net/
@@ -39,9 +39,8 @@
* fails loudly on any lib/ dir not enrolled here, so new modules can't
* ship uncovered.
*
* Compile+cmp only (--sep -o redirects every artifact to a getpid-keyed
* /tmp dir; WW_PKGCACHE pinned there so out/.pkgcache is untouched), so
* this stays phase-1 parallel-safe next to the 9xx _run tests.
* Compile+cmp only; -o redirects every artifact to a getpid-keyed
* /tmp directory for isolation.
*
* 9xx is full; shares the 989 prefix per the 989_sha256 precedent (the
* `short` name keys the binary).
@@ -53,7 +52,7 @@
#include <sys/wait.h>
#include <sys/stat.h>
enum { M_ID, M_DIVERGE, M_WWREJECT, NENT_EXPECT = 42 };
enum { M_ID, M_DIVERGE, M_WWREJECT, NENT_EXPECT = 43 };
struct ent {
const char *fixture; /* repo-relative .ww; NULL → probe entry */
@@ -94,6 +93,8 @@ static const struct ent ents[] = {
{ .fixture = "lib/math/random/random_test.ww", .mode = M_ID },
{ .fixture = "lib/memio/memiotest.ww", .mode = M_ID },
{ .fixture = "lib/os/ostest.ww", .mode = M_ID },
{ .probe = "package main;\nimport os.exec;\nfn main() i32 = { return 0; };\n",
.mode = M_ID, .sentinel = "package exec;", .moddir = "lib/os/exec" },
{ .fixture = "lib/regex/regex_test.ww", .mode = M_ID },
{ .fixture = "lib/strconv/test/ftostest.ww", .mode = M_ID },
/* graduated from #59.10 DIVERGE by the #62 float-literal fold fix
@@ -227,9 +228,10 @@ check_one(const char *bin, const char *cwd, const struct ent *e, int idx)
int rc = -1;
snprintf(td, sizeof td, "/tmp/wwlbi_%d_%d", getpid(), idx);
snprintf(cmd, sizeof cmd, "rm -rf %s", td);
runwait(cmd);
mkdir(td, 0755);
if (mkdir(td, 0755) != 0) {
perror(td);
return -1;
}
char base[256];
if (e->fixture) {
@@ -271,34 +273,34 @@ check_one(const char *bin, const char *cwd, const struct ent *e, int idx)
char *sd = strrchr(stem, '.');
if (sd) *sd = '\0';
/* Two sep driver builds. @test fixtures are main-less, so `test -c
* --sep` carries -T (synthesizes the entry + keeps @test fns + auto-
/* Two compiler-only sep driver builds. @test fixtures are main-less,
* so `test -S ` carries -T (synthesizes the entry + keeps @test fns + auto-
* bundles lib/test's run() callee) and emits per-package asm without
* a harness run; import-probes carry their own `fn main()`, which -T
* loud-rejects (910), so they `build --sep` (non-T). Each stage's
* loud-rejects (910), so they `build -S ` (non-T). Each stage's
* artifacts land under its own -o stem so out/ and the source tree
* stay clean; WW_PKGCACHE is pinned to td. */
const char *sub = e->fixture ? "test -c --sep" : "build --sep";
* stay clean. */
const char *sub = e->fixture ? "test -S " : "build -S ";
char stemc[600], stemw[600];
snprintf(stemc, sizeof stemc, "%s/c_%s", td, stem);
snprintf(stemw, sizeof stemw, "%s/w_%s", td, stem);
snprintf(cmd, sizeof cmd,
"cd %s && WW_PKGCACHE=%s/pc timeout 180 %s/ww %s %s -o %s %s "
">/dev/null 2>&1", td, td, bin, sub, incs, stemc, base);
"cd %s && timeout 180 %s/ww %s %s -o %s %s "
">/dev/null 2>&1", td, bin, sub, incs, stemc, base);
int ce = runwait(cmd);
snprintf(cmd, sizeof cmd,
"cd %s && WW_PKGCACHE=%s/pw timeout 180 %s/ww_ww %s %s -o %s %s "
">/dev/null 2>&1", td, td, bin, sub, incs, stemw, base);
"cd %s && timeout 180 %s/ww_ww %s %s -o %s %s "
">/dev/null 2>&1", td, bin, sub, incs, stemw, base);
int we = runwait(cmd);
/* the cstage --sep build resolves the units (root + each package);
/* the cstage build resolves the units (root + each package);
* its __root.unit.ww proves resolution ran. WWREJECT still requires
* cstage to compile, so this holds for every mode. */
char rootu[760];
snprintf(rootu, sizeof rootu, "%s.sepwork/__root.unit.ww", stemc);
if (ce != 0 || access(rootu, 0) != 0) {
fprintf(stderr, "lib_byteid FAIL: %s — cstage --sep produced "
fprintf(stderr, "lib_byteid FAIL: %s — cstage produced "
"no resolved unit\n", label);
goto out;
}
@@ -322,7 +324,7 @@ check_one(const char *bin, const char *cwd, const struct ent *e, int idx)
if (e->mode == M_WWREJECT) {
if (we == 0) {
fprintf(stderr, "lib_byteid FAIL: %s — wwstage --sep now "
fprintf(stderr, "lib_byteid FAIL: %s — wwstage now "
"compiles this; graduate the %s pin to ID or "
"DIVERGE\n", label, e->cite);
goto out;
@@ -331,7 +333,7 @@ check_one(const char *bin, const char *cwd, const struct ent *e, int idx)
goto out;
}
if (we != 0) {
fprintf(stderr, "lib_byteid FAIL: %s — wwstage --sep rejected\n",
fprintf(stderr, "lib_byteid FAIL: %s — wwstage rejected\n",
label);
goto out;
}
@@ -345,10 +347,18 @@ check_one(const char *bin, const char *cwd, const struct ent *e, int idx)
snprintf(ws, sizeof ws, "%s/all_w.s", td);
snprintf(cmd, sizeof cmd, "cat %s.sepwork/*.s > %s 2>/dev/null",
stemc, cs);
if (system(cmd)) {}
if (runwait(cmd) != 0) {
fprintf(stderr, "lib_byteid FAIL: %s — cstage .s concat "
"failed (no per-package .s)\n", label);
goto out;
}
snprintf(cmd, sizeof cmd, "cat %s.sepwork/*.s > %s 2>/dev/null",
stemw, ws);
if (system(cmd)) {}
if (runwait(cmd) != 0) {
fprintf(stderr, "lib_byteid FAIL: %s — wwstage .s concat "
"failed (no per-package .s)\n", label);
goto out;
}
char *bc = NULL, *bw = NULL;
size_t nc = 0, nw = 0;
@@ -359,6 +369,12 @@ check_one(const char *bin, const char *cwd, const struct ent *e, int idx)
}
int same = (nc == nw && memcmp(bc, bw, nc) == 0);
free(bc); free(bw);
/* two empty concats compare equal — that green covers nothing */
if (nc == 0 || nw == 0) {
fprintf(stderr, "lib_byteid FAIL: %s — empty .s concat "
"(cs %zu, ww %zu bytes)\n", label, nc, nw);
goto out;
}
if (e->mode == M_ID && !same) {
fprintf(stderr, "lib_byteid FAIL: %s — cs %zu vs ww %zu bytes "
@@ -373,7 +389,10 @@ check_one(const char *bin, const char *cwd, const struct ent *e, int idx)
rc = 0;
out:
snprintf(cmd, sizeof cmd, "rm -rf %s", td);
runwait(cmd);
if (runwait(cmd) != 0) {
fprintf(stderr, "lib_byteid: cleanup rm -rf %s failed\n", td);
if (rc == 0) rc = -1;
}
return rc;
}