test: cover shared directory test build plans

This commit is contained in:
2026-08-12 11:42:29 +09:00
parent dd975d195c
commit 02574c88f1
2 changed files with 326 additions and 72 deletions

View File

@@ -2849,11 +2849,16 @@ has one test variant; the coordinator rejects one output name for a multi-varian
or recursive request. Explicit `ww test FILE` retains its compatibility path.
The test coordinator still discovers requested directories, enumerates the
test package names, schedules independent binaries, executes them, and emits
test package names, selects variants, executes independent binaries, and emits
captured results in byte-sorted package order. It no longer concatenates a
generated production/test root or resolves imports. Instead it asks the Cstage
or WWstage command to build one of two non-importable root variants from the
real directory:
generated production/test root, resolves imports, or starts one package graph
per binary. Instead it sends one ordered build request per directory to the
Cstage or WWstage command. Its semantic selections are only the directory and
the selected variant/package identities; it also carries output destinations,
coordinator-private completion paths, import search roots, and the optional
shared work-directory policy. The command owns source selection,
package loading, compiler inputs, archive construction, and linking for both
non-importable roots:
- `same-test` selects the byte-sorted production files followed by the
byte-sorted matching `package p` test files. They form one compiler unit, so
@@ -2863,32 +2868,55 @@ real directory:
directory. That node selects every production file, emits `p.wwi` and `p.a`,
and exposes no private declaration to the external root.
The command loads those roots into one command-scoped package universe. The
roots retain distinct artifact keys (`__ww-test-same` and
`__ww-test-external`) that cannot collide with a legal import identity,
while imports of the same canonical production directory intern to one
production node. A deterministic dependency-first traversal of the union
therefore invokes the compiler and archiver once for every reachable canonical
production package, even when both test products need it. Each root is still
compiled once with its own selected sources and linked separately. The shared
plan is deliberately package-test-specific: it is not a generalized scheduler,
action schema, cache, or protocol.
A production action failure blocks exactly the roots that reach it. A
root-local compile or link failure does not suppress a successfully built
sibling product: the command records completion per product, and the
coordinator can run and report successful siblings while attributing each
missing product as a build failure. Directory builds and completed test
products share the coordinator's existing `-j` process bound; captured output
is still emitted only in byte-sorted directory/package order.
Every non-root dependency is always a production variant, so dependency
`*_test.ww` files never enter the graph. Imports that occur only in selected
test files add edges only to that test root. The compiler unit for each package
contains only its byte-sorted direct dependency `.wwi` artifacts; the final
test link still receives the root object and the complete reverse-topological
archive closure. The compiler-generated `-T` dispatcher owns the implicit
direct test-runtime support edge and remains embedded in each independent test
root. The command resolves that edge from the selected toolchain source tree,
not the user search path. Normally its graph qualifier is `test`, so an explicit
source `import test` coalesces with the same canonical package. When a real user
package occupies that identity, the command presents the runtime edge to the
compiler under the reserved `__wwtest` qualifier. This keeps a production
package named `test` available to external tests while preserving raw `w6c -T`
compatibility, whose default unresolved qualifier remains `test`.
direct test-runtime support edge and remains embedded in each independently
compiled test root; it is the narrow test-main variant, not a
coordinator-generated graph package. The shared plan compiles the common
runtime production package once. The command resolves that edge from the
selected toolchain source tree, not the user search path. Normally its graph
qualifier is `test`, so an explicit source `import test` coalesces with the same
canonical package. When a real user package occupies that identity, the command
presents the runtime edge to the compiler under the reserved `__wwtest`
qualifier. This keeps a production package named `test` available to external
tests while preserving raw `w6c -T` compatibility, whose default unresolved
qualifier remains `test`.
The selected test root and a production variant reached by its imports or test
runtime closure are the only sanctioned pair of graph nodes that may share a
The selected test roots and a production variant reached by their imports or
test-runtime closure are the only sanctioned graph nodes that may share a
physical directory. This also lets a toolchain package's own tests coexist with
the production variant required by the test runtime. A same-package root
already defines those production symbols, so the duplicate production archive
is omitted from its final link while that node's dependency archives remain in
the closure. All ordinary logical and physical package-identity collision
checks remain unchanged. Recursive
discovery groups by physical directory before sorting filenames, and persistent
coordinator work directories use an injective escaped `(directory, test
package)` key. Every `*_test.ww` package variant is built even when a file only
already defines those production symbols, so the production archive is omitted
from that product's final link while the production node's dependency archives
remain in its closure. The external product includes the production archive.
Variant-only archives are never linked into the other product. All ordinary
logical and physical package-identity collision checks remain unchanged.
Recursive discovery groups by physical directory before sorting filenames, and
persistent coordinator work directories use one injective escaped directory
plan key. Every `*_test.ww` package variant is built even when a file only
declares helpers and contains no `@test`, so its package clause and imports are
still checked by the shared loader. Every built variant is run, and a successful
compiler-owned dispatcher with empty output is reported as `[no tests]`.
@@ -2896,9 +2924,15 @@ compiler-owned dispatcher with empty output is reported as `[no tests]`.
This ownership split follows Go 1.26.5's separation of production,
same-package-test, external-test, and generated test-main inputs in
[`cmd/go/internal/load/test.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/test.go),
while retaining WW's compiler-owned dispatcher. Direct compile dependencies and
the separately expanded link closure follow the boundary in
[`cmd/go/internal/work/action.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/action.go).
while retaining WW's compiler-owned dispatcher. Go's loader returns the same
cached package pointer for repeated imports, and its command-scoped builder
deduplicates compile actions by package identity; WW borrows that one-universe,
multi-root ownership boundary without borrowing Go's cache machinery. Direct
compile dependencies and the separately expanded link closure follow the
boundary in
[`cmd/go/internal/work/action.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/action.go),
with compiler and linker import configurations emitted separately in
[`cmd/go/internal/work/exec.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go).
## 12. Candidate architectures and hard-gate decision

