ww test: @test name-filter via fnmatch (both stages)
`ww test <file> <pattern>` runs only the @test fns whose names match the fnmatch glob; no pattern runs all (byte-for-byte the pre-filter path); zero matches prints "No tests run" and exits 0 (Hare ground truth ref/hare/test/+test.ha:114-117). A pattern in directory mode is rejected "ww test: pattern needs a single test file" (rc 2), identical wording in both twins (cmd/ww/main.c do_test + selfhost/cmd/ww/main.ww dotest). Mechanism (a): rt/start.s stashes argc/argv into rt_argc/rt_argv getters (rt_envp twin shape, -T synth untouched so 990-997 byte-id holds); lib/os.args() rebuilds the []str view, build-once-cached; lib/test/run.ww imports fnmatch and filters av[1..] (argv[0] is the binary path). The driver forwards the 2nd positional as argv[1] via fork/execv (cstage) / procrun (wwstage) so glob metachars aren't shell-expanded. os.args() is the first `alloc`-caller in the base os module, so os.ww now imports rt — the `alloc` builtin's malloc lowers to rt_malloc only when the rt binding is bundled (mirror lib/strings/strings.ww:30); without it a plain `ww build` of any os-importing program links bare libc `malloc` (undefined). os is bundled by ~every program, so this is load-bearing. The lib/test floor rises os-only -> os+fnmatch+ascii+strings in every -T build; the bundled `ascii` module vs a `@test fn ascii` collision that exposed is closed by the preceding #30 promote commit. 989_test_filter pins the full matrix on both twins byte-identically; 949 gains the dir-mode reject row. (#17)
This commit is contained in:
@@ -54,6 +54,32 @@ run(const char *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* run_test_bin — exec the built test binary with an optional name-filter
|
||||
* pattern as argv[1] (lib/test run() reads it via os.args). fork+execv
|
||||
* (not system()) so glob metacharacters in the pattern reach the binary
|
||||
* verbatim instead of being expanded by the shell. Mirrors the wwstage
|
||||
* twin (selfhost/cmd/ww/main.ww runsingletest, which always builds an
|
||||
* execargv for procrun). #17 fnmatch filter. */
|
||||
static int
|
||||
run_test_bin(const char *bin, const char *pattern)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) { perror("ww: fork"); return -1; }
|
||||
if (pid == 0) {
|
||||
char *xargv[3];
|
||||
xargv[0] = (char *)bin;
|
||||
if (pattern) { xargv[1] = (char *)pattern; xargv[2] = NULL; }
|
||||
else { xargv[1] = NULL; }
|
||||
execv(bin, xargv);
|
||||
perror("ww: exec");
|
||||
_exit(127);
|
||||
}
|
||||
int status = 0;
|
||||
waitpid(pid, &status, 0);
|
||||
if (WIFEXITED(status)) return WEXITSTATUS(status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set of imported module paths, kept on the heap. Used to break
|
||||
* cycles in `use` resolution. Linear because typical imports are
|
||||
* a handful per build. */
|
||||
@@ -815,6 +841,10 @@ do_test(int argc, char **argv)
|
||||
* wwstage twin (selfhost/cmd/ww/main.ww dotest). */
|
||||
int compileonly = 0;
|
||||
char outstem[1024] = {0};
|
||||
/* #17: an optional second positional after the target is a fnmatch
|
||||
* name-filter pattern, forwarded to the test binary as argv[1]. Only
|
||||
* meaningful for a single test file/module — rejected in dir mode. */
|
||||
const char *pattern = NULL;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (argv[i][0] == '-') {
|
||||
if (argv[i][1] == 'I') {
|
||||
@@ -849,6 +879,8 @@ do_test(int argc, char **argv)
|
||||
}
|
||||
} else if (src == NULL) {
|
||||
src = argv[i];
|
||||
} else if (pattern == NULL) {
|
||||
pattern = argv[i];
|
||||
}
|
||||
}
|
||||
const char *target = src ? src : ".";
|
||||
@@ -870,7 +902,7 @@ do_test(int argc, char **argv)
|
||||
if (build_one(resolved, is_dir, outp, outstem[0] ? outstem : NULL,
|
||||
incs, "", "", 1) != 0) return 1;
|
||||
if (compileonly) return 0;
|
||||
int rc = run(outp);
|
||||
int rc = run_test_bin(outp, pattern);
|
||||
if (!outstem[0]) unlink(outp);
|
||||
return rc;
|
||||
}
|
||||
@@ -883,7 +915,7 @@ do_test(int argc, char **argv)
|
||||
if (build_one(target, 0, outp, outstem[0] ? outstem : NULL,
|
||||
incs, "", "", 1) != 0) return 1;
|
||||
if (compileonly) return 0;
|
||||
int rc = run(outp);
|
||||
int rc = run_test_bin(outp, pattern);
|
||||
if (!outstem[0]) unlink(outp);
|
||||
return rc;
|
||||
}
|
||||
@@ -895,6 +927,12 @@ do_test(int argc, char **argv)
|
||||
fprintf(stderr, "ww test: -c/-o need a single test file\n");
|
||||
return 2;
|
||||
}
|
||||
/* #17: a name-filter pattern is per-binary; directory mode builds one
|
||||
* binary per *_test.ww, so a single pattern can't sensibly route. */
|
||||
if (pattern) {
|
||||
fprintf(stderr, "ww test: pattern needs a single test file\n");
|
||||
return 2;
|
||||
}
|
||||
/* directory — run every *_test.ww inside. */
|
||||
char **files = NULL;
|
||||
int n = 0;
|
||||
|
||||
Reference in New Issue
Block a user