ww: select build action from package declaration

This commit is contained in:
2026-08-13 13:36:10 +09:00
parent 61a2ee5221
commit dab3cb4998
61 changed files with 872 additions and 157 deletions

View File

@@ -150,7 +150,7 @@ fn samefile(a: str, b: str, why: str) void = {
"late/example/foo", "late/example/foo", fooalias, fooalias];
i = 0;
for (i < rootouts.len) {
let rav: []str = [testenv.driver(rootdrivers[i]), "build", "-p",
let rav: []str = [testenv.driver(rootdrivers[i]), "build",
"-I", early, "-I", late, "-o", rootouts[i], roottargets[i]];
expectcode(td, strings.concat("foo_root_", roottags[i]), rav, 0);
let rw: str = strings.concat(rootouts[i], ".sepwork/");

View File

@@ -166,9 +166,9 @@ fn rejectstable(dir: str, label: str, target: str, needle: str) void = {
"fn hidden() i32 = { return 99; };\n"));
let ca: str = strings.concat(td, "/libonly-c.a");
let wa: str = strings.concat(td, "/libonly-w.a");
let cav: []str = [testenv.driver("ww"), "build", "-p", "-I", td,
let cav: []str = [testenv.driver("ww"), "build", "-I", td,
"-o", ca, lib];
let wav: []str = [testenv.driver("ww_ww"), "build", "-p", "-I", td,
let wav: []str = [testenv.driver("ww_ww"), "build", "-I", td,
"-o", wa, lib];
if (code(td, "build_package_c", cav) != 0
|| code(td, "build_package_w", wav) != 0) {
@@ -302,10 +302,10 @@ fn rejectstable(dir: str, label: str, target: str, needle: str) void = {
strings.concat(td, "/api-c2.a"), strings.concat(td, "/api-w.a")];
i = 0;
for (i < packages.len) {
let pav: []str = [testenv.driver(drivers[i]), "build", "-p", "-I", td,
let pav: []str = [testenv.driver(drivers[i]), "build", "-I", td,
"-o", packages[i], api];
if (code(td, strings.concat("package_", tags[i]), pav) != 0) {
fail("self-contained", "ww build -p api failed");
fail("self-contained", "ww build api failed");
};
i += 1;
};
@@ -907,7 +907,7 @@ fn writediamond(td: str, reverse: bool) str = {
"/.wwtool.w6a")), testenv.readfile(assembler))
|| !testenv.same(testenv.readfile(strings.concat(work,
"/.wwtool.stamp")),
"ww workdir fmt 10 mode build asm 0\n")) {
"ww workdir fmt 12 mode build asm 0\n")) {
fail("driver-identity", "persistent artifacts or identities are incomplete");
};
let coldwwi: str = testenv.readfile(strings.concat(work, "/dep.wwi"));
@@ -1224,9 +1224,9 @@ fn writediamond(td: str, reverse: bool) str = {
"export fn nestedvalue() i32 = { return 41; };\n"));
let ca: str = strings.concat(td, "/nested-c.a");
let wa: str = strings.concat(td, "/nested-w.a");
let cav: []str = [testenv.driver("ww"), "build", "-p", "-I", root,
let cav: []str = [testenv.driver("ww"), "build", "-I", root,
"-o", ca, "foo.bar"];
let wav: []str = [testenv.driver("ww_ww"), "build", "-p", "-I", root,
let wav: []str = [testenv.driver("ww_ww"), "build", "-I", root,
"-o", wa, "foo.bar"];
if (code(td, "nested_package_c", cav) != 0
|| code(td, "nested_package_w", wav) != 0) {
@@ -1247,22 +1247,575 @@ fn writediamond(td: str, reverse: bool) str = {
let i: i32 = 0;
for (i < drivers.len) {
let badout: str = strings.concat(td, "/bad-flags-", drivers[i]);
let av: []str = [testenv.driver(drivers[i]), "build", "-p", "-S",
let av: []str = [testenv.driver(drivers[i]), "build", "-p",
"-I", root, "-o", badout, "foo.bar"];
let co: testenv.commandout;
command(td, strings.concat("package_flag_contract_", drivers[i]),
av, &co);
if (co.termination != exec.termination.EXIT || co.code == 0
|| !testenv.has(co.stderr,
"ww build: -p and -S cannot be combined")) {
|| !testenv.has(co.stderr, "ww build: unknown flag")) {
fail("package-flags", strings.concat(drivers[i],
" accepted -p -S"));
" accepted the removed package-action flag"));
};
i += 1;
};
testenv.clean(td);
};
@test fn package_kind_selects_build_action() void = {
let td: str = testenv.fresh();
let source: str = strings.concat(td, "/source");
let foo: str = strings.concat(source, "/foo");
let dep: str = strings.concat(foo, "/dep");
let bar: str = strings.concat(foo, "/bar");
let commanddir: str = strings.concat(foo, "/cmd");
let cyclea: str = strings.concat(foo, "/cyclea");
let cycleb: str = strings.concat(foo, "/cycleb");
let tools: str = strings.concat(td, "/tools");
mkdir(source); mkdir(foo); mkdir(dep); mkdir(bar); mkdir(commanddir);
mkdir(cyclea); mkdir(cycleb); mkdir(tools);
let depsrc: str = strings.concat(dep, "/dep.ww");
let depbase: str = strings.concat(
"package dep;\n",
"// DEP_SOURCE\n",
"fn hidden() i32 = { return 40; };\n",
"export fn value() i32 = { return hidden(); };\n");
let depprivate: str = strings.concat(
"package dep;\n",
"// DEP_SOURCE\n",
"fn hidden() i32 = { return 41; };\n",
"export fn value() i32 = { return hidden(); };\n");
let depexported: str = strings.concat(depprivate,
"export fn additional() i32 = { return 1; };\n");
testenv.writefile(depsrc, depbase);
testenv.writefile(strings.concat(bar, "/a.ww"), strings.concat(
"package bar;\nimport foo.dep;\n",
"// ROOT_A\n",
"export fn value() i32 = { return dep.value() + 2; };\n"));
testenv.writefile(strings.concat(bar, "/z.ww"), strings.concat(
"package bar;\nimport foo.dep;\n",
"// ROOT_Z\n",
"export fn other() i32 = { return 9; };\n"));
testenv.writefile(strings.concat(commanddir, "/main.ww"), strings.concat(
"package main;\nimport foo.bar;\n",
"// COMMAND_OWNER\n",
"fn main() i32 = { return bar.value(); };\n"));
testenv.writefile(strings.concat(cyclea, "/a.ww"), strings.concat(
"package cyclea;\nimport foo.cycleb;\n",
"export fn value() i32 = { return cycleb.value(); };\n"));
testenv.writefile(strings.concat(cycleb, "/b.ww"), strings.concat(
"package cycleb;\nimport foo.cyclea;\n",
"export fn value() i32 = { return cyclea.value(); };\n"));
let compiler: str = strings.concat(tools, "/w6c.sh");
let assembler: str = strings.concat(tools, "/w6a.sh");
let linker: str = strings.concat(tools, "/w6l.sh");
testenv.writeexecutable(compiler, strings.concat(
"#!/bin/sh\n",
"printf 'BEGIN' >> \"$WW_ROOT_COMPILER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_ROOT_COMPILER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_ROOT_COMPILER_TRACE\"\n",
"exec \"$WW_ROOT_REAL_COMPILER\" \"$@\"\n"));
testenv.writeexecutable(assembler, strings.concat(
"#!/bin/sh\n",
"printf 'BEGIN' >> \"$WW_ROOT_ASSEMBLER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_ROOT_ASSEMBLER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_ROOT_ASSEMBLER_TRACE\"\n",
"exec \"$WW_ROOT_REAL_ASSEMBLER\" \"$@\"\n"));
testenv.writeexecutable(linker, strings.concat(
"#!/bin/sh\n",
"printf 'BEGIN' >> \"$WW_ROOT_LINKER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_ROOT_LINKER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_ROOT_LINKER_TRACE\"\n",
"exec \"$WW_ROOT_REAL_LINKER\" \"$@\"\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 suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"];
let rootreference: []str = ["", "", "", "", ""];
let depreference: []str = ["", "", "", "", ""];
let commandreference: []str = ["", "", "", "", ""];
let nooutrootreference: []str = ["", "", "", "", ""];
let nooutdepreference: []str = ["", "", "", "", ""];
let publishreference: str = "";
let exportreference: str = "";
let binaryreference: str = "";
let diagnosticreference: str = "";
let cyclediagreference: str = "";
let cyclepathdiagreference: str = "";
let pathdiagreference: str = "";
let runtime: str = strings.concat(testenv.repo(), "/out/lib");
let si: i32 = 0;
for (si < stages.len) {
let work: str = strings.concat(td, "/work-", tags[si]);
let outpath: str = strings.concat(td, "/libbar-", tags[si], ".a");
let compilertrace: str = strings.concat(td, "/compiler-", tags[si]);
let assemblertrace: str = strings.concat(td, "/assembler-", tags[si]);
let linkertrace: str = strings.concat(td, "/linker-", tags[si]);
mkdir(work);
testenv.writefile(compilertrace, "");
testenv.writefile(assemblertrace, "");
testenv.writefile(linkertrace, "");
let env: []str = roottraceenv(source, runtime,
compiler, assembler, linker,
compilertrace, assemblertrace, linkertrace,
testenv.driver(compilers[si]),
testenv.driver(assemblers[si]),
testenv.driver(linkers[si]));
let av: []str = [testenv.driver(stages[si]), "build",
"-w", work, "-I", source, "-o", outpath, "foo.bar"];
let out: testenv.commandout;
testenv.runcommandenv(td, td, strings.concat("auto-cold-", tags[si]),
av, env, tmo(), &out);
if (out.termination != exec.termination.EXIT || out.code != 0
|| out.stderr.len != 0) {
fail("package-autoaction", strings.concat(tags[si],
" cold library build failed: ", out.stderr));
};
let ctrace: str = testenv.readfile(compilertrace);
let atrace: str = testenv.readfile(assemblertrace);
let wantcompiler: str = strings.concat(
"BEGIN<-c><-I><", work,
"/foo.dep.wwi.new><-o><", work,
"/foo.dep.s.new><", work, "/foo.dep.unit.new>\n",
"BEGIN<-c><--import><foo.dep><", work,
"/foo.dep.wwi><-I><", work,
"/foo.bar.wwi.new><-o><", work,
"/foo.bar.s.new><", work, "/foo.bar.unit.new>\n");
let wantassembler: str = strings.concat(
"BEGIN<-o><", work, "/foo.dep.o.new><", work,
"/foo.dep.s.new>\n",
"BEGIN<-o><", work, "/foo.bar.o.new><", work,
"/foo.bar.s.new>\n");
if (!testenv.same(ctrace, wantcompiler)
|| !testenv.same(atrace, wantassembler)
|| testenv.readfile(linkertrace).len != 0) {
fail("package-autoaction",
"library action tool arguments are not compile-only/direct");
};
let rootunit: str = testenv.readfile(strings.concat(work,
"/foo.bar.unit.ww"));
if (testenv.pos(rootunit, "// ROOT_A") < 0
|| testenv.pos(rootunit, "// ROOT_Z")
<= testenv.pos(rootunit, "// ROOT_A")
|| testenv.has(rootunit, "DEP_SOURCE")
|| testenv.occurrences(rootunit,
"//ww:module-reset foo.bar\n") != 2) {
fail("package-autoaction",
"library unit is not owner-only and byte-sorted");
};
if (!testenv.exists(outpath)
|| !testenv.exists(strings.concat(outpath, ".wwi"))
|| !testenv.same(testenv.readfile(outpath),
testenv.readfile(strings.concat(work, "/foo.bar.a")))
|| !testenv.same(testenv.readfile(strings.concat(outpath, ".wwi")),
testenv.readfile(strings.concat(work, "/foo.bar.wwi")))) {
fail("package-autoaction", "explicit package publication changed bytes");
};
let ai: i32 = 0;
for (ai < suffixes.len) {
let rootbytes: str = testenv.readfile(strings.concat(work,
"/foo.bar", suffixes[ai]));
let depbytes: str = testenv.readfile(strings.concat(work,
"/foo.dep", suffixes[ai]));
if (si == 0) {
rootreference[ai] = strings.dup(rootbytes);
depreference[ai] = strings.dup(depbytes);
} else { if (!testenv.same(rootreference[ai], rootbytes)
|| !testenv.same(depreference[ai], depbytes)) {
fail("package-autoaction",
"Cstage and WWstage package artifacts differ");
}; };
ai += 1;
};
if (si == 0) {
publishreference = strings.dup(testenv.readfile(outpath));
exportreference = strings.dup(testenv.readfile(strings.concat(
outpath, ".wwi")));
} else { if (!testenv.same(publishreference,
testenv.readfile(outpath)) || !testenv.same(exportreference,
testenv.readfile(strings.concat(outpath, ".wwi")))) {
fail("package-autoaction", "published stage artifacts differ");
}; };
// The other AutoAction half remains declaration-selected: package main
// alone receives --entry and its complete archive-only link closure.
testenv.clean(compilertrace); testenv.writefile(compilertrace, "");
testenv.clean(assemblertrace); testenv.writefile(assemblertrace, "");
testenv.clean(linkertrace); testenv.writefile(linkertrace, "");
let commandwork: str = strings.concat(td, "/command-work-", tags[si]);
let commandbin: str = strings.concat(td, "/command-", tags[si]);
mkdir(commandwork);
let commandav: []str = [testenv.driver(stages[si]), "build",
"-w", commandwork, "-I", source, "-o", commandbin, "foo.cmd"];
testenv.runcommandenv(td, td, strings.concat("auto-command-", tags[si]),
commandav, env, tmo(), &out);
ctrace = testenv.readfile(compilertrace);
atrace = testenv.readfile(assemblertrace);
let commandlink: str = testenv.readfile(linkertrace);
let wantcommandcompiler: str = strings.concat(
"BEGIN<-c><-I><", commandwork,
"/foo.dep.wwi.new><-o><", commandwork,
"/foo.dep.s.new><", commandwork, "/foo.dep.unit.new>\n",
"BEGIN<-c><--import><foo.dep><", commandwork,
"/foo.dep.wwi><-I><", commandwork,
"/foo.bar.wwi.new><-o><", commandwork,
"/foo.bar.s.new><", commandwork, "/foo.bar.unit.new>\n",
"BEGIN<--entry><-c><--import><foo.bar><", commandwork,
"/foo.bar.wwi><-I><", commandwork,
"/foo.cmd.wwi.new><-o><", commandwork,
"/foo.cmd.s.new><", commandwork, "/foo.cmd.unit.new>\n");
let wantcommandassembler: str = strings.concat(
"BEGIN<-o><", commandwork, "/foo.dep.o.new><", commandwork,
"/foo.dep.s.new>\n",
"BEGIN<-o><", commandwork, "/foo.bar.o.new><", commandwork,
"/foo.bar.s.new>\n",
"BEGIN<-o><", commandwork, "/foo.cmd.o.new><", commandwork,
"/foo.cmd.s.new>\n");
let wantcommandlink: str = strings.concat("BEGIN<-o><", commandbin,
"><", commandwork, "/foo.cmd.a><", commandwork,
"/foo.bar.a><", commandwork, "/foo.dep.a><", runtime,
"/libwwrt.a>\n");
if (out.termination != exec.termination.EXIT || out.code != 0
|| out.stderr.len != 0
|| !testenv.same(ctrace, wantcommandcompiler)
|| !testenv.same(atrace, wantcommandassembler)
|| !testenv.same(commandlink, wantcommandlink)
|| testenv.has(commandlink, ".wwi>")) {
fail("package-autoaction",
"main action arguments or archive closure changed");
};
let commandunit: str = testenv.readfile(strings.concat(commandwork,
"/foo.cmd.unit.ww"));
if (!testenv.has(commandunit, "// COMMAND_OWNER")
|| testenv.has(commandunit, "// ROOT_A")
|| testenv.has(commandunit, "// DEP_SOURCE")) {
fail("package-autoaction", "command unit contains foreign sources");
};
ai = 0;
for (ai < suffixes.len) {
let commandbytes: str = testenv.readfile(strings.concat(commandwork,
"/foo.cmd", suffixes[ai]));
if (si == 0) { commandreference[ai] = strings.dup(commandbytes); }
else { if (!testenv.same(commandreference[ai], commandbytes)) {
fail("package-autoaction",
"Cstage and WWstage command artifacts differ");
}; };
ai += 1;
};
let commandrun: []str = [commandbin];
if (code(td, strings.concat("auto-command-run-", tags[si]),
commandrun) != 42) {
fail("package-autoaction", "main action binary returned wrong value");
};
// The public run command must make the same declaration-driven choice;
// its private temp paths make exact argv intentionally inapplicable here.
let drivercommandrun: []str = [testenv.driver(stages[si]), "run",
"-I", source, "foo.cmd"];
testenv.runcommand(td, td, strings.concat("auto-driver-command-run-",
tags[si]), drivercommandrun, tmo(), &out);
if (out.termination != exec.termination.EXIT || out.code != 42
|| out.stdout.len != 0 || out.stderr.len != 0) {
fail("package-autoaction", "ww run rejected or misran package main");
};
if (si == 0) {
binaryreference = strings.dup(testenv.readfile(commandbin));
} else { if (!testenv.same(binaryreference,
testenv.readfile(commandbin))) {
fail("package-autoaction", "linked stage binaries differ");
}; };
testenv.clean(compilertrace); testenv.writefile(compilertrace, "");
testenv.clean(assemblertrace); testenv.writefile(assemblertrace, "");
testenv.clean(linkertrace); testenv.writefile(linkertrace, "");
let nooutwork: str = strings.concat(td, "/no-output-work-", tags[si]);
mkdir(nooutwork);
let noout: []str = [testenv.driver(stages[si]), "build",
"-w", nooutwork, "-I", source, "foo.bar"];
testenv.runcommandenv(td, td, strings.concat("auto-no-output-", tags[si]),
noout, env, tmo(), &out);
ctrace = testenv.readfile(compilertrace);
atrace = testenv.readfile(assemblertrace);
let wantnooutcompiler: str = strings.concat(
"BEGIN<-c><-I><", nooutwork,
"/foo.dep.wwi.new><-o><", nooutwork,
"/foo.dep.s.new><", nooutwork, "/foo.dep.unit.new>\n",
"BEGIN<-c><--import><foo.dep><", nooutwork,
"/foo.dep.wwi><-I><", nooutwork,
"/foo.bar.wwi.new><-o><", nooutwork,
"/foo.bar.s.new><", nooutwork, "/foo.bar.unit.new>\n");
let wantnooutassembler: str = strings.concat(
"BEGIN<-o><", nooutwork, "/foo.dep.o.new><", nooutwork,
"/foo.dep.s.new>\n",
"BEGIN<-o><", nooutwork, "/foo.bar.o.new><", nooutwork,
"/foo.bar.s.new>\n");
if (out.termination != exec.termination.EXIT || out.code != 0
|| out.stderr.len != 0 || testenv.exists(strings.concat(td, "/bar"))
|| !testenv.same(ctrace, wantnooutcompiler)
|| !testenv.same(atrace, wantnooutassembler)
|| testenv.readfile(linkertrace).len != 0) {
fail("package-autoaction",
"cold no-output library build did not remain compile-only");
};
ai = 0;
for (ai < suffixes.len) {
let nooutroot: str = testenv.readfile(strings.concat(nooutwork,
"/foo.bar", suffixes[ai]));
let nooutdep: str = testenv.readfile(strings.concat(nooutwork,
"/foo.dep", suffixes[ai]));
if (!testenv.same(nooutroot, rootreference[ai])
|| !testenv.same(nooutdep, depreference[ai])) {
fail("package-autoaction",
"publication request changed package artifact bytes");
};
if (si == 0) {
nooutrootreference[ai] = strings.dup(nooutroot);
nooutdepreference[ai] = strings.dup(nooutdep);
} else { if (!testenv.same(nooutrootreference[ai], nooutroot)
|| !testenv.same(nooutdepreference[ai], nooutdep)) {
fail("package-autoaction",
"cold no-output artifacts differ by stage");
}; };
ai += 1;
};
// An explicitly empty -o is observably the same no-publication request
// in both drivers and therefore reuses the same semantic actions.
testenv.clean(compilertrace); testenv.writefile(compilertrace, "");
testenv.clean(assemblertrace); testenv.writefile(assemblertrace, "");
testenv.clean(linkertrace); testenv.writefile(linkertrace, "");
let emptyout: []str = [testenv.driver(stages[si]), "build",
"-w", nooutwork, "-I", source, "-o", "", "foo.bar"];
testenv.runcommandenv(td, td, strings.concat("auto-empty-output-",
tags[si]), emptyout, env, tmo(), &out);
if (out.termination != exec.termination.EXIT || out.code != 0
|| out.stderr.len != 0
|| testenv.readfile(compilertrace).len != 0
|| testenv.readfile(assemblertrace).len != 0
|| testenv.readfile(linkertrace).len != 0) {
fail("package-autoaction",
"empty -o changed no-publication action semantics");
};
// Publication is not semantic action identity: an already-populated
// package workdir is reusable when the next request omits -o.
testenv.clean(compilertrace); testenv.writefile(compilertrace, "");
testenv.clean(assemblertrace); testenv.writefile(assemblertrace, "");
testenv.clean(linkertrace); testenv.writefile(linkertrace, "");
let warmnoout: []str = [testenv.driver(stages[si]), "build",
"-w", work, "-I", source, "foo.bar"];
testenv.runcommandenv(td, td, strings.concat("auto-warm-no-output-",
tags[si]), warmnoout, env, tmo(), &out);
if (out.termination != exec.termination.EXIT || out.code != 0
|| out.stderr.len != 0
|| testenv.readfile(compilertrace).len != 0
|| testenv.readfile(assemblertrace).len != 0
|| testenv.readfile(linkertrace).len != 0) {
fail("package-autoaction",
"publication request entered persistent action identity");
};
testenv.clean(compilertrace); testenv.writefile(compilertrace, "");
testenv.clean(assemblertrace); testenv.writefile(assemblertrace, "");
testenv.clean(linkertrace); testenv.writefile(linkertrace, "");
let pathwork: str = strings.concat(td, "/path-work-", tags[si]);
mkdir(pathwork);
let longout: str = strings.concat(td, "/");
for (longout.len < 4090) { longout = strings.concat(longout, "x"); };
let pathav: []str = [testenv.driver(stages[si]), "build",
"-w", pathwork, "-I", source, "-o", longout, "foo.bar"];
testenv.runcommandenv(td, td, strings.concat("auto-output-path-", tags[si]),
pathav, env, tmo(), &out);
let wantpathdiag: str = "ww: package output path is too long\n";
if (out.termination != exec.termination.EXIT || out.code != 1
|| !testenv.same(out.stderr, wantpathdiag)
|| testenv.readfile(compilertrace).len != 0
|| testenv.readfile(assemblertrace).len != 0
|| testenv.readfile(linkertrace).len != 0
|| testenv.exists(strings.concat(pathwork, "/foo.dep.unit.ww"))
|| testenv.exists(strings.concat(pathwork, "/foo.bar.unit.ww"))) {
fail("package-autoaction",
"package publication path failed after the tool boundary");
};
if (si == 0) { pathdiagreference = strings.dup(out.stderr); }
else { if (!testenv.same(pathdiagreference, out.stderr)) {
fail("package-autoaction", "output path diagnostics differ by stage");
}; };
// Output publication is unused under -S, so even this spelling must not
// participate in an assembly-only action or its failure behavior.
testenv.clean(compilertrace); testenv.writefile(compilertrace, "");
testenv.clean(assemblertrace); testenv.writefile(assemblertrace, "");
testenv.clean(linkertrace); testenv.writefile(linkertrace, "");
let asmwork: str = strings.concat(td, "/asm-work-", tags[si]);
mkdir(asmwork);
let asmav: []str = [testenv.driver(stages[si]), "build", "-S",
"-w", asmwork, "-I", source, "-o", longout, "foo.bar"];
testenv.runcommandenv(td, td, strings.concat("auto-asm-long-output-",
tags[si]), asmav, env, tmo(), &out);
let wantasmcompiler: str = strings.concat(
"BEGIN<-c><-I><", asmwork,
"/foo.dep.wwi.new><-o><", asmwork,
"/foo.dep.s.new><", asmwork, "/foo.dep.unit.new>\n",
"BEGIN<-c><--import><foo.dep><", asmwork,
"/foo.dep.wwi><-I><", asmwork,
"/foo.bar.wwi.new><-o><", asmwork,
"/foo.bar.s.new><", asmwork, "/foo.bar.unit.new>\n");
if (out.termination != exec.termination.EXIT || out.code != 0
|| out.stderr.len != 0
|| !testenv.same(testenv.readfile(compilertrace), wantasmcompiler)
|| testenv.readfile(assemblertrace).len != 0
|| testenv.readfile(linkertrace).len != 0
|| testenv.exists(strings.concat(asmwork, "/foo.dep.o"))
|| testenv.exists(strings.concat(asmwork, "/foo.dep.a"))
|| testenv.exists(strings.concat(asmwork, "/foo.bar.o"))
|| testenv.exists(strings.concat(asmwork, "/foo.bar.a"))) {
fail("package-autoaction",
"assembly-only action consumed an unused publication path");
};
testenv.clean(compilertrace); testenv.writefile(compilertrace, "");
testenv.clean(assemblertrace); testenv.writefile(assemblertrace, "");
testenv.clean(linkertrace); testenv.writefile(linkertrace, "");
let runav: []str = [testenv.driver(stages[si]), "run",
"-I", source, "foo.bar"];
testenv.runcommandenv(td, td, strings.concat("auto-run-reject-", tags[si]),
runav, env, tmo(), &out);
let wantdiag: str = "ww: package foo.bar is not a main package\n";
if (out.termination != exec.termination.EXIT || out.code != 1
|| !testenv.same(out.stderr, wantdiag)
|| testenv.readfile(compilertrace).len != 0
|| testenv.readfile(assemblertrace).len != 0
|| testenv.readfile(linkertrace).len != 0) {
fail("package-autoaction", "run crossed the non-main tool boundary");
};
if (si == 0) { diagnosticreference = strings.dup(out.stderr); }
else { if (!testenv.same(diagnosticreference, out.stderr)) {
fail("package-autoaction", "run diagnostics differ by stage");
}; };
let cyclerun: []str = [testenv.driver(stages[si]), "run",
"-I", source, "foo.cyclea"];
testenv.runcommandenv(td, td, strings.concat("auto-run-cycle-", tags[si]),
cyclerun, env, tmo(), &out);
if (out.termination != exec.termination.EXIT || out.code != 1
|| !testenv.has(out.stderr,
"ww: dependency cycle: foo.cyclea -> foo.cycleb -> foo.cyclea\n")
|| testenv.has(out.stderr, "is not a main package")
|| testenv.readfile(compilertrace).len != 0
|| testenv.readfile(assemblertrace).len != 0
|| testenv.readfile(linkertrace).len != 0) {
fail("package-autoaction",
"run command-kind validation masked a graph failure");
};
if (si == 0) { cyclediagreference = strings.dup(out.stderr); }
else { if (!testenv.same(cyclediagreference, out.stderr)) {
fail("package-autoaction", "run cycle diagnostics differ by stage");
}; };
let cyclepathwork: str = strings.concat(td, "/cycle-path-work-",
tags[si]);
mkdir(cyclepathwork);
let cyclepathav: []str = [testenv.driver(stages[si]), "build",
"-w", cyclepathwork, "-I", source, "-o", longout,
"foo.cyclea"];
testenv.runcommandenv(td, td, strings.concat("auto-cycle-path-", tags[si]),
cyclepathav, env, tmo(), &out);
if (out.termination != exec.termination.EXIT || out.code != 1
|| !testenv.has(out.stderr, "ww: dependency cycle: ")
|| !testenv.has(out.stderr, "foo.cyclea")
|| !testenv.has(out.stderr, "foo.cycleb")
|| testenv.has(out.stderr, "package output path is too long")
|| testenv.readfile(compilertrace).len != 0
|| testenv.readfile(assemblertrace).len != 0
|| testenv.readfile(linkertrace).len != 0) {
fail("package-autoaction",
strings.concat("publication path validation masked a graph failure: ",
out.stderr));
};
if (si == 0) { cyclepathdiagreference = strings.dup(out.stderr); }
else { if (!testenv.same(cyclepathdiagreference, out.stderr)) {
fail("package-autoaction",
"cycle/output-path diagnostic differs by stage");
}; };
assert(os.remove(depsrc) == 0);
testenv.writefile(depsrc, depprivate);
testenv.runcommandenv(td, td, strings.concat("auto-private-", tags[si]),
av, env, tmo(), &out);
ctrace = testenv.readfile(compilertrace);
atrace = testenv.readfile(assemblertrace);
let wantprivatecompiler: str = strings.concat(
"BEGIN<-c><-I><", work,
"/foo.dep.wwi.new><-o><", work,
"/foo.dep.s.new><", work, "/foo.dep.unit.new>\n");
let wantprivateassembler: str = strings.concat(
"BEGIN<-o><", work, "/foo.dep.o.new><", work,
"/foo.dep.s.new>\n");
if (out.termination != exec.termination.EXIT || out.code != 0
|| !testenv.same(ctrace, wantprivatecompiler)
|| !testenv.same(atrace, wantprivateassembler)
|| testenv.readfile(linkertrace).len != 0
|| !testenv.same(rootreference[4], testenv.readfile(strings.concat(
work, "/foo.bar.a")))) {
fail("package-autoaction",
"private dependency change escaped its export boundary");
};
testenv.clean(compilertrace); testenv.writefile(compilertrace, "");
testenv.clean(assemblertrace); testenv.writefile(assemblertrace, "");
testenv.clean(linkertrace); testenv.writefile(linkertrace, "");
assert(os.remove(depsrc) == 0);
testenv.writefile(depsrc, depexported);
testenv.runcommandenv(td, td, strings.concat("auto-export-", tags[si]),
av, env, tmo(), &out);
ctrace = testenv.readfile(compilertrace);
atrace = testenv.readfile(assemblertrace);
let wantexportcompiler: str = strings.concat(
"BEGIN<-c><-I><", work,
"/foo.dep.wwi.new><-o><", work,
"/foo.dep.s.new><", work, "/foo.dep.unit.new>\n",
"BEGIN<-c><--import><foo.dep><", work,
"/foo.dep.wwi><-I><", work,
"/foo.bar.wwi.new><-o><", work,
"/foo.bar.s.new><", work, "/foo.bar.unit.new>\n");
let wantexportassembler: str = strings.concat(
"BEGIN<-o><", work, "/foo.dep.o.new><", work,
"/foo.dep.s.new>\n",
"BEGIN<-o><", work, "/foo.bar.o.new><", work,
"/foo.bar.s.new>\n");
if (out.termination != exec.termination.EXIT || out.code != 0
|| !testenv.same(ctrace, wantexportcompiler)
|| !testenv.same(atrace, wantexportassembler)
|| testenv.readfile(linkertrace).len != 0) {
fail("package-autoaction",
"exported dependency change did not reach its direct importer");
};
testenv.clean(compilertrace); testenv.writefile(compilertrace, "");
testenv.clean(assemblertrace); testenv.writefile(assemblertrace, "");
testenv.clean(linkertrace); testenv.writefile(linkertrace, "");
testenv.runcommandenv(td, td, strings.concat("auto-warm-", tags[si]),
av, env, tmo(), &out);
if (out.termination != exec.termination.EXIT || out.code != 0
|| out.stderr.len != 0
|| testenv.readfile(compilertrace).len != 0
|| testenv.readfile(assemblertrace).len != 0
|| testenv.readfile(linkertrace).len != 0) {
fail("package-autoaction", "warm library build did not fully reuse");
};
assert(os.remove(depsrc) == 0);
testenv.writefile(depsrc, depbase);
si += 1;
};
testenv.clean(td);
};
@test fn generated_test_hook_is_not_a_user_exemption() void = {
let td: str = testenv.fresh();
let src: str = strings.concat(td, "/case.ww");