/* * 949_missingpkg — #16 ENFORCE-driver, BOTH branches (rob A inline-aware): * miss — `import nosuchpkg;` with no inline package → the cstage `ww` * driver exits nonzero + "ww: cannot find package nosuchpkg" * (was a silent `continue` masking a typo'd/missing package). * inline — a single-file multi-package unit (`package aa; … package * main; import aa; …`) names a package the bundler can't pull * as a file but the checker binds inline; the locate-miss is * inline-satisfied → ww BUILDS + runs green (exit 7). Pins the * skip branch so the fatal can't regress into over-firing on * the legitimate inline-package import-crutch pattern. * * Cstage driver in a 9xx (rule-14: only WWSTAGE-driver tests are pinned to * 950/990-997). The ww_ww twin + cstage/wwstage parity live in 993_ww_ww. * Fixtures staged in /tmp so driver intermediates never touch the tree. */ #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; } /* miss branch: `ww build` a missing import → nonzero + "cannot find * package nosuchpkg" on stderr. Returns 0 on success. */ static int run_miss(const char *bin) { int pid = getpid(); char tmpdir[64], src[128], errf[128], outb[128], cmd[2048]; char rmcmd[160], line[4096]; /* source + binary + intermediates + .sepwork all under one tmpdir so * the compiler's output-derived .sepwork scratch lands here (not bare * /tmp where unlink/rmdir would never name it) and the single rm -rf * reclaims it on every exit path. */ snprintf(tmpdir, sizeof tmpdir, "/tmp/mp949_miss_%d_d", pid); mkdir(tmpdir, 0755); snprintf(src, sizeof src, "%s/mp949_miss_%d.ww", tmpdir, pid); snprintf(errf, sizeof errf, "%s/mp949_miss_%d.err", tmpdir, pid); /* -o a writable stem inside tmpdir (not /dev/null): post-T3 the * intermediate .combined.ww/.s/.o follow -o, so /dev/null would yield * an uncreatable /dev/null.combined.ww and mask the missing-pkg fatal. */ snprintf(outb, sizeof outb, "%s/mp949_miss_%d.out", tmpdir, pid); snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir); FILE *f = fopen(src, "w"); if (!f) { fprintf(stderr, "949 FAIL: stage miss\n"); runwait(rmcmd); return 1; } fputs("package main;\n" "import nosuchpkg;\n" "export fn main() i32 = { return 0; };\n", f); fclose(f); snprintf(cmd, sizeof cmd, "%s/ww build %s -o %s 2>%s", bin, src, outb, errf); int rc = runwait(cmd); if (rc == 0) { fprintf(stderr, "949 FAIL: ww accepted a missing import\n"); runwait(rmcmd); return 1; } int found = 0; f = fopen(errf, "r"); if (f) { while (fgets(line, sizeof line, f)) if (strstr(line, "cannot find package nosuchpkg")) { found = 1; break; } fclose(f); } runwait(rmcmd); if (!found) { fprintf(stderr, "949 FAIL: no 'cannot find package nosuchpkg' " "on stderr\n"); return 1; } return 0; } /* inline branch: a single-file multi-package unit whose `import aa` is * satisfied by the inline `package aa` must BUILD (locate-miss → inline * scan → skip) and run to exit 7. Returns 0 on success. */ static int run_inline(const char *bin) { int pid = getpid(); char tmpdir[64], src[128], outb[128], cmd[2048], rmcmd[160]; /* source + binary + .sepwork all under one tmpdir so the compiler's * source-derived .sepwork scratch lands here (not bare /tmp) and the * single rm -rf reclaims it. */ snprintf(tmpdir, sizeof tmpdir, "/tmp/mp949_inl_%d_d", pid); mkdir(tmpdir, 0755); snprintf(src, sizeof src, "%s/mp949_inl_%d.ww", tmpdir, pid); snprintf(outb, sizeof outb, "%s/mp949_inl_%d", tmpdir, pid); snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir); FILE *f = fopen(src, "w"); if (!f) { fprintf(stderr, "949 FAIL: stage inline\n"); runwait(rmcmd); return 1; } fputs("package aa;\n" "export fn getv() i32 = { return 7; };\n" "package main;\n" "import aa;\n" "export fn main() i32 = { return aa.getv(); };\n", f); fclose(f); snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s >/dev/null 2>&1", bin, outb, src); int rc = runwait(cmd); if (rc != 0) { fprintf(stderr, "949 FAIL: inline-package build failed " "(inline-skip branch regressed)\n"); runwait(rmcmd); return 1; } int got = runwait(outb); runwait(rmcmd); if (got != 7) { fprintf(stderr, "949 FAIL: inline-package exit=%d want=7\n", got); return 1; } return 0; } 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; } int fail = 0; fail += run_miss(bin); fail += run_inline(bin); if (fail) return 1; printf("missing-package: miss->fatal + inline->skip(build+run) both pinned\n"); return 0; }