test: prove canonical directory package identity

This commit is contained in:
2026-08-13 02:48:17 +09:00
parent 0aff801def
commit cc6799c3b1
5 changed files with 530 additions and 149 deletions

View File

@@ -257,10 +257,42 @@ fn workescape(s: str) str = {
return strings.frombytes(out);
};
fn localidentity(dir: str, leaf: str) str = {
let out: []u8 = alloc([], (dir.len * 4 + leaf.len + 16): u64)!;
let prefix: str = "__wwlocal.p";
let i: i32 = 0;
for (i < prefix.len) { append(out, prefix[i]); i += 1; };
let hex: str = "0123456789abcdef";
i = 0;
for (i < dir.len) {
let c: u8 = dir[i];
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9')) {
append(out, c);
} else if (c == '_') {
append(out, '_'); append(out, 'u');
} else if (c == '/') {
append(out, '_'); append(out, 's');
} else {
let high: i32 = (c / 16u8): i32;
let low: i32 = (c % 16u8): i32;
append(out, '_'); append(out, 'x');
append(out, hex[high]); append(out, hex[low]);
};
i += 1;
};
append(out, '.');
i = 0;
for (i < leaf.len) { append(out, leaf[i]); i += 1; };
return strings.frombytes(out);
};
@test fn deterministic_routing_and_filters() void = {
let root: str = fresh();
let target: str = packagepath("routing");
let av: []str = [driver("ww"), "test", "-list", target];
let sourceroot: str = strings.concat(repo(), "/test/package");
let av: []str = [driver("ww"), "test", "-I", sourceroot,
"-list", target];
let out: commandout;
runcommand(root, "list", av, (30i64 * (time.second: i64)): time.duration,
&out);
@@ -273,7 +305,7 @@ fn workescape(s: str) str = {
assert(occurrences(out.stdout, "routing.same_package\n") == 1);
assert(occurrences(out.stdout, "routing_test.external_package\n") == 1);
let rav: []str = [driver("ww"), "test", target];
let rav: []str = [driver("ww"), "test", "-I", sourceroot, target];
runcommand(root, "run", rav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
@@ -287,7 +319,7 @@ fn workescape(s: str) str = {
let fav: []str = [driver("ww"), "test", "-run",
"routing.private_helper_first", "-filter", "external_package",
target];
"-I", sourceroot, target];
runcommand(root, "filters", fav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
@@ -295,7 +327,8 @@ fn workescape(s: str) str = {
assert(!has(out.stdout, "routing.same_package ..."));
assert(has(out.stdout, "routing_test.external_package ... ok\n"));
let nav: []str = [driver("ww"), "test", "-run", "no-such-*", target];
let nav: []str = [driver("ww"), "test", "-I", sourceroot,
"-run", "no-such-*", target];
runcommand(root, "nomatch", nav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
@@ -306,7 +339,7 @@ fn workescape(s: str) str = {
"2 discovered, 0 selected, 0 started, 0 completed\n") == 1);
let lnav: []str = [driver("ww"), "test", "-list", "-run",
"no-such-*", target];
"no-such-*", "-I", sourceroot, target];
runcommand(root, "list-nomatch", lnav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
@@ -594,17 +627,19 @@ fn workescape(s: str) str = {
@test fn cstage_wwstage_behavior_and_assembly_match() void = {
let root: str = fresh();
writefile(strings.concat(root, "/route.ww"),
let route: str = strings.concat(root, "/route");
assert(os.mkdir(route, 448i32) == 0);
writefile(strings.concat(route, "/route.ww"),
"package route;\nexport fn value() int = { return 7; };\n");
writefile(strings.concat(root, "/a_test.ww"),
writefile(strings.concat(route, "/a_test.ww"),
"package route;\n@test fn white() void = { assert(value() == 7); };\n");
writefile(strings.concat(root, "/z_test.ww"),
writefile(strings.concat(route, "/z_test.ww"),
"package route_test;\nimport route;\n@test fn external() void = { assert(route.value() == 7); };\n");
let outc: commandout;
let outw: commandout;
let listc: []str = [driver("ww"), "test", "-list", root];
let listw: []str = [driver("ww_ww"), "test", "-list", root];
let listc: []str = [driver("ww"), "test", "-I", root, "-list", route];
let listw: []str = [driver("ww_ww"), "test", "-I", root, "-list", route];
runcommand(root, "list-c", listc,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "list-ww", listw,
@@ -625,9 +660,9 @@ fn workescape(s: str) str = {
assert(has(outc.stderr, "ww test: -run needs an argument\n"));
let timeoutc: []str = [driver("ww"), "test",
"-timeout-ms=4000000", root];
"-timeout-ms=4000000", "-I", root, route];
let timeoutw: []str = [driver("ww_ww"), "test",
"-timeout-ms=4000000", root];
"-timeout-ms=4000000", "-I", root, route];
runcommand(root, "timeout-misuse-c", timeoutc, time.second, &outc);
runcommand(root, "timeout-misuse-ww", timeoutw, time.second, &outw);
expectexit(&outc, 2);
@@ -636,31 +671,31 @@ fn workescape(s: str) str = {
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "usage: wwtest package"));
let cc: []str = [driver("ww"), "test", "-c", root];
let cc: []str = [driver("ww"), "test", "-c", "-I", root, route];
runcommand(root, "compile-c", cc,
(30i64 * (time.second: i64)): time.duration, &outc);
expectexit(&outc, 0);
assert(has(outc.stdout, strings.concat(" -> ", root, "/route.test\n")));
assert(has(outc.stdout, strings.concat(" -> ", route, "/route.test\n")));
assert(has(outc.stdout,
strings.concat(" -> ", root, "/route_test.test\n")));
let cwhite: str = readfile(strings.concat(root,
strings.concat(" -> ", route, "/route_test.test\n")));
let cwhite: str = readfile(strings.concat(route,
"/route.test.sepwork/route-internal-test.s"));
let cexternal: str = readfile(strings.concat(root,
let cexternal: str = readfile(strings.concat(route,
"/route.test.sepwork/route_test-external-test.s"));
// The explicit package `-c` outputs are caller-owned artifacts. Release
// 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(route, "/route.test.sepwork"));
let wc: []str = [driver("ww_ww"), "test", "-c", root];
let wc: []str = [driver("ww_ww"), "test", "-c", "-I", root, route];
runcommand(root, "compile-ww", wc,
(30i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outw, 0);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
assert(same(cwhite, readfile(strings.concat(root,
assert(same(cwhite, readfile(strings.concat(route,
"/route.test.sepwork/route-internal-test.s"))));
assert(same(cexternal, readfile(strings.concat(root,
assert(same(cexternal, readfile(strings.concat(route,
"/route.test.sepwork/route_test-external-test.s"))));
clean(root);
};
@@ -777,6 +812,28 @@ fn workescape(s: str) str = {
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 wwtraceenv: []str = alloc([], (baseenv.len + 6): u64)!;
ei = 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(wwtraceenv, baseenv[ei]);
};
ei += 1;
};
append(wwtraceenv, strings.concat("WW_W6C=", compilerwrapper));
append(wwtraceenv, strings.concat("WW_W6L=", linkerwrapper));
append(wwtraceenv, strings.concat("WW_PACKAGE_COMPILER_TRACE=",
compilertrace));
append(wwtraceenv, strings.concat("WW_PACKAGE_LINKER_TRACE=", linkertrace));
append(wwtraceenv, strings.concat("WW_PACKAGE_W6C=", driver("w6c_ww")));
append(wwtraceenv, strings.concat("WW_PACKAGE_W6L=", driver("w6l_ww")));
let drivers: []str = ["ww", "ww", "ww_ww"];
let tags: []str = ["c1", "c2", "ww"];
let referenceout: str = "";
@@ -1012,8 +1069,7 @@ fn workescape(s: str) str = {
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/");
let warmwork: str = strings.concat(warmroot, "/d_", workescape(pkg), "/");
assert(has(readfile(strings.concat(warmwork, "__same.unit.ww")),
"package __same;"));
assert(has(readfile(strings.concat(warmwork,
@@ -1038,14 +1094,17 @@ fn workescape(s: str) str = {
externalbin, strings.concat(root, "/order-external.status"),
"--ww-package-test", "same", "pkg", pkg,
samebin, strings.concat(root, "/order-same.status"), pkg];
let cordertracebefore: str = strings.dup(readfile(compilertrace));
let corderlinkbefore: str = strings.dup(readfile(linkertrace));
runcommandenv(root, "variant-order-reversed", orderav, traceenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let ordertrace: str = readfile(compilertrace);
let coldcounts: []i32 = [occurrences(ordertrace, "/pkg.unit.new"),
occurrences(ordertrace, "/pkg-internal-test.unit.new"),
occurrences(ordertrace, "/pkg_test-external-test.unit.new")];
assert(coldcounts[0] == 2 && coldcounts[1] == 2 && coldcounts[2] == 2);
let cordertraceafter: str = strings.dup(readfile(compilertrace));
let corderlinkafter: str = strings.dup(readfile(linkertrace));
let creversedtrace: str = strings.dup(strings.sub(cordertraceafter,
cordertracebefore.len, cordertraceafter.len));
let creversedlink: str = strings.dup(strings.sub(corderlinkafter,
corderlinkbefore.len, corderlinkafter.len));
let orderworkdir: str = strings.concat(orderwork, "/");
let orderactions: []str = ["pkg", "pkg-internal-test",
"pkg_test-external-test", "pkg-internal-test-main",
@@ -1062,6 +1121,30 @@ fn workescape(s: str) str = {
};
oi += 1;
};
clean(orderwork);
assert(os.mkdir(orderwork, 448i32) == 0);
let orderforwardav: []str = [driver("ww"), "test", "-c", "-w",
orderwork, "-I", root,
"--ww-package-test", "same", "pkg", pkg,
samebin, strings.concat(root, "/order-same.status"),
"--ww-package-test", "external", "pkg_test", pkg,
externalbin, strings.concat(root, "/order-external.status"), pkg];
let cforwardtracebefore: str = strings.dup(readfile(compilertrace));
let cforwardlinkbefore: str = strings.dup(readfile(linkertrace));
runcommandenv(root, "variant-order-forward", orderforwardav, traceenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let cforwardtraceafter: str = strings.dup(readfile(compilertrace));
let cforwardlinkafter: str = strings.dup(readfile(linkertrace));
assert(same(creversedtrace, strings.sub(cforwardtraceafter,
cforwardtracebefore.len, cforwardtraceafter.len)));
assert(same(creversedlink, strings.sub(cforwardlinkafter,
cforwardlinkbefore.len, cforwardlinkafter.len)));
let ordertrace: str = readfile(compilertrace);
let coldcounts: []i32 = [occurrences(ordertrace, "/pkg.unit.new"),
occurrences(ordertrace, "/pkg-internal-test.unit.new"),
occurrences(ordertrace, "/pkg_test-external-test.unit.new")];
assert(coldcounts[0] == 3 && coldcounts[1] == 3 && coldcounts[2] == 3);
let orderwwwork: str = strings.concat(root, "/order-ww-work");
let orderwwsame: str = strings.concat(root, "/order-ww-same.test");
let orderwwexternal: str = strings.concat(root, "/order-ww-external.test");
@@ -1072,9 +1155,36 @@ fn workescape(s: str) str = {
orderwwexternal, strings.concat(root, "/order-ww-external.status"),
"--ww-package-test", "same", "pkg", pkg,
orderwwsame, strings.concat(root, "/order-ww-same.status"), pkg];
runcommand(root, "variant-order-reversed-ww", orderwwav,
let wordertracebefore: str = strings.dup(readfile(compilertrace));
let worderlinkbefore: str = strings.dup(readfile(linkertrace));
runcommandenv(root, "variant-order-reversed-ww", orderwwav, wwtraceenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let wordertraceafter: str = strings.dup(readfile(compilertrace));
let worderlinkafter: str = strings.dup(readfile(linkertrace));
let wreversedtrace: str = strings.dup(strings.sub(wordertraceafter,
wordertracebefore.len, wordertraceafter.len));
let wreversedlink: str = strings.dup(strings.sub(worderlinkafter,
worderlinkbefore.len, worderlinkafter.len));
clean(orderwwwork);
assert(os.mkdir(orderwwwork, 448i32) == 0);
let orderwwforward: []str = [driver("ww_ww"), "test", "-c", "-w",
orderwwwork, "-I", root,
"--ww-package-test", "same", "pkg", pkg,
orderwwsame, strings.concat(root, "/order-ww-same.status"),
"--ww-package-test", "external", "pkg_test", pkg,
orderwwexternal, strings.concat(root, "/order-ww-external.status"), pkg];
let wforwardtracebefore: str = strings.dup(readfile(compilertrace));
let wforwardlinkbefore: str = strings.dup(readfile(linkertrace));
runcommandenv(root, "variant-order-forward-ww", orderwwforward, wwtraceenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let wforwardtraceafter: str = strings.dup(readfile(compilertrace));
let wforwardlinkafter: str = strings.dup(readfile(linkertrace));
assert(same(wreversedtrace, strings.sub(wforwardtraceafter,
wforwardtracebefore.len, wforwardtraceafter.len)));
assert(same(wreversedlink, strings.sub(wforwardlinkafter,
wforwardlinkbefore.len, wforwardlinkafter.len)));
oi = 0;
for (oi < orderactions.len) {
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
@@ -1087,6 +1197,11 @@ fn workescape(s: str) str = {
};
oi += 1;
};
let tracedorders: str = readfile(compilertrace);
coldcounts[0] = occurrences(tracedorders, "/pkg.unit.new");
coldcounts[1] = occurrences(tracedorders, "/pkg-internal-test.unit.new");
coldcounts[2] = occurrences(tracedorders,
"/pkg_test-external-test.unit.new");
runcommandenv(root, "variant-warm-reuse", warmav, traceenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
@@ -1611,13 +1726,15 @@ fn workescape(s: str) str = {
let warmparallel: []str = [driver("ww"), "test", "-j", "4", "-w",
warmroot, "-I", suite, "-I", root,
strings.concat(suite, "/...")];
runcommandenv(root, "multidir-warm-reuse", warmparallel, traceenv,
let warmequivalentc: []str = [driver("ww"), "test", "-j", "4", "-w",
warmroot, "-I", suite, "-I", root,
strings.concat(suite, "/./...")];
runcommandenv(root, "multidir-warm-reuse", warmequivalentc, 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 warmkey: str = strings.concat("/d_", workescape(suite), "_p_alpha/");
let warmkey: str = strings.concat("/d_", workescape(suite), "/");
let warmwork: str = strings.concat(warmroot, warmkey);
assert(os.exists(strings.concat(warmwork,
"alpha-internal-test.unit.ww")));
@@ -1632,10 +1749,12 @@ fn workescape(s: str) str = {
assert(same(warmstdout, out.stdout));
assert(same(warmstderr, out.stderr));
let warmwwtrace: str = strings.dup(readfile(wwcompilertrace));
runcommandenv(root, "multidir-warm-ww-reuse", warmww, wwtraceenv,
let warmwwequivalent: []str = [wwtracedriver, "test", "-j", "4", "-w",
warmwwroot, "-I", suite, "-I", root,
strings.concat(suite, "/./...")];
runcommandenv(root, "multidir-warm-ww-reuse", warmwwequivalent, wwtraceenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(warmstdout, out.stdout));
assert(same(warmstderr, out.stderr));
assert(same(warmwwtrace, readfile(wwcompilertrace)));
let warmwwwork: str = strings.concat(warmwwroot, warmkey);
@@ -1719,6 +1838,78 @@ fn workescape(s: str) str = {
wwtraceenv, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(wafterchange, readfile(wwcompilertrace)));
// Exercise the inverse discovery order explicitly. aaroot is selected and
// loaded before zimporter, which later imports it; gamma above is first
// discovered through beta and only later visited as a selected root. Both
// orders must compile one production action, and a root-only build must emit
// byte-identical owner unit, export, and archive.
let aaroot: str = strings.concat(root, "/aaroot");
let zimporter: str = strings.concat(root, "/zimporter");
assert(os.mkdir(aaroot, 448i32) == 0);
assert(os.mkdir(zimporter, 448i32) == 0);
writefile(strings.concat(aaroot, "/aaroot.ww"), strings.concat(
"package aaroot;\n// ROOT_FIRST_OWNER\n",
"export fn value() i32 = { return 42; };\n"));
writefile(strings.concat(zimporter, "/zimporter.ww"), strings.concat(
"package zimporter;\nimport aaroot;\n",
"export fn value() i32 = { return aaroot.value(); };\n"));
let rootrefs: []str = ["", "", ""];
let rootstages: []str = ["ww", "ww_ww"];
let rsi: i32 = 0;
for (rsi < rootstages.len) {
let uniondriver: str = driver(rootstages[rsi]);
if (rsi == 1) { uniondriver = wwtracedriver; };
let rootout: str = strings.concat(root, "/root-only-",
rootstages[rsi], ".a");
let rootav: []str = [driver(rootstages[rsi]), "build", "-p",
"-I", root, "-o", rootout, aaroot];
runcommand(root, strings.concat("root-only-", rootstages[rsi]), rootav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let rootwork: str = strings.concat(rootout, ".sepwork/");
let depbin: str = strings.concat(root, "/root-first-",
rootstages[rsi], "-dep.test");
let userbin: str = strings.concat(root, "/root-first-",
rootstages[rsi], "-user.test");
let unionav: []str = [uniondriver, "test", "-c",
"-I", root,
"--ww-package-test", "production", "aaroot", aaroot, depbin,
strings.concat(root, "/root-first-", rootstages[rsi],
"-dep.status"),
"--ww-package-test", "production", "zimporter", zimporter,
userbin, strings.concat(root, "/root-first-", rootstages[rsi],
"-user.status"), aaroot];
let beforetrace: str = "";
if (rsi == 0) { beforetrace = strings.dup(readfile(compilertrace)); }
else { beforetrace = strings.dup(readfile(wwcompilertrace)); };
if (rsi == 0) {
runcommandenv(root, "root-first-c", unionav, traceenv,
(120i64 * (time.second: i64)): time.duration, &out);
} else {
runcommandenv(root, "root-first-ww", unionav, wwtraceenv,
(120i64 * (time.second: i64)): time.duration, &out);
};
expectexit(&out, 0);
let aftertrace: str = "";
if (rsi == 0) { aftertrace = strings.dup(readfile(compilertrace)); }
else { aftertrace = strings.dup(readfile(wwcompilertrace)); };
assert(occurrences(aftertrace, "/aaroot.unit.ww")
== occurrences(beforetrace, "/aaroot.unit.ww") + 1);
let unionwork: str = strings.concat(depbin, ".sepwork/");
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
let xi: i32 = 0;
for (xi < suffixes.len) {
let rootbytes: str = readfile(strings.concat(rootwork, "aaroot",
suffixes[xi]));
assert(same(rootbytes, readfile(strings.concat(unionwork, "aaroot",
suffixes[xi]))));
if (rsi == 0) { rootrefs[xi] = strings.dup(rootbytes); }
else { assert(same(rootrefs[xi], rootbytes)); };
xi += 1;
};
rsi += 1;
};
clean(wwtracebin);
clean(root);
};
@@ -1754,6 +1945,34 @@ fn workescape(s: str) str = {
"package good;\nfn value() i32 = { return 42; };\n");
writefile(strings.concat(good, "/good_test.ww"),
"package good;\n@test fn unrelated_runs() void = { assert(value() == 42); };\n");
let tooltrace: str = strings.concat(root, "/context-tool.trace");
let compilerwrapper: str = strings.concat(root, "/context-w6c.sh");
let linkerwrapper: str = strings.concat(root, "/context-w6l.sh");
writefile(tooltrace, "");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\nprintf 'compile\\n' >> \"$WW_CONTEXT_TRACE\"\n",
"exec \"$WW_CONTEXT_W6C\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\nprintf 'link\\n' >> \"$WW_CONTEXT_TRACE\"\n",
"exec \"$WW_CONTEXT_W6L\" \"$@\"\n"));
let baseenv: []str = os.getenvs();
let traceenv: []str = alloc([], (baseenv.len + 5): 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_CONTEXT_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_CONTEXT_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_CONTEXT_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_CONTEXT_TRACE=", tooltrace));
append(traceenv, strings.concat("WW_CONTEXT_W6C=", driver("w6c")));
append(traceenv, strings.concat("WW_CONTEXT_W6L=", driver("w6l")));
let stages: []str = ["ww", "ww_ww"];
let jobs: []str = ["1", "4"];
let diagnostics: []str = ["", ""];
@@ -1763,8 +1982,29 @@ fn workescape(s: str) str = {
for (i < stages.len) {
let av: []str = [driver(stages[i]), "test", "-j", jobs[i],
"-I", root, strings.concat(suite, "/...")];
runcommand(root, strings.concat("context-conflict-", stages[i]), av,
(120i64 * (time.second: i64)): time.duration, &out);
let stageenv: []str = traceenv;
if (i == 1) {
let wwenv: []str = alloc([], (baseenv.len + 5): u64)!;
stageenv = wwenv;
ei = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_W6L=")
&& !strings.hasprefix(baseenv[ei], "WW_CONTEXT_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_CONTEXT_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_CONTEXT_W6L=")) {
append(stageenv, baseenv[ei]);
};
ei += 1;
};
append(stageenv, strings.concat("WW_W6C=", compilerwrapper));
append(stageenv, strings.concat("WW_W6L=", linkerwrapper));
append(stageenv, strings.concat("WW_CONTEXT_TRACE=", tooltrace));
append(stageenv, strings.concat("WW_CONTEXT_W6C=", driver("w6c_ww")));
append(stageenv, strings.concat("WW_CONTEXT_W6L=", driver("w6l_ww")));
};
runcommandenv(root, strings.concat("context-conflict-", stages[i]), av,
stageenv, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, strings.concat(
"ww: package _leaf resolves to directories ", aleaf,
@@ -1782,14 +2022,15 @@ fn workescape(s: str) str = {
i += 1;
};
assert(same(diagnostics[0], diagnostics[1]));
assert(readfile(tooltrace).len == 0);
clean(root);
};
@test fn mixed_named_test_and_toolchain_test_actions_do_not_collide() void = {
let root: str = fresh();
let suite: str = strings.concat(root, "/suite");
let named: str = strings.concat(suite, "/a_named");
let consumer: str = strings.concat(suite, "/b_consumer");
let named: str = strings.concat(suite, "/test");
let consumer: str = strings.concat(suite, "/zconsumer");
assert(os.mkdir(suite, 448i32) == 0);
assert(os.mkdir(named, 448i32) == 0);
assert(os.mkdir(consumer, 448i32) == 0);
@@ -1805,16 +2046,16 @@ fn workescape(s: str) str = {
"@test fn named_external_runs() void = {",
" assert(test.value() == 42); };\n"));
writefile(strings.concat(consumer, "/consumer.ww"), strings.concat(
"package consumer;\n",
"package zconsumer;\n",
"// MIXED_GENERATED_TOOLCHAIN_TEST_SUPPORT\n",
"export fn value() i32 = { return 42; };\n"));
writefile(strings.concat(consumer, "/same_test.ww"), strings.concat(
"package consumer;\n@test fn consumer_same_runs() void = {",
"package zconsumer;\n@test fn consumer_same_runs() void = {",
" assert(value() == 42); };\n"));
writefile(strings.concat(consumer, "/external_test.ww"), strings.concat(
"package consumer_test;\nimport consumer;\n",
"package zconsumer_test;\nimport zconsumer;\n",
"@test fn consumer_external_runs() void = {",
" assert(consumer.value() == 42); };\n"));
" assert(zconsumer.value() == 42); };\n"));
let linktrace: str = strings.concat(root, "/mixed-link.trace");
let linkwrapper: str = strings.concat(root, "/mixed-w6l.sh");
writefile(linktrace, "");
@@ -1837,10 +2078,10 @@ fn workescape(s: str) str = {
append(linkenv, strings.concat("WW_MIXED_W6L=", driver("w6l")));
let bins: []str = [strings.concat(named, "/test.test"),
strings.concat(named, "/test_test.test"),
strings.concat(consumer, "/consumer.test"),
strings.concat(consumer, "/consumer_test.test")];
strings.concat(consumer, "/zconsumer.test"),
strings.concat(consumer, "/zconsumer_test.test")];
let keys: []str = ["test-internal-test", "test_test-external-test",
"consumer-internal-test", "consumer_test-external-test"];
"zconsumer-internal-test", "zconsumer_test-external-test"];
let expected: []str = ["named_same_runs ... ok\n",
"named_external_runs ... ok\n", "consumer_same_runs ... ok\n",
"consumer_external_runs ... ok\n"];
@@ -1981,7 +2222,8 @@ fn workescape(s: str) str = {
let bin: str = strings.concat(target, "/target.test");
let workroot: str = strings.concat(bin, ".sepwork");
let work: str = strings.concat(workroot, "/");
let cargv: []str = [driver("ww"), "test", "-c", "-I", root, target];
let cargv: []str = [driver("ww"), "test", "-c", "-I", d3,
"-I", root, target];
let out: commandout;
runcommandenv(root, "long-link-c", cargv, env,
(120i64 * (time.second: i64)): time.duration, &out);
@@ -2010,7 +2252,8 @@ fn workescape(s: str) str = {
expectexit(&out, 0);
assert(has(out.stdout, "complete_long_closure ... ok\n"));
clean(workroot); clean(bin);
let wargv: []str = [driver("ww_ww"), "test", "-c", "-I", root, target];
let wargv: []str = [driver("ww_ww"), "test", "-c", "-I", d3,
"-I", root, target];
runcommand(root, "long-link-ww", wargv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
@@ -2307,8 +2550,8 @@ fn workescape(s: str) str = {
let out: commandout;
let i: i32 = 0;
for (i < stages.len) {
let av: []str = [driver(stages[i]), "test", "-c", "-o", bin,
pkg];
let av: []str = [driver(stages[i]), "test", "-c", "-I", root,
"-o", bin, pkg];
runcommand(root, strings.concat("named-test-build-", stages[i]), av,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
@@ -2366,7 +2609,7 @@ fn workescape(s: str) str = {
let base: str = strings.concat(source, "/ww_root_parity_base_7f3");
let left: str = strings.concat(source, "/ww_root_parity_left_7f3");
let right: str = strings.concat(source, "/ww_root_parity_right_7f3");
let target: str = strings.concat(source, "/ww_root_parity_target_7f3");
let target: str = strings.concat(source, "/main");
let tools: str = strings.concat(root, "/tool wrappers");
assert(os.mkdir(source, 448i32) == 0);
assert(os.mkdir(runtime, 448i32) == 0);
@@ -2700,25 +2943,19 @@ fn workescape(s: str) str = {
let right: str = strings.concat(root, "/right");
let conflict: str = strings.concat(root, "/conflict");
let privatepkg: str = strings.concat(root, "/privatepkg");
let exportroot: str = strings.concat(root, "/exportroot");
let exportdep: str = strings.concat(root, "/dupexport");
let identityroot: str = strings.concat(root, "/identityroot");
let identityactual: str = strings.concat(root, "/identityactual");
let identityalias: str = strings.concat(root, "/identityalias");
let dupleft: str = strings.concat(root, "/dupleft");
let dupright: str = strings.concat(root, "/dupright");
let reserved: str = strings.concat(root, "/reservedprobe");
assert(os.mkdir(missing, 448i32) == 0);
assert(os.mkdir(cycle, 448i32) == 0);
assert(os.mkdir(left, 448i32) == 0);
assert(os.mkdir(right, 448i32) == 0);
assert(os.mkdir(conflict, 448i32) == 0);
assert(os.mkdir(privatepkg, 448i32) == 0);
assert(os.mkdir(exportroot, 448i32) == 0);
assert(os.mkdir(exportdep, 448i32) == 0);
assert(os.mkdir(identityroot, 448i32) == 0);
assert(os.mkdir(identityactual, 448i32) == 0);
assert(os.mkdir(dupleft, 448i32) == 0);
assert(os.mkdir(dupright, 448i32) == 0);
assert(os.mkdir(reserved, 448i32) == 0);
writefile(strings.concat(missing, "/missing.ww"),
"package missing;\nfn local() void = { };\n");
writefile(strings.concat(missing, "/missing_test.ww"), strings.concat(
@@ -2747,11 +2984,6 @@ fn workescape(s: str) str = {
writefile(strings.concat(privatepkg, "/external_test.ww"), strings.concat(
"package privatepkg_test;\nimport privatepkg;\n",
"@test fn private_use() void = { assert(privatepkg.hidden() == 2); };\n"));
writefile(strings.concat(exportroot, "/exportroot.ww"), strings.concat(
"package dupexport;\nimport dupexport;\n",
"export fn value() i32 = { return dupexport.value(); };\n"));
writefile(strings.concat(exportdep, "/dupexport.ww"),
"package dupexport;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(identityactual, "/identityactual.ww"),
"package identityactual;\nexport fn value() i32 = { return 1; };\n");
let linkout: commandout;
@@ -2761,16 +2993,9 @@ fn workescape(s: str) str = {
writefile(strings.concat(identityroot, "/identityroot.ww"), strings.concat(
"package identityroot;\nimport identityactual;\n",
"import identityalias;\nexport fn value() i32 = { return 1; };\n"));
writefile(strings.concat(dupleft, "/dupproduct.ww"),
"package dupproduct;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(dupleft, "/external_test.ww"), strings.concat(
"package dupproduct_test;\nimport dupproduct;\n",
"@test fn left() void = { assert(dupproduct.value() == 1); };\n"));
writefile(strings.concat(dupright, "/dupproduct.ww"),
"package dupproduct;\nexport fn value() i32 = { return 2; };\n");
writefile(strings.concat(dupright, "/external_test.ww"), strings.concat(
"package dupproduct_test;\nimport dupproduct;\n",
"@test fn right() void = { assert(dupproduct.value() == 2); };\n"));
writefile(strings.concat(reserved, "/reservedprobe.ww"), strings.concat(
"package reservedprobe;\nimport __wwlocal.fake;\n",
"export fn value() i32 = { return 1; };\n"));
rejectpackagestable(root, "missing", missing,
"cannot find package nowhere");
rejectpackagestable(root, "cycle", cycle, "ww: dependency cycle:");
@@ -2778,7 +3003,6 @@ fn workescape(s: str) str = {
"conflicting package names conflict and other");
rejectpackagestable(root, "private", privatepkg,
"package 'privatepkg' has no exported declaration 'hidden'");
let exportdiagnostics: []str = ["", ""];
let stages: []str = ["ww", "ww_ww"];
let tooltrace: str = strings.concat(root, "/identity-tool.trace");
let compilerwrapper: str = strings.concat(root, "/identity-w6c.sh");
@@ -2810,21 +3034,6 @@ fn workescape(s: str) str = {
append(traceenv, strings.concat("WW_IDENTITY_W6L=", driver("w6l")));
let out: commandout;
let i: i32 = 0;
for (i < stages.len) {
let av: []str = [driver(stages[i]), "build", "-p", "-I", root,
"-o", strings.concat(root, "/bad-export-", stages[i], ".a"),
exportroot];
runcommandenv(root,
strings.concat("duplicate-export-module-", stages[i]),
av, traceenv, (60i64 * (time.second: i64)): time.duration, &out);
assert(out.termination == exec.termination.EXIT && out.code != 0);
assert(has(out.stderr, strings.concat(
"ww: package dupexport resolves to directories ", exportdep,
" and ", exportroot, "\n")));
exportdiagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
i += 1;
};
assert(same(exportdiagnostics[0], exportdiagnostics[1]));
let identitydiagnostics: []str = ["", ""];
i = 0;
for (i < stages.len) {
@@ -2842,29 +3051,24 @@ fn workescape(s: str) str = {
i += 1;
};
assert(same(identitydiagnostics[0], identitydiagnostics[1]));
let productdiagnostics: []str = ["", ""];
// A canonical directory acquiring two import identities rejects before
// compiler or linker invocation. The converse is covered by the shared
// multi-context resolution test above.
assert(readfile(tooltrace).len == 0);
let reserveddiagnostics: []str = ["", ""];
i = 0;
for (i < stages.len) {
let av: []str = [driver(stages[i]), "test", "-c", "-I", root,
"--ww-package-test", "external", "dupproduct_test", dupright,
strings.concat(root, "/dup-right-", stages[i], ".test"),
strings.concat(root, "/dup-right-", stages[i], ".status"),
"--ww-package-test", "external", "dupproduct_test", dupleft,
strings.concat(root, "/dup-left-", stages[i], ".test"),
strings.concat(root, "/dup-left-", stages[i], ".status"), root];
runcommandenv(root, strings.concat("duplicate-product-identity-",
stages[i]), av, traceenv,
(60i64 * (time.second: i64)): time.duration, &out);
let av: []str = [driver(stages[i]), "build", "-p", "-I", root,
"-o", strings.concat(root, "/bad-reserved-", stages[i], ".a"),
reserved];
runcommandenv(root, strings.concat("reserved-local-import-", stages[i]),
av, traceenv, (60i64 * (time.second: i64)): time.duration, &out);
assert(out.termination == exec.termination.EXIT && out.code != 0);
assert(has(out.stderr, strings.concat(
"ww: package dupproduct resolves to directories ", dupleft,
" and ", dupright, "\n")));
productdiagnostics[i] = strings.dup(out.stderr);
assert(has(out.stderr, "package path __wwlocal.fake is reserved"));
reserveddiagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
i += 1;
};
assert(same(productdiagnostics[0], productdiagnostics[1]));
// Both identity directions reject while the command-global package
// universe is still unambiguous, before compiler or linker invocation.
assert(same(reserveddiagnostics[0], reserveddiagnostics[1]));
assert(readfile(tooltrace).len == 0);
clean(root);
};
@@ -3070,22 +3274,28 @@ fn workescape(s: str) str = {
@test fn persistent_package_request_workdir_is_stable() void = {
let root: str = fresh();
let tree: str = strings.concat(root, "/tree");
let a: str = strings.concat(tree, "/a");
let ab: str = strings.concat(tree, "/a_b");
let work: str = strings.concat(root, "/work");
let adir: str = strings.concat(tree, "/a");
let bdir: str = strings.concat(tree, "/b");
let a: str = strings.concat(adir, "/foo");
let b: str = strings.concat(bdir, "/foo");
let workc: str = strings.concat(root, "/work-c");
let workww: str = strings.concat(root, "/work-ww");
assert(os.mkdir(tree, 448i32) == 0);
assert(os.mkdir(adir, 448i32) == 0);
assert(os.mkdir(bdir, 448i32) == 0);
assert(os.mkdir(a, 448i32) == 0);
assert(os.mkdir(ab, 448i32) == 0);
assert(os.mkdir(work, 448i32) == 0);
writefile(strings.concat(a, "/a.ww"),
"package b_c;\nfn value() i32 = { return 1; };\n");
writefile(strings.concat(a, "/a_test.ww"),
"package b_c;\n@test fn first() void = { assert(value() == 1); };\n");
writefile(strings.concat(ab, "/ab.ww"),
"package c;\nfn value() i32 = { return 2; };\n");
writefile(strings.concat(ab, "/ab_test.ww"),
"package c;\n@test fn second() void = { assert(value() == 2); };\n");
let av: []str = [driver("ww"), "test", "-j", "2", "-w", work,
assert(os.mkdir(b, 448i32) == 0);
assert(os.mkdir(workc, 448i32) == 0);
assert(os.mkdir(workww, 448i32) == 0);
writefile(strings.concat(a, "/foo.ww"),
"package foo;\nfn value() i32 = { return 1; };\n");
writefile(strings.concat(a, "/foo_test.ww"),
"package foo;\n@test fn first() void = { assert(value() == 1); };\n");
writefile(strings.concat(b, "/foo.ww"),
"package foo;\nfn value() i32 = { return 2; };\n");
writefile(strings.concat(b, "/foo_test.ww"),
"package foo;\n@test fn second() void = { assert(value() == 2); };\n");
let av: []str = [driver("ww"), "test", "-j", "2", "-w", workc,
strings.concat(tree, "/...")];
let out: commandout;
runcommand(root, "workkey-cold", av,
@@ -3093,18 +3303,110 @@ fn workescape(s: str) str = {
expectexit(&out, 0);
let cold: str = strings.dup(out.stdout);
assert(has(cold, strings.concat("ok ", a,
" [b_c, same-package]\n")));
assert(has(cold, strings.concat("ok ", ab,
" [c, same-package]\n")));
let key: str = strings.concat(work, "/d_", workescape(tree), "_p_",
workescape("b_c"));
assert(os.exists(key));
assert(os.exists(strings.concat(key, "/b_c-internal-test.unit.ww")));
assert(os.exists(strings.concat(key, "/c-internal-test.unit.ww")));
" [foo, same-package]\n")));
assert(has(cold, strings.concat("ok ", b,
" [foo, same-package]\n")));
let ckey: str = strings.concat(workc, "/d_", workescape(tree));
assert(os.exists(ckey));
let aaction: str = "a.foo-internal-test";
let baction: str = "b.foo-internal-test";
assert(os.exists(strings.concat(ckey, "/", aaction, ".unit.ww")));
assert(os.exists(strings.concat(ckey, "/", baction, ".unit.ww")));
let aunit: str = readfile(strings.concat(ckey, "/", aaction, ".unit.ww"));
let bunit: str = readfile(strings.concat(ckey, "/", baction, ".unit.ww"));
let awwi: str = readfile(strings.concat(ckey, "/", aaction, ".wwi"));
let bwwi: str = readfile(strings.concat(ckey, "/", baction, ".wwi"));
let aa: str = readfile(strings.concat(ckey, "/", aaction, ".a"));
let ba: str = readfile(strings.concat(ckey, "/", baction, ".a"));
assert(has(aunit, "return 1") && !has(aunit, "return 2"));
assert(has(bunit, "return 2") && !has(bunit, "return 1"));
runcommand(root, "workkey-warm", av,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(cold, out.stdout));
let wwav: []str = [driver("ww_ww"), "test", "-j", "1", "-w", workww,
strings.concat(tree, "/...")];
runcommand(root, "workkey-ww", wwav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(cold, out.stdout));
let wwkey: str = strings.concat(workww, "/d_", workescape(tree));
assert(same(aunit, readfile(strings.concat(wwkey, "/", aaction,
".unit.ww"))));
assert(same(bunit, readfile(strings.concat(wwkey, "/", baction,
".unit.ww"))));
assert(same(awwi, readfile(strings.concat(wwkey, "/", aaction, ".wwi"))));
assert(same(bwwi, readfile(strings.concat(wwkey, "/", baction, ".wwi"))));
assert(same(aa, readfile(strings.concat(wwkey, "/", aaction, ".a"))));
assert(same(ba, readfile(strings.concat(wwkey, "/", baction, ".a"))));
// The canonical coordinator key and warm action set are unchanged by an
// equivalent recursive-root spelling.
let equivalentav: []str = [driver("ww_ww"), "test", "-j", "2", "-w",
workww, strings.concat(tree, "/./...")];
runcommand(root, "workkey-equivalent", equivalentav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, strings.concat("ok ", tree,
"/./a/foo [foo, same-package]\n")));
assert(has(out.stdout, strings.concat("ok ", tree,
"/./b/foo [foo, same-package]\n")));
assert(os.exists(wwkey));
assert(same(aunit, readfile(strings.concat(wwkey, "/", aaction,
".unit.ww"))));
assert(same(bunit, readfile(strings.concat(wwkey, "/", baction,
".unit.ww"))));
assert(same(awwi, readfile(strings.concat(wwkey, "/", aaction, ".wwi"))));
assert(same(bwwi, readfile(strings.concat(wwkey, "/", baction, ".wwi"))));
assert(same(aa, readfile(strings.concat(wwkey, "/", aaction, ".a"))));
assert(same(ba, readfile(strings.concat(wwkey, "/", baction, ".a"))));
// Outside every active import root, equal declaration leaves remain two
// deterministic command-local identities derived from canonical dirs.
let localleft: str = strings.concat(root, "/local-left");
let localright: str = strings.concat(root, "/local-right");
assert(os.mkdir(localleft, 448i32) == 0);
assert(os.mkdir(localright, 448i32) == 0);
writefile(strings.concat(localleft, "/foo.ww"),
"package foo;\nexport fn value() i32 = { return 11; };\n");
writefile(strings.concat(localright, "/foo.ww"),
"package foo;\nexport fn value() i32 = { return 22; };\n");
let localids: []str = [localidentity(localleft, "foo"),
localidentity(localright, "foo")];
assert(!same(localids[0], localids[1]));
let stages: []str = ["ww", "ww_ww"];
let localrefs: []str = ["", "", "", "", "", ""];
let si: i32 = 0;
for (si < stages.len) {
let leftout: str = strings.concat(root, "/local-", stages[si],
"-left.test");
let rightout: str = strings.concat(root, "/local-", stages[si],
"-right.test");
let lav: []str = [driver(stages[si]), "test", "-c",
"--ww-package-test", "production", "foo", localleft, leftout,
strings.concat(root, "/local-", stages[si], "-left.status"),
"--ww-package-test", "production", "foo", localright, rightout,
strings.concat(root, "/local-", stages[si], "-right.status"),
localleft];
runcommand(root, strings.concat("local-command-union-", stages[si]),
lav, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let localwork: str = strings.concat(leftout, ".sepwork/");
let li: i32 = 0;
for (li < localids.len) {
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
let xi: i32 = 0;
for (xi < suffixes.len) {
let artifact: str = readfile(strings.concat(localwork,
localids[li], suffixes[xi]));
let refi: i32 = li * 3 + xi;
if (si == 0) { localrefs[refi] = strings.dup(artifact); }
else { assert(same(localrefs[refi], artifact)); };
xi += 1;
};
li += 1;
};
si += 1;
};
clean(root);
};
@@ -3414,8 +3716,8 @@ fn runtimepath(relative: str) str = {
for (i < 2) {
let named: str = strings.concat(outdir, "/out_", drvs[i],
".bin");
let coav: []str = [driver(drvs[i]), "test", "-c", "-o",
named, pdir];
let coav: []str = [driver(drvs[i]), "test", "-c", "-I", root,
"-o", named, pdir];
runcommand(root, strings.concat("nameco_", drvs[i]), coav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
@@ -3434,8 +3736,8 @@ fn runtimepath(relative: str) str = {
expectexit(&out, 0);
assert(has(out.stdout, "seven ... ok"));
let nocav: []str = [driver(drvs[i]), "test", "-o", named,
pdir];
let nocav: []str = [driver(drvs[i]), "test", "-I", root,
"-o", named, pdir];
runcommand(root, strings.concat("noc_", drvs[i]), nocav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 2);