selfhost: mirror @test runner via ww_ww (997_at_test_ww)
@test parsing already works under ww_ww (parseattrs lives in the shared lib/ww/parse/decl.ww, picked up by both Cstage and wwstage), so this is the test-side parity: 997 is 910 with `ww run` swapped for `ww_ww run`, exercising the selfhost driver+compiler+assembler+ linker end-to-end on the same attest_pass.ww fixture. Suite is now 22 tests.
This commit is contained in:
6
Makefile
6
Makefile
@@ -215,7 +215,7 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \
|
||||
$(BIN)/test_at_test \
|
||||
$(BIN)/test_selfhost $(BIN)/test_w6a_ww $(BIN)/test_w6l_ww \
|
||||
$(BIN)/test_w6c_ww $(BIN)/test_ww_ww $(BIN)/test_self_rebuild \
|
||||
$(BIN)/test_dyn_ww $(BIN)/test_selfcheck
|
||||
$(BIN)/test_dyn_ww $(BIN)/test_selfcheck $(BIN)/test_at_test_ww
|
||||
|
||||
$(BIN)/test_smoke: test/wcc/000_smoke.c $(LIB)/libwcc.a | $(BIN)
|
||||
$(CC) $(CFLAGS) $(INCS) -o $@ $< -L$(LIB) -lwcc
|
||||
@@ -290,6 +290,10 @@ $(BIN)/test_dyn_ww: test/wcc/996_dyn_ww.c $(BIN)/ww $(BIN)/w6l $(BIN)/w6l_ww \
|
||||
$(LIB)/libwwrt.a | $(BIN)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
$(BIN)/test_at_test_ww: test/wcc/997_at_test_ww.c $(BIN)/ww_ww $(BIN)/w6c_ww \
|
||||
$(BIN)/w6a_ww $(BIN)/w6l_ww $(LIB)/libwwrt.a | $(BIN)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
test: all $(TESTS)
|
||||
@WW=$(BIN)/ww BIN=$(BIN) sh test/run
|
||||
|
||||
|
||||
170
test/wcc/997_at_test_ww.c
Normal file
170
test/wcc/997_at_test_ww.c
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* 997_at_test_ww — same as 910_at_test, driven through `ww_ww`
|
||||
* (the selfhost driver) instead of `ww` (the C driver). Confirms
|
||||
* the ww-built toolchain parses, compiles, and runs an @test
|
||||
* fixture end-to-end.
|
||||
*
|
||||
* Scanning is regex-free, matching the literal sequence
|
||||
* `\n@test\s+fn\s+(IDENT)`. Same parser shape as ww accepts.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
static int
|
||||
runwait(const char *cmd)
|
||||
{
|
||||
int rc = system(cmd);
|
||||
if (rc == -1) return -1;
|
||||
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
isws(int c)
|
||||
{
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\r';
|
||||
}
|
||||
|
||||
static int
|
||||
isident(int c)
|
||||
{
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
||||
(c >= '0' && c <= '9') || c == '_';
|
||||
}
|
||||
|
||||
/* find_attest — scan src for `@test\s+fn\s+(ident)`; on a match,
|
||||
* write the identifier into `out` (NUL-terminated) and return the
|
||||
* scan position past the matched ident. Returns -1 when no more. */
|
||||
static long
|
||||
find_attest(const char *src, long pos, char *out, size_t outsz)
|
||||
{
|
||||
long n = (long)strlen(src);
|
||||
while (pos < n) {
|
||||
const char *q = strstr(src + pos, "@test");
|
||||
if (q == NULL) return -1;
|
||||
long off = q - src;
|
||||
/* must be a top-level marker: previous non-space char is
|
||||
* '\n' or we're at the file start. */
|
||||
long pre = off - 1;
|
||||
while (pre >= 0 && (src[pre] == ' ' || src[pre] == '\t')) pre--;
|
||||
if (pre >= 0 && src[pre] != '\n') {
|
||||
pos = off + 1;
|
||||
continue;
|
||||
}
|
||||
long c = off + 5; /* past "@test" */
|
||||
while (c < n && isws(src[c])) c++;
|
||||
if (c + 2 > n || strncmp(src + c, "fn", 2) != 0) {
|
||||
pos = off + 1;
|
||||
continue;
|
||||
}
|
||||
c += 2;
|
||||
if (c < n && isident(src[c])) {
|
||||
pos = off + 1;
|
||||
continue;
|
||||
}
|
||||
while (c < n && isws(src[c])) c++;
|
||||
long ids = c;
|
||||
while (c < n && isident(src[c])) c++;
|
||||
if (c == ids) {
|
||||
pos = off + 1;
|
||||
continue;
|
||||
}
|
||||
size_t len = (size_t)(c - ids);
|
||||
if (len + 1 > outsz) return -1;
|
||||
memcpy(out, src + ids, len);
|
||||
out[len] = '\0';
|
||||
return c;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *
|
||||
slurp(const char *path)
|
||||
{
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (!f) return NULL;
|
||||
fseek(f, 0, SEEK_END);
|
||||
long n = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
char *b = malloc((size_t)n + 1);
|
||||
if (!b) { fclose(f); return NULL; }
|
||||
if (fread(b, 1, (size_t)n, f) != (size_t)n) {
|
||||
free(b); fclose(f); return NULL;
|
||||
}
|
||||
b[n] = '\0';
|
||||
fclose(f);
|
||||
return b;
|
||||
}
|
||||
|
||||
static int
|
||||
runtests(const char *path, const char *bin)
|
||||
{
|
||||
char *src = slurp(path);
|
||||
if (!src) {
|
||||
fprintf(stderr, "997 FAIL: cannot read %s\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Build a synthetic test driver: original source + a main()
|
||||
* that calls each @test fn. Each test that runs to completion
|
||||
* (no abort/exit) counts as a pass. */
|
||||
char tmpsrc[256];
|
||||
snprintf(tmpsrc, sizeof tmpsrc, "/tmp/wwd_attest_ww_%d.ww", getpid());
|
||||
FILE *out = fopen(tmpsrc, "wb");
|
||||
if (!out) { free(src); return -1; }
|
||||
fputs(src, out);
|
||||
fputs("\nexport fn main() i32 = {\n", out);
|
||||
|
||||
long pos = 0;
|
||||
int count = 0;
|
||||
for (;;) {
|
||||
char name[128];
|
||||
long next = find_attest(src, pos, name, sizeof name);
|
||||
if (next < 0) break;
|
||||
fprintf(out, "\t%s();\n", name);
|
||||
pos = next;
|
||||
count++;
|
||||
}
|
||||
fputs("\treturn 0;\n};\n", out);
|
||||
fclose(out);
|
||||
free(src);
|
||||
|
||||
if (count == 0) {
|
||||
fprintf(stderr, "997 FAIL: no @test fns found in %s\n", path);
|
||||
unlink(tmpsrc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char cmd[2048];
|
||||
snprintf(cmd, sizeof cmd, "%s/ww_ww run %s 2>/dev/null", bin, tmpsrc);
|
||||
int rc = runwait(cmd);
|
||||
unlink(tmpsrc);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "997 FAIL: %s: %d @test fn(s), driver exited %d\n",
|
||||
path, count, rc);
|
||||
return -1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
const char *bin = getenv("BIN");
|
||||
if (!bin) bin = "out/bin";
|
||||
const char *files[] = {
|
||||
"test/wcc/data/attest_pass.ww",
|
||||
NULL,
|
||||
};
|
||||
int total = 0;
|
||||
for (int i = 0; files[i]; i++) {
|
||||
int n = runtests(files[i], bin);
|
||||
if (n < 0) return 1;
|
||||
total += n;
|
||||
}
|
||||
printf("@test (ww_ww): %d test(s) ran ok\n", total);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user