/* * 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 #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) { char tmpdir[] = "/tmp/mp949_miss_XXXXXX"; char src[128], errf[128], outb[128], scratch[144], cmd[2048]; char line[4096]; if (mkdtemp(tmpdir) == NULL) { fprintf(stderr, "949 FAIL: acquire miss workspace\n"); return 1; } /* Source, capture, output, and output-derived .sepwork all live under * this invocation-owned directory. */ snprintf(src, sizeof src, "%s/miss.ww", tmpdir); snprintf(errf, sizeof errf, "%s/miss.err", tmpdir); /* -o needs a writable stem inside tmpdir (not /dev/null): the * output-derived .sepwork follows -o, so /dev/null would yield an * uncreatable /dev/null.sepwork and mask the missing-package fatal. */ snprintf(outb, sizeof outb, "%s/miss.out", tmpdir); snprintf(scratch, sizeof scratch, "%s.sepwork", outb); int result = 1; FILE *f = fopen(src, "w"); if (!f) { fprintf(stderr, "949 FAIL: stage miss\n"); goto cleanup; } 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"); goto cleanup; } 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); } if (!found) { fprintf(stderr, "949 FAIL: no 'cannot find package nosuchpkg' " "on stderr\n"); goto cleanup; } result = 0; cleanup: { int bad = 0; snprintf(cmd, sizeof cmd, "rm -rf %s", scratch); if (runwait(cmd) != 0) bad = 1; if (unlink(outb) != 0 && errno != ENOENT) bad = 1; if (unlink(errf) != 0 && errno != ENOENT) bad = 1; if (unlink(src) != 0 && errno != ENOENT) bad = 1; if (rmdir(tmpdir) != 0) bad = 1; if (bad) { fprintf(stderr, "949 FAIL: cleanup miss workspace\n"); result = 1; } } return result; } /* 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) { char tmpdir[] = "/tmp/mp949_inl_XXXXXX"; char src[128], outb[128], scratch[144], cmd[2048]; if (mkdtemp(tmpdir) == NULL) { fprintf(stderr, "949 FAIL: acquire inline workspace\n"); return 1; } /* Source, output, and output-derived .sepwork all live under this * invocation-owned directory. */ snprintf(src, sizeof src, "%s/inline.ww", tmpdir); snprintf(outb, sizeof outb, "%s/inline", tmpdir); snprintf(scratch, sizeof scratch, "%s.sepwork", outb); int result = 1; FILE *f = fopen(src, "w"); if (!f) { fprintf(stderr, "949 FAIL: stage inline\n"); goto cleanup; } 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"); goto cleanup; } int got = runwait(outb); if (got != 7) { fprintf(stderr, "949 FAIL: inline-package exit=%d want=7\n", got); goto cleanup; } result = 0; cleanup: { int bad = 0; snprintf(cmd, sizeof cmd, "rm -rf %s", scratch); if (runwait(cmd) != 0) bad = 1; if (unlink(outb) != 0 && errno != ENOENT) bad = 1; if (unlink(src) != 0 && errno != ENOENT) bad = 1; if (rmdir(tmpdir) != 0) bad = 1; if (bad) { fprintf(stderr, "949 FAIL: cleanup inline workspace\n"); result = 1; } } return result; } 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; }