View File

@@ -71,6 +71,17 @@ fn writefile(path: str, content: str) void = {
assert(os.close(fd) == 0);
};
fn writeexecutable(path: str, content: str) void = {
let fd: i32 = os.open(path,
os.flag.WRONLY | os.flag.CREATE | os.flag.EXCL, 448i32);
assert(fd >= 0);
match (os.writeall(fd, content.ptr, content.len: u64)) {
case let n: i64 => assert(n == content.len: i64);
case let e: os.oserror => abort("write failed");
};
assert(os.close(fd) == 0);
};
fn runcommand(root: str, name: str, argv: []str,
lifetime: time.duration, out: *commandout) void = {
let c: exec.command;
@@ -169,6 +180,22 @@ fn occurrences(haystack: str, needle: str) i32 = {
return count;
};
fn linecontaining(text: str, needle: str) str = {
let start: i32 = 0;
let i: i32 = 0;
for (i <= text.len) {
if (i == text.len || text[i] == '\n': u8) {
let line: str;
line.ptr = text.ptr + (start: u64);
line.len = i - start;
if (has(line, needle)) { return line; };
start = i + 1;
};
i += 1;
};
abort("missing trace line");
};
fn expectexit(out: *commandout, code: i32) void = {
assert(out.termination == exec.termination.EXIT);
assert(out.code == code);
@@ -617,14 +644,13 @@ fn workescape(s: str) str = {
assert(has(outc.stdout,
strings.concat(" -> ", root, "/route_test.test\n")));
let cwhite: str = readfile(strings.concat(root,
"/route.test.sepwork/__root.s"));
"/route.test.sepwork/__ww-test-same.s"));
let cexternal: str = readfile(strings.concat(root,
"/route_test.test.sepwork/__root.s"));
"/route.test.sepwork/__ww-test-external.s"));
// The explicit package `-c` outputs are caller-owned artifacts. Release
// the two exact C-stage trees before asking the WW driver to acquire the
// same stems; the driver never deletes a pre-existing `.sepwork` path.
// the shared C-stage tree before asking the WW driver to acquire the same
// stem; the driver never deletes a pre-existing `.sepwork` path.
clean(strings.concat(root, "/route.test.sepwork"));
clean(strings.concat(root, "/route_test.test.sepwork"));
let wc: []str = [driver("ww_ww"), "test", "-c", root];
runcommand(root, "compile-ww", wc,
@@ -633,9 +659,9 @@ fn workescape(s: str) str = {
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
assert(same(cwhite, readfile(strings.concat(root,
"/route.test.sepwork/__root.s"))));
"/route.test.sepwork/__ww-test-same.s"))));
assert(same(cexternal, readfile(strings.concat(root,
"/route_test.test.sepwork/__root.s"))));
"/route.test.sepwork/__ww-test-external.s"))));
clean(root);
};
@@ -643,8 +669,8 @@ fn workescape(s: str) str = {
let root: str = fresh();
let implementation: str = strings.concat(root, "/implementation");
let api: str = strings.concat(root, "/api");
let testonly: str = strings.concat(root, "/testonly");
let externalonly: str = strings.concat(root, "/externalonly");
let testonly: str = strings.concat(root, "/__same");
let externalonly: str = strings.concat(root, "/__external");
let pkg: str = strings.concat(root, "/pkg");
assert(os.mkdir(implementation, 448i32) == 0);
assert(os.mkdir(api, 448i32) == 0);
@@ -662,11 +688,11 @@ fn workescape(s: str) str = {
writefile(strings.concat(api, "/api_test.ww"), strings.concat(
"package api;\n",
"TEST_DEPENDENCY_MUST_NOT_COMPILE\n"));
writefile(strings.concat(testonly, "/testonly.ww"), strings.concat(
"package testonly;\n",
writefile(strings.concat(testonly, "/__same.ww"), strings.concat(
"package __same;\n",
"export fn value() i32 = { return 1; };\n"));
writefile(strings.concat(externalonly, "/externalonly.ww"), strings.concat(
"package externalonly;\n",
writefile(strings.concat(externalonly, "/__external.ww"), strings.concat(
"package __external;\n",
"export fn value() i32 = { return 1; };\n"));
writefile(strings.concat(pkg, "/a.ww"), strings.concat(
"package pkg;\nimport api;\n",
@@ -678,16 +704,16 @@ fn workescape(s: str) str = {
"fn secret() i32 = { return 6; };\n",
"export fn second() i32 = { return 9; };\n"));
writefile(strings.concat(pkg, "/same_test.ww"), strings.concat(
"package pkg;\nimport testonly;\n",
"package pkg;\nimport __same;\n",
"// SAME_TEST_SOURCE\n",
"@test fn same_graph() void = {\n",
" assert(value() + testonly.value() == 42);\n",
" assert(value() + __same.value() == 42);\n",
" assert(secret() == 6);\n};\n"));
writefile(strings.concat(pkg, "/external_test.ww"), strings.concat(
"package pkg_test;\nimport externalonly;\nimport pkg;\n",
"package pkg_test;\nimport __external;\nimport pkg;\n",
"// EXTERNAL_TEST_SOURCE\n",
"@test fn external_graph() void = {\n",
" assert(pkg.value() + externalonly.value() == 42);\n",
" assert(pkg.value() + __external.value() == 42);\n",
" assert(pkg.second() == 9);\n};\n"));
let prodout: str = strings.concat(root, "/production.a");
@@ -702,19 +728,54 @@ fn workescape(s: str) str = {
"pkg.unit.ww"));
assert(has(produnit, "//ww:module api\n"));
assert(!has(produnit, "//ww:module implementation\n"));
assert(!has(produnit, "testonly"));
assert(!has(produnit, "externalonly"));
assert(!os.exists(strings.concat(prodwork, "testonly.unit.ww")));
assert(!os.exists(strings.concat(prodwork, "externalonly.unit.ww")));
assert(!has(produnit, "__same"));
assert(!has(produnit, "__external"));
assert(!os.exists(strings.concat(prodwork, "__same.unit.ww")));
assert(!os.exists(strings.concat(prodwork, "__external.unit.ww")));
assert(!has(readfile(strings.concat(prodwork, "api.unit.ww")),
"TEST_DEPENDENCY_MUST_NOT_COMPILE"));
let samebin: str = strings.concat(pkg, "/pkg.test");
let externalbin: str = strings.concat(pkg, "/pkg_test.test");
let sameworkroot: str = strings.concat(samebin, ".sepwork");
let externalworkroot: str = strings.concat(externalbin, ".sepwork");
let samework: str = strings.concat(sameworkroot, "/");
let externalwork: str = strings.concat(externalworkroot, "/");
let sharedworkroot: str = strings.concat(samebin, ".sepwork");
let sharedwork: str = strings.concat(sharedworkroot, "/");
let compilertrace: str = strings.concat(root, "/compiler.trace");
let linkertrace: str = strings.concat(root, "/linker.trace");
let compilerwrapper: str = strings.concat(root, "/trace-w6c.sh");
let linkerwrapper: str = strings.concat(root, "/trace-w6l.sh");
writefile(compilertrace, "");
writefile(linkertrace, "");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_COMPILER_TRACE\"\n",
"exec \"$WW_PACKAGE_W6C\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_LINKER_TRACE\"\n",
"exec \"$WW_PACKAGE_W6L\" \"$@\"\n"));
let baseenv: []str = os.getenvs();
let traceenv: []str = alloc([], (baseenv.len + 6): u64)!;
let ei: i32 = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_W6L=")
&& !strings.hasprefix(baseenv[ei],
"WW_PACKAGE_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_PACKAGE_LINKER_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6L=")) {
append(traceenv, baseenv[ei]);
};
ei += 1;
};
append(traceenv, strings.concat("WW_W6C=", compilerwrapper));
append(traceenv, strings.concat("WW_W6L=", linkerwrapper));
append(traceenv, strings.concat("WW_PACKAGE_COMPILER_TRACE=",
compilertrace));
append(traceenv, strings.concat("WW_PACKAGE_LINKER_TRACE=", linkertrace));
append(traceenv, strings.concat("WW_PACKAGE_W6C=", driver("w6c")));
append(traceenv, strings.concat("WW_PACKAGE_W6L=", driver("w6l")));
let drivers: []str = ["ww", "ww", "ww_ww"];
let tags: []str = ["c1", "c2", "ww"];
let referenceout: str = "";
@@ -728,34 +789,41 @@ fn workescape(s: str) str = {
for (i < drivers.len) {
let av: []str = [driver(drivers[i]), "test", "-c", "-I", root,
pkg];
runcommand(root, strings.concat("variant-build-", tags[i]), av,
(120i64 * (time.second: i64)): time.duration, &out);
if (i == 0) {
runcommandenv(root, strings.concat("variant-build-", tags[i]), av,
traceenv, (120i64 * (time.second: i64)): time.duration,
&out);
} else {
runcommand(root, strings.concat("variant-build-", tags[i]), av,
(120i64 * (time.second: i64)): time.duration, &out);
};
expectexit(&out, 0);
let buildstdout: str = strings.dup(out.stdout);
let buildstderr: str = strings.dup(out.stderr);
let sameunit: str = readfile(strings.concat(samework,
"__root.unit.ww"));
let externalunit: str = readfile(strings.concat(externalwork,
"__root.unit.ww"));
let externalproduction: str = readfile(strings.concat(externalwork,
let sameunit: str = readfile(strings.concat(sharedwork,
"__ww-test-same.unit.ww"));
let externalunit: str = readfile(strings.concat(sharedwork,
"__ww-test-external.unit.ww"));
let externalproduction: str = readfile(strings.concat(sharedwork,
"pkg.unit.ww"));
assert(!os.exists(strings.concat(externalbin, ".sepwork")));
assert(has(sameunit, "//ww:module api\n"));
assert(has(sameunit, "//ww:module testonly\n"));
assert(has(sameunit, "//ww:module __same\n"));
assert(has(sameunit, "//ww:module test\n"));
assert(!has(sameunit, "//ww:module implementation\n"));
assert(!has(sameunit, "//ww:module externalonly\n"));
assert(!os.exists(strings.concat(samework,
"externalonly.unit.ww")));
assert(!has(sameunit, "//ww:module __external\n"));
assert(os.exists(strings.concat(sharedwork,
"__external.unit.ww")));
assert(has(sameunit, "PACKAGE_PRODUCTION_A"));
assert(has(sameunit, "PACKAGE_PRODUCTION_Z"));
assert(has(sameunit, "SAME_TEST_SOURCE"));
assert(!has(sameunit, "EXTERNAL_TEST_SOURCE"));
assert(has(externalunit, "//ww:module pkg\n"));
assert(has(externalunit, "//ww:module externalonly\n"));
assert(has(externalunit, "//ww:module __external\n"));
assert(has(externalunit, "//ww:module test\n"));
assert(!has(externalunit, "//ww:module api\n"));
assert(!has(externalunit, "//ww:module implementation\n"));
assert(!has(externalunit, "//ww:module testonly\n"));
assert(!has(externalunit, "//ww:module __same\n"));
assert(has(externalunit, "EXTERNAL_TEST_SOURCE"));
assert(!has(externalunit, "PACKAGE_PRODUCTION_A"));
assert(!has(externalunit, "PACKAGE_PRODUCTION_Z"));
@@ -765,12 +833,61 @@ fn workescape(s: str) str = {
assert(!has(externalproduction, "//ww:module implementation\n"));
assert(!has(externalproduction, "SAME_TEST_SOURCE"));
assert(!has(externalproduction, "EXTERNAL_TEST_SOURCE"));
assert(!has(readfile(strings.concat(externalwork, "api.unit.ww")),
assert(!has(readfile(strings.concat(sharedwork, "api.unit.ww")),
"TEST_DEPENDENCY_MUST_NOT_COMPILE"));
assert(os.exists(strings.concat(samework, "implementation.a")));
assert(os.exists(strings.concat(externalwork, "implementation.a")));
assert(os.exists(strings.concat(externalwork, "api.a")));
assert(os.exists(strings.concat(externalwork, "pkg.a")));
let artifacts: []str = ["implementation", "api", "pkg",
"__same", "__external", "test"];
let ai: i32 = 0;
for (ai < artifacts.len) {
assert(os.exists(strings.concat(sharedwork, artifacts[ai], ".wwi")));
assert(os.exists(strings.concat(sharedwork, artifacts[ai], ".a")));
ai += 1;
};
assert(os.exists(strings.concat(sharedwork, "__ww-test-same.o")));
assert(os.exists(strings.concat(sharedwork, "__ww-test-external.o")));
assert(!os.exists(strings.concat(sharedwork, "__ww-test-same.wwi")));
assert(!os.exists(strings.concat(sharedwork,
"__ww-test-external.wwi")));
assert(!os.exists(strings.concat(sharedwork, "__ww-test-same.a")));
assert(!os.exists(strings.concat(sharedwork,
"__ww-test-external.a")));
assert(os.exists(samebin));
assert(os.exists(externalbin));
if (i == 0) {
let ctrace: str = readfile(compilertrace);
assert(occurrences(ctrace, "implementation.unit.ww") == 1);
assert(occurrences(ctrace, "api.unit.ww") == 1);
assert(occurrences(ctrace, "pkg.unit.ww") == 1);
assert(occurrences(ctrace, "/__same.unit.ww") == 1);
assert(occurrences(ctrace, "/__external.unit.ww") == 1);
assert(occurrences(ctrace, "/test.unit.ww") == 1);
assert(occurrences(ctrace, "__ww-test-same.unit.ww") == 1);
assert(occurrences(ctrace,
"__ww-test-external.unit.ww") == 1);
assert(occurrences(ctrace,
"-T --test-support-module") == 2);
let ltrace: str = readfile(linkertrace);
assert(occurrences(ltrace, "\n") == 2);
let samelink: str = linecontaining(ltrace,
strings.concat("-o ", samebin, " "));
let externallink: str = linecontaining(ltrace,
strings.concat("-o ", externalbin, " "));
assert(has(samelink, strings.concat(sharedwork, "api.a")));
assert(has(samelink,
strings.concat(sharedwork, "implementation.a")));
assert(has(samelink, strings.concat(sharedwork, "__same.a")));
assert(!has(samelink, strings.concat(sharedwork, "pkg.a")));
assert(!has(samelink,
strings.concat(sharedwork, "__external.a")));
assert(has(externallink, strings.concat(sharedwork, "pkg.a")));
assert(has(externallink, strings.concat(sharedwork, "api.a")));
assert(has(externallink,
strings.concat(sharedwork, "implementation.a")));
assert(has(externallink,
strings.concat(sharedwork, "__external.a")));
assert(!has(externallink,
strings.concat(sharedwork, "__same.a")));
};
let runav: []str = [samebin];
runcommand(root, strings.concat("variant-run-same-", tags[i]), runav,
(60i64 * (time.second: i64)): time.duration, &out);
@@ -799,11 +916,39 @@ fn workescape(s: str) str = {
assert(same(referenceerr, buildstderr));
};
if (i + 1 < drivers.len) {
clean(sameworkroot); clean(externalworkroot);
clean(sharedworkroot);
clean(samebin); clean(externalbin);
};
i += 1;
};
// The illegal-in-import root keys stay disjoint from the valid packages
// literally named __same and __external, including warm reuse.
let warmroot: str = strings.concat(root, "/warm");
assert(os.mkdir(warmroot, 448i32) == 0);
let warmav: []str = [driver("ww"), "test", "-w", warmroot,
"-I", root, pkg];
runcommandenv(root, "variant-warm-cold", warmav, traceenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let warmstdout: str = strings.dup(out.stdout);
let warmstderr: str = strings.dup(out.stderr);
let warmtrace: str = readfile(compilertrace);
let warmwork: str = strings.concat(warmroot, "/d_", workescape(pkg),
"_p_pkg/");
assert(has(readfile(strings.concat(warmwork, "__same.unit.ww")),
"package __same;"));
assert(has(readfile(strings.concat(warmwork,
"__ww-test-same.unit.ww")), "SAME_TEST_SOURCE"));
assert(has(readfile(strings.concat(warmwork, "__external.unit.ww")),
"package __external;"));
assert(has(readfile(strings.concat(warmwork,
"__ww-test-external.unit.ww")), "EXTERNAL_TEST_SOURCE"));
runcommandenv(root, "variant-warm-reuse", warmav, traceenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(warmstdout, out.stdout));
assert(same(warmstderr, out.stderr));
assert(same(warmtrace, readfile(compilertrace)));
let aliasunit: str = strings.concat(root, "/alias.unit.ww");
writefile(aliasunit, strings.concat(
"//ww:module-reset __wwtest\n",
@@ -834,6 +979,79 @@ fn workescape(s: str) str = {
clean(root);
};
// One failing root is a product failure, not permission for the shared build
// request to suppress an independently compilable sibling root.
@test fn sibling_test_variant_failures_are_isolated() void = {
let root: str = fresh();
let badexternal: str = strings.concat(root, "/badexternal");
let badsame: str = strings.concat(root, "/badsame");
assert(os.mkdir(badexternal, 448i32) == 0);
assert(os.mkdir(badsame, 448i32) == 0);
writefile(strings.concat(badexternal, "/badexternal.ww"), strings.concat(
"package badexternal;\n",
"fn hidden() i32 = { return 41; };\n",
"export fn shown() i32 = { return 41; };\n"));
writefile(strings.concat(badexternal, "/same_test.ww"), strings.concat(
"package badexternal;\n",
"@test fn valid_same_runs() void = { assert(hidden() == 41); };\n"));
writefile(strings.concat(badexternal, "/external_test.ww"), strings.concat(
"package badexternal_test;\nimport badexternal;\n",
"@test fn invalid_external() void = {\n",
" assert(badexternal.hidden() == 41);\n};\n"));
writefile(strings.concat(badsame, "/badsame.ww"), strings.concat(
"package badsame;\n",
"export fn shown() i32 = { return 42; };\n"));
writefile(strings.concat(badsame, "/same_test.ww"), strings.concat(
"package badsame;\n",
"@test fn invalid_same() void = { assert(missing() == 0); };\n"));
writefile(strings.concat(badsame, "/external_test.ww"), strings.concat(
"package badsame_test;\nimport badsame;\n",
"@test fn valid_external_runs() void = {\n",
" assert(badsame.shown() == 42);\n};\n"));
let stages: []str = ["ww", "ww_ww"];
let tags: []str = ["c", "ww"];
let externaldiagnostics: []str = ["", ""];
let samediagnostics: []str = ["", ""];
let out: commandout;
let i: i32 = 0;
for (i < stages.len) {
let externalav: []str = [driver(stages[i]), "test", "-I", root,
badexternal];
runcommand(root, strings.concat("isolated-external-", tags[i]),
externalav, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout, "valid_same_runs ... ok\n"));
assert(has(out.stdout, "[badexternal, same-package]\n"));
assert(has(out.stderr,
"has no exported declaration 'hidden'"));
assert(has(out.stderr,
strings.concat("FAIL ", badexternal,
" [badexternal_test] (build exit 1)\n")));
assert(!has(out.stderr, strings.concat("FAIL ", badexternal,
" [badexternal]")));
externaldiagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
let sameav: []str = [driver(stages[i]), "test", "-I", root,
badsame];
runcommand(root, strings.concat("isolated-same-", tags[i]), sameav,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout, "valid_external_runs ... ok\n"));
assert(has(out.stdout, "[badsame_test, external]\n"));
assert(has(out.stderr, "undefined: missing"));
assert(has(out.stderr, strings.concat("FAIL ", badsame,
" [badsame] (build exit 1)\n")));
assert(!has(out.stderr, strings.concat("FAIL ", badsame,
" [badsame_test]")));
samediagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
i += 1;
};
assert(same(externaldiagnostics[0], externaldiagnostics[1]));
assert(same(samediagnostics[0], samediagnostics[1]));
clean(root);
};
// The compiler-generated runner uses a reserved graph qualifier rather than
// claiming the user-visible import path `test`. A real multi-file production
// package named test can therefore be the normal direct dependency of its
@@ -872,7 +1090,8 @@ fn workescape(s: str) str = {
runcommand(root, strings.concat("named-test-build-", stages[i]), av,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let rootunit: str = readfile(strings.concat(work, "__root.unit.ww"));
let rootunit: str = readfile(strings.concat(work,
"__ww-test-external.unit.ww"));
let produnit: str = readfile(strings.concat(work, "test.unit.ww"));
let supportunit: str = readfile(strings.concat(work,
"__wwtest.unit.ww"));
@@ -967,7 +1186,8 @@ fn workescape(s: str) str = {
expectexit(&out, 0);
assert(occurrences(readfile(trace), "shared.unit.ww") == 1);
let work: str = strings.concat(bin, ".sepwork/");
let unit: str = readfile(strings.concat(work, "__root.unit.ww"));
let unit: str = readfile(strings.concat(work,
"__ww-test-same.unit.ww"));
assert(has(unit, "//ww:module left\n"));
assert(has(unit, "//ww:module right\n"));
assert(!has(unit, "//ww:module shared\n"));
@@ -1185,8 +1405,8 @@ fn workescape(s: str) str = {
assert(has(outc.stderr,
"ww test: -o needs -c for a package target\n"));
// -w on a package target forwards to the coordinator: one
// persistent driver workdir per package group under the root,
// -w on a package target forwards to the coordinator: one shared
// persistent driver workdir per directory plan under the root,
// reuse owned by the driver's content-identity contract. The
// byte stream must match the plain run, cold and warm.
let wdroot: str = strings.concat(root, "/wd");