ww test: report no tests to run

This commit is contained in:
2026-08-21 16:15:12 +09:00
parent 2387d3e2d2
commit 17b2879c3e
6 changed files with 443 additions and 24 deletions

View File

@@ -7635,8 +7635,9 @@ name per selected descriptor and emits no harness list bytes when its filters
select zero tests. The test product still starts, package initialization still
runs, the harness returns success without accounting, and the coordinator still
emits the normal package `ok` result. Ordinary non-list execution with zero
selected tests remains distinct: it keeps `[no matches]` and its
discovered/selected/started/completed accounting.
selected tests remains distinct: it keeps its
discovered/selected/started/completed accounting and, as implemented later in
section 11.39, uses the pinned no-tests warning and package-result suffix.
#### Pinned Go evidence and fact classification
@@ -7695,7 +7696,9 @@ runtime difference:
([`go/build/build.go`, lines 538549](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L538-L549)
and [939967](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L939-L967)),
asserted by `TestMultiplePackageImport` and official `testdata/multi`
([`go/build/build_test.go`, lines 105133](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build_test.go#L105-L133)).
([`go/build/build_test.go`, lines 105133](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build_test.go#L105-L133),
[`testdata/multi/file.go`, lines 15](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/testdata/multi/file.go#L1-L5),
and [`file_appengine.go`, lines 15](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/testdata/multi/file_appengine.go#L1-L5)).
Both WW stages rejected an `alpha`/`beta` directory with zero stdout and the
same 159 stderr bytes (SHA-256
`eaaa0c91f41b5d3deac4caf4299d5c7c650a1330be9b43edd090b8bfea906076`).
@@ -7742,7 +7745,8 @@ initialization order, symbols, and publication names keep their existing roles.
The product process and package initialization still run in list mode; no
per-test child starts. Positive matching, option diagnostics and precedence,
ordinary non-list no-match output, no-test-file results, and raw-file rejection
are unchanged.
were unchanged by this list-only slice; section 11.39 subsequently changes only
the ordinary no-match warning and successful result annotation.
The shared support implementation change legitimately changes its object,
archive, and linked test-product bytes. Its exported signature and `.wwi` byte
@@ -7766,7 +7770,8 @@ initialization, cold and warm persistent work, absence of list/accounting
sentinels, positive deterministic selection, running `-o` retention, later
direct execution, stage stdout/stderr equality, retained executable byte
identity, and `.new` cleanup. The existing routing observer separately keeps
ordinary non-list `[no matches]` plus accounting pinned.
the section-11.37 baseline for ordinary non-list reporting; section 11.39
supersedes that private marker while retaining the accounting.
No persisted-byte contract changed: build workdir format remains `18`, test
workdir format remains `19`, and semantic storage format remains `3`.
@@ -7946,6 +7951,174 @@ check introduces no independently interruptible or shared state.
No valid persisted-byte contract changed. Build workdir format remains `18`,
test workdir format remains `19`, and semantic storage format remains `3`.
### 11.39 Implemented ordinary zero-match test results
An ordinary successful directory `ww test` whose valid `-run`/`-filter`
selection starts no registered test now uses Go's externally visible no-tests
protocol. The shared test runtime writes exactly
`testing: warning: no tests to run\n` through standard error, retains WW's
discovered/selected/started/completed accounting, and returns success. The
directory coordinator recognizes that exact line at capture byte zero or after
a newline and appends ` [no tests to run]` to the corresponding successful
package `ok` result. WW's former `[no matches]` sentinel is no longer emitted.
This is deliberately distinct from the completed list-mode rule: list mode
returns before the warning/accounting branch and retains an unsuffixed package
result. A source-bearing directory without test files also retains its separate
`? <package> [no test files]` result and starts no runtime product.
#### Pinned Go evidence and fact classification
The sole semantic authority is official Go 1.26.5 at commit
`c19862e5f8415b4f24b189d065ed739517c548ba`:
- `testing.(*M).Run` returns directly from list mode at lines 24072411. In
ordinary execution it gathers whether tests, examples, or fuzz targets ran,
writes exactly `testing: warning: no tests to run` to stderr when none did,
and keeps the outcome successful when no independent failure occurred
([`testing/testing.go`, lines 24322485](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/testing/testing.go#L2432-L2485)).
- `cmd/go` defines the line-delimited `noTestsToRun` marker
([`cmd/go/internal/test/test.go`, line 1385](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1385))
and, after a successful test process, recognizes it at capture byte zero or
after a newline and appends ` [no tests to run]` to the package result
([method `(*runTestActor).Act`, lines 17061732](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1706-L1732)).
- Official script/testdata `test_match_no_tests.txt` runs one registered test
through a nonmatching filter and asserts the suffixed successful package
result
([lines 111](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_match_no_tests.txt#L1-L11)).
- Official precedence script/testdata `test_match_no_tests_build_failure.txt`
asserts that a build failure under a nonmatching filter produces `FAIL` and
does not acquire a successful no-tests result
([lines 118](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_match_no_tests_build_failure.txt#L1-L18)).
Those branches, exact bytes, success conditions, delimiter checks, result
suffix, and script assertions are **behavior directly implemented or asserted
by pinned Go**. That the runtime owns whether a test ran, the coordinator owns
the package-result annotation, a build failure precedes both, and an arbitrary
mid-line substring is not the marker are **behavior derived from the pinned
implementation**.
WW retains its fnmatch-based local `-run`/`-filter` language rather than
adopting Go regular expressions. WW also has an established always-visible
harness report rather than Go's quiet/`-v` presentation switch, so this slice
does not suppress every successful product capture or replace WW accounting
with Go's `PASS` line. Within that honest local presentation boundary, the
zero-execution warning, stream owner, success classification, marker delimiter,
and package annotation apply directly.
#### Fresh four-axis audit and direct pre-fix measurements
The bounded audit examined all four permanent axes before selecting this test
runtime/coordinator difference. Commands used Cstage `out/bin/ww` and WWstage
`out/bin/ww_ww` against identical sources:
- **Go-like build:** pinned linker method
`(*ErrorReporter).errorUnresolved` gives missing `main.main` a dedicated
failure ([`cmd/link/internal/ld/errors.go`, lines 2967](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/errors.go#L29-L67)),
asserted by `TestUndefinedRelocErrors` and official `issue10978`
([`cmd/link/internal/ld/ld_test.go`, lines 1945](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/ld_test.go#L19-L45),
[`testdata/issue10978/main.go`, lines 527](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/testdata/issue10978/main.go#L5-L27)).
Both WW stages rejected a declared-main package with no entry, emitted empty
stdout and the same 50 stderr bytes (SHA-256
`9ed4d7684412c6d2e615041902072c81e9e09acb3970246d89a2c8bdddd2fcfa`),
and published nothing. This applicable build property was aligned.
- **Go-like test:** with one registered test, both stages exited 0 for
`test -run no-such-*`, emitted empty stderr, and emitted the same 120 stdout
bytes (SHA-256
`ca12f88ebf1f94d3a2ca63ed1bc1e9b5a4811a660df3af4e70c7b9624ef97c40`):
`[no matches]`, zero-selection accounting, and an unsuffixed package `ok`.
This private marker and missing result annotation were the selected gap.
Empty list selection and positive ordinary selection were already aligned
controls and stayed outside the changed branch.
- **Go-like package:** pinned `MultiplePackageError` and directory scanning
reject conflicting declarations
([`go/build/build.go`, lines 538549](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L538-L549)
and [939967](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L939-L967)),
asserted by `TestMultiplePackageImport` and official `testdata/multi`
([`go/build/build_test.go`, lines 105133](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build_test.go#L105-L133)).
Both WW stages rejected one `first`/`second` directory with empty stdout and
byte-identical 161-byte stderr (SHA-256
`a2d95681b8a97d55c26367084cd294632fa015882d1aa53b0df63f24bcf24ced`).
This applicable package property was aligned.
- **Go-like import:** pinned `unusedImports` and `errorUnusedPkg` reject every
nonblank unused import
([`cmd/compile/internal/types2/resolver.go`, lines 706740](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L740)),
asserted by official `importdecl0a.go`
([lines 926](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/importdecl0/importdecl0a.go#L9-L26)).
Both stages rejected an unused dotted `fmt` import with empty stdout and the
same semantic diagnostic;
raw stderr differed only in the deliberately stage-named private output path.
This applicable import property was aligned.
The WW statuses, streams, lengths, hashes, and diagnostics are **directly
measured WW behavior**. The linked official implementation and testdata are
**behavior directly implemented or asserted by pinned Go**. Applying the
runtime/coordinator split without changing WW's filter syntax or harness report
is **behavior derived from the pinned implementation**.
#### Ownership, final behavior, and preserved boundaries
`lib/test/run.ww` is the runtime owner. Its existing `selected == 0` branch now
writes the pinned warning through the same EINTR-safe fd writer used elsewhere,
targeting stderr, then writes the unchanged accounting to stdout and returns 0.
Its earlier list return is untouched. A directly invoked retained binary
therefore exposes the warning on stderr and accounting on stdout.
`internal/wwpackage/package.ww` is the directory result owner. It already gives
each product one combined stdout/stderr capture and emits that capture in
canonical group order. Its new predicate accepts only the exact warning at byte
zero or following `\n`; after `pkgrunok` succeeds, `pkgemitgroup` appends the
suffix to the result it already owns. Text embedded mid-line in a running test
does not match. A failed, signalled, timed-out, interrupted, or unstartable test
does not reach the successful result. A producer failure never starts the
runtime and cannot synthesize the warning or suffix.
Both selected driver stages compile the same `lib/test` code into test products
and delegate directory execution to the same WW-native coordinator, so no
C-only or self-host-only semantic fork was introduced. Direct post-fix probes
through both stages exited 0, emitted empty coordinator stderr, and emitted the
same 159 stdout bytes (SHA-256
`a67242ab79b9bd9bca1a32073c1fccbb9aa4fa9d8ad52ced667b25c54dc1be08`):
the warning, unchanged accounting, and suffixed package result.
Loading and Go-platform source selection are unchanged. Production,
internal-test, external-test, recompiled-for-test, support, and generated-main
graph nodes and actions are unchanged. Compilers, assemblers, archivers, and
linkers retain their diagnostics and scheduling. The support implementation
change legitimately changes its object/archive and linked test-product bytes,
but its exported signature and `.wwi` contract do not change; valid Cstage and
WWstage retained products remain byte-identical.
Declared package names and canonical dotted import identities remain separate.
The coordinator annotates an already-owned result; it derives no identity from
the warning, alias, declared name, path leaf, filename, physical directory,
output path, artifact name, or linker order. Physical directories remain test
cwd and result-label metadata only, never package/import/graph/action/artifact/
symbol/`.wwi`/publication/persistence identity.
Cold and warm persistent work produce identical result bytes and still run the
test product because there is no test-result cache. A successful retained run
publishes the privately tested executable through the existing guarded install.
A later producer failure preserves prior public bytes, and restored valid reuse
reproduces the same warning/suffix without rewriting an identical executable.
Publication rejection, rollback, existing-output preservation, concurrency,
interruption, process-group cancellation, capture separation, final `FAIL`, and
cleanup remain with their existing owners. No active `.new`, `.install`,
`.wwtxn.*`, adjacent `.sepwork`, process, or capture residue is introduced.
The WW-native `ordinary_no_match_uses_go_warning_and_result_suffix` observer
proves both stages; cold/warm reuse; concurrent reverse-requested packages and
ordered per-product markers; exact mid-line rejection; positive, list, and
no-test-files controls; retained publication and direct stderr ownership;
producer-failure precedence; cold/repeated failure; prior-output preservation;
restored reuse; normalized diagnostic parity; retained executable byte identity;
and transaction/output-scratch cleanup. Existing signal, timeout, interruption,
and process-group observers continue to prove those unchanged mechanisms.
This is runtime/coordinator presentation, not a persisted-byte contract. Build
workdir format remains `18`, test workdir format remains `19`, and semantic
storage format remains `3`.
## 12. Candidate architectures and hard-gate decision
Five candidates were developed as coherent systems, not as feature bins.

View File

@@ -828,12 +828,18 @@ List mode starts the same directory-owned product and therefore performs its
ordinary package initialization, but it does not start any selected test child.
The harness emits exactly one newline-terminated qualified name for each test
selected by the command's filters, in descriptor order. If the selected set is
empty, the harness emits no list payload, no `[no matches]` sentinel, and no
accounting, and returns success; the coordinator still emits the ordinary
successful package result. This does not alter non-list execution: a valid
filter selecting no tests continues to emit `[no matches]` and the
discovered/selected/started/completed accounting. A retained binary invoked
directly has no coordinator package result.
empty, the harness emits no list payload, warning, or accounting and returns
success; the coordinator still emits the ordinary successful package result
without a no-tests suffix. Ordinary non-list execution is distinct: a valid
filter selecting no tests writes exactly
`testing: warning: no tests to run\n` through the harness's standard error,
preserves the discovered/selected/started/completed accounting and successful
exit, and causes a successful directory package result to end in
` [no tests to run]`. The coordinator recognizes that exact warning only at
capture byte zero or after a newline. Directory execution combines the warning
and accounting in its product-local capture; a retained binary invoked directly
keeps the warning on standard error, its accounting on standard output, and has
no coordinator package result.
After those ordered results, an ordinary explicit `ww test` request that records
an attributable setup, build, or execution failure emits exactly one standalone

View File

@@ -222,12 +222,18 @@ run loop exactly. Measured on the 31-package `lib/...` walk:
List mode uses that same product process and initialization boundary but starts
no per-test child. The shared language harness emits only selected qualified
test names, one per line in descriptor order. A valid filter selecting no tests
therefore produces no harness list bytes, no `[no matches]` marker, and no
accounting while the process returns success; the coordinator continues with
the package's normal `ok` result. Ordinary non-list zero-selection execution
retains its `[no matches]` marker and accounting. Concurrent products keep
independent empty or nonempty captures, and persistent work never caches a test
result.
therefore produces no harness list bytes, warning, or accounting while the
process returns success; the coordinator continues with the package's normal
unsuffixed `ok` result. Ordinary non-list zero-selection execution instead
writes the exact line `testing: warning: no tests to run` through harness
stderr, retains its accounting and successful status, and gives the successful
package `ok` result the suffix ` [no tests to run]`. Marker recognition is
line-delimited, at capture byte zero or after a newline; an arbitrary substring
in user output does not annotate the result. Concurrent products keep
independent empty or nonempty captures, markers, and suffixes, and persistent
work never caches a test result. A directly invoked retained binary exposes the
warning on stderr and accounting on stdout because no coordinator combines its
descriptors or emits a package result.
Directory test binaries are always linked under the coordinator's temporary
product root. `-c` independently requests a caller-visible executable copy and

View File

@@ -1819,6 +1819,15 @@ fn pkgemitinstall(g: *pkggroup) bool = {
return true;
};
// Pinned cmd/go recognizes the testing package's exact no-tests warning only
// at capture byte zero or after a newline. The harness owns whether a test ran;
// this coordinator owns only the corresponding package-result suffix.
fn pkgnoteststorun(output: str) bool = {
let first: str = "testing: warning: no tests to run\n";
let later: str = "\ntesting: warning: no tests to run\n";
return strings.hasprefix(output, first) || strings.contains(output, later);
};
fn pkgemitgroup(g: *pkggroup, compileonly: bool,
statusfailed: *bool) bool = {
if (g.notests) {
@@ -1850,6 +1859,9 @@ fn pkgemitgroup(g: *pkggroup, compileonly: bool,
};
pkgput(os.STDOUT_FILENO, "ok ");
pkglabel(g);
if (pkgnoteststorun(runoutput)) {
pkgput(os.STDOUT_FILENO, " [no tests to run]");
};
pkgput(os.STDOUT_FILENO, "\n");
return true;
};

View File

@@ -116,8 +116,7 @@ export fn run(tests: [](str, *fn() void)) i32 = {
return 0;
};
if (selected == 0) {
if (pkgprefix.len != 0) { tstputs("[no matches]\n"); }
else { tstputs("No tests run\n"); };
tsterrputs("testing: warning: no tests to run\n");
tstputaccounting(tests.len, 0, 0, 0);
return 0;
};
@@ -626,6 +625,10 @@ fn tstputs(s: str) void = {
tstfdwriteall(os.STDOUT_FILENO, s.ptr, s.len: u64);
};
fn tsterrputs(s: str) void = {
tstfdwriteall(os.STDERR_FILENO, s.ptr, s.len: u64);
};
fn tstputuint(n: i32) void = {
let buf: [16]u8;
let i: i32 = 16;

View File

@@ -835,16 +835,21 @@ fn cwdwritedata(dir: str, label: str) void = {
runcommand(root, "nomatch", nav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(out.stdout, "[no matches]\n") == 1);
assert(out.stderr.len == 0);
assert(occurrences(out.stdout,
"testing: warning: no tests to run\n") == 1);
assert(occurrences(out.stdout,
"3 discovered, 0 selected, 0 started, 0 completed\n") == 1);
assert(occurrences(out.stdout, strings.concat("ok ", target,
" [routing] [no tests to run]\n")) == 1);
let lnav: []str = [driver("ww"), "test", "-list", "-run",
"no-such-*", "-I", sourceroot, target];
runcommand(root, "list-nomatch", lnav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(out.stdout, "[no matches]\n") == 0);
assert(!has(out.stdout, "testing: warning: no tests to run"));
assert(!has(out.stdout, " [no tests to run]"));
assert(!has(out.stdout, " discovered, "));
clean(root);
};
@@ -901,7 +906,8 @@ fn cwdwritedata(dir: str, label: str) void = {
assert(occurrences(out.stdout, "alpha-init\n") == 1);
assert(occurrences(out.stdout, "beta-init\n") == 1);
assert(occurrences(out.stdout, "ok ") == 2);
assert(!has(out.stdout, "[no matches]"));
assert(!has(out.stdout, "testing: warning: no tests to run"));
assert(!has(out.stdout, " [no tests to run]"));
assert(!has(out.stdout, " discovered, "));
assert(!has(out.stdout, "list_alpha.first"));
assert(!has(out.stdout, "list_alpha.second"));
@@ -945,7 +951,8 @@ fn cwdwritedata(dir: str, label: str) void = {
assert(out.stderr.len == 0);
assert(occurrences(out.stdout, "alpha-init\n") == 1);
assert(occurrences(out.stdout, "ok ") == 1);
assert(!has(out.stdout, "[no matches]"));
assert(!has(out.stdout, "testing: warning: no tests to run"));
assert(!has(out.stdout, " [no tests to run]"));
assert(!has(out.stdout, "list_alpha."));
assert(os.exists(retained[i]));
retainedout[i] = strings.dup(out.stdout);
@@ -973,6 +980,216 @@ fn cwdwritedata(dir: str, label: str) void = {
clean(root);
};
@test fn ordinary_no_match_uses_go_warning_and_result_suffix() void = {
let root: str = fresh();
let alpha: str = strings.concat(root, "/alpha");
let beta: str = strings.concat(root, "/beta");
let none: str = strings.concat(root, "/none");
let broken: str = strings.concat(root, "/broken");
mkdirall(alpha);
mkdirall(beta);
mkdirall(none);
mkdirall(broken);
writefile(strings.concat(alpha, "/alpha.ww"),
"package zero_alpha;\nfn value() i32 = { return 1; };\n");
writefile(strings.concat(alpha, "/alpha_test.ww"), strings.concat(
"package zero_alpha;\nimport os;\n",
"@test fn first() void = {};\n",
"@test fn marker_text() void = {\n",
" let text: str = \"not-a-marker testing: warning: no tests to run\\n\";\n",
" os.write(os.STDOUT_FILENO, text.ptr, text.len: u64);\n",
"};\n"));
writefile(strings.concat(beta, "/beta.ww"),
"package zero_beta;\nfn value() i32 = { return 2; };\n");
writefile(strings.concat(beta, "/beta_test.ww"),
"package zero_beta;\n@test fn only() void = {};\n");
writefile(strings.concat(none, "/none.ww"),
"package zero_none;\nfn value() i32 = { return 3; };\n");
writefile(strings.concat(broken, "/broken.ww"),
"package zero_broken;\nfn value() missing_type = { return 4; };\n");
writefile(strings.concat(broken, "/broken_test.ww"),
"package zero_broken;\n@test fn registered() void = {};\n");
let warning: str = "testing: warning: no tests to run\n";
let suffix: str = " [no tests to run]";
let stages: []str = ["ww", "ww_ww"];
let tags: []str = ["c", "ww"];
let works: []str = [strings.concat(root, "/work-c"),
strings.concat(root, "/work-ww")];
let retained: []str = [strings.concat(root, "/retained-c.test"),
strings.concat(root, "/retained-ww.test")];
let coldout: []str = ["", ""];
let colderror: []str = ["", ""];
let positiveout: []str = ["", ""];
let positiveerror: []str = ["", ""];
let listout: []str = ["", ""];
let listerror: []str = ["", ""];
let retainedout: []str = ["", ""];
let retainederror: []str = ["", ""];
let manualout: []str = ["", ""];
let manualerror: []str = ["", ""];
let failurediagnostic: []str = ["", ""];
let out: commandout;
let i: i32 = 0;
for (i < stages.len) {
// Reverse request order and run two products concurrently. Result bytes
// remain directory-sorted and each product owns its own marker/suffix.
let emptyav: []str = [driver(stages[i]), "test", "-j", "2",
"-w", works[i], "-run", "no-such-*", beta, alpha];
runcommand(root, strings.concat("ordinary-empty-cold-", tags[i]),
emptyav, (90i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stderr.len == 0);
assert(occurrences(out.stdout, warning) == 2);
assert(!has(out.stdout, "[no matches]"));
assert(occurrences(out.stdout,
"2 discovered, 0 selected, 0 started, 0 completed\n") == 1);
assert(occurrences(out.stdout,
"1 discovered, 0 selected, 0 started, 0 completed\n") == 1);
let alphaok: str = strings.concat("ok ", alpha,
" [zero_alpha] [no tests to run]\n");
let betaok: str = strings.concat("ok ", beta,
" [zero_beta] [no tests to run]\n");
let alphacount: i32 = pos(out.stdout,
"2 discovered, 0 selected, 0 started, 0 completed\n");
let alphareport: i32 = pos(out.stdout, alphaok);
let betacount: i32 = pos(out.stdout,
"1 discovered, 0 selected, 0 started, 0 completed\n");
let betareport: i32 = pos(out.stdout, betaok);
assert(alphacount >= 0 && alphacount < alphareport
&& alphareport < betacount && betacount < betareport);
assert(occurrences(out.stdout, alphaok) == 1);
assert(occurrences(out.stdout, betaok) == 1);
coldout[i] = strings.dup(out.stdout);
colderror[i] = strings.dup(out.stderr);
runcommand(root, strings.concat("ordinary-empty-warm-", tags[i]),
emptyav, (90i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(out.stdout, coldout[i]));
assert(same(out.stderr, colderror[i]));
assert(!directoryhasnew(works[i]));
// The same bytes inside a running test, but not at a line boundary, are
// ordinary user output and must not annotate a successful package result.
let positiveav: []str = [driver(stages[i]), "test", "-w",
works[i], "-run", "marker_text", alpha];
runcommand(root, strings.concat("ordinary-positive-", tags[i]),
positiveav, (90i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stderr.len == 0);
assert(occurrences(out.stdout, warning) == 1);
assert(has(out.stdout, strings.concat("not-a-marker ", warning)));
assert(!has(out.stdout, suffix));
assert(has(out.stdout, strings.concat("ok ", alpha,
" [zero_alpha]\n")));
positiveout[i] = strings.dup(out.stdout);
positiveerror[i] = strings.dup(out.stderr);
// The already-closed list behavior remains an early return: no warning,
// accounting, old sentinel, or package suffix.
let listav: []str = [driver(stages[i]), "test", "-w", works[i],
"-list", "-run", "no-such-*", alpha];
runcommand(root, strings.concat("ordinary-list-control-", tags[i]),
listav, (90i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(out.stdout, strings.concat("ok ", alpha,
" [zero_alpha]\n")));
assert(out.stderr.len == 0);
assert(!has(out.stdout, warning) && !has(out.stdout, suffix));
assert(!has(out.stdout, " discovered, "));
listout[i] = strings.dup(out.stdout);
listerror[i] = strings.dup(out.stderr);
let noneav: []str = [driver(stages[i]), "test", "-w", works[i],
none];
runcommand(root, strings.concat("ordinary-no-files-", tags[i]),
noneav, (90i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(out.stdout, strings.concat("? ", none,
" [no test files]\n")));
assert(out.stderr.len == 0);
assert(!has(out.stdout, warning) && !has(out.stdout, suffix));
// A successful zero-selection run may publish its retained test binary.
let retainav: []str = [driver(stages[i]), "test", "-w", works[i],
"-o", retained[i], "-run", "no-such-*", alpha];
runcommand(root, strings.concat("ordinary-retained-", tags[i]),
retainav, (90i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stderr.len == 0);
assert(occurrences(out.stdout, warning) == 1);
assert(occurrences(out.stdout, alphaok) == 1);
assert(os.exists(retained[i]));
assert(!os.exists(strings.concat(retained[i], ".sepwork")));
let prior: str = strings.dup(readfile(retained[i]));
retainedout[i] = strings.dup(out.stdout);
retainederror[i] = strings.dup(out.stderr);
// Direct execution exposes the harness-owned stream boundary: accounting
// remains stdout while the exact pinned warning is stderr.
let manualav: []str = [retained[i], "-package=zero_alpha",
"no-such-*"];
runcommand(root, strings.concat("ordinary-manual-", tags[i]), manualav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(out.stdout,
"2 discovered, 0 selected, 0 started, 0 completed\n"));
assert(same(out.stderr, warning));
manualout[i] = strings.dup(out.stdout);
manualerror[i] = strings.dup(out.stderr);
// A producer failure wins before runtime and preserves a prior public
// binary. Cold and repeated failure have no warning, ok line, or suffix.
let failav: []str = [driver(stages[i]), "test", "-w", works[i],
"-o", retained[i], "-run", "no-such-*", broken];
runcommand(root, strings.concat("ordinary-failure-cold-", tags[i]),
failav, (90i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(same(out.stdout, "FAIL\n"));
assert(out.stderr.len != 0);
assert(!has(out.stdout, warning) && !has(out.stderr, warning));
assert(!has(out.stdout, suffix) && !has(out.stderr, suffix));
assert(!has(out.stdout, "ok ") && !has(out.stderr, "ok "));
assert(same(prior, readfile(retained[i])));
failurediagnostic[i] = strings.dup(primarydiagnostic(out.stderr));
let failstderr: str = strings.dup(out.stderr);
runcommand(root, strings.concat("ordinary-failure-warm-", tags[i]),
failav, (90i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(same(out.stdout, "FAIL\n"));
assert(same(out.stderr, failstderr));
assert(same(prior, readfile(retained[i])));
assert(!has(out.stdout, warning) && !has(out.stderr, warning));
// Restored valid reuse still emits the success marker/suffix and never
// rewrites an already-identical retained binary.
runcommand(root, strings.concat("ordinary-restored-", tags[i]), retainav,
(90i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(out.stdout, retainedout[i]));
assert(same(out.stderr, retainederror[i]));
assert(same(prior, readfile(retained[i])));
assert(!directoryhasnew(works[i]));
assert(!os.exists(strings.concat(retained[i], ".sepwork")));
i += 1;
};
assert(same(coldout[0], coldout[1]));
assert(same(colderror[0], colderror[1]));
assert(same(positiveout[0], positiveout[1]));
assert(same(positiveerror[0], positiveerror[1]));
assert(same(listout[0], listout[1]));
assert(same(listerror[0], listerror[1]));
assert(same(retainedout[0], retainedout[1]));
assert(same(retainederror[0], retainederror[1]));
assert(same(manualout[0], manualout[1]));
assert(same(manualerror[0], manualerror[1]));
assert(same(failurediagnostic[0], failurediagnostic[1]));
assert(same(readfile(retained[0]), readfile(retained[1])));
clean(root);
};
// Directory-package execution context is one product-level runtime property.
// This fixture keeps every source tree disposable while covering the variant,
// dependency, environment, routing, concurrency, persistence, and failure
@@ -1317,7 +1534,9 @@ fn cwdwritedata(dir: str, label: str) void = {
cwdassertpackage(out.stdout, "dep-init", p3, "p3-data", "p3-testdata");
cwdassertpackage(out.stdout, "testdep-init", p3,
"p3-data", "p3-testdata");
assert(has(out.stdout, "[no matches]\n"));
assert(has(out.stdout, "testing: warning: no tests to run\n"));
assert(has(out.stdout, strings.concat("ok ", p3,
" [p3] [no tests to run]\n")));
assert(!has(out.stdout, "p3-internal cwd="));
assert(!has(out.stdout, "p3-external cwd="));