test: make T0 harness results complete
This commit is contained in:
@@ -106,7 +106,7 @@ main(void)
|
||||
if (access(wtool, X_OK) != 0) {
|
||||
fprintf(stderr, "w6a_parsenum: skip (no %s)\n", wtool);
|
||||
printf("w6a_parsenum: skipped\n");
|
||||
return 0;
|
||||
return 77;
|
||||
}
|
||||
|
||||
int nid = (int)(sizeof idrows / sizeof idrows[0]);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* the loader requires the right .gnu.version_r entry to bind
|
||||
* the default vDSO-aware impl.
|
||||
*
|
||||
* Skipped (passing trivially) on systems without /usr/lib/libc.so.6.
|
||||
* Reports the harness skip status on systems without a supported libc.so.6.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -108,7 +108,7 @@ main(void)
|
||||
&& access("/lib/x86_64-linux-gnu/libc.so.6", 0) != 0
|
||||
&& access("/lib64/libc.so.6", 0) != 0) {
|
||||
puts("dyn: no libc.so.6 on this system — skipping");
|
||||
return 0;
|
||||
return 77;
|
||||
}
|
||||
|
||||
const char *bin = getenv("BIN");
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
* small pins the headers-fit-page path stays correct and byte-identical.
|
||||
*
|
||||
* Generates the dyn-sym set from `nm -D <libc>` (default-versioned text
|
||||
* exports) so it adapts to whatever glibc is present; skips (passing) when
|
||||
* libc / nm are unavailable or too few symbols to overflow the first page.
|
||||
* exports) so it adapts to whatever glibc is present; reports the harness
|
||||
* skip status when libc / nm are unavailable or too few symbols are available
|
||||
* to overflow the first page.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -87,14 +88,14 @@ main(void)
|
||||
if (access("/usr/lib/libc.so.6", 0) == 0) { libc = "/usr/lib/libc.so.6"; libdir = "/usr/lib"; }
|
||||
else if (access("/lib/x86_64-linux-gnu/libc.so.6", 0) == 0) { libc = "/lib/x86_64-linux-gnu/libc.so.6"; libdir = "/lib/x86_64-linux-gnu"; }
|
||||
else if (access("/lib64/libc.so.6", 0) == 0) { libc = "/lib64/libc.so.6"; libdir = "/lib64"; }
|
||||
if (!libc) { puts("dynentry: no libc.so.6 — skipping"); return 0; }
|
||||
if (!libc) { puts("dynentry: no libc.so.6 — skipping"); return 77; }
|
||||
|
||||
static char syms[200][32];
|
||||
int ns = harvest_syms(libc, syms, 200);
|
||||
if (ns < 130) {
|
||||
printf("dynentry: only %d libc syms harvested (<130, can't overflow "
|
||||
"first page) — skipping\n", ns);
|
||||
return 0;
|
||||
return 77;
|
||||
}
|
||||
|
||||
const char *bin = getenv("BIN");
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
enum { M_ID, M_DIVERGE, M_WWREJECT };
|
||||
enum { M_ID, M_DIVERGE, M_WWREJECT, NENT_EXPECT = 42 };
|
||||
|
||||
struct ent {
|
||||
const char *fixture; /* repo-relative .ww; NULL → probe entry */
|
||||
@@ -95,10 +95,6 @@ static const struct ent ents[] = {
|
||||
{ .fixture = "lib/memio/memiotest.ww", .mode = M_ID },
|
||||
{ .fixture = "lib/os/ostest.ww", .mode = M_ID },
|
||||
{ .fixture = "lib/regex/regex_test.ww", .mode = M_ID },
|
||||
/* in-package white-box half (#9): the wb/ driver dir-resolves
|
||||
* `import regex` and bundles lib/regex/regex_whitebox.ww (package
|
||||
* regex), so this fixture byte-ids the moved engine probes. */
|
||||
{ .fixture = "lib/regex/wb/regex_test.ww", .mode = M_ID },
|
||||
{ .fixture = "lib/strconv/test/ftostest.ww", .mode = M_ID },
|
||||
/* graduated from #59.10 DIVERGE by the #62 float-literal fold fix
|
||||
* (wwstage lexer now folds through strconv.stof64, matching
|
||||
@@ -457,6 +453,12 @@ main(void)
|
||||
if (!bin) return 1;
|
||||
char cwd[1024];
|
||||
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
|
||||
int nent = (int)(sizeof ents / sizeof ents[0]) - 1;
|
||||
if (nent != NENT_EXPECT) {
|
||||
fprintf(stderr, "lib_byteid FAIL: corpus has %d entries, want %d\n",
|
||||
nent, NENT_EXPECT);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fail = 0, n = 0, nid = 0, ndiv = 0, nrej = 0;
|
||||
if (corpus_complete(cwd) != 0) fail++;
|
||||
|
||||
@@ -1,67 +1,201 @@
|
||||
/*
|
||||
* 989_regex_run — execute BOTH lib/regex @test halves under the C-side
|
||||
* `ww test` driver and assert exit 0:
|
||||
* 1. lib/regex/regex_test.ww — BLACK-BOX, package regex_test.
|
||||
* 2. lib/regex/wb/regex_test.ww — the WHITE-BOX driver (#9): its
|
||||
* `import regex` dir-resolves and bundles lib/regex/regex_whitebox.ww
|
||||
* (package regex), so -T collects the in-package engine probes.
|
||||
* Both are main-less @test files; -T synthesizes the entry, runs the
|
||||
* fork-per-test record-and-continue harness, and exits nonzero iff any
|
||||
* @test fails.
|
||||
*
|
||||
* Sibling to 984_base64_run / 989_sha256_run (9xx is full so this
|
||||
* shares the 989 prefix — the `short` name keys the binary, cf the
|
||||
* 949_* / 989_sha256 precedent).
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
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 = system(cmd);
|
||||
if (rc == -1) return -1;
|
||||
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
|
||||
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 = getenv("BIN");
|
||||
if (!bin) bin = "out/bin";
|
||||
char absbin[1024];
|
||||
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] != '/') {
|
||||
char cwd[1024];
|
||||
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
|
||||
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
|
||||
if (getcwd(cwd, sizeof cwd) == NULL)
|
||||
return 1;
|
||||
if (snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin)
|
||||
>= (int)sizeof absbin)
|
||||
return 1;
|
||||
bin = absbin;
|
||||
}
|
||||
char cwd[1024];
|
||||
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
|
||||
if (getcwd(cwd, sizeof cwd) == NULL)
|
||||
return 1;
|
||||
if (mkdtemp(tmp) == NULL)
|
||||
return 1;
|
||||
|
||||
const char *srcs[] = {
|
||||
"lib/regex/regex_test.ww",
|
||||
"lib/regex/wb/regex_test.ww",
|
||||
};
|
||||
for (size_t i = 0; i < sizeof srcs / sizeof srcs[0]; i++) {
|
||||
const char *src = srcs[i];
|
||||
char path[1024], cmd[2048];
|
||||
snprintf(path, sizeof path, "%s/%s", cwd, src);
|
||||
/* timeout 180 per repo convention (732/775; test/run does not
|
||||
* bound runtime): the fold-2c zero-length findall rows turn a
|
||||
* regression of the ha:946-952 rune-advancement guard into an
|
||||
* infinite loop (frees are no-ops, so OOM is the only other
|
||||
* exit) — timeout converts the hang into a loud 124. */
|
||||
snprintf(cmd, sizeof cmd, "timeout 180 %s/ww test %s", bin, path);
|
||||
int rc = runwait(cmd);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "regex_run FAIL: %s exited %d\n", src, rc);
|
||||
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");
|
||||
}
|
||||
printf("regex_run: %s ok\n", src);
|
||||
}
|
||||
return 0;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ main(void)
|
||||
if (access(wdrv, X_OK) != 0) {
|
||||
fprintf(stderr, "structlocal_frame: skip (no %s)\n", wdrv);
|
||||
printf("structlocal_frame: skipped (no wwstage)\n");
|
||||
return 0;
|
||||
return 77;
|
||||
}
|
||||
|
||||
int n = (int)(sizeof rows / sizeof rows[0]);
|
||||
|
||||
@@ -27,11 +27,13 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
enum { Nexpect = 4 };
|
||||
|
||||
struct row {
|
||||
const char *pat; /* pattern arg, or NULL for none */
|
||||
int rc; /* expected exit code */
|
||||
const char *must[4]; /* substrings required in stdout */
|
||||
const char *mustnot[4]; /* substrings forbidden in stdout */
|
||||
const char *must[Nexpect]; /* substrings required in stdout */
|
||||
const char *mustnot[Nexpect]; /* substrings forbidden in stdout */
|
||||
};
|
||||
|
||||
static const struct row rows[] = {
|
||||
@@ -46,7 +48,7 @@ static const struct row rows[] = {
|
||||
{ "alpha", "beta", NULL } },
|
||||
/* no match → "No tests run", success */
|
||||
{ "zzz", 0, { "No tests run", NULL },
|
||||
{ "alpha", "beta", "gamma", "passed", NULL } },
|
||||
{ "alpha", "beta", "gamma", "passed" } },
|
||||
/* star matches everything */
|
||||
{ "*", 0, { "alpha ... ok", "beta ... ok", "gamma ... ok",
|
||||
"3 passed, 0 failed" }, { NULL } },
|
||||
@@ -93,7 +95,12 @@ main(void)
|
||||
if (bin[0] != '/') {
|
||||
char cwd[1024];
|
||||
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
|
||||
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
|
||||
size_t ncwd = strlen(cwd);
|
||||
size_t nbin = strlen(bin);
|
||||
if (nbin >= sizeof absbin - ncwd - 1) return 1;
|
||||
memcpy(absbin, cwd, ncwd);
|
||||
absbin[ncwd] = '/';
|
||||
memcpy(absbin + ncwd + 1, bin, nbin + 1);
|
||||
bin = absbin;
|
||||
}
|
||||
|
||||
@@ -110,13 +117,13 @@ main(void)
|
||||
pat, crc, rows[i].rc);
|
||||
fail = 1;
|
||||
}
|
||||
for (int k = 0; k < 4 && rows[i].must[k]; k++)
|
||||
for (int k = 0; k < Nexpect && rows[i].must[k]; k++)
|
||||
if (!strstr(cout, rows[i].must[k])) {
|
||||
fprintf(stderr, "989 FAIL: ww pat=%s stdout missing "
|
||||
"'%s' (got '%s')\n", pat, rows[i].must[k], cout);
|
||||
fail = 1;
|
||||
}
|
||||
for (int k = 0; k < 4 && rows[i].mustnot[k]; k++)
|
||||
for (int k = 0; k < Nexpect && rows[i].mustnot[k]; k++)
|
||||
if (strstr(cout, rows[i].mustnot[k])) {
|
||||
fprintf(stderr, "989 FAIL: ww pat=%s stdout has "
|
||||
"forbidden '%s' (got '%s')\n",
|
||||
|
||||
Reference in New Issue
Block a user