test: cover exact package tool invocation paths

This commit is contained in:
2026-08-12 14:29:17 +09:00
parent d78020baf7
commit bb71b31f81
6 changed files with 321 additions and 31 deletions

View File

@@ -1110,10 +1110,9 @@ 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")));
// The WW driver intentionally takes sibling tools rather than WW_W6C
// overrides. Run an exact copied driver beside narrow tracing wrappers so
// its real compiler/linker actions are observable without changing that
// production contract.
// Exercise default sibling discovery independently of the exact-path
// override contract covered below: the copied driver sits beside narrow
// tracing wrappers for its real compiler and linker actions.
let wwtracebin: str = strings.concat(repo(), "/out/package-trace-",
workescape(root));
assert(os.mkdir(wwtracebin, 448i32) == 0);
@@ -2143,7 +2142,8 @@ fn workescape(s: str) str = {
let trace: str = strings.concat(root, "/compiler.trace");
let wrapper: str = strings.concat(root, "/trace-w6c.sh");
writefile(trace, "");
writefile(wrapper, strings.concat(
writeexecutable(wrapper, strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_TRACE\"\n",
"exec \"$WW_PACKAGE_W6C\" \"$@\"\n"));
let baseenv: []str = os.getenvs();
@@ -2157,7 +2157,7 @@ fn workescape(s: str) str = {
};
ei += 1;
};
append(env, strings.concat("WW_W6C=/bin/sh ", wrapper));
append(env, strings.concat("WW_W6C=", wrapper));
append(env, strings.concat("WW_PACKAGE_TRACE=", trace));
append(env, strings.concat("WW_PACKAGE_W6C=", driver("w6c")));
let bin: str = strings.concat(root, "/diamond.test");
@@ -2187,6 +2187,245 @@ fn workescape(s: str) str = {
clean(root);
};
@test fn exact_package_tool_argv_stage_parity() void = {
let root: str = fresh();
let source: str = strings.concat(root, "/source tree");
let leaf: str = strings.concat(source, "/leaf");
let dep: str = strings.concat(source, "/dep");
let target: str = strings.concat(source, "/target");
let tools: str = strings.concat(root, "/tool wrappers");
assert(os.mkdir(source, 448i32) == 0);
assert(os.mkdir(leaf, 448i32) == 0);
assert(os.mkdir(dep, 448i32) == 0);
assert(os.mkdir(target, 448i32) == 0);
assert(os.mkdir(tools, 448i32) == 0);
writefile(strings.concat(leaf, "/leaf.ww"), strings.concat(
"package leaf;\n",
"export fn value() i32 = { return 40; };\n"));
writefile(strings.concat(dep, "/dep.ww"), strings.concat(
"package dep;\nimport leaf;\n",
"export fn value() i32 = { return leaf.value() + 2; };\n"));
writefile(strings.concat(target, "/target.ww"), strings.concat(
"package target;\nimport dep;\n",
"fn value() i32 = { return dep.value(); };\n"));
writefile(strings.concat(target, "/target_test.ww"), strings.concat(
"package target;\n",
"@test fn exact_argv() void = { assert(value() == 42); };\n"));
let compilerwrapper: str = strings.concat(tools, "/w6c wrapper.sh");
let assemblerwrapper: str = strings.concat(tools, "/w6a wrapper.sh");
let linkerwrapper: str = strings.concat(tools, "/w6l wrapper.sh");
let failurewrapper: str = strings.concat(tools, "/failing w6c wrapper.sh");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\n",
"printf 'BEGIN' >> \"$WW_ARGV_COMPILER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_ARGV_COMPILER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_ARGV_COMPILER_TRACE\"\n",
"exec \"$WW_ARGV_REAL_COMPILER\" \"$@\"\n"));
writeexecutable(assemblerwrapper, strings.concat(
"#!/bin/sh\n",
"printf 'BEGIN' >> \"$WW_ARGV_ASSEMBLER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_ARGV_ASSEMBLER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_ARGV_ASSEMBLER_TRACE\"\n",
"exec \"$WW_ARGV_REAL_ASSEMBLER\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\n",
"printf 'BEGIN' >> \"$WW_ARGV_LINKER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_ARGV_LINKER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_ARGV_LINKER_TRACE\"\n",
"exec \"$WW_ARGV_REAL_LINKER\" \"$@\"\n"));
writeexecutable(failurewrapper, strings.concat(
"#!/bin/sh\n",
"printf 'BEGIN' >> \"$WW_ARGV_FAILURE_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_ARGV_FAILURE_TRACE\"; done\n",
"printf '\\n' >> \"$WW_ARGV_FAILURE_TRACE\"\n",
"exit 23\n"));
let stages: []str = ["ww", "ww_ww"];
let compilers: []str = ["w6c", "w6c_ww"];
let assemblers: []str = ["w6a", "w6a_ww"];
let linkers: []str = ["w6l", "w6l_ww"];
let tags: []str = ["c", "ww"];
let bin: str = strings.concat(root, "/published test binary");
let workroot: str = strings.concat(bin, ".sepwork");
let work: str = strings.concat(workroot, "/");
let referenceunit: str = "";
let referencewwi: str = "";
let referencearchive: str = "";
let referencebin: str = "";
let referencecompiler: str = "";
let referenceassembler: str = "";
let referencelinker: str = "";
let referenceout: str = "";
let referenceerr: str = "";
let referencefailure: str = "";
let baseenv: []str = os.getenvs();
let si: i32 = 0;
for (si < stages.len) {
let compilertrace: str = strings.concat(root, "/", tags[si],
" compiler trace");
let assemblertrace: str = strings.concat(root, "/", tags[si],
" assembler trace");
let linkertrace: str = strings.concat(root, "/", tags[si],
" linker trace");
let failuretrace: str = strings.concat(root, "/", tags[si],
" failure trace");
writefile(compilertrace, "");
writefile(assemblertrace, "");
writefile(linkertrace, "");
writefile(failuretrace, "");
let env: []str = alloc([], (baseenv.len + 9): u64)!;
let ei: i32 = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_W6A=")
&& !strings.hasprefix(baseenv[ei], "WW_W6L=")
&& !strings.hasprefix(baseenv[ei],
"WW_ARGV_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_ARGV_ASSEMBLER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_ARGV_LINKER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_ARGV_REAL_COMPILER=")
&& !strings.hasprefix(baseenv[ei],
"WW_ARGV_REAL_ASSEMBLER=")
&& !strings.hasprefix(baseenv[ei],
"WW_ARGV_REAL_LINKER=")) {
append(env, baseenv[ei]);
};
ei += 1;
};
append(env, strings.concat("WW_W6C=", compilerwrapper));
append(env, strings.concat("WW_W6A=", assemblerwrapper));
append(env, strings.concat("WW_W6L=", linkerwrapper));
append(env, strings.concat("WW_ARGV_COMPILER_TRACE=", compilertrace));
append(env, strings.concat("WW_ARGV_ASSEMBLER_TRACE=", assemblertrace));
append(env, strings.concat("WW_ARGV_LINKER_TRACE=", linkertrace));
append(env, strings.concat("WW_ARGV_REAL_COMPILER=",
driver(compilers[si])));
append(env, strings.concat("WW_ARGV_REAL_ASSEMBLER=",
driver(assemblers[si])));
append(env, strings.concat("WW_ARGV_REAL_LINKER=",
driver(linkers[si])));
let av: []str = [driver(stages[si]), "test", "-c", "-o", bin,
"-I", source, target];
let out: commandout;
runcommandenv(root, strings.concat("exact-argv-", tags[si]), av, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stderr.len == 0);
let rootunit: str = readfile(strings.concat(work,
"__ww-test-000-same.unit.ww"));
let depunit: str = readfile(strings.concat(work, "dep.unit.ww"));
assert(has(rootunit, "//ww:module dep\n"));
assert(!has(rootunit, "//ww:module leaf\n"));
assert(has(depunit, "//ww:module leaf\n"));
assert(os.exists(strings.concat(work, "leaf.wwi")));
assert(os.exists(strings.concat(work, "leaf.a")));
assert(os.exists(strings.concat(work, "dep.wwi")));
assert(os.exists(strings.concat(work, "dep.a")));
assert(!os.exists(strings.concat(work,
"__ww-test-000-same.wwi")));
assert(!os.exists(strings.concat(work,
"__ww-test-000-same.a")));
assert(os.exists(bin));
let ctrace: str = readfile(compilertrace);
let atrace: str = readfile(assemblertrace);
let ltrace: str = readfile(linkertrace);
assert(occurrences(ctrace, strings.concat("<", work,
"leaf.unit.ww>")) == 1);
assert(occurrences(ctrace, strings.concat("<", work,
"dep.unit.ww>")) == 1);
assert(occurrences(ctrace, strings.concat("<", work,
"__ww-test-000-same.unit.ww>")) == 1);
assert(pos(ctrace, strings.concat("<", work, "leaf.unit.ww>"))
< pos(ctrace, strings.concat("<", work, "dep.unit.ww>")));
assert(pos(ctrace, strings.concat("<", work, "dep.unit.ww>"))
< pos(ctrace, strings.concat("<", work,
"__ww-test-000-same.unit.ww>")));
assert(has(ctrace, strings.concat("BEGIN<-c><-I><", work,
"dep.wwi><-o><", work, "dep.s><", work, "dep.unit.ww>")));
assert(has(ctrace, strings.concat(
"BEGIN<-T><--test-support-module><test><-c><-o><", work,
"__ww-test-000-same.s><", work,
"__ww-test-000-same.unit.ww>")));
assert(has(atrace, strings.concat("BEGIN<-o><", work,
"dep.o><", work, "dep.s>")));
assert(occurrences(ltrace, "\n") == 1);
assert(has(ltrace, strings.concat("BEGIN<-o><", bin, "><", work,
"__ww-test-000-same.o>")));
assert(has(ltrace, strings.concat("<", work, "dep.a>")));
assert(has(ltrace, strings.concat("<", work, "leaf.a>")));
assert(has(ltrace, strings.concat("<", work, "test.a>")));
assert(!has(ltrace, ".wwi>"));
let runav: []str = [bin];
runcommand(root, strings.concat("exact-argv-run-", tags[si]), runav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "exact_argv ... ok\n"));
if (si == 0) {
referenceunit = strings.dup(rootunit);
referencewwi = strings.dup(readfile(strings.concat(work,
"dep.wwi")));
referencearchive = strings.dup(readfile(strings.concat(work,
"dep.a")));
referencebin = strings.dup(readfile(bin));
referencecompiler = strings.dup(ctrace);
referenceassembler = strings.dup(atrace);
referencelinker = strings.dup(ltrace);
referenceout = strings.dup(out.stdout);
referenceerr = strings.dup(out.stderr);
} else {
assert(same(referenceunit, rootunit));
assert(same(referencewwi,
readfile(strings.concat(work, "dep.wwi"))));
assert(same(referencearchive,
readfile(strings.concat(work, "dep.a"))));
assert(same(referencebin, readfile(bin)));
assert(same(referencecompiler, ctrace));
assert(same(referenceassembler, atrace));
assert(same(referencelinker, ltrace));
assert(same(referenceout, out.stdout));
assert(same(referenceerr, out.stderr));
};
clean(workroot);
clean(bin);
let failenv: []str = alloc([], (env.len + 2): u64)!;
ei = 0;
for (ei < env.len) {
if (!strings.hasprefix(env[ei], "WW_W6C=")
&& !strings.hasprefix(env[ei],
"WW_ARGV_FAILURE_TRACE=")) {
append(failenv, env[ei]);
};
ei += 1;
};
append(failenv, strings.concat("WW_W6C=", failurewrapper));
append(failenv, strings.concat("WW_ARGV_FAILURE_TRACE=", failuretrace));
runcommandenv(root, strings.concat("exact-argv-fail-", tags[si]), av,
failenv, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "ww: w6c failed for leaf\n"));
assert(has(readfile(failuretrace), strings.concat("<-I><", work,
"leaf.wwi>")));
if (si == 0) { referencefailure = strings.dup(out.stderr); }
else { assert(same(referencefailure, out.stderr)); };
clean(workroot);
if (os.exists(bin)) { clean(bin); };
si += 1;
};
clean(root);
};
@test fn package_graph_diagnostics_are_stable() void = {
let root: str = fresh();
let missing: str = strings.concat(root, "/missing");
@@ -2640,9 +2879,9 @@ fn runtimepath(relative: str) str = {
let ctraced: str = readfile(linktrace);
assert(has(ctraced, strings.concat(" -L ", root, " -l extra")));
// WWstage intentionally locates sibling tools. Copy the real driver beside
// a tracing linker and exact compiler/assembler siblings to inspect its
// joined native-linker flag contract.
// Keep this row on default sibling discovery: a copied driver beside a
// tracing linker and exact compiler/assembler siblings exposes WWstage's
// joined native-linker flag contract independently of tool overrides.
let tracedir: str = strings.concat(repo(), "/out/link-flag-trace-",
workescape(root));
assert(os.mkdir(tracedir, 448i32) == 0);