/* * 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 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 src[64], errf[64], outb[64], comb[80], cmd[2048], line[4096]; snprintf(src, sizeof src, "/tmp/mp949_miss_%d.ww", pid); snprintf(errf, sizeof errf, "/tmp/mp949_miss_%d.err", pid); /* -o a writable /tmp stem (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, "/tmp/mp949_miss_%d.out", pid); snprintf(comb, sizeof comb, "/tmp/mp949_miss_%d.out.combined.ww", pid); FILE *f = fopen(src, "w"); if (!f) { fprintf(stderr, "949 FAIL: stage miss\n"); return 1; } fputs("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"); unlink(src); unlink(errf); unlink(outb); unlink(comb); 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); } unlink(src); unlink(errf); unlink(outb); unlink(comb); 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 src[64], outb[64], cmd[2048]; snprintf(src, sizeof src, "/tmp/mp949_inl_%d.ww", pid); snprintf(outb, sizeof outb, "/tmp/mp949_inl_%d", pid); FILE *f = fopen(src, "w"); if (!f) { fprintf(stderr, "949 FAIL: stage inline\n"); 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); /* `ww build` emits the binary by basename in the cwd, so build from * /tmp to keep both source and output out of the tree. */ snprintf(cmd, sizeof cmd, "cd /tmp && %s/ww build mp949_inl_%d.ww >/dev/null 2>&1", bin, pid); int rc = runwait(cmd); if (rc != 0) { fprintf(stderr, "949 FAIL: inline-package build failed " "(inline-skip branch regressed)\n"); unlink(src); return 1; } int got = runwait(outb); unlink(src); unlink(outb); 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; }