driver: ignore package documentation sources

This commit is contained in:
2026-08-23 11:29:25 +09:00
parent f6fabfc6ac
commit e67b8e1bc4
8 changed files with 2419 additions and 389 deletions

View File

@@ -14278,6 +14278,550 @@ fn runtimepath(relative: str) str = {
return strings.concat(repo(), "/test/package/runtime/", relative);
};
// `documentation` is a source-loader reservation, not a package identity.
// Keep this matrix here rather than splitting it between command tests: both
// drivers and the shared package coordinator must make the same decision
// before a body, import edge, action, or public artifact exists.
fn documentationrecord(out: *commandout, code: i32, records: *[]str) void = {
expectexit(out, code);
append(*records, strings.dup(out.stdout));
append(*records, strings.dup(out.stderr));
};
fn documentationrecordssame(a: []str, b: []str) void = {
assert(a.len == b.len);
let i: i32 = 0;
for (i < a.len) { assert(same(a[i], b[i])); i += 1; };
};
fn documentationclean(root: str) void = {
assert(!directoryhasnew(root)
&& !directoryhasfragment(root, ".wwtxn.")
&& !directoryhasfragment(root, ".install")
&& !directoryhasfragment(root, ".sepwork")
&& !wrongsuffixpathfragment(root, ".new"));
};
@test fn package_documentation_is_omitted_before_body_or_actions() void = {
let root: str = fresh();
let docs: str = strings.concat(root, "/docs");
let controls: str = strings.concat(root, "/controls");
let bomdir: str = strings.concat(root, "/bom");
let trivia: str = strings.concat(root, "/trivia");
let rawidir: str = strings.concat(root, "/raw-i");
let rawitree: str = strings.concat(root, "/raw-i-tree");
let literal: str = strings.concat(root, "/literal");
let include: str = strings.concat(root, "/include");
let logicaldir: str = strings.concat(include, "/logic");
let logicaltestdir: str = strings.concat(include, "/logicaltest");
let tree: str = strings.concat(root, "/tree");
let doconlytree: str = strings.concat(root, "/doconlytree");
let doconlydocs: str = strings.concat(doconlytree, "/docs");
let treedocs: str = strings.concat(tree, "/docs");
let treemain: str = strings.concat(tree, "/main");
let mixed: str = strings.concat(root, "/mixed");
let control: str = strings.concat(root, "/control");
let warm: str = strings.concat(root, "/warm");
let exact: str = strings.concat(root, "/exact");
let importer: str = strings.concat(root, "/importer");
let importerone: str = strings.concat(root, "/importer-one");
let docdep: str = strings.concat(include, "/docdep");
mkdirall(docs); mkdirall(controls); mkdirall(bomdir); mkdirall(trivia);
mkdirall(rawidir); mkdirall(rawitree); mkdirall(literal); mkdirall(logicaldir);
mkdirall(logicaltestdir); mkdirall(treedocs); mkdirall(treemain);
mkdirall(doconlydocs);
mkdirall(mixed); mkdirall(control); mkdirall(warm); mkdirall(exact); mkdirall(importer); mkdirall(importerone);
mkdirall(docdep);
let doc: str = strings.concat(docs, "/doc.ww");
let doclink: str = strings.concat(root, "/doclink.ww");
let logical: str = strings.concat(logicaldir, "/doc.ww");
let rawi: str = strings.concat(rawidir, "/rawi.ww");
let rawitreefile: str = strings.concat(rawitree, "/rawi.ww");
let badheader: str = strings.concat(controls, "/badheader.ww");
let badpackage: str = strings.concat(controls, "/badpackage.ww");
let bom: str = strings.concat(bomdir, "/bom.ww");
let triviafile: str = strings.concat(trivia, "/trivia.ww");
let literaltest: str = strings.concat(literal, "/literal_test.ww");
let logicaltest: str = strings.concat(logicaltestdir, "/provider_test.ww");
let mixdoc: str = strings.concat(mixed, "/doc.ww");
let warmfile: str = strings.concat(warm, "/main.ww");
let maintext: str = "package main;\nfn main() i32 = { return 31; };\n";
let doctext: str = strings.concat("// leading trivia\npackage documentation;\n",
"this is deliberately malformed ordinary body;\n",
"import absent.after.boundary;\nfn main() i32 = { return 99; };\n");
writefile(doc, doctext); writefile(logical, doctext);
assert(os.symlink(doc, doclink) == 0);
writefile(rawi, "package documentation;\ni this_is_not_import;\n");
writefile(badheader, "package documentation;\nimport ;\n");
writefile(badpackage, "package ;\n");
putbomfile(bom, "// bom and comment\npackage documentation;\n",
"this malformed body is past the header;\n", false);
writefile(triviafile, strings.concat("//ww:module ignored.header\n",
"package /* comment between clause and name */ documentation;\n",
"this malformed body is past the header;\n"));
writefile(rawitreefile,
"package documentation;\ni this_is_not_import;\n");
writefile(literaltest, "package documentation;\n");
writefile(logicaltest, doctext);
writefile(mixdoc, doctext); writefile(strings.concat(mixed, "/main.ww"), maintext);
writefile(strings.concat(control, "/main.ww"), maintext);
writefile(warmfile, maintext);
writefile(strings.concat(treedocs, "/doc.ww"), doctext);
writefile(strings.concat(doconlydocs, "/doc.ww"), doctext);
writefile(strings.concat(treemain, "/main.ww"), maintext);
writefile(strings.concat(treemain, "/main_test.ww"),
"package main;\n@test fn retained() void = { assert(true); };\n");
writefile(strings.concat(docdep, "/doc.ww"), doctext);
writefile(strings.concat(importer, "/user.ww"), strings.concat(
"package user;\nimport docdep;\n",
"export fn value() i32 = { return docdep.value(); };\n"));
writefile(strings.concat(include, "/docone.ww"), doctext);
writefile(strings.concat(importerone, "/user.ww"), strings.concat(
"package userone;\nimport docone;\n",
"export fn value() i32 = { return docone.value(); };\n"));
writefile(strings.concat(exact, "/x.ww"),
"package documentationx;\nimport absent.exact;\n");
writefile(strings.concat(exact, "/t.ww"),
"package documentation_test;\nimport absent.exact;\n");
let stages: []str = ["ww", "ww_ww"];
let tags: []str = ["c", "ww"];
let compilers: []str = ["w6c", "w6c_ww"];
let assemblers: []str = ["w6a", "w6a_ww"];
let linkers: []str = ["w6l", "w6l_ww"];
let baseenv: []str = os.getenvs();
let records: []str = alloc([], 96u64)!;
let cross: []str = alloc([], 96u64)!;
let mixedcross: str = "";
let mixedsemanticcross: str = "";
let warmcross: str = "";
let out: commandout;
let si: i32 = 0;
for (si < stages.len) {
records.len = 0;
let work: str = strings.concat(root, "/docs-work-", tags[si]);
let rawwork: str = strings.concat(root, "/raw-work-", tags[si]);
let mixwork: str = strings.concat(root, "/mixed-work-", tags[si]);
let ctlwork: str = strings.concat(root, "/control-work-", tags[si]);
let outputdir: str = strings.concat(root, "/outputs-", tags[si]);
let mixedout: str = strings.concat(root, "/mixed-", tags[si]);
let controlout: str = strings.concat(root, "/control-", tags[si]);
let trace: str = strings.concat(root, "/tools-", tags[si], ".trace");
let cwrap: str = strings.concat(root, "/w6c-", tags[si], ".sh");
let awrap: str = strings.concat(root, "/w6a-", tags[si], ".sh");
let lwrap: str = strings.concat(root, "/w6l-", tags[si], ".sh");
mkdirall(work); mkdirall(rawwork); mkdirall(mixwork); mkdirall(ctlwork);
mkdirall(outputdir); writefile(trace, "");
writeexecutable(cwrap, "#!/bin/sh\nprintf C >> \"$WW_DOC_TRACE\"\nexec \"$WW_DOC_REAL_C\" \"$@\"\n");
writeexecutable(awrap, "#!/bin/sh\nprintf A >> \"$WW_DOC_TRACE\"\nexec \"$WW_DOC_REAL_A\" \"$@\"\n");
writeexecutable(lwrap, "#!/bin/sh\nprintf L >> \"$WW_DOC_TRACE\"\nexec \"$WW_DOC_REAL_L\" \"$@\"\n");
let env: []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_W6A=")
&& !strings.hasprefix(baseenv[ei], "WW_W6L=")
&& !strings.hasprefix(baseenv[ei], "WW_DOC_")) { append(env, baseenv[ei]); };
ei += 1;
};
append(env, strings.concat("WW_W6C=", cwrap));
append(env, strings.concat("WW_W6A=", awrap));
append(env, strings.concat("WW_W6L=", lwrap));
append(env, strings.concat("WW_DOC_REAL_C=", driver(compilers[si])));
append(env, strings.concat("WW_DOC_REAL_A=", driver(assemblers[si])));
append(env, strings.concat("WW_DOC_REAL_L=", driver(linkers[si])));
append(env, strings.concat("WW_DOC_TRACE=", trace));
let directerr: str = strings.concat("ww: ", docs,
": directory contains no WW package sources\n");
let namederr: str = strings.concat("ww: ", docs,
": directory contains no WW package sources\n");
let coordinatorerr: str = strings.concat("wwtest package: ", docs,
": directory contains no WW package sources\n");
let before: str = treesnapshot(work);
let av: []str = [driver(stages[si]), "build", "-w", work, docs];
runcommandenv(root, strings.concat("documentation-build-", tags[si]), av,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, directerr)
&& same(before, treesnapshot(work)) && readfile(trace).len == 0);
let namedav: []str = [driver(stages[si]), "build", "-w", work, doc];
runcommandenv(root, strings.concat("documentation-named-", tags[si]), namedav,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, namederr)
&& same(before, treesnapshot(work)) && readfile(trace).len == 0);
let linkav: []str = [driver(stages[si]), "build", "-w", work, doclink];
runcommandenv(root, strings.concat("documentation-named-link-", tags[si]),
linkav, env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat("ww: ", root,
": directory contains no WW package sources\n"))
&& same(before, treesnapshot(work)) && readfile(trace).len == 0);
let logicalav: []str = [driver(stages[si]), "build", "-w", work,
"-I", include, "logic.doc"];
runcommandenv(root, strings.concat("documentation-logical-", tags[si]), logicalav,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat("ww: ",
logicaldir, ": directory contains no WW package sources\n")));
let logicaltestav: []str = [driver(stages[si]), "build", "-w", work,
"-I", include, "logicaltest.provider_test"];
runcommandenv(root, strings.concat("documentation-logical-test-", tags[si]),
logicaltestav, env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat("ww: ",
logicaltestdir, ": directory contains no WW package sources\n")));
let coordav: []str = [driver(stages[si]), "build", "-o", outputdir, docs];
runcommandenv(root, strings.concat("documentation-coordinator-", tags[si]), coordav,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, coordinatorerr)
&& !directoryhasnew(outputdir) && readfile(trace).len == 0);
let runav: []str = [driver(stages[si]), "run", docs];
runcommandenv(root, strings.concat("documentation-run-dir-", tags[si]), runav,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, directerr) && readfile(trace).len == 0);
let runnamed: []str = [driver(stages[si]), "run", doc];
runcommandenv(root, strings.concat("documentation-run-file-", tags[si]), runnamed,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, namederr) && readfile(trace).len == 0);
let runlogical: []str = [driver(stages[si]), "run", "-I", include, "logic.doc"];
runcommandenv(root, strings.concat("documentation-run-logical-", tags[si]),
runlogical, env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat("ww: ",
logicaldir, ": directory contains no WW package sources\n")));
let literalplain: []str = [driver(stages[si]), "build", literaltest];
runcommandenv(root, strings.concat("documentation-literal-plain-", tags[si]),
literalplain, env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 0, &records);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let literalnull: []str = [driver(stages[si]), "build", "-o", "/dev/null", literaltest];
runcommandenv(root, strings.concat("documentation-literal-null-", tags[si]),
literalnull, env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 0, &records);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let literalfile: str = strings.concat(root, "/literal-file-", tags[si]);
let literalfileav: []str = [driver(stages[si]), "build", "-o", literalfile, literaltest];
runcommandenv(root, strings.concat("documentation-literal-file-", tags[si]),
literalfileav, env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, "ww: no packages to build\n")
&& !os.exists(literalfile));
let literaloutdir: str = strings.concat(root, "/literal-output-", tags[si]);
mkdirall(literaloutdir);
let literaldirav: []str = [driver(stages[si]), "build", "-o", literaloutdir, literaltest];
runcommandenv(root, strings.concat("documentation-literal-dir-", tags[si]),
literaldirav, env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, "ww: no main packages to build\n")
&& !directoryhasnew(literaloutdir));
let rawbefore: str = treesnapshot(rawwork);
let rawtest: []str = [driver(stages[si]), "test", "-w", rawwork, doc];
runcommandenv(root, strings.concat("documentation-test-raw-", tags[si]), rawtest,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(same(out.stdout, "FAIL\n") && same(out.stderr, namederr)
&& same(rawbefore, treesnapshot(rawwork)) && readfile(trace).len == 0);
let logicalraw: []str = [driver(stages[si]), "test", "-I", include, "logic.doc"];
runcommandenv(root, strings.concat("documentation-test-logical-", tags[si]),
logicalraw, env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(same(out.stdout, "FAIL\n") && same(out.stderr, strings.concat("ww: ",
logicaldir, ": directory contains no WW package sources\n")));
let rawcompile: []str = [driver(stages[si]), "test", "-c", "-w", rawwork, doc];
runcommandenv(root, strings.concat("documentation-test-c-", tags[si]), rawcompile,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, namederr));
let rawasmout: str = strings.concat(root, "/raw-asm-", tags[si]);
let rawasm: []str = [driver(stages[si]), "test", "-S", "-w", rawwork,
"-o", rawasmout, doc];
runcommandenv(root, strings.concat("documentation-test-s-", tags[si]), rawasm,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, namederr) && !os.exists(rawasmout));
let dirtest: []str = [driver(stages[si]), "test", docs];
runcommandenv(root, strings.concat("documentation-test-dir-", tags[si]), dirtest,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(same(out.stdout, "FAIL\n") && same(out.stderr, coordinatorerr));
let dircompile: []str = [driver(stages[si]), "test", "-c", docs];
runcommandenv(root, strings.concat("documentation-test-dir-c-", tags[si]), dircompile,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, coordinatorerr));
let dirasm: []str = [driver(stages[si]), "test", "-S", docs];
runcommandenv(root, strings.concat("documentation-test-dir-s-", tags[si]), dirasm,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 2, &records);
assert(out.stdout.len == 0 && same(out.stderr,
"ww test: -S needs -o\n"));
let dirasmout: str = strings.concat(root, "/dir-asm-", tags[si]);
let dirasmwithoutput: []str = [driver(stages[si]), "test", "-S",
"-o", dirasmout, docs];
runcommandenv(root, strings.concat("documentation-test-dir-s-output-", tags[si]),
dirasmwithoutput, env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 2, &records);
assert(out.stdout.len == 0 && same(out.stderr,
"ww test: -S needs a single test file\n"));
let spec: str = strings.concat(doconlytree, "/...");
let recbuild: []str = [driver(stages[si]), "build", spec];
runcommandenv(root, strings.concat("documentation-rec-build-", tags[si]), recbuild,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 0, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat("ww: warning: \"",
spec, "\" matched no packages\n")));
let recbuildtwice: []str = [driver(stages[si]), "build", spec, spec];
runcommandenv(root, strings.concat("documentation-rec-build-twice-", tags[si]),
recbuildtwice, env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 0, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat("ww: warning: \"",
spec, "\" matched no packages\nww: warning: \"", spec,
"\" matched no packages\n")));
let rectest: []str = [driver(stages[si]), "test", spec];
runcommandenv(root, strings.concat("documentation-rec-test-", tags[si]), rectest,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat("ww: warning: \"",
spec, "\" matched no packages\nww test: no packages to test\n")));
let rectesttwice: []str = [driver(stages[si]), "test", spec, spec];
runcommandenv(root, strings.concat("documentation-rec-test-twice-", tags[si]),
rectesttwice, env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat("ww: warning: \"",
spec, "\" matched no packages\nww: warning: \"", spec,
"\" matched no packages\nww test: no packages to test\n")));
let mixedspec: str = strings.concat(tree, "/...");
let mixedrecbuild: []str = [driver(stages[si]), "build", "-o", "/dev/null",
mixedspec];
runcommandenv(root, strings.concat("documentation-rec-mixed-build-", tags[si]),
mixedrecbuild, env, (60i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 0, &records);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let mixedrectest: []str = [driver(stages[si]), "test", mixedspec];
runcommandenv(root, strings.concat("documentation-rec-mixed-test-", tags[si]),
mixedrectest, env, (60i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 0, &records);
assert(out.stderr.len == 0 && has(out.stdout, "retained ... ok\n")
&& !has(out.stdout, "documentation"));
rewritefile(trace, "");
let rawiav: []str = [driver(stages[si]), "build", rawi];
runcommandenv(root, strings.concat("documentation-raw-i-", tags[si]), rawiav,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat(rawi,
":2:1: error: expected top-level decl\n")) && readfile(trace).len == 0);
let rawirun: []str = [driver(stages[si]), "run", rawi];
runcommandenv(root, strings.concat("documentation-raw-i-run-", tags[si]), rawirun,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat(rawi,
":2:1: error: expected top-level decl\n")));
let rawitest: []str = [driver(stages[si]), "test", rawi];
runcommandenv(root, strings.concat("documentation-raw-i-test-", tags[si]), rawitest,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(same(out.stdout, "FAIL\n") && same(out.stderr, strings.concat(rawi,
":2:1: error: expected top-level decl\n")));
let rawicompile: []str = [driver(stages[si]), "test", "-c", rawi];
runcommandenv(root, strings.concat("documentation-raw-i-c-", tags[si]), rawicompile,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat(rawi,
":2:1: error: expected top-level decl\n")));
let rawiasmout: str = strings.concat(root, "/raw-i-asm-", tags[si]);
let rawiasm: []str = [driver(stages[si]), "test", "-S", "-o", rawiasmout, rawi];
runcommandenv(root, strings.concat("documentation-raw-i-s-", tags[si]), rawiasm,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat(rawi,
":2:1: error: expected top-level decl\n")) && !os.exists(rawiasmout));
let rawidirectorytest: []str = [driver(stages[si]), "test", rawidir];
runcommandenv(root, strings.concat("documentation-raw-i-dir-test-", tags[si]),
rawidirectorytest, env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(same(out.stdout, "FAIL\n") && same(out.stderr, strings.concat(rawi,
":2:1: error: expected top-level decl\n")));
let rawispec: str = strings.concat(rawitree, "/...");
let rawirectest: []str = [driver(stages[si]), "test", rawispec];
runcommandenv(root, strings.concat("documentation-raw-i-rec-test-", tags[si]),
rawirectest, env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(same(out.stdout, "FAIL\n") && same(out.stderr, strings.concat(rawitreefile,
":2:1: error: expected top-level decl\n")));
let headerav: []str = [driver(stages[si]), "build", badheader];
runcommandenv(root, strings.concat("documentation-header-", tags[si]), headerav,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat(badheader,
":2:8: error: expected identifier, got ;\n")));
let packageav: []str = [driver(stages[si]), "build", badpackage];
runcommandenv(root, strings.concat("documentation-package-", tags[si]), packageav,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat(badpackage,
":1:9: error: invalid or missing package clause\n")));
let bomav: []str = [driver(stages[si]), "build", bom];
runcommandenv(root, strings.concat("documentation-bom-", tags[si]), bomav,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat("ww: ",
bomdir, ": directory contains no WW package sources\n")));
let triviaav: []str = [driver(stages[si]), "build", triviafile];
runcommandenv(root, strings.concat("documentation-trivia-", tags[si]), triviaav,
env, (30i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 1, &records);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat("ww: ",
trivia, ": directory contains no WW package sources\n")));
let exactav: []str = [driver(stages[si]), "build", strings.concat(exact, "/x.ww")];
runcommandenv(root, strings.concat("documentation-exact-x-", tags[si]), exactav,
env, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1); assert(!has(out.stderr, "directory contains no WW package sources"));
let exacttav: []str = [driver(stages[si]), "build", strings.concat(exact, "/t.ww")];
runcommandenv(root, strings.concat("documentation-exact-t-", tags[si]), exacttav,
env, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1); assert(!has(out.stderr, "directory contains no WW package sources"));
let importav: []str = [driver(stages[si]), "build", "-I", include, importer];
runcommandenv(root, strings.concat("documentation-imported-", tags[si]), importav,
env, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1); assert(!os.exists(strings.concat(root, "/imported-", tags[si]))
&& readfile(trace).len == 0);
let importoneav: []str = [driver(stages[si]), "build", "-I", include, importerone];
runcommandenv(root, strings.concat("documentation-imported-one-", tags[si]),
importoneav, env, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1); assert(has(out.stderr,
":2:1: error: cannot find package docone\n")
&& !has(out.stderr, "directory contains no WW package sources")
&& readfile(trace).len == 0);
let mixav: []str = [driver(stages[si]), "build", "-w", mixwork,
"-o", mixedout, mixed];
let ctlav: []str = [driver(stages[si]), "build", "-w", ctlwork,
"-o", controlout, control];
runcommandenv(root, strings.concat("documentation-mixed-cold-", tags[si]), mixav,
env, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0 && os.exists(mixedout));
runcommandenv(root, strings.concat("documentation-control-cold-", tags[si]), ctlav,
env, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0
&& same(readfile(mixedout), readfile(controlout)));
let mixedbytes: str = strings.dup(readfile(mixedout));
let mixedtree: str = strings.dup(artifacttreesnapshot(mixwork));
let mixedsemantic: str = strings.dup(wrongsuffixsemantictreesnapshot(mixwork));
if (si == 0) {
mixedcross = strings.dup(mixedbytes);
mixedsemanticcross = strings.dup(mixedsemantic);
} else {
assert(same(mixedcross, mixedbytes)
&& same(mixedsemanticcross, mixedsemantic));
};
let mixabsent: str = strings.concat(mixdoc, ".absent");
assert(os.rename(mixdoc, mixabsent) == 0);
rewritefile(trace, "");
runcommandenv(root, strings.concat("documentation-mixed-absent-", tags[si]), mixav,
env, (60i64 * (time.second: i64)): time.duration, &out);
documentationrecord(&out, 0, &records);
assert(out.stdout.len == 0 && out.stderr.len == 0
&& same(mixedbytes, readfile(mixedout))
&& same(mixedtree, artifacttreesnapshot(mixwork))
&& same(mixedsemantic, wrongsuffixsemantictreesnapshot(mixwork))
&& same(readfile(trace), "L"));
assert(os.rename(mixabsent, mixdoc) == 0);
rewritefile(trace, ""); rewritefile(mixdoc, strings.concat(doctext, "still ignored\n"));
runcommandenv(root, strings.concat("documentation-mixed-warm-", tags[si]), mixav,
env, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0
&& same(mixedbytes, readfile(mixedout)) && same(mixedtree, artifacttreesnapshot(mixwork))
&& same(readfile(trace), "L"));
let warmwork: str = strings.concat(root, "/warm-work-", tags[si]);
let warmout: str = strings.concat(root, "/warm-output-", tags[si]);
mkdirall(warmwork);
let warmav: []str = [driver(stages[si]), "build", "-w", warmwork,
"-o", warmout, warm];
runcommandenv(root, strings.concat("documentation-warm-cold-", tags[si]), warmav,
env, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0);
let warmbytes: str = strings.dup(readfile(warmout));
let warmtree: str = strings.dup(artifacttreesnapshot(warmwork));
if (si == 0) { warmcross = strings.dup(warmbytes); }
else { assert(same(warmcross, warmbytes)); };
rewritefile(trace, ""); rewritefile(warmfile, doctext);
runcommandenv(root, strings.concat("documentation-warm-docs-", tags[si]), warmav,
env, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat("ww: ", warm,
": directory contains no WW package sources\n")) && same(warmbytes, readfile(warmout))
&& same(warmtree, artifacttreesnapshot(warmwork)) && readfile(trace).len == 0);
rewritefile(warmfile, "package documentation;\nimport ;\n");
runcommandenv(root, strings.concat("documentation-warm-header-", tags[si]), warmav,
env, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && same(out.stderr, strings.concat(warmfile,
":2:8: error: expected identifier, got ;\n")) && same(warmbytes, readfile(warmout))
&& same(warmtree, artifacttreesnapshot(warmwork)) && readfile(trace).len == 0);
rewritefile(warmfile, maintext);
documentationclean(root);
if (si == 0) {
let ri: i32 = 0;
for (ri < records.len) { append(cross, strings.dup(records[ri])); ri += 1; };
} else { documentationrecordssame(cross, records); };
si += 1;
};
// Header classification has no shared action identity or lock: simultaneous
// Cstage/WWstage requests may read the same source but must leave separate
// caller-owned work roots untouched.
let cwork: str = strings.concat(root, "/parallel-c-work");
let wwork: str = strings.concat(root, "/parallel-ww-work");
mkdirall(cwork); mkdirall(wwork);
let cbefore: str = treesnapshot(cwork);
let wbefore: str = treesnapshot(wwork);
let cav: []str = [driver("ww"), "build", "-w", cwork, docs];
let wav: []str = [driver("ww_ww"), "build", "-w", wwork, docs];
let cc: exec.command;
cc.path = cav[0]; cc.argv = cav; cc.env = os.getenvs(); cc.dir = repo();
cc.stdoutpath = strings.concat(root, "/documentation-parallel-c.stdout");
cc.stderrpath = strings.concat(root, "/documentation-parallel-c.stderr");
cc.deadline = time.add(time.now(time.clock.monotonic),
(30i64 * (time.second: i64)): time.duration);
cc.grace = (100i64 * (time.millisecond: i64)): time.duration;
let wc: exec.command;
wc.path = wav[0]; wc.argv = wav; wc.env = os.getenvs(); wc.dir = repo();
wc.stdoutpath = strings.concat(root, "/documentation-parallel-ww.stdout");
wc.stderrpath = strings.concat(root, "/documentation-parallel-ww.stderr");
wc.deadline = time.add(time.now(time.clock.monotonic),
(30i64 * (time.second: i64)): time.duration);
wc.grace = (100i64 * (time.millisecond: i64)): time.duration;
let cp: exec.process;
let wp: exec.process;
exec.start(&cp, &cc); exec.start(&wp, &wc);
let cdone: bool = false;
let wdone: bool = false;
for (!cdone || !wdone) {
if (!cdone) { cdone = exec.poll(&cp); };
if (!wdone) { wdone = exec.poll(&wp); };
if (!cdone || !wdone) { time.sleep(time.millisecond, time.clock.monotonic); };
};
let parallelerr: str = strings.concat("ww: ", docs,
": directory contains no WW package sources\n");
assert(cp.result.errno == 0 && cp.result.cleanuperrno == 0
&& cp.result.termination == exec.termination.EXIT && cp.result.code == 1
&& wp.result.errno == 0 && wp.result.cleanuperrno == 0
&& wp.result.termination == exec.termination.EXIT && wp.result.code == 1
&& readfile(cc.stdoutpath).len == 0 && readfile(wc.stdoutpath).len == 0
&& same(readfile(cc.stderrpath), parallelerr)
&& same(readfile(wc.stderrpath), parallelerr)
&& same(cbefore, treesnapshot(cwork)) && same(wbefore, treesnapshot(wwork)));
documentationclean(root);
clean(root);
};
// The single-FILE `ww test <file>` route wraps the same in-binary test
// runtime as the directory-package route (cases/*), but through the
// driver's single-file leg. One row per outcome class keeps that leg's