/* * The white-box half must be the -T root: dependency packages lose @test * declarations before code generation. Keep it separate from the external * regex_test binary because each -T unit owns main and __wwtests. */ #include #include #include #include #include static const char *whitebox[] = { "thread_shape", "newmatch_discriminates", "is_consuming_kinds", "delete_thread_middle", "add_thread_dedup_inherit", "add_thread_dup_independence", "run_thread_literal_program", "run_thread_anchored_route", "search_matches", "search_early_exit", "search_no_match", "find_last_groupstart_cases", "shift_direct", "run_thread_group_arms", "parse_repetition_cases", }; static int runwait(const char *cmd) { int rc; rc = system(cmd); if (rc == -1) return -1; if (WIFEXITED(rc)) return WEXITSTATUS(rc); return 1; } static int runcapture(const char *cmd, char *out, size_t outsz) { FILE *p; size_t n; int ch, overflow, status; p = popen(cmd, "r"); if (p == NULL) return -1; n = 0; overflow = 0; while ((ch = fgetc(p)) != EOF) { if (n + 1 < outsz) out[n++] = ch; else overflow = 1; } out[n] = '\0'; status = pclose(p); if (overflow || status == -1) return -1; if (WIFEXITED(status)) return WEXITSTATUS(status); return 1; } static int linecount(const char *out, const char *want) { const char *p, *end; size_t n; int count; n = strlen(want); count = 0; for (p = out; *p != '\0'; p = *end == '\0' ? end : end + 1) { end = strchr(p, '\n'); if (end == NULL) end = p + strlen(p); if ((size_t)(end - p) == n && memcmp(p, want, n) == 0) count++; } return count; } static int okcount(const char *out) { const char *p, *end; static const char suffix[] = " ... ok"; size_t n, slen; int count; slen = sizeof suffix - 1; count = 0; for (p = out; *p != '\0'; p = *end == '\0' ? end : end + 1) { end = strchr(p, '\n'); if (end == NULL) end = p + strlen(p); n = (size_t)(end - p); if (n >= slen && memcmp(end - slen, suffix, slen) == 0) count++; } return count; } static int checkresult(const char *label, const char *out, int expected, const char *const *names, size_t nnames) { char summary[64], row[256]; int bad; bad = 0; snprintf(summary, sizeof summary, "%d passed, 0 failed", expected); if (linecount(out, summary) != 1 || okcount(out) != expected || strstr(out, "FAIL") != NULL || strstr(out, "No tests run") != NULL) { fprintf(stderr, "regex_run FAIL: %s result was incomplete\n%s", label, out); bad = 1; } for (size_t i = 0; i < nnames; i++) { snprintf(row, sizeof row, "%s ... ok", names[i]); if (linecount(out, row) != 1) { fprintf(stderr, "regex_run FAIL: %s did not execute exactly once\n", names[i]); bad = 1; } } return bad ? -1 : 0; } int main(void) { const char *bin; char absbin[1024], cwd[1024], tmp[] = "/tmp/wwregex.XXXXXX"; char cmd[4096], output[32768], cleanup[1200]; int rc, failed; bin = getenv("BIN"); if (bin == NULL) bin = "out/bin"; if (bin[0] != '/') { if (getcwd(cwd, sizeof cwd) == NULL) return 1; if (snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin) >= (int)sizeof absbin) return 1; bin = absbin; } if (getcwd(cwd, sizeof cwd) == NULL) return 1; if (mkdtemp(tmp) == NULL) return 1; failed = 0; /* A unique cwd prevents an unrelated local `regex` path from winning * the module lookup; the private cache keeps the source tree untouched. */ if (snprintf(cmd, sizeof cmd, "cd '%s' && WW_PKGCACHE='%s/cache-black' timeout 180 '%s/ww' " "test -I '%s/lib' '%s/lib/regex/regex_test.ww'", tmp, tmp, bin, cwd, cwd) >= (int)sizeof cmd) { failed = 1; } else { rc = runcapture(cmd, output, sizeof output); if (rc != 0 || checkresult("black-box", output, 33, NULL, 0) != 0) { fprintf(stderr, "regex_run FAIL: black-box exited %d\n", rc); failed = 1; } else { printf("regex_run: black-box 33 discovered, 33 passed, 0 failed\n"); } } /* Resolving the package directory as the root keeps -T off imported * dependencies while making every in-package probe visible to the synth. */ if (snprintf(cmd, sizeof cmd, "cd '%s' && WW_PKGCACHE='%s/cache-white' timeout 180 '%s/ww' " "test -I '%s/lib' regex", tmp, tmp, bin, cwd) >= (int)sizeof cmd) { failed = 1; } else { rc = runcapture(cmd, output, sizeof output); if (rc != 0 || checkresult("white-box", output, 15, whitebox, sizeof whitebox / sizeof whitebox[0]) != 0) { fprintf(stderr, "regex_run FAIL: white-box exited %d\n", rc); failed = 1; } else { printf("regex_run: white-box 15 discovered, 15 passed, 0 failed\n"); } } snprintf(cleanup, sizeof cleanup, "rm -rf -- '%s'", tmp); if (runwait(cleanup) != 0) { fprintf(stderr, "regex_run FAIL: cannot clean temporary directory\n"); failed = 1; } return failed ? 1 : 0; }