/* * 737_direnum — driver-level sentinel for task #22 directory-as- * module enumeration. Two row families pinning the contract: * * ok — multi-file dir is concatenated by both stages; the entry * reads cross-pkg bare-leaf fns from sibling files. Build * must succeed for both C-built `ww` and ww-built `ww_ww`. * bad — multi-file dir with mismatched `package ;` decls * triggers the strict-same-package error (task #25 subset * bundled with #22 because the failure mode is dir-enum's * own; cross-stage symmetric). * * Asm-presence isn't checked separately — 968_utf8_run, 966_strings_ * run, 995_self_rebuild already exercise dir-enum end-to-end at * binary level. This file pins the cstage/wwstage symmetric error * path so a regression on either driver fails loud. */ #include #include #include #include #include #include static int runwait(const char *cmd) { int rc = system(cmd); if (rc == -1) return -1; if (WIFEXITED(rc)) return WEXITSTATUS(rc); return 1; } static int stderr_contains(const char *path, const char *needle) { FILE *f = fopen(path, "rb"); if (!f) return 0; char buf[4096]; size_t n = fread(buf, 1, sizeof buf - 1, f); fclose(f); buf[n] = '\0'; return strstr(buf, needle) != NULL; } int main(void) { const char *bin = getenv("BIN"); if (!bin) bin = "out/bin"; char absbin[1024]; if (bin[0] != '/') { char cwd[1024]; if (getcwd(cwd, sizeof cwd) == NULL) return 1; snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); bin = absbin; } char ww[1280], ww_ww[1280]; snprintf(ww, sizeof ww, "%s/ww", bin); snprintf(ww_ww, sizeof ww_ww, "%s/ww_ww", bin); int total = 0, fail = 0; char errp[64]; /* ok: cross-pkg bare-leaf via dir-enum, both stages. `ww run` routes * its scratch through /tmp/ww_run_.sepwork and removes it itself * (do_run keepscratch 0), so no per-invocation tmpdir is needed here. */ { const char *src = "test/wcc/data/direnum/entry.ww"; char cmd[2048]; snprintf(cmd, sizeof cmd, "%s run %s >/dev/null 2>&1", ww, src); total++; if (runwait(cmd) != 0) { fprintf(stderr, "737[ok-cstage]: ww run %s failed\n", src); fail++; } if (access(ww_ww, X_OK) == 0) { snprintf(cmd, sizeof cmd, "%s run %s >/dev/null 2>&1", ww_ww, src); total++; if (runwait(cmd) != 0) { fprintf(stderr, "737[ok-wwstage]: ww_ww run %s failed\n", src); fail++; } } } /* bad: mismatched package decls in same dir → import-path mismatch * error. E3-C1: the amalgamator's strict-same-package "differs from" * check is deleted; under sep w6c rejects the composed unit with * "package

does not match import path " (wwstage is terser per * #68, so match the shared "does not match import path" substring). * Both stages must surface it in stderr. */ { const char *src = "test/wcc/data/direnum/bad_entry.ww"; snprintf(errp, sizeof errp, "/tmp/direnum_%d_bad.err", getpid()); /* CLASS B: build INPUT stays the in-repo fixture, but -o points the * output stem (and thus its .sepwork scratch) at a unique /tmp * tmpdir so nothing leaks into the tracked tree — even on the * expected build failure, since scratch is mkdir'd before the reject. * rm -rf the tmpdir on every exit path. */ char td[64], rmcmd[128]; char cmd[2048]; snprintf(td, sizeof td, "/tmp/direnum_%d_bad_c", getpid()); mkdir(td, 0755); snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", td); snprintf(cmd, sizeof cmd, "%s build -o %s/out %s 2>%s >/dev/null", ww, td, src, errp); int rc = runwait(cmd); runwait(rmcmd); total++; if (rc == 0) { fprintf(stderr, "737[bad-cstage]: expected build failure, succeeded\n"); fail++; } else if (!stderr_contains(errp, "does not match import path")) { fprintf(stderr, "737[bad-cstage]: stderr missing 'does not match import path'\n"); fail++; } unlink(errp); if (access(ww_ww, X_OK) == 0) { snprintf(td, sizeof td, "/tmp/direnum_%d_bad_w", getpid()); mkdir(td, 0755); snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", td); snprintf(cmd, sizeof cmd, "%s build -o %s/out %s 2>%s >/dev/null", ww_ww, td, src, errp); rc = runwait(cmd); runwait(rmcmd); total++; if (rc == 0) { fprintf(stderr, "737[bad-wwstage]: expected build failure, succeeded\n"); fail++; } else if (!stderr_contains(errp, "does not match import path")) { fprintf(stderr, "737[bad-wwstage]: stderr missing 'does not match import path'\n"); fail++; } unlink(errp); } } /* bad-deep: same mismatch, but one file's `package` decl sits behind * a >2048-byte comment header. Pins the PREP-peek whole-file read * (#16): the old 2048-capped peek missed that decl, so the strict- * same-package check skipped the file and the mismatch went * undetected (build wrongly succeeded); the whole-file peek finds it * → "does not match import path". Both stages. (reviewer-batcha pin.) */ { const char *src = "test/wcc/data/direnum/bad_deep_entry.ww"; snprintf(errp, sizeof errp, "/tmp/direnum_%d_baddeep.err", getpid()); /* CLASS B (see bad block): -o into a unique /tmp tmpdir keeps the * .sepwork scratch out of the tracked tree on the expected * reject; rm -rf on every exit path. */ char td[64], rmcmd[128]; char cmd[2048]; snprintf(td, sizeof td, "/tmp/direnum_%d_baddeep_c", getpid()); mkdir(td, 0755); snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", td); snprintf(cmd, sizeof cmd, "%s build -o %s/out %s 2>%s >/dev/null", ww, td, src, errp); int rc = runwait(cmd); runwait(rmcmd); total++; if (rc == 0) { fprintf(stderr, "737[bad-deep-cstage]: expected build failure, succeeded\n"); fail++; } else if (!stderr_contains(errp, "does not match import path")) { fprintf(stderr, "737[bad-deep-cstage]: stderr missing 'does not match import path'\n"); fail++; } unlink(errp); if (access(ww_ww, X_OK) == 0) { snprintf(td, sizeof td, "/tmp/direnum_%d_baddeep_w", getpid()); mkdir(td, 0755); snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", td); snprintf(cmd, sizeof cmd, "%s build -o %s/out %s 2>%s >/dev/null", ww_ww, td, src, errp); rc = runwait(cmd); runwait(rmcmd); total++; if (rc == 0) { fprintf(stderr, "737[bad-deep-wwstage]: expected build failure, succeeded\n"); fail++; } else if (!stderr_contains(errp, "does not match import path")) { fprintf(stderr, "737[bad-deep-wwstage]: stderr missing 'does not match import path'\n"); fail++; } unlink(errp); } } if (fail) { fprintf(stderr, "737_direnum: %d/%d fixtures failed\n", fail, total); return 1; } printf("737_direnum: %d/%d ok\n", total, total); return 0; }