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:
2026-06-11 04:51:17 +09:00
parent 64f0ddf01b
commit b9c4562135
16 changed files with 853 additions and 165 deletions

View File

@@ -9,7 +9,9 @@
* rejected with "ww test: unknown flag" (rc 2); a lone -I/-o
* is "ww test: -X needs an argument" (rc 2); -c/-o without a
* single test file is "ww test: -c/-o need a single test file"
* (rc 2, #17).
* (rc 2, #17); a 2nd positional (fnmatch name-filter pattern)
* in directory mode is "ww test: pattern needs a single test
* file" (rc 2, #17).
* Each row asserts the expected rc + stderr substring AND that the two
* drivers are byte-identical (rule 10): the cstage parse_build_flags /
* do_test must match the wwstage main.ww dobuild/dorun/dotest verbatim.
@@ -46,6 +48,10 @@ static const struct row rows[] = {
{ "test -o", 2, "ww test: -o needs an argument" },
{ "test -o x", 2, "ww test: -c/-o need a single test file" },
{ "test -c", 2, "ww test: -c/-o need a single test file" },
/* #17: a 2nd positional is a fnmatch name-filter pattern, valid only
* for a single test file/module; in directory mode (target ".") it
* has no single binary to route to and is rejected (rc 2). */
{ "test . zzz", 2, "ww test: pattern needs a single test file" },
};
/* Run "<bin>/<drv> <args>" capturing rc + stderr text into err (NUL-