Files
ww/test/package/package_test.ww

3090 lines
124 KiB
Plaintext

package package_test;
// Make builds and invokes this one binary; discovery, subprocess ownership,
// output interpretation, and assertions remain WW code.
import os;
import os.exec;
import strings;
import temp;
import time;
type commandout = struct {
termination: exec.termination,
code: i32,
stdout: str,
stderr: str,
};
fn envrequired(name: str) str = {
match (os.getenv(name)) {
case let value: str => {
assert(value.len != 0);
return strings.dup(value);
};
case void => abort("missing package-test environment");
};
};
fn repo() str = { return envrequired("WW_PACKAGE_REPO"); };
fn driver(name: str) str = {
return strings.concat(repo(), "/out/bin/", name);
};
fn readfile(path: str) str = {
let fd: i32 = os.open(path, os.flag.RDONLY, 0i32);
assert(fd >= 0);
let sr: (i64 | os.oserror) = os.filesize(fd);
let n: i64 = -1i64;
match (sr) {
case let v: i64 => n = v;
case let e: os.oserror => abort("filesize failed");
};
assert(n >= 0i64);
let b: []u8 = alloc([], (n + 1i64): u64)!;
b.len = (n + 1i64): i32;
let rr: (i64 | os.oserror) = os.readall(fd, b.ptr, n: u64);
os.close(fd);
let got: i64 = -1i64;
match (rr) {
case let v: i64 => got = v;
case let e: os.oserror => abort("read failed");
};
assert(got == n);
let ni: i32 = n: i32;
b[ni] = 0u8;
let out: str;
out.ptr = b.ptr;
out.len = n: i32;
return out;
};
fn writefile(path: str, content: str) void = {
let fd: i32 = os.open(path,
os.flag.WRONLY | os.flag.CREATE | os.flag.EXCL, 384i32);
assert(fd >= 0);
match (os.writeall(fd, content.ptr, content.len: u64)) {
case let n: i64 => assert(n == content.len: i64);
case let e: os.oserror => abort("write failed");
};
assert(os.close(fd) == 0);
};
fn writeexecutable(path: str, content: str) void = {
let fd: i32 = os.open(path,
os.flag.WRONLY | os.flag.CREATE | os.flag.EXCL, 448i32);
assert(fd >= 0);
match (os.writeall(fd, content.ptr, content.len: u64)) {
case let n: i64 => assert(n == content.len: i64);
case let e: os.oserror => abort("write failed");
};
assert(os.close(fd) == 0);
};
fn runcommand(root: str, name: str, argv: []str,
lifetime: time.duration, out: *commandout) void = {
let c: exec.command;
c.path = argv[0];
c.argv = argv;
c.env = os.getenvs();
c.dir = repo();
c.stdoutpath = strings.concat(root, "/", name, ".stdout");
c.stderrpath = strings.concat(root, "/", name, ".stderr");
c.deadline = time.add(time.now(time.clock.monotonic), lifetime);
c.grace = (100i64 * (time.millisecond: i64)): time.duration;
let r: exec.result;
exec.run(&c, &r);
assert(r.errno == 0 && r.cleanuperrno == 0);
out.termination = r.termination;
out.code = r.code;
out.stdout = readfile(c.stdoutpath);
out.stderr = readfile(c.stderrpath);
};
fn runcommandenv(root: str, name: str, argv: []str, env: []str,
lifetime: time.duration, out: *commandout) void = {
let c: exec.command;
c.path = argv[0];
c.argv = argv;
c.env = env;
c.dir = repo();
c.stdoutpath = strings.concat(root, "/", name, ".stdout");
c.stderrpath = strings.concat(root, "/", name, ".stderr");
c.deadline = time.add(time.now(time.clock.monotonic), lifetime);
c.grace = (100i64 * (time.millisecond: i64)): time.duration;
let r: exec.result;
exec.run(&c, &r);
assert(r.errno == 0 && r.cleanuperrno == 0);
out.termination = r.termination;
out.code = r.code;
out.stdout = readfile(c.stdoutpath);
out.stderr = readfile(c.stderrpath);
};
fn clean(root: str) void = {
let av: []str = ["/bin/rm", "-rf", "--", root];
let c: exec.command;
c.path = av[0];
c.argv = av;
c.env = os.getenvs();
c.dir = "/";
c.stdoutpath = strings.concat(root, ".cleanup.stdout");
c.stderrpath = strings.concat(root, ".cleanup.stderr");
c.deadline = time.add(time.now(time.clock.monotonic), time.second);
c.grace = (50i64 * (time.millisecond: i64)): time.duration;
let r: exec.result;
exec.run(&c, &r);
assert(r.termination == exec.termination.EXIT && r.code == 0);
assert(os.remove(c.stdoutpath) == 0);
assert(os.remove(c.stderrpath) == 0);
};
fn fresh() str = { return strings.dup(temp.dir()); };
fn pos(haystack: str, needle: str) i32 = {
match (strings.index(haystack, needle)) {
case let n: i32 => return n;
case void => return -1;
};
};
fn has(haystack: str, needle: str) bool = {
return pos(haystack, needle) >= 0;
};
fn same(a: str, b: str) bool = {
if (a.len != b.len) { return false; };
let i: i32 = 0;
for (i < a.len) {
if (a[i] != b[i]) { return false; };
i += 1;
};
return true;
};
fn occurrences(haystack: str, needle: str) i32 = {
if (needle.len == 0 || haystack.len < needle.len) { return 0; };
let count: i32 = 0;
let i: i32 = 0;
for (i + needle.len <= haystack.len) {
let matches: bool = true;
let j: i32 = 0;
for (j < needle.len) {
if (haystack[i + j] != needle[j]) { matches = false; break; };
j += 1;
};
if (matches) { count += 1; i += needle.len; }
else { i += 1; };
};
return count;
};
fn linecontaining(text: str, needle: str) str = {
let start: i32 = 0;
let i: i32 = 0;
for (i <= text.len) {
if (i == text.len || text[i] == '\n': u8) {
let line: str;
line.ptr = text.ptr + (start: u64);
line.len = i - start;
if (has(line, needle)) { return line; };
start = i + 1;
};
i += 1;
};
abort("missing trace line");
};
fn expectexit(out: *commandout, code: i32) void = {
assert(out.termination == exec.termination.EXIT);
assert(out.code == code);
};
fn primarydiagnostic(s: str) str = {
let begin: i32 = pos(s, ": error: ");
if (begin >= 0) { begin += 9; }
else { begin = pos(s, "ww: dependency cycle: "); };
if (begin < 0) { return s; };
let end: i32 = begin;
for (end < s.len && s[end] != '\n') { end += 1; };
return strings.sub(s, begin, end);
};
fn rejectpackagestable(root: str, label: str, target: str,
needle: str) void = {
let drivers: []str = ["ww", "ww_ww", "ww", "ww_ww"];
let tags: []str = ["c1", "w1", "c2", "w2"];
let diagnostics: []str = ["", "", "", ""];
let outstem: str = strings.concat(root, "/reject-", label);
let i: i32 = 0;
for (i < drivers.len) {
let av: []str = [driver(drivers[i]), "test", "-c", "-o",
outstem, "-I", root, target];
let out: commandout;
runcommand(root, strings.concat("reject-", label, "-", tags[i]),
av, (60i64 * (time.second: i64)): time.duration, &out);
assert(out.termination == exec.termination.EXIT && out.code != 0);
assert(has(out.stderr, needle));
diagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
let scratch: str = strings.concat(outstem, ".sepwork");
if (os.exists(scratch)) { clean(scratch); };
if (os.exists(outstem)) { clean(outstem); };
i += 1;
};
assert(same(diagnostics[0], diagnostics[2]));
assert(same(diagnostics[1], diagnostics[3]));
assert(same(diagnostics[0], diagnostics[1]));
};
fn packagepath(relative: str) str = {
return strings.concat(repo(), "/test/package/", relative);
};
fn workescape(s: str) str = {
let out: []u8 = alloc([], (s.len * 2 + 1): u64)!;
let i: i32 = 0;
for (i < s.len) {
if (s[i] == '_') {
append(out, '_'); append(out, 'u');
} else { if (s[i] == '/') {
append(out, '_'); append(out, 's');
} else {
append(out, s[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 out: commandout;
runcommand(root, "list", av, (30i64 * (time.second: i64)): time.duration,
&out);
expectexit(&out, 0);
let first: i32 = pos(out.stdout, "routing.private_helper_first\n");
let second: i32 = pos(out.stdout, "routing.same_package\n");
let third: i32 = pos(out.stdout, "routing_test.external_package\n");
assert(first >= 0 && first < second && second < third);
assert(occurrences(out.stdout, "routing.private_helper_first\n") == 1);
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];
runcommand(root, "run", rav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "routing.private_helper_first ... ok\n"));
assert(has(out.stdout, "routing.same_package ... ok\n"));
assert(has(out.stdout, "routing_test.external_package ... ok\n"));
assert(has(out.stdout,
"2 passed, 0 failed, 0 skipped, 0 harness errors\n"));
assert(has(out.stdout,
"1 passed, 0 failed, 0 skipped, 0 harness errors\n"));
let fav: []str = [driver("ww"), "test", "-run",
"routing.private_helper_first", "-filter", "external_package",
target];
runcommand(root, "filters", fav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "routing.private_helper_first ... ok\n"));
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];
runcommand(root, "nomatch", nav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(out.stdout, "[no matches]\n") == 2);
assert(occurrences(out.stdout,
"1 discovered, 0 selected, 0 started, 0 completed\n") == 1);
assert(occurrences(out.stdout,
"2 discovered, 0 selected, 0 started, 0 completed\n") == 1);
let lnav: []str = [driver("ww"), "test", "-list", "-run",
"no-such-*", target];
runcommand(root, "list-nomatch", lnav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(out.stdout, "[no matches]\n") == 2);
clean(root);
};
@test fn imported_dependency_tests_do_not_leak() void = {
let root: str = fresh();
let base: str = packagepath("dependency");
let av: []str = [driver("ww"), "test", "-I", base,
strings.concat(base, "/root")];
let out: commandout;
runcommand(root, "dependency", av,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "root.imported_production_only ... ok\n"));
assert(!has(out.stdout, "imported_dependency_test_must_not_leak"));
assert(has(out.stdout,
"1 discovered, 1 selected, 1 started, 1 completed\n"));
clean(root);
};
// Go's contract: only *_test.ww sources are test sources; a line-leading
// @test anywhere else fails classification loudly rather than run or
// drop silently.
@test fn noncanonical_attest_rejected() void = {
let root: str = fresh();
let pkgdir: str = strings.concat(root, "/noncanon");
assert(os.mkdir(pkgdir, 448i32) == 0);
writefile(strings.concat(pkgdir, "/noncanon.ww"), strings.concat(
"package noncanon;\n",
"@test\n/* lexer whitespace is legal here */\n",
"fn hidden() void = { assert(false); };\n"));
let stages: []str = ["ww", "ww_ww"];
let out: commandout;
let i: i32 = 0;
for (i < stages.len) {
let av: []str = [driver(stages[i]), "test", pkgdir];
runcommand(root, strings.concat("noncanon-", stages[i]), av,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "@test declaration outside *_test.ww"));
assert(!has(out.stdout, "hidden"));
i += 1;
};
clean(root);
};
@test fn empty_and_invalid_package_classes() void = {
let root: str = fresh();
let av: []str = [driver("ww"), "test", packagepath("no_tests")];
let out: commandout;
runcommand(root, "notests", av,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, " [no tests]\n"));
assert(!has(out.stdout, " ... ok"));
let bad: []str = [driver("ww"), "test", packagepath("bad_external")];
runcommand(root, "badexternal", bad,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr,
"test package must match production package or <package>_test"));
let empty: str = strings.concat(root, "/empty");
assert(os.mkdir(empty, 448i32) == 0);
let emptyav: []str = [driver("ww"), "test", empty];
runcommand(root, "emptydir", emptyav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "directory contains no WW package sources"));
let invalid: str = strings.concat(root, "/invalid-no-tests");
assert(os.mkdir(invalid, 448i32) == 0);
writefile(strings.concat(invalid, "/invalid.ww"),
"package invalid;\nimport nowhere;\n");
let invalidav: []str = [driver("ww"), "test", invalid];
runcommand(root, "invalid-no-tests", invalidav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "cannot find package nowhere"));
assert(!has(out.stdout, "[no tests]"));
// A test file is part of its variant even when it only supplies helpers.
// Its imports and package clause must therefore reach the shared loader;
// the coordinator cannot use textual @test presence as a source filter.
let helperbad: str = strings.concat(root, "/helperbad");
assert(os.mkdir(helperbad, 448i32) == 0);
writefile(strings.concat(helperbad, "/helperbad.ww"),
"package helperbad;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(helperbad, "/helper_test.ww"),
"package helperbad_test;\nimport nowhere;\nfn helper() void = { };\n");
let stages: []str = ["ww", "ww_ww"];
let si: i32 = 0;
for (si < stages.len) {
let helperav: []str = [driver(stages[si]), "test", helperbad];
runcommand(root, strings.concat("helper-only-", stages[si]), helperav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "cannot find package nowhere"));
si += 1;
};
let helperwrong: str = strings.concat(root, "/helperwrong");
assert(os.mkdir(helperwrong, 448i32) == 0);
writefile(strings.concat(helperwrong, "/helperwrong.ww"),
"package helperwrong;\nfn value() void = { };\n");
writefile(strings.concat(helperwrong, "/wrong_test.ww"),
"package unrelated;\nfn helper() void = { };\n");
let wrongav: []str = [driver("ww"), "test", helperwrong];
runcommand(root, "helper-wrong-package", wrongav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr,
"test package must match production package or <package>_test"));
// The bootstrap drivers store package identities in the same 256-byte
// slot. Reject an overlong coordinator selector before either stage can
// truncate it into a different package graph.
let longdir: str = strings.concat(root, "/long-package");
assert(os.mkdir(longdir, 448i32) == 0);
let chunk: str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
let longname: str = strings.concat(chunk, chunk, chunk, chunk,
chunk, chunk, chunk, chunk);
assert(longname.len == 256);
writefile(strings.concat(longdir, "/long.ww"),
strings.concat("package ", longname, ";\nfn value() void = { };\n"));
let longc: []str = [driver("ww"), "test", longdir];
let longw: []str = [driver("ww_ww"), "test", longdir];
let outc: commandout;
let outw: commandout;
runcommand(root, "long-package-c", longc,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "long-package-ww", longw,
(30i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "invalid --ww-package-test variant"));
let multiline: str = strings.concat(root, "/multiline-test");
assert(os.mkdir(multiline, 448i32) == 0);
writefile(strings.concat(multiline, "/multiline.ww"),
"package multiline;\nfn value() i32 = { return 42; };\n");
writefile(strings.concat(multiline, "/multiline_test.ww"),
strings.concat("package multiline;\n@test\n",
"/* lexer whitespace between attribute and declaration */\n",
"fn actually_runs() void = { assert(value() == 42); };\n"));
let multilineav: []str = [driver("ww"), "test", multiline];
runcommand(root, "multiline-test", multilineav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "multiline.actually_runs ... ok\n"));
assert(!has(out.stdout, "[no tests]"));
let commented: str = strings.concat(root, "/commented-test");
assert(os.mkdir(commented, 448i32) == 0);
writefile(strings.concat(commented, "/commented.ww"),
"package commented;\nfn value() i32 = { return 1; };\n");
writefile(strings.concat(commented, "/commented_test.ww"), strings.concat(
"package commented;\n/*\n",
"@test fn phantom() void = { assert(false); };\n",
"*/\nfn helper() void = { };\n"));
let commentedav: []str = [driver("ww"), "test", commented];
runcommand(root, "commented-test", commentedav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, " [no tests]\n"));
assert(!has(out.stdout, "phantom"));
clean(root);
};
@test fn symlink_package_is_rejected() void = {
let root: str = fresh();
let real: str = strings.concat(root, "/real");
let link: str = strings.concat(root, "/link");
assert(os.mkdir(real, 448i32) == 0);
writefile(strings.concat(real, "/real.ww"),
"package real;\nexport fn value() int = { return 1; };\n");
let lav: []str = ["/bin/ln", "-s", real, link];
let out: commandout;
runcommand(root, "link", lav, time.second, &out);
expectexit(&out, 0);
let av: []str = [driver("ww"), "test", link];
runcommand(root, "reject", av,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "symlink traversal is not allowed"));
clean(root);
};
@test fn pass_skip_and_expected_abort() void = {
let root: str = fresh();
let av: []str = [driver("ww"), "test", packagepath("cases/pass")];
let out: commandout;
runcommand(root, "pass", av,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "pass_test.alpha_pass ... ok\n"));
assert(has(out.stdout,
"pass_test.beta_skip ... SKIP: synthetic unavailable feature\n"));
assert(has(out.stdout, "pass_test.gamma_expected_abort ... ok\n"));
assert(has(out.stdout, "pass_test.delta_pass ... ok\n"));
assert(has(out.stdout,
"3 passed, 0 failed, 1 skipped, 0 harness errors\n"));
assert(has(out.stdout,
"4 discovered, 4 selected, 4 started, 4 completed\n"));
clean(root);
};
@test fn failures_are_distinct_and_clamped() void = {
let root: str = fresh();
let out: commandout;
let av: []str = [driver("ww"), "test",
packagepath("cases/assert_failure")];
runcommand(root, "assert", av,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout,
"assert_failure_test.assertion_failure ... FAIL (exit 1)\n"));
assert(!has(out.stderr, "captures:"));
let nonzeroav: []str = [driver("ww"), "test",
packagepath("cases/nonzero")];
runcommand(root, "nonzero", nonzeroav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout,
"nonzero_test.deliberate_nonzero_exit ... FAIL (exit 7)\n"));
let prematureav: []str = [driver("ww"), "test",
packagepath("cases/premature")];
runcommand(root, "premature", prematureav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout,
"premature_test.clean_exit_without_completion ... HARNESS (incomplete result)\n"));
let signalav: []str = [driver("ww"), "test",
packagepath("cases/signal")];
runcommand(root, "signal", signalav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout,
"signal_test.signal_is_not_exit ... FAIL (signal 15)\n"));
let multiav: []str = [driver("ww"), "test",
packagepath("cases/multi_fail")];
runcommand(root, "multifail", multiav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout,
"1 passed, 2 failed, 0 skipped, 0 harness errors\n"));
assert(has(out.stdout,
"3 discovered, 3 selected, 3 started, 3 completed\n"));
clean(root);
};
@test fn timeout_and_descendant_cleanup() void = {
let root: str = fresh();
let av: []str = [driver("ww"), "test", "-timeout-ms=100",
packagepath("cases/timeout")];
let out: commandout;
runcommand(root, "timeout", av,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout,
"timeout_test.timeout_clears_term_resistant_descendant ... FAIL(timeout)\n"));
assert(has(out.stdout,
"1 discovered, 1 selected, 1 started, 1 completed\n"));
let descendantav: []str = [driver("ww"), "test",
packagepath("cases/descendant")];
runcommand(root, "descendant", descendantav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout,
"descendant_test.normal_return_clears_descendant ... ok\n"));
assert(!has(out.stdout, "HARNESS"));
clean(root);
};
@test fn cstage_wwstage_behavior_and_assembly_match() void = {
let root: str = fresh();
writefile(strings.concat(root, "/route.ww"),
"package route;\nexport fn value() int = { return 7; };\n");
writefile(strings.concat(root, "/a_test.ww"),
"package route;\n@test fn white() void = { assert(value() == 7); };\n");
writefile(strings.concat(root, "/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];
runcommand(root, "list-c", listc,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "list-ww", listw,
(30i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 0);
expectexit(&outw, 0);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
let misusec: []str = [driver("ww"), "test", "-run"];
let misusew: []str = [driver("ww_ww"), "test", "-run"];
runcommand(root, "misuse-c", misusec, time.second, &outc);
runcommand(root, "misuse-ww", misusew, time.second, &outw);
expectexit(&outc, 2);
expectexit(&outw, 2);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "ww test: -run needs an argument\n"));
let timeoutc: []str = [driver("ww"), "test",
"-timeout-ms=4000000", root];
let timeoutw: []str = [driver("ww_ww"), "test",
"-timeout-ms=4000000", root];
runcommand(root, "timeout-misuse-c", timeoutc, time.second, &outc);
runcommand(root, "timeout-misuse-ww", timeoutw, time.second, &outw);
expectexit(&outc, 2);
expectexit(&outw, 2);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "usage: wwtest package"));
let cc: []str = [driver("ww"), "test", "-c", root];
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(" -> ", root, "/route_test.test\n")));
let cwhite: str = readfile(strings.concat(root,
"/route.test.sepwork/__ww-test-000-same.s"));
let cexternal: str = readfile(strings.concat(root,
"/route.test.sepwork/__ww-test-001-external.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"));
let wc: []str = [driver("ww_ww"), "test", "-c", root];
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,
"/route.test.sepwork/__ww-test-000-same.s"))));
assert(same(cexternal, readfile(strings.concat(root,
"/route.test.sepwork/__ww-test-001-external.s"))));
clean(root);
};
@test fn directory_package_graph_variants() void = {
let root: str = fresh();
let implementation: str = strings.concat(root, "/implementation");
let api: str = strings.concat(root, "/api");
let testonly: str = strings.concat(root, "/__same");
let externalonly: str = strings.concat(root, "/__external");
let pkg: str = strings.concat(root, "/pkg");
assert(os.mkdir(implementation, 448i32) == 0);
assert(os.mkdir(api, 448i32) == 0);
assert(os.mkdir(testonly, 448i32) == 0);
assert(os.mkdir(externalonly, 448i32) == 0);
assert(os.mkdir(pkg, 448i32) == 0);
writefile(strings.concat(implementation, "/implementation.ww"),
strings.concat("package implementation;\n",
"// IMPLEMENTATION_SOURCE\n",
"export fn value() i32 = { return 41; };\n"));
writefile(strings.concat(api, "/api.ww"), strings.concat(
"package api;\nimport implementation;\n",
"// API_SOURCE\n",
"export fn value() i32 = { return implementation.value(); };\n"));
writefile(strings.concat(api, "/api_test.ww"), strings.concat(
"package api;\n",
"TEST_DEPENDENCY_MUST_NOT_COMPILE\n"));
writefile(strings.concat(testonly, "/__same.ww"), strings.concat(
"package __same;\n",
"export fn value() i32 = { return 1; };\n"));
writefile(strings.concat(externalonly, "/__external.ww"), strings.concat(
"package __external;\n",
"export fn value() i32 = { return 1; };\n"));
writefile(strings.concat(pkg, "/a.ww"), strings.concat(
"package pkg;\nimport api;\n",
"// PACKAGE_PRODUCTION_A\n",
"export fn value() i32 = { return api.value(); };\n"));
writefile(strings.concat(pkg, "/z.ww"), strings.concat(
"package pkg;\n",
"// PACKAGE_PRODUCTION_Z\n",
"fn secret() i32 = { return 6; };\n",
"export fn second() i32 = { return 9; };\n"));
writefile(strings.concat(pkg, "/same_test.ww"), strings.concat(
"package pkg;\nimport __same;\n",
"// SAME_TEST_SOURCE\n",
"@test fn same_graph() void = {\n",
" assert(value() + __same.value() == 42);\n",
" assert(secret() == 6);\n};\n"));
writefile(strings.concat(pkg, "/external_test.ww"), strings.concat(
"package pkg_test;\nimport __external;\nimport pkg;\n",
"// EXTERNAL_TEST_SOURCE\n",
"@test fn external_graph() void = {\n",
" assert(pkg.value() + __external.value() == 42);\n",
" assert(pkg.second() == 9);\n};\n"));
let prodout: str = strings.concat(root, "/production.a");
let prodav: []str = [driver("ww"), "build", "-p", "-I", root,
"-o", prodout, pkg];
let out: commandout;
runcommand(root, "production-build", prodav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let prodwork: str = strings.concat(prodout, ".sepwork/");
let produnit: str = readfile(strings.concat(prodwork,
"pkg.unit.ww"));
assert(has(produnit, "//ww:module api\n"));
assert(!has(produnit, "//ww:module implementation\n"));
assert(!has(produnit, "__same"));
assert(!has(produnit, "__external"));
assert(!os.exists(strings.concat(prodwork, "__same.unit.ww")));
assert(!os.exists(strings.concat(prodwork, "__external.unit.ww")));
assert(!has(readfile(strings.concat(prodwork, "api.unit.ww")),
"TEST_DEPENDENCY_MUST_NOT_COMPILE"));
let samebin: str = strings.concat(pkg, "/pkg.test");
let externalbin: str = strings.concat(pkg, "/pkg_test.test");
let sharedworkroot: str = strings.concat(samebin, ".sepwork");
let sharedwork: str = strings.concat(sharedworkroot, "/");
let compilertrace: str = strings.concat(root, "/compiler.trace");
let linkertrace: str = strings.concat(root, "/linker.trace");
let compilerwrapper: str = strings.concat(root, "/trace-w6c.sh");
let linkerwrapper: str = strings.concat(root, "/trace-w6l.sh");
writefile(compilertrace, "");
writefile(linkertrace, "");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_COMPILER_TRACE\"\n",
"exec \"$WW_PACKAGE_W6C\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_LINKER_TRACE\"\n",
"exec \"$WW_PACKAGE_W6L\" \"$@\"\n"));
let baseenv: []str = os.getenvs();
let traceenv: []str = alloc([], (baseenv.len + 6): u64)!;
let ei: i32 = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_W6L=")
&& !strings.hasprefix(baseenv[ei],
"WW_PACKAGE_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_PACKAGE_LINKER_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6L=")) {
append(traceenv, baseenv[ei]);
};
ei += 1;
};
append(traceenv, strings.concat("WW_W6C=", compilerwrapper));
append(traceenv, strings.concat("WW_W6L=", linkerwrapper));
append(traceenv, strings.concat("WW_PACKAGE_COMPILER_TRACE=",
compilertrace));
append(traceenv, strings.concat("WW_PACKAGE_LINKER_TRACE=", linkertrace));
append(traceenv, strings.concat("WW_PACKAGE_W6C=", driver("w6c")));
append(traceenv, strings.concat("WW_PACKAGE_W6L=", driver("w6l")));
let drivers: []str = ["ww", "ww", "ww_ww"];
let tags: []str = ["c1", "c2", "ww"];
let referenceout: str = "";
let referenceerr: str = "";
let referencesame: str = "";
let referenceexternal: str = "";
let referencesameunit: str = "";
let referenceexternalunit: str = "";
let referenceproductionunit: str = "";
let i: i32 = 0;
for (i < drivers.len) {
let av: []str = [driver(drivers[i]), "test", "-c", "-I", root,
pkg];
if (i == 0) {
runcommandenv(root, strings.concat("variant-build-", tags[i]), av,
traceenv, (120i64 * (time.second: i64)): time.duration,
&out);
} else {
runcommand(root, strings.concat("variant-build-", tags[i]), av,
(120i64 * (time.second: i64)): time.duration, &out);
};
expectexit(&out, 0);
let buildstdout: str = strings.dup(out.stdout);
let buildstderr: str = strings.dup(out.stderr);
let sameunit: str = readfile(strings.concat(sharedwork,
"__ww-test-000-same.unit.ww"));
let externalunit: str = readfile(strings.concat(sharedwork,
"__ww-test-001-external.unit.ww"));
let externalproduction: str = readfile(strings.concat(sharedwork,
"__ww-test-001-external-production.unit.ww"));
assert(!os.exists(strings.concat(externalbin, ".sepwork")));
assert(has(sameunit, "//ww:module api\n"));
assert(has(sameunit, "//ww:module __same\n"));
assert(has(sameunit, "//ww:module test\n"));
assert(!has(sameunit, "//ww:module implementation\n"));
assert(!has(sameunit, "//ww:module __external\n"));
assert(os.exists(strings.concat(sharedwork,
"__external.unit.ww")));
assert(has(sameunit, "PACKAGE_PRODUCTION_A"));
assert(has(sameunit, "PACKAGE_PRODUCTION_Z"));
assert(has(sameunit, "SAME_TEST_SOURCE"));
assert(!has(sameunit, "EXTERNAL_TEST_SOURCE"));
assert(has(externalunit, "//ww:module pkg\n"));
assert(has(externalunit, "//ww:module __external\n"));
assert(has(externalunit, "//ww:module test\n"));
assert(!has(externalunit, "//ww:module api\n"));
assert(!has(externalunit, "//ww:module implementation\n"));
assert(!has(externalunit, "//ww:module __same\n"));
assert(has(externalunit, "EXTERNAL_TEST_SOURCE"));
assert(!has(externalunit, "PACKAGE_PRODUCTION_A"));
assert(!has(externalunit, "PACKAGE_PRODUCTION_Z"));
assert(has(externalproduction, "PACKAGE_PRODUCTION_A"));
assert(has(externalproduction, "PACKAGE_PRODUCTION_Z"));
assert(has(externalproduction, "//ww:module api\n"));
assert(!has(externalproduction, "//ww:module implementation\n"));
assert(!has(externalproduction, "SAME_TEST_SOURCE"));
assert(!has(externalproduction, "EXTERNAL_TEST_SOURCE"));
assert(!has(readfile(strings.concat(sharedwork, "api.unit.ww")),
"TEST_DEPENDENCY_MUST_NOT_COMPILE"));
let artifacts: []str = ["implementation", "api",
"__ww-test-001-external-production",
"__same", "__external", "test"];
let ai: i32 = 0;
for (ai < artifacts.len) {
assert(os.exists(strings.concat(sharedwork, artifacts[ai], ".wwi")));
assert(os.exists(strings.concat(sharedwork, artifacts[ai], ".a")));
ai += 1;
};
assert(os.exists(strings.concat(sharedwork, "__ww-test-000-same.o")));
assert(os.exists(strings.concat(sharedwork,
"__ww-test-001-external.o")));
assert(!os.exists(strings.concat(sharedwork,
"__ww-test-000-same.wwi")));
assert(!os.exists(strings.concat(sharedwork,
"__ww-test-001-external.wwi")));
assert(!os.exists(strings.concat(sharedwork,
"__ww-test-000-same.a")));
assert(!os.exists(strings.concat(sharedwork,
"__ww-test-001-external.a")));
assert(os.exists(samebin));
assert(os.exists(externalbin));
if (i == 0) {
let ctrace: str = readfile(compilertrace);
assert(occurrences(ctrace, "implementation.unit.ww") == 1);
assert(occurrences(ctrace, "api.unit.ww") == 1);
assert(occurrences(ctrace,
"__ww-test-001-external-production.unit.ww") == 1);
assert(occurrences(ctrace, "/__same.unit.ww") == 1);
assert(occurrences(ctrace, "/__external.unit.ww") == 1);
assert(occurrences(ctrace, "/test.unit.ww") == 1);
assert(occurrences(ctrace,
"__ww-test-000-same.unit.ww") == 1);
assert(occurrences(ctrace,
"__ww-test-001-external.unit.ww") == 1);
assert(occurrences(ctrace,
"-T --test-support-module") == 2);
let ltrace: str = readfile(linkertrace);
assert(occurrences(ltrace, "\n") == 2);
let samelink: str = linecontaining(ltrace,
strings.concat("-o ", samebin, " "));
let externallink: str = linecontaining(ltrace,
strings.concat("-o ", externalbin, " "));
assert(has(samelink, strings.concat(sharedwork, "api.a")));
assert(has(samelink,
strings.concat(sharedwork, "implementation.a")));
assert(has(samelink, strings.concat(sharedwork, "__same.a")));
assert(!has(samelink, strings.concat(sharedwork,
"__ww-test-001-external-production.a")));
assert(!has(samelink,
strings.concat(sharedwork, "__external.a")));
assert(has(externallink, strings.concat(sharedwork,
"__ww-test-001-external-production.a")));
assert(has(externallink, strings.concat(sharedwork, "api.a")));
assert(has(externallink,
strings.concat(sharedwork, "implementation.a")));
assert(has(externallink,
strings.concat(sharedwork, "__external.a")));
assert(!has(externallink,
strings.concat(sharedwork, "__same.a")));
};
let runav: []str = [samebin];
runcommand(root, strings.concat("variant-run-same-", tags[i]), runav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "same_graph ... ok\n"));
let externalrun: []str = [externalbin];
runcommand(root, strings.concat("variant-run-external-", tags[i]),
externalrun, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "external_graph ... ok\n"));
if (i == 0) {
referenceout = buildstdout;
referenceerr = buildstderr;
referencesame = readfile(samebin);
referenceexternal = readfile(externalbin);
referencesameunit = strings.dup(sameunit);
referenceexternalunit = strings.dup(externalunit);
referenceproductionunit = strings.dup(externalproduction);
} else {
assert(same(referencesame, readfile(samebin)));
assert(same(referenceexternal, readfile(externalbin)));
assert(same(referencesameunit, sameunit));
assert(same(referenceexternalunit, externalunit));
assert(same(referenceproductionunit, externalproduction));
assert(same(referenceout, buildstdout));
assert(same(referenceerr, buildstderr));
};
if (i + 1 < drivers.len) {
clean(sharedworkroot);
clean(samebin); clean(externalbin);
};
i += 1;
};
// The illegal-in-import root keys stay disjoint from the valid packages
// literally named __same and __external, including warm reuse.
let warmroot: str = strings.concat(root, "/warm");
assert(os.mkdir(warmroot, 448i32) == 0);
let warmav: []str = [driver("ww"), "test", "-w", warmroot,
"-I", root, pkg];
runcommandenv(root, "variant-warm-cold", warmav, traceenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let warmstdout: str = strings.dup(out.stdout);
let warmstderr: str = strings.dup(out.stderr);
let warmtrace: str = readfile(compilertrace);
let warmwork: str = strings.concat(warmroot, "/d_", workescape(pkg),
"_p_pkg/");
assert(has(readfile(strings.concat(warmwork, "__same.unit.ww")),
"package __same;"));
assert(has(readfile(strings.concat(warmwork,
"__ww-test-000-same.unit.ww")), "SAME_TEST_SOURCE"));
assert(has(readfile(strings.concat(warmwork, "__external.unit.ww")),
"package __external;"));
assert(has(readfile(strings.concat(warmwork,
"__ww-test-001-external.unit.ww")), "EXTERNAL_TEST_SOURCE"));
assert(has(readfile(strings.concat(warmwork,
"__ww-test-001-external-production.unit.ww")),
"PACKAGE_PRODUCTION_A"));
runcommandenv(root, "variant-warm-reuse", warmav, traceenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(warmstdout, out.stdout));
assert(same(warmstderr, out.stderr));
assert(same(warmtrace, readfile(compilertrace)));
let aliasunit: str = strings.concat(root, "/alias.unit.ww");
writefile(aliasunit, strings.concat(
"//ww:module-reset __wwtest\n",
"package test;\nexport fn value() i32 = { return 1; };\n"));
let aliasstages: []str = ["w6c", "w6c_ww"];
let aliaserrs: []str = ["", ""];
i = 0;
for (i < aliasstages.len) {
let asmout: str = strings.concat(root, "/alias-", aliasstages[i],
".s");
let rawav: []str = [driver(aliasstages[i]), "-c", "-o", asmout,
aliasunit];
runcommand(root, strings.concat("alias-unowned-", aliasstages[i]),
rawav, (30i64 * (time.second: i64)): time.duration, &out);
assert(out.termination == exec.termination.EXIT && out.code != 0);
assert(has(out.stderr, "package")
&& has(out.stderr, "does not match import path"));
let badav: []str = [driver(aliasstages[i]), "-c",
"--test-support-module", "arbitrary", "-o", asmout, aliasunit];
runcommand(root, strings.concat("alias-arbitrary-", aliasstages[i]),
badav, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 2);
assert(has(out.stderr, "invalid --test-support-module"));
aliaserrs[i] = strings.dup(out.stderr);
i += 1;
};
assert(same(aliaserrs[0], aliaserrs[1]));
clean(root);
};
@test fn multi_directory_shared_package_plan() void = {
let root: str = fresh();
let leaf: str = strings.concat(root, "/leaf");
let common: str = strings.concat(root, "/common");
let suite: str = strings.concat(root, "/suite");
let alpha: str = strings.concat(suite, "/alpha");
let beta: str = strings.concat(suite, "/beta");
let alphasame: str = strings.concat(alpha, "/_alpha_same");
let alphaexternal: str = strings.concat(alpha, "/_alpha_external");
let betasame: str = strings.concat(beta, "/_beta_same");
let betaexternal: str = strings.concat(beta, "/_beta_external");
let alphashadow: str = strings.concat(root, "/_alpha_same");
let betashadow: str = strings.concat(root, "/_beta_same");
let dirs: []str = [leaf, common, suite, alpha, beta, alphasame,
alphaexternal, betasame, betaexternal, alphashadow, betashadow];
let di: i32 = 0;
for (di < dirs.len) {
assert(os.mkdir(dirs[di], 448i32) == 0);
di += 1;
};
writefile(strings.concat(leaf, "/leaf.ww"), strings.concat(
"package leaf;\n",
"// MULTIDIR_LEAF\n",
"export fn value() i32 = { return 40; };\n"));
writefile(strings.concat(common, "/common.ww"), strings.concat(
"package common;\nimport leaf;\n",
"// MULTIDIR_COMMON\n",
"export fn value() i32 = { return leaf.value(); };\n"));
writefile(strings.concat(common, "/common_test.ww"), strings.concat(
"package common;\n",
"DEPENDENCY_TEST_FILE_MUST_NOT_COMPILE\n"));
writefile(strings.concat(alphasame, "/_alpha_same.ww"),
"package _alpha_same;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(alphaexternal, "/_alpha_external.ww"),
"package _alpha_external;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(betasame, "/_beta_same.ww"),
"package _beta_same;\nexport fn value() i32 = { return 2; };\n");
writefile(strings.concat(betaexternal, "/_beta_external.ww"),
"package _beta_external;\nexport fn value() i32 = { return 2; };\n");
// The explicit -I root contains deliberately wrong shadows. Each selected
// directory must retain its own first lookup root inside the union plan.
writefile(strings.concat(alphashadow, "/_alpha_same.ww"),
"package _alpha_same;\nexport fn value() i32 = { return 99; };\n");
writefile(strings.concat(betashadow, "/_beta_same.ww"),
"package _beta_same;\nexport fn value() i32 = { return 99; };\n");
writefile(strings.concat(alpha, "/a.ww"), strings.concat(
"package alpha;\nimport common;\n",
"// MULTIDIR_ALPHA_A\n",
"export fn value() i32 = { return common.value(); };\n"));
writefile(strings.concat(alpha, "/z.ww"), strings.concat(
"package alpha;\n",
"// MULTIDIR_ALPHA_Z\n",
"fn secret() i32 = { return 1; };\n",
"export fn exported() i32 = { return 1; };\n"));
writefile(strings.concat(alpha, "/same_test.ww"), strings.concat(
"package alpha;\nimport _alpha_same;\n",
"// MULTIDIR_ALPHA_SAME\n",
"@test fn alpha_same_runs() void = {\n",
" assert(value() + secret() + _alpha_same.value() == 42);\n};\n"));
writefile(strings.concat(alpha, "/external_test.ww"), strings.concat(
"package alpha_test;\nimport alpha;\nimport _alpha_external;\n",
"// MULTIDIR_ALPHA_EXTERNAL\n",
"@test fn alpha_external_runs() void = {\n",
" assert(alpha.value() + alpha.exported()",
" + _alpha_external.value() == 42);\n};\n"));
writefile(strings.concat(beta, "/beta.ww"), strings.concat(
"package beta;\nimport common;\nimport alpha;\n",
"// MULTIDIR_BETA\n",
"fn secret() i32 = { return 2; };\n",
"export fn value() i32 = { return common.value(); };\n",
"export fn exported() i32 = { return alpha.exported() + 1; };\n"));
writefile(strings.concat(beta, "/same_test.ww"), strings.concat(
"package beta;\nimport _beta_same;\n",
"// MULTIDIR_BETA_SAME\n",
"@test fn beta_same_runs() void = {\n",
" assert(value() + secret() + _beta_same.value() == 44);\n};\n"));
writefile(strings.concat(beta, "/external_test.ww"), strings.concat(
"package beta_test;\nimport beta;\nimport _beta_external;\n",
"// MULTIDIR_BETA_EXTERNAL\n",
"@test fn beta_external_runs() void = {\n",
" assert(beta.value() + beta.exported()",
" + _beta_external.value() == 44);\n};\n"));
let compilertrace: str = strings.concat(root, "/compiler.trace");
let linkertrace: str = strings.concat(root, "/linker.trace");
let compilerwrapper: str = strings.concat(root, "/trace-w6c.sh");
let linkerwrapper: str = strings.concat(root, "/trace-w6l.sh");
writefile(compilertrace, "");
writefile(linkertrace, "");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_COMPILER_TRACE\"\n",
"exec \"$WW_PACKAGE_W6C\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_LINKER_TRACE\"\n",
"exec \"$WW_PACKAGE_W6L\" \"$@\"\n"));
let baseenv: []str = os.getenvs();
let traceenv: []str = alloc([], (baseenv.len + 6): u64)!;
let ei: i32 = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_W6L=")
&& !strings.hasprefix(baseenv[ei],
"WW_PACKAGE_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_PACKAGE_LINKER_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6L=")) {
append(traceenv, baseenv[ei]);
};
ei += 1;
};
append(traceenv, strings.concat("WW_W6C=", compilerwrapper));
append(traceenv, strings.concat("WW_W6L=", linkerwrapper));
append(traceenv, strings.concat("WW_PACKAGE_COMPILER_TRACE=",
compilertrace));
append(traceenv, strings.concat("WW_PACKAGE_LINKER_TRACE=", linkertrace));
append(traceenv, strings.concat("WW_PACKAGE_W6C=", driver("w6c")));
append(traceenv, strings.concat("WW_PACKAGE_W6L=", driver("w6l")));
// 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);
let wwtracedriver: str = strings.concat(wwtracebin, "/ww_ww");
let wwcompilertrace: str = strings.concat(root, "/ww-compiler.trace");
let wwlinkertrace: str = strings.concat(root, "/ww-linker.trace");
writefile(wwcompilertrace, "");
writefile(wwlinkertrace, "");
writeexecutable(wwtracedriver, readfile(driver("ww_ww")));
writeexecutable(strings.concat(wwtracebin, "/wwtest"),
readfile(driver("wwtest")));
writeexecutable(strings.concat(wwtracebin, "/w6c_ww"), strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_WW_COMPILER_TRACE\"\n",
"exec \"$WW_PACKAGE_W6C_WW\" \"$@\"\n"));
writeexecutable(strings.concat(wwtracebin, "/w6a_ww"), strings.concat(
"#!/bin/sh\nexec \"$WW_PACKAGE_W6A_WW\" \"$@\"\n"));
writeexecutable(strings.concat(wwtracebin, "/w6l_ww"), strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_WW_LINKER_TRACE\"\n",
"exec \"$WW_PACKAGE_W6L_WW\" \"$@\"\n"));
let wwtraceenv: []str = alloc([], (baseenv.len + 5): u64)!;
ei = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_PACKAGE_WW_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_WW_LINKER_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C_WW=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6A_WW=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6L_WW=")) {
append(wwtraceenv, baseenv[ei]);
};
ei += 1;
};
append(wwtraceenv, strings.concat("WW_PACKAGE_WW_COMPILER_TRACE=",
wwcompilertrace));
append(wwtraceenv, strings.concat("WW_PACKAGE_WW_LINKER_TRACE=",
wwlinkertrace));
append(wwtraceenv, strings.concat("WW_PACKAGE_W6C_WW=", driver("w6c_ww")));
append(wwtraceenv, strings.concat("WW_PACKAGE_W6A_WW=", driver("w6a_ww")));
append(wwtraceenv, strings.concat("WW_PACKAGE_W6L_WW=", driver("w6l_ww")));
let bins: []str = [strings.concat(alpha, "/alpha.test"),
strings.concat(alpha, "/alpha_test.test"),
strings.concat(beta, "/beta.test"),
strings.concat(beta, "/beta_test.test")];
let rootkeys: []str = ["__ww-test-000-same",
"__ww-test-001-external", "__ww-test-002-same",
"__ww-test-003-external"];
let alphaartifact: str = "__ww-test-001-external-production";
let betaartifact: str = "__ww-test-003-external-production";
let expectedtests: []str = ["alpha_same_runs ... ok\n",
"alpha_external_runs ... ok\n", "beta_same_runs ... ok\n",
"beta_external_runs ... ok\n"];
let sharedworkroot: str = strings.concat(bins[0], ".sepwork");
let sharedwork: str = strings.concat(sharedworkroot, "/");
let referencebins: []str = ["", "", "", ""];
let referenceroots: []str = ["", "", "", ""];
let referenceout: str = "";
let referenceerr: str = "";
let referencecommonwwi: str = "";
let referencecommona: str = "";
let referencealphaa: str = "";
let stages: []str = ["ww", "ww", "ww_ww"];
let tags: []str = ["c1", "c2", "ww"];
let out: commandout;
let si: i32 = 0;
for (si < stages.len) {
let stagepath: str = driver(stages[si]);
if (si == 2) { stagepath = wwtracedriver; };
let av: []str = [stagepath, "test", "-c", "-j", "1",
"-I", suite, "-I", root, strings.concat(suite, "/...")];
if (si == 0) {
runcommandenv(root, "multidir-c1", av, traceenv,
(120i64 * (time.second: i64)): time.duration, &out);
} else { if (si == 2) {
runcommandenv(root, strings.concat("multidir-", tags[si]), av,
wwtraceenv,
(120i64 * (time.second: i64)): time.duration, &out);
} else {
runcommand(root, strings.concat("multidir-", tags[si]), av,
(120i64 * (time.second: i64)): time.duration, &out);
}; };
expectexit(&out, 0);
let buildstdout: str = strings.dup(out.stdout);
let buildstderr: str = strings.dup(out.stderr);
let commonunit: str = readfile(strings.concat(sharedwork,
"common.unit.ww"));
let alphaunit: str = readfile(strings.concat(sharedwork,
alphaartifact, ".unit.ww"));
let betaunit: str = readfile(strings.concat(sharedwork,
betaartifact, ".unit.ww"));
assert(has(commonunit, "//ww:module leaf\n"));
assert(!has(commonunit, "//ww:module test\n"));
assert(has(alphaunit, "//ww:module common\n"));
assert(!has(alphaunit, "//ww:module leaf\n"));
assert(has(alphaunit, "MULTIDIR_ALPHA_A"));
assert(has(alphaunit, "MULTIDIR_ALPHA_Z"));
assert(has(betaunit, "//ww:module common\n"));
assert(has(betaunit, "//ww:module alpha\n"));
assert(!has(betaunit, "//ww:module leaf\n"));
assert(!has(commonunit, "DEPENDENCY_TEST_FILE_MUST_NOT_COMPILE"));
let roots: []str = [readfile(strings.concat(sharedwork,
rootkeys[0], ".unit.ww")), readfile(strings.concat(sharedwork,
rootkeys[1], ".unit.ww")), readfile(strings.concat(sharedwork,
rootkeys[2], ".unit.ww")), readfile(strings.concat(sharedwork,
rootkeys[3], ".unit.ww"))];
assert(has(roots[0], "//ww:module _alpha_same\n"));
assert(has(roots[0], "//ww:module common\n"));
assert(has(roots[0], "//ww:module test\n"));
assert(!has(roots[0], "//ww:module leaf\n"));
assert(!has(roots[0], "//ww:module alpha\n"));
assert(has(roots[0], "MULTIDIR_ALPHA_A"));
assert(has(roots[0], "MULTIDIR_ALPHA_Z"));
assert(has(roots[1], "//ww:module alpha\n"));
assert(has(roots[1], "//ww:module _alpha_external\n"));
assert(has(roots[1], "//ww:module test\n"));
assert(!has(roots[1], "//ww:module common\n"));
assert(!has(roots[1], "//ww:module _alpha_same\n"));
assert(has(roots[2], "//ww:module _beta_same\n"));
assert(has(roots[2], "//ww:module common\n"));
assert(has(roots[2], "//ww:module alpha\n"));
assert(has(roots[2], "//ww:module test\n"));
assert(!has(roots[2], "//ww:module leaf\n"));
assert(!has(roots[2], "//ww:module beta\n"));
assert(has(roots[3], "//ww:module beta\n"));
assert(has(roots[3], "//ww:module _beta_external\n"));
assert(has(roots[3], "//ww:module test\n"));
assert(!has(roots[3], "//ww:module common\n"));
let products: []str = ["leaf", "common", alphaartifact, betaartifact,
"_alpha_same", "_alpha_external", "_beta_same",
"_beta_external", "test"];
let pi: i32 = 0;
for (pi < products.len) {
assert(os.exists(strings.concat(sharedwork, products[pi],
".unit.ww")));
assert(os.exists(strings.concat(sharedwork, products[pi], ".wwi")));
assert(os.exists(strings.concat(sharedwork, products[pi], ".a")));
pi += 1;
};
let ri: i32 = 0;
for (ri < rootkeys.len) {
assert(os.exists(strings.concat(sharedwork, rootkeys[ri], ".o")));
assert(!os.exists(strings.concat(sharedwork, rootkeys[ri], ".wwi")));
assert(!os.exists(strings.concat(sharedwork, rootkeys[ri], ".a")));
assert(os.exists(bins[ri]));
if (ri > 0) {
assert(!os.exists(strings.concat(bins[ri], ".sepwork")));
};
let runav: []str = [bins[ri]];
runcommand(root, strings.concat("multidir-run-", tags[si], "-",
rootkeys[ri]), runav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, expectedtests[ri]));
ri += 1;
};
if (si == 0) {
let ctrace: str = readfile(compilertrace);
let once: []str = ["leaf", "common", alphaartifact, betaartifact,
"_alpha_same", "_alpha_external", "_beta_same",
"_beta_external", "test"];
pi = 0;
for (pi < once.len) {
assert(occurrences(ctrace, strings.concat("/", once[pi],
".unit.ww")) == 1);
pi += 1;
};
// alpha is both a selected external-test production package and a
// direct dependency of beta. Those identities must intern to the one
// owning production action above, never a second alpha.unit.ww.
assert(occurrences(ctrace, "/alpha.unit.ww") == 0);
ri = 0;
for (ri < rootkeys.len) {
assert(occurrences(ctrace, strings.concat(rootkeys[ri],
".unit.ww")) == 1);
ri += 1;
};
assert(pos(ctrace, "/leaf.unit.ww")
< pos(ctrace, "/common.unit.ww"));
assert(pos(ctrace, "/common.unit.ww")
< pos(ctrace, strings.concat("/", alphaartifact,
".unit.ww")));
assert(pos(ctrace, "/common.unit.ww")
< pos(ctrace, strings.concat("/", betaartifact,
".unit.ww")));
let ltrace: str = readfile(linkertrace);
assert(occurrences(ltrace, "\n") == 4);
ri = 0;
for (ri < bins.len) {
let link: str = linecontaining(ltrace,
strings.concat("-o ", bins[ri], " "));
assert(has(link, strings.concat(sharedwork, rootkeys[ri], ".o")));
assert(has(link, strings.concat(sharedwork, "common.a")));
assert(has(link, strings.concat(sharedwork, "leaf.a")));
assert(has(link, strings.concat(sharedwork, "test.a")));
if (ri < 2) {
assert(!has(link, strings.concat(sharedwork,
betaartifact, ".a")));
assert(!has(link, strings.concat(sharedwork, "_beta_same.a")));
assert(!has(link, strings.concat(sharedwork,
"_beta_external.a")));
} else {
assert(has(link, strings.concat(sharedwork,
alphaartifact, ".a")));
assert(!has(link, strings.concat(sharedwork, "_alpha_same.a")));
assert(!has(link, strings.concat(sharedwork,
"_alpha_external.a")));
};
if (ri == 0) {
assert(has(link, strings.concat(sharedwork, "_alpha_same.a")));
assert(!has(link, strings.concat(sharedwork,
alphaartifact, ".a")));
assert(!has(link, strings.concat(sharedwork,
"_alpha_external.a")));
} else { if (ri == 1) {
assert(has(link, strings.concat(sharedwork,
alphaartifact, ".a")));
assert(has(link, strings.concat(sharedwork,
"_alpha_external.a")));
assert(!has(link, strings.concat(sharedwork, "_alpha_same.a")));
} else { if (ri == 2) {
assert(has(link, strings.concat(sharedwork, "_beta_same.a")));
assert(!has(link, strings.concat(sharedwork,
betaartifact, ".a")));
assert(!has(link, strings.concat(sharedwork,
"_beta_external.a")));
} else {
assert(has(link, strings.concat(sharedwork,
betaartifact, ".a")));
assert(has(link, strings.concat(sharedwork,
"_beta_external.a")));
assert(!has(link, strings.concat(sharedwork, "_beta_same.a")));
}; }; };
ri += 1;
};
referenceout = buildstdout;
referenceerr = buildstderr;
referencecommonwwi = strings.dup(readfile(strings.concat(sharedwork,
"common.wwi")));
referencecommona = strings.dup(readfile(strings.concat(sharedwork,
"common.a")));
referencealphaa = strings.dup(readfile(strings.concat(sharedwork,
alphaartifact, ".a")));
ri = 0;
for (ri < bins.len) {
referencebins[ri] = strings.dup(readfile(bins[ri]));
referenceroots[ri] = strings.dup(roots[ri]);
ri += 1;
};
} else {
assert(same(referenceout, buildstdout));
assert(same(referenceerr, buildstderr));
assert(same(referencecommonwwi,
readfile(strings.concat(sharedwork, "common.wwi"))));
assert(same(referencecommona,
readfile(strings.concat(sharedwork, "common.a"))));
assert(same(referencealphaa,
readfile(strings.concat(sharedwork, alphaartifact, ".a"))));
ri = 0;
for (ri < bins.len) {
assert(same(referencebins[ri], readfile(bins[ri])));
assert(same(referenceroots[ri], roots[ri]));
ri += 1;
};
};
if (si == 2) {
let wwtrace: str = readfile(wwcompilertrace);
let once: []str = ["leaf", "common", alphaartifact, betaartifact,
"_alpha_same", "_alpha_external", "_beta_same",
"_beta_external", "test"];
pi = 0;
for (pi < once.len) {
assert(occurrences(wwtrace, strings.concat("/", once[pi],
".unit.ww")) == 1);
pi += 1;
};
assert(occurrences(wwtrace, "/alpha.unit.ww") == 0);
ri = 0;
for (ri < rootkeys.len) {
assert(occurrences(wwtrace, strings.concat(rootkeys[ri],
".unit.ww")) == 1);
ri += 1;
};
assert(occurrences(readfile(wwlinkertrace), "\n") == 4);
};
if (si + 1 < stages.len) {
clean(sharedworkroot);
ri = 0;
for (ri < bins.len) { clean(bins[ri]); ri += 1; };
};
si += 1;
};
clean(sharedworkroot);
let bi: i32 = 0;
for (bi < bins.len) { clean(bins[bi]); bi += 1; };
let warmroot: str = strings.concat(root, "/warm-c");
let warmwwroot: str = strings.concat(root, "/warm-ww");
assert(os.mkdir(warmroot, 448i32) == 0);
assert(os.mkdir(warmwwroot, 448i32) == 0);
let warmc: []str = [driver("ww"), "test", "-j", "1", "-w",
warmroot, "-I", suite, "-I", root,
strings.concat(suite, "/...")];
runcommandenv(root, "multidir-warm-cold", warmc, traceenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let warmstdout: str = strings.dup(out.stdout);
let warmstderr: str = strings.dup(out.stderr);
let warmtrace: str = readfile(compilertrace);
let warmparallel: []str = [driver("ww"), "test", "-j", "4", "-w",
warmroot, "-I", suite, "-I", root,
strings.concat(suite, "/...")];
runcommandenv(root, "multidir-warm-reuse", warmparallel, 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 warmwork: str = strings.concat(warmroot, warmkey);
assert(os.exists(strings.concat(warmwork,
"__ww-test-000-same.unit.ww")));
assert(os.exists(strings.concat(warmwork,
"__ww-test-003-external.unit.ww")));
let warmww: []str = [wwtracedriver, "test", "-j", "4", "-w",
warmwwroot, "-I", suite, "-I", root,
strings.concat(suite, "/...")];
runcommandenv(root, "multidir-warm-ww", warmww, wwtraceenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
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,
(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);
assert(same(readfile(strings.concat(warmwork, "common.wwi")),
readfile(strings.concat(warmwwwork, "common.wwi"))));
assert(same(readfile(strings.concat(warmwork, "common.a")),
readfile(strings.concat(warmwwwork, "common.a"))));
assert(same(readfile(strings.concat(warmwork,
"__ww-test-000-same.unit.ww")), readfile(strings.concat(warmwwwork,
"__ww-test-000-same.unit.ww"))));
clean(wwtracebin);
clean(root);
};
@test fn shared_package_resolution_context_conflict_is_stable() void = {
let root: str = fresh();
let suite: str = strings.concat(root, "/suite");
let a: str = strings.concat(suite, "/a");
let b: str = strings.concat(suite, "/b");
let good: str = strings.concat(suite, "/good");
let aleaf: str = strings.concat(a, "/_leaf");
let bleaf: str = strings.concat(b, "/_leaf");
let common: str = strings.concat(root, "/common");
let dirs: []str = [suite, a, b, good, aleaf, bleaf, common];
let di: i32 = 0;
for (di < dirs.len) { assert(os.mkdir(dirs[di], 448i32) == 0); di += 1; };
writefile(strings.concat(aleaf, "/_leaf.ww"),
"package _leaf;\nexport fn value() i32 = { return 20; };\n");
writefile(strings.concat(bleaf, "/_leaf.ww"),
"package _leaf;\nexport fn value() i32 = { return 21; };\n");
writefile(strings.concat(common, "/common.ww"), strings.concat(
"package common;\nimport _leaf;\n",
"export fn value() i32 = { return _leaf.value(); };\n"));
writefile(strings.concat(a, "/a.ww"),
"package a;\nimport common;\nfn value() i32 = { return common.value(); };\n");
writefile(strings.concat(a, "/a_test.ww"),
"package a;\n@test fn a_context() void = { assert(value() == 20); };\n");
writefile(strings.concat(b, "/b.ww"),
"package b;\nimport common;\nfn value() i32 = { return common.value(); };\n");
writefile(strings.concat(b, "/b_test.ww"),
"package b;\n@test fn b_context() void = { assert(value() == 21); };\n");
writefile(strings.concat(good, "/good.ww"),
"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 stages: []str = ["ww", "ww_ww"];
let jobs: []str = ["1", "4"];
let diagnostics: []str = ["", ""];
let referenceout: str = "";
let out: commandout;
let i: i32 = 0;
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);
expectexit(&out, 1);
assert(has(out.stderr,
"ww: package _leaf resolves to more than one location\n"));
assert(has(out.stderr, strings.concat("FAIL ", a,
" [a] (build exit 1)\n")));
assert(has(out.stderr, strings.concat("FAIL ", b,
" [b] (build exit 1)\n")));
assert(!has(out.stderr, strings.concat("FAIL ", good, " [")));
assert(has(out.stdout, "unrelated_runs ... ok\n"));
assert(has(out.stdout, strings.concat("ok ", good,
" [good, same-package]\n")));
diagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
if (i == 0) { referenceout = strings.dup(out.stdout); }
else { assert(same(referenceout, out.stdout)); };
i += 1;
};
assert(same(diagnostics[0], diagnostics[1]));
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");
assert(os.mkdir(suite, 448i32) == 0);
assert(os.mkdir(named, 448i32) == 0);
assert(os.mkdir(consumer, 448i32) == 0);
writefile(strings.concat(named, "/named.ww"), strings.concat(
"package test;\n// MIXED_USER_TEST_PRODUCTION\n",
"fn hidden() i32 = { return 19; };\n",
"export fn value() i32 = { return 42; };\n"));
writefile(strings.concat(named, "/same_test.ww"), strings.concat(
"package test;\n@test fn named_same_runs() void = {",
" assert(hidden() == 19); };\n"));
writefile(strings.concat(named, "/external_test.ww"), strings.concat(
"package test_test;\nimport test;\n",
"@test fn named_external_runs() void = {",
" assert(test.value() == 42); };\n"));
writefile(strings.concat(consumer, "/consumer.ww"), strings.concat(
"package consumer;\nimport test;\n",
"// MIXED_EXPLICIT_TOOLCHAIN_TEST_IMPORT\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 = {",
" assert(value() == 42); };\n"));
writefile(strings.concat(consumer, "/external_test.ww"), strings.concat(
"package consumer_test;\nimport consumer;\n",
"@test fn consumer_external_runs() void = {",
" assert(consumer.value() == 42); };\n"));
let linktrace: str = strings.concat(root, "/mixed-link.trace");
let linkwrapper: str = strings.concat(root, "/mixed-w6l.sh");
writefile(linktrace, "");
writeexecutable(linkwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_MIXED_LINK_TRACE\"\n",
"exec \"$WW_MIXED_W6L\" \"$@\"\n"));
let baseenv: []str = os.getenvs();
let linkenv: []str = alloc([], (baseenv.len + 3): u64)!;
let ei: i32 = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_W6L=")
&& !strings.hasprefix(baseenv[ei], "WW_MIXED_LINK_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_MIXED_W6L=")) {
append(linkenv, baseenv[ei]);
};
ei += 1;
};
append(linkenv, strings.concat("WW_W6L=", linkwrapper));
append(linkenv, strings.concat("WW_MIXED_LINK_TRACE=", linktrace));
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")];
let keys: []str = ["__ww-test-000-same", "__ww-test-001-external",
"__ww-test-002-same", "__ww-test-003-external"];
let expected: []str = ["named_same_runs ... ok\n",
"named_external_runs ... ok\n", "consumer_same_runs ... ok\n",
"consumer_external_runs ... ok\n"];
let workroot: str = strings.concat(bins[0], ".sepwork");
let work: str = strings.concat(workroot, "/");
let referenceunits: []str = ["", "", "", ""];
let stages: []str = ["ww", "ww_ww"];
let out: commandout;
let si: i32 = 0;
for (si < stages.len) {
let av: []str = [driver(stages[si]), "test", "-c", "-j", "1",
"-I", root, strings.concat(suite, "/...")];
if (si == 0) {
runcommandenv(root, "mixed-actions-c", av, linkenv,
(120i64 * (time.second: i64)): time.duration, &out);
} else {
runcommand(root, "mixed-actions-ww", av,
(120i64 * (time.second: i64)): time.duration, &out);
};
expectexit(&out, 0);
let namedprod: str = readfile(strings.concat(work,
"__ww-test-001-external-production.unit.ww"));
let normaltest: str = readfile(strings.concat(work, "test.unit.ww"));
let support: str = readfile(strings.concat(work, "__wwtest.unit.ww"));
assert(has(namedprod, "MIXED_USER_TEST_PRODUCTION"));
assert(!has(normaltest, "MIXED_USER_TEST_PRODUCTION"));
assert(has(normaltest, "//ww:module-reset test\n"));
assert(has(support, "//ww:module-reset __wwtest\n"));
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
let actions: []str = ["__ww-test-001-external-production",
"test", "__wwtest"];
let ai: i32 = 0;
for (ai < actions.len) {
let xi: i32 = 0;
for (xi < suffixes.len) {
assert(os.exists(strings.concat(work, actions[ai], suffixes[xi])));
xi += 1;
};
ai += 1;
};
let ri: i32 = 0;
for (ri < keys.len) {
let unit: str = readfile(strings.concat(work, keys[ri], ".unit.ww"));
assert(has(unit, "//ww:module __wwtest\n"));
if (ri == 1 || ri == 2) {
assert(has(unit, "//ww:module test\n"));
};
if (ri == 3) {
assert(has(unit, "//ww:module consumer\n"));
};
let runav: []str = [bins[ri]];
runcommand(root, strings.concat("mixed-run-", stages[si], "-",
keys[ri]), runav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, expected[ri]));
if (si == 0) { referenceunits[ri] = strings.dup(unit); }
else { assert(same(referenceunits[ri], unit)); };
ri += 1;
};
if (si == 0) {
let links: str = readfile(linktrace);
assert(occurrences(links, "\n") == 4);
let namedsame: str = linecontaining(links,
strings.concat("-o ", bins[0], " "));
let namedexternal: str = linecontaining(links,
strings.concat("-o ", bins[1], " "));
let consumersame: str = linecontaining(links,
strings.concat("-o ", bins[2], " "));
let consumerexternal: str = linecontaining(links,
strings.concat("-o ", bins[3], " "));
assert(has(namedsame, strings.concat(work, "__wwtest.a")));
assert(!has(namedsame, strings.concat(work, "test.a")));
assert(has(namedexternal, strings.concat(work,
"__ww-test-001-external-production.a")));
assert(has(namedexternal, strings.concat(work, "__wwtest.a")));
assert(!has(namedexternal, strings.concat(work, "test.a")));
assert(has(consumersame, strings.concat(work, "test.a")));
assert(has(consumersame, strings.concat(work, "__wwtest.a")));
assert(!has(consumersame, strings.concat(work,
"__ww-test-001-external-production.a")));
assert(has(consumerexternal, strings.concat(work, "test.a")));
assert(has(consumerexternal, strings.concat(work, "__wwtest.a")));
assert(!has(consumerexternal, strings.concat(work,
"__ww-test-001-external-production.a")));
};
if (si == 0) {
clean(workroot);
let bi: i32 = 0;
for (bi < bins.len) { clean(bins[bi]); bi += 1; };
};
si += 1;
};
clean(root);
};
@test fn long_shared_link_closure_is_complete() void = {
let root: str = fresh();
let d1: str = strings.concat(root,
"/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
let d2: str = strings.concat(d1,
"/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
let d3: str = strings.concat(d2,
"/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc");
let target: str = strings.concat(d3, "/target");
assert(os.mkdir(d1, 448i32) == 0);
assert(os.mkdir(d2, 448i32) == 0);
assert(os.mkdir(d3, 448i32) == 0);
assert(os.mkdir(target, 448i32) == 0);
let names: []str = ["p00", "p01", "p02", "p03", "p04", "p05",
"p06", "p07", "p08", "p09", "p10", "p11", "p12", "p13"];
let i: i32 = 0;
for (i < names.len) {
let dir: str = strings.concat(root, "/", names[i]);
assert(os.mkdir(dir, 448i32) == 0);
let source: str = "";
if (i + 1 < names.len) {
source = strings.concat("package ", names[i], ";\nimport ",
names[i + 1], ";\nexport fn value() i32 = { return ",
names[i + 1], ".value(); };\n");
} else {
source = strings.concat("package ", names[i],
";\nexport fn value() i32 = { return 42; };\n");
};
writefile(strings.concat(dir, "/", names[i], ".ww"), source);
i += 1;
};
writefile(strings.concat(target, "/target.ww"), strings.concat(
"package target;\nimport p00;\n",
"fn value() i32 = { return p00.value(); };\n"));
writefile(strings.concat(target, "/target_test.ww"), strings.concat(
"package target;\n@test fn complete_long_closure() void = {",
" assert(value() == 42); };\n"));
let trace: str = strings.concat(root, "/long-link.trace");
let wrapper: str = strings.concat(root, "/long-w6l.sh");
writefile(trace, "");
writeexecutable(wrapper, strings.concat(
"#!/bin/sh\nfor arg in \"$@\"; do printf '%s\\n' \"$arg\"; done",
" >> \"$WW_LONG_LINK_TRACE\"\nexec \"$WW_LONG_W6L\" \"$@\"\n"));
let baseenv: []str = os.getenvs();
let env: []str = alloc([], (baseenv.len + 3): u64)!;
let ei: i32 = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_W6L=")
&& !strings.hasprefix(baseenv[ei], "WW_LONG_LINK_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_LONG_W6L=")) {
append(env, baseenv[ei]);
};
ei += 1;
};
append(env, strings.concat("WW_W6L=", wrapper));
append(env, strings.concat("WW_LONG_LINK_TRACE=", trace));
append(env, strings.concat("WW_LONG_W6L=", driver("w6l")));
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 out: commandout;
runcommandenv(root, "long-link-c", cargv, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let cstdout: str = strings.dup(out.stdout);
let cstderr: str = strings.dup(out.stderr);
let cbin: str = readfile(bin);
let rootunit: str = readfile(strings.concat(work,
"__ww-test-000-same.unit.ww"));
assert(has(rootunit, "//ww:module p00\n"));
assert(!has(rootunit, "//ww:module p01\n"));
let linkargs: str = readfile(trace);
assert(linkargs.len > 8192);
assert(!has(linkargs, ".wwi\n"));
i = 0;
for (i < names.len) {
assert(os.exists(strings.concat(work, names[i], ".wwi")));
assert(os.exists(strings.concat(work, names[i], ".a")));
assert(has(linkargs, strings.concat(work, names[i], ".a\n")));
i += 1;
};
assert(has(linkargs, strings.concat(work, "test.a\n")));
let runav: []str = [bin];
runcommand(root, "long-link-run-c", runav,
(60i64 * (time.second: i64)): time.duration, &out);
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];
runcommand(root, "long-link-ww", wargv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(cstdout, out.stdout));
assert(same(cstderr, out.stderr));
assert(same(cbin, readfile(bin)));
i = 0;
for (i < names.len) {
assert(os.exists(strings.concat(work, names[i], ".a")));
i += 1;
};
runcommand(root, "long-link-run-ww", runav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "complete_long_closure ... ok\n"));
clean(root);
};
@test fn multi_directory_test_failures_are_isolated() void = {
let root: str = fresh();
let suite: str = strings.concat(root, "/suite");
let alpha: str = strings.concat(suite, "/alpha");
let beta: str = strings.concat(suite, "/beta");
assert(os.mkdir(suite, 448i32) == 0);
assert(os.mkdir(alpha, 448i32) == 0);
assert(os.mkdir(beta, 448i32) == 0);
writefile(strings.concat(alpha, "/alpha.ww"), strings.concat(
"package alpha;\n",
"fn hidden() i32 = { return 41; };\n",
"export fn shown() i32 = { return 41; };\n"));
writefile(strings.concat(alpha, "/same_test.ww"), strings.concat(
"package alpha;\n",
"@test fn alpha_same_survives() void = {",
" assert(hidden() == 41); };\n"));
writefile(strings.concat(alpha, "/external_test.ww"), strings.concat(
"package alpha_test;\nimport alpha;\n",
"@test fn alpha_external_fails() void = {",
" assert(alpha.hidden() == 41); };\n"));
writefile(strings.concat(beta, "/beta.ww"), strings.concat(
"package beta;\n",
"fn hidden() i32 = { return 42; };\n",
"export fn shown() i32 = { return 42; };\n"));
writefile(strings.concat(beta, "/same_test.ww"), strings.concat(
"package beta;\n",
"@test fn beta_same_survives() void = {",
" assert(hidden() == 42); };\n"));
writefile(strings.concat(beta, "/external_test.ww"), strings.concat(
"package beta_test;\nimport beta;\n",
"@test fn beta_external_survives() void = {",
" assert(beta.shown() == 42); };\n"));
let stages: []str = ["ww", "ww_ww"];
let jobs: []str = ["1", "4"];
let diagnostics: []str = ["", ""];
let referenceout: str = "";
let out: commandout;
let i: i32 = 0;
for (i < stages.len) {
let av: []str = [driver(stages[i]), "test", "-j", jobs[i],
"-I", root, strings.concat(suite, "/...")];
runcommand(root, strings.concat("multidir-failure-", stages[i]), av,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout, "alpha_same_survives ... ok\n"));
assert(has(out.stdout, "beta_same_survives ... ok\n"));
assert(has(out.stdout, "beta_external_survives ... ok\n"));
assert(has(out.stdout, strings.concat("ok ", alpha,
" [alpha, same-package]\n")));
assert(has(out.stdout, strings.concat("ok ", beta,
" [beta, same-package]\n")));
assert(has(out.stdout, strings.concat("ok ", beta,
" [beta_test, external]\n")));
assert(!has(out.stdout, "alpha_external_fails ..."));
assert(has(out.stderr, "has no exported declaration 'hidden'"));
assert(has(out.stderr, strings.concat("FAIL ", alpha,
" [alpha_test] (build exit 1)\n")));
assert(!has(out.stderr, strings.concat("FAIL ", alpha,
" [alpha]")));
assert(!has(out.stderr, strings.concat("FAIL ", beta, " [")));
let alphapos: i32 = pos(out.stdout, strings.concat("ok ", alpha,
" [alpha, same-package]\n"));
let betapos: i32 = pos(out.stdout, strings.concat("ok ", beta,
" [beta, same-package]\n"));
assert(alphapos >= 0 && alphapos < betapos);
diagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
if (i == 0) { referenceout = strings.dup(out.stdout); }
else { assert(same(referenceout, out.stdout)); };
i += 1;
};
assert(same(diagnostics[0], diagnostics[1]));
clean(root);
};
// One failing root is a product failure, not permission for the shared build
// request to suppress an independently compilable sibling root.
@test fn sibling_test_variant_failures_are_isolated() void = {
let root: str = fresh();
let badexternal: str = strings.concat(root, "/badexternal");
let badsame: str = strings.concat(root, "/badsame");
assert(os.mkdir(badexternal, 448i32) == 0);
assert(os.mkdir(badsame, 448i32) == 0);
writefile(strings.concat(badexternal, "/badexternal.ww"), strings.concat(
"package badexternal;\n",
"fn hidden() i32 = { return 41; };\n",
"export fn shown() i32 = { return 41; };\n"));
writefile(strings.concat(badexternal, "/same_test.ww"), strings.concat(
"package badexternal;\n",
"@test fn valid_same_runs() void = { assert(hidden() == 41); };\n"));
writefile(strings.concat(badexternal, "/external_test.ww"), strings.concat(
"package badexternal_test;\nimport badexternal;\n",
"@test fn invalid_external() void = {\n",
" assert(badexternal.hidden() == 41);\n};\n"));
writefile(strings.concat(badsame, "/badsame.ww"), strings.concat(
"package badsame;\n",
"export fn shown() i32 = { return 42; };\n"));
writefile(strings.concat(badsame, "/same_test.ww"), strings.concat(
"package badsame;\n",
"@test fn invalid_same() void = { assert(missing() == 0); };\n"));
writefile(strings.concat(badsame, "/external_test.ww"), strings.concat(
"package badsame_test;\nimport badsame;\n",
"@test fn valid_external_runs() void = {\n",
" assert(badsame.shown() == 42);\n};\n"));
let stages: []str = ["ww", "ww_ww"];
let tags: []str = ["c", "ww"];
let externaldiagnostics: []str = ["", ""];
let samediagnostics: []str = ["", ""];
let out: commandout;
let i: i32 = 0;
for (i < stages.len) {
let externalav: []str = [driver(stages[i]), "test", "-I", root,
badexternal];
runcommand(root, strings.concat("isolated-external-", tags[i]),
externalav, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout, "valid_same_runs ... ok\n"));
assert(has(out.stdout, "[badexternal, same-package]\n"));
assert(has(out.stderr,
"has no exported declaration 'hidden'"));
assert(has(out.stderr,
strings.concat("FAIL ", badexternal,
" [badexternal_test] (build exit 1)\n")));
assert(!has(out.stderr, strings.concat("FAIL ", badexternal,
" [badexternal]")));
externaldiagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
let sameav: []str = [driver(stages[i]), "test", "-I", root,
badsame];
runcommand(root, strings.concat("isolated-same-", tags[i]), sameav,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout, "valid_external_runs ... ok\n"));
assert(has(out.stdout, "[badsame_test, external]\n"));
assert(has(out.stderr, "undefined: missing"));
assert(has(out.stderr, strings.concat("FAIL ", badsame,
" [badsame] (build exit 1)\n")));
assert(!has(out.stderr, strings.concat("FAIL ", badsame,
" [badsame_test]")));
samediagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
i += 1;
};
assert(same(externaldiagnostics[0], externaldiagnostics[1]));
assert(same(samediagnostics[0], samediagnostics[1]));
// A first persistent union pass may contain a root-local compiler failure.
// Its successfully committed actions still become reusable: only the
// uncommitted failing root is compiled again on the next request in both
// driver stages.
let warmroot: str = strings.concat(root, "/warm-partial");
assert(os.mkdir(warmroot, 448i32) == 0);
let trace: str = strings.concat(root, "/warm-partial.trace");
let wrapper: str = strings.concat(root, "/warm-partial-w6c.sh");
writefile(trace, "");
writeexecutable(wrapper, strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_COMPILER_TRACE\"\n",
"exec \"$WW_PACKAGE_W6C\" \"$@\"\n"));
let baseenv: []str = os.getenvs();
let traceenv: []str = alloc([], (baseenv.len + 3): u64)!;
let ei: i32 = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
&& !strings.hasprefix(baseenv[ei],
"WW_PACKAGE_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C=")) {
append(traceenv, baseenv[ei]);
};
ei += 1;
};
append(traceenv, strings.concat("WW_W6C=", wrapper));
append(traceenv, strings.concat("WW_PACKAGE_COMPILER_TRACE=", trace));
append(traceenv, strings.concat("WW_PACKAGE_W6C=", driver("w6c")));
let warmav: []str = [driver("ww"), "test", "-j", "4", "-w",
warmroot, "-I", root, badexternal];
runcommandenv(root, "isolated-warm-first", warmav, traceenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let firsttrace: str = readfile(trace);
assert(occurrences(firsttrace,
"/__ww-test-000-same.unit.new") == 1);
assert(occurrences(firsttrace,
"/__ww-test-001-external.unit.new") == 1);
runcommandenv(root, "isolated-warm-reuse", warmav, traceenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let secondtrace: str = readfile(trace);
assert(occurrences(secondtrace,
"/__ww-test-000-same.unit.new") == 1);
assert(occurrences(secondtrace,
"/__ww-test-001-external.unit.new") == 2);
let wwtracebin: str = strings.concat(repo(), "/out/partial-trace-",
workescape(root));
assert(os.mkdir(wwtracebin, 448i32) == 0);
let wwdriver: str = strings.concat(wwtracebin, "/ww_ww");
let wwtrace: str = strings.concat(root, "/warm-partial-ww.trace");
let wwwarmroot: str = strings.concat(root, "/warm-partial-ww");
assert(os.mkdir(wwwarmroot, 448i32) == 0);
writefile(wwtrace, "");
writeexecutable(wwdriver, readfile(driver("ww_ww")));
writeexecutable(strings.concat(wwtracebin, "/wwtest"),
readfile(driver("wwtest")));
writeexecutable(strings.concat(wwtracebin, "/w6c_ww"), strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_WW_COMPILER_TRACE\"\n",
"exec \"$WW_PACKAGE_W6C_WW\" \"$@\"\n"));
writeexecutable(strings.concat(wwtracebin, "/w6a_ww"),
readfile(driver("w6a_ww")));
writeexecutable(strings.concat(wwtracebin, "/w6l_ww"),
readfile(driver("w6l_ww")));
let wwenv: []str = alloc([], (baseenv.len + 2): u64)!;
ei = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei],
"WW_PACKAGE_WW_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C_WW=")) {
append(wwenv, baseenv[ei]);
};
ei += 1;
};
append(wwenv, strings.concat("WW_PACKAGE_WW_COMPILER_TRACE=", wwtrace));
append(wwenv, strings.concat("WW_PACKAGE_W6C_WW=", driver("w6c_ww")));
let wwwarmav: []str = [wwdriver, "test", "-j", "4", "-w",
wwwarmroot, "-I", root, badexternal];
runcommandenv(root, "isolated-warm-ww-first", wwwarmav, wwenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let wwfirst: str = readfile(wwtrace);
assert(occurrences(wwfirst,
"/__ww-test-000-same.unit.new") == 1);
assert(occurrences(wwfirst,
"/__ww-test-001-external.unit.new") == 1);
runcommandenv(root, "isolated-warm-ww-reuse", wwwarmav, wwenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let wwsecond: str = readfile(wwtrace);
assert(occurrences(wwsecond,
"/__ww-test-000-same.unit.new") == 1);
assert(occurrences(wwsecond,
"/__ww-test-001-external.unit.new") == 2);
clean(wwtracebin);
clean(root);
};
// The compiler-generated runner uses a reserved graph qualifier rather than
// claiming the user-visible import path `test`. A real multi-file production
// package named test can therefore be the normal direct dependency of its
// external test variant in both bootstrap stages.
@test fn production_package_named_test_remains_available() void = {
let root: str = fresh();
let pkg: str = strings.concat(root, "/test");
assert(os.mkdir(pkg, 448i32) == 0);
writefile(strings.concat(pkg, "/a.ww"), strings.concat(
"package test;\n",
"// USER_TEST_PACKAGE_A\n",
"export fn first() i32 = { return 19; };\n"));
writefile(strings.concat(pkg, "/z.ww"), strings.concat(
"package test;\n",
"// USER_TEST_PACKAGE_Z\n",
"export fn second() i32 = { return 23; };\n"));
writefile(strings.concat(pkg, "/external_test.ww"), strings.concat(
"package test_test;\nimport test;\n",
"// USER_TEST_EXTERNAL\n",
"@test fn package_name_is_not_reserved() void = {\n",
" assert(test.first() + test.second() == 42);\n};\n"));
let bin: str = strings.concat(root, "/named-test.bin");
let workroot: str = strings.concat(bin, ".sepwork");
let work: str = strings.concat(workroot, "/");
let stages: []str = ["ww", "ww_ww"];
let referencebin: str = "";
let referenceroot: str = "";
let referenceprod: str = "";
let referencesupport: str = "";
let out: commandout;
let i: i32 = 0;
for (i < stages.len) {
let av: []str = [driver(stages[i]), "test", "-c", "-o", bin,
pkg];
runcommand(root, strings.concat("named-test-build-", stages[i]), av,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let rootunit: str = readfile(strings.concat(work,
"__ww-test-000-external.unit.ww"));
let produnit: str = readfile(strings.concat(work,
"__ww-test-000-external-production.unit.ww"));
let supportunit: str = readfile(strings.concat(work,
"__wwtest.unit.ww"));
assert(has(rootunit, "//ww:module test\n"));
assert(has(rootunit, "//ww:module __wwtest\n"));
assert(has(rootunit, "USER_TEST_EXTERNAL"));
assert(!has(rootunit, "USER_TEST_PACKAGE_A"));
assert(!has(rootunit, "USER_TEST_PACKAGE_Z"));
assert(has(produnit, "USER_TEST_PACKAGE_A"));
assert(has(produnit, "USER_TEST_PACKAGE_Z"));
assert(has(supportunit, "//ww:module-reset __wwtest\n"));
assert(has(supportunit, "package test;\n"));
assert(os.exists(strings.concat(work,
"__ww-test-000-external-production.wwi")));
assert(os.exists(strings.concat(work,
"__ww-test-000-external-production.a")));
assert(os.exists(strings.concat(work, "__wwtest.wwi")));
assert(os.exists(strings.concat(work, "__wwtest.a")));
let runav: []str = [bin];
runcommand(root, strings.concat("named-test-run-", stages[i]), runav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "package_name_is_not_reserved ... ok\n"));
if (i == 0) {
referencebin = readfile(bin);
referenceroot = strings.dup(rootunit);
referenceprod = strings.dup(produnit);
referencesupport = strings.dup(supportunit);
} else {
assert(same(referencebin, readfile(bin)));
assert(same(referenceroot, rootunit));
assert(same(referenceprod, produnit));
assert(same(referencesupport, supportunit));
};
if (i + 1 < stages.len) {
clean(workroot);
clean(bin);
};
i += 1;
};
clean(root);
};
@test fn diamond_test_dependency_compiles_once() void = {
let root: str = fresh();
let shared: str = strings.concat(root, "/shared");
let left: str = strings.concat(root, "/left");
let right: str = strings.concat(root, "/right");
let target: str = strings.concat(root, "/diamond");
assert(os.mkdir(shared, 448i32) == 0);
assert(os.mkdir(left, 448i32) == 0);
assert(os.mkdir(right, 448i32) == 0);
assert(os.mkdir(target, 448i32) == 0);
writefile(strings.concat(shared, "/shared.ww"),
"package shared;\nexport fn value() i32 = { return 20; };\n");
writefile(strings.concat(left, "/left.ww"), strings.concat(
"package left;\nimport shared;\n",
"export fn value() i32 = { return shared.value(); };\n"));
writefile(strings.concat(right, "/right.ww"), strings.concat(
"package right;\nimport shared;\n",
"export fn value() i32 = { return shared.value() + 1; };\n"));
writefile(strings.concat(target, "/diamond.ww"),
"package diamond;\nfn local() i32 = { return 1; };\n");
writefile(strings.concat(target, "/diamond_test.ww"), strings.concat(
"package diamond;\nimport left;\nimport right;\n",
"@test fn one_shared_compile() void = {\n",
" assert(left.value() + right.value() + local() == 42);\n};\n"));
let trace: str = strings.concat(root, "/compiler.trace");
let wrapper: str = strings.concat(root, "/trace-w6c.sh");
writefile(trace, "");
writeexecutable(wrapper, strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_TRACE\"\n",
"exec \"$WW_PACKAGE_W6C\" \"$@\"\n"));
let baseenv: []str = os.getenvs();
let env: []str = alloc([], (baseenv.len + 3): u64)!;
let ei: i32 = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C=")) {
append(env, baseenv[ei]);
};
ei += 1;
};
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");
let av: []str = [driver("ww"), "test", "-c", "-o", bin,
"-I", root, target];
let out: commandout;
runcommandenv(root, "diamond-build", av, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(readfile(trace), "shared.unit.ww") == 1);
let work: str = strings.concat(bin, ".sepwork/");
let unit: str = readfile(strings.concat(work,
"__ww-test-000-same.unit.ww"));
assert(has(unit, "//ww:module left\n"));
assert(has(unit, "//ww:module right\n"));
assert(!has(unit, "//ww:module shared\n"));
assert(has(readfile(strings.concat(work, "left.unit.ww")),
"//ww:module shared\n"));
assert(has(readfile(strings.concat(work, "right.unit.ww")),
"//ww:module shared\n"));
assert(os.exists(strings.concat(work, "shared.a")));
let runav: []str = [bin];
runcommand(root, "diamond-run", runav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "one_shared_compile ... ok\n"));
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");
let cycle: str = strings.concat(root, "/cycle");
let left: str = strings.concat(root, "/left");
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");
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);
writefile(strings.concat(missing, "/missing.ww"),
"package missing;\nfn local() void = { };\n");
writefile(strings.concat(missing, "/missing_test.ww"), strings.concat(
"package missing;\nimport nowhere;\n",
"@test fn missing_import() void = { };\n"));
writefile(strings.concat(cycle, "/cycle.ww"),
"package cycle;\nfn local() void = { };\n");
writefile(strings.concat(cycle, "/cycle_test.ww"), strings.concat(
"package cycle;\nimport left;\n",
"@test fn cycle_import() void = { };\n"));
writefile(strings.concat(left, "/left.ww"),
"package left;\nimport right;\nexport fn v() i32 = { return right.v(); };\n");
writefile(strings.concat(right, "/right.ww"),
"package right;\nimport left;\nexport fn v() i32 = { return left.v(); };\n");
writefile(strings.concat(conflict, "/a.ww"),
"package conflict;\nfn a() void = { };\n");
writefile(strings.concat(conflict, "/z.ww"),
"package other;\nfn z() void = { };\n");
writefile(strings.concat(conflict, "/conflict_test.ww"),
"package conflict;\n@test fn conflict_name() void = { };\n");
writefile(strings.concat(privatepkg, "/a.ww"), strings.concat(
"package privatepkg;\n",
"export fn shown() i32 = { return 1; };\n"));
writefile(strings.concat(privatepkg, "/z.ww"),
"package privatepkg;\nfn hidden() i32 = { return 2; };\n");
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");
rejectpackagestable(root, "missing", missing,
"cannot find package nowhere");
rejectpackagestable(root, "cycle", cycle, "ww: dependency cycle:");
rejectpackagestable(root, "conflict", conflict,
"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 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];
runcommand(root, strings.concat("duplicate-export-module-", stages[i]),
av, (60i64 * (time.second: i64)): time.duration, &out);
assert(out.termination == exec.termination.EXIT && out.code != 0);
assert(has(out.stderr,
"product closure contains multiple packages named dupexport"));
exportdiagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
i += 1;
};
assert(same(exportdiagnostics[0], exportdiagnostics[1]));
clean(root);
};
// Invalid @test attribute shapes reject at build with stable text on
// BOTH frontends (the -T synth checker owns them; the fixture corpus
// cannot reach -T, so these rows live here). Fragments only — the
// stages' error-line prefixes legitimately differ (file:line:col vs
// file:).
@test fn invalid_test_shapes_reject() void = {
let root: str = fresh();
let shapes: []str = [
"@test export fn t() void = { };",
"@test fn t() void;",
"@test fn t(x: i32) void = { };",
"@test fn t() i32 = { return 0; };",
"@test @test fn t() void = { };",
];
let frags: []str = [
"@test fn 't' cannot be exported",
"@test fn 't' needs a body",
"@test fn 't' must be fn() void",
"@test fn 't' must be fn() void",
"duplicate @test on fn 't'",
];
let digits: []str = ["0", "1", "2", "3", "4"];
let outc: commandout;
let outw: commandout;
let i: i32 = 0;
for (i < shapes.len) {
let dir: str = strings.concat(root, "/shape", digits[i]);
assert(os.mkdir(dir, 448i32) == 0);
let src: str = strings.concat(dir, "/bad_test.ww");
writefile(src, strings.concat("package main;\n",
shapes[i], "\n"));
let avc: []str = [driver("ww"), "test", src];
let avw: []str = [driver("ww_ww"), "test", src];
runcommand(root, strings.concat("shape-c", digits[i]), avc,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, strings.concat("shape-ww", digits[i]), avw,
(30i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(has(outc.stderr, frags[i]));
assert(has(outw.stderr, frags[i]));
i += 1;
};
clean(root);
};
// Go's ./... parity: a trailing "..." element walks the tree, one package
// run per test-bearing directory, dot- and underscore-prefixed directory
// names excluded. The excluded sentinels hold failing tests so a wrong
// descent turns the whole run red rather than passing silently.
@test fn recursive_tree_discovery() void = {
let root: str = fresh();
let tree: str = strings.concat(root, "/tree");
assert(os.mkdir(tree, 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/alpha"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/beta"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/beta/inner"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/gamma"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/.hidden"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/_skip"), 448i32) == 0);
writefile(strings.concat(tree, "/a.ww"),
"package rootpkg;\nfn first() i32 = { return 1; };\n");
writefile(strings.concat(tree, "/root_test.ww"), strings.concat(
"package rootpkg;\n",
"@test fn treeroot() void = { assert(first() + last() == 3); };\n"));
writefile(strings.concat(tree, "/z.ww"),
"package rootpkg;\nfn last() i32 = { return 2; };\n");
writefile(strings.concat(tree, "/alpha/alpha.ww"),
"package alpha;\nexport fn value() int = { return 7; };\n");
writefile(strings.concat(tree, "/alpha/alpha_test.ww"),
"package alpha_test;\nimport alpha;\n@test fn treealpha() void = { assert(alpha.value() == 7); };\n");
writefile(strings.concat(tree, "/beta/inner/inner_test.ww"),
"package inner;\n@test fn treeinner() void = { assert(1 == 1); };\n");
writefile(strings.concat(tree, "/gamma/gamma.ww"),
"package gamma;\nexport fn g() int = { return 1; };\n");
writefile(strings.concat(tree, "/.hidden/hid_test.ww"),
"package hid;\n@test fn hidden() void = { assert(false); };\n");
writefile(strings.concat(tree, "/_skip/skip_test.ww"),
"package skip;\n@test fn skipped() void = { assert(false); };\n");
let spec: str = strings.concat(tree, "/...");
let outc: commandout;
let outw: commandout;
let treec: []str = [driver("ww"), "test", spec];
let treew: []str = [driver("ww_ww"), "test", spec];
runcommand(root, "tree-c", treec,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "tree-ww", treew,
(30i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 0);
expectexit(&outw, 0);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stdout, strings.concat("ok ", tree,
" [rootpkg, same-package]\n")));
assert(has(outc.stdout, strings.concat("ok ", tree,
"/alpha [alpha_test, external]\n")));
assert(has(outc.stdout, strings.concat("ok ", tree,
"/beta/inner [inner, same-package]\n")));
assert(has(outc.stdout, strings.concat("? ", tree,
"/gamma [no tests]\n")));
let rootreport: i32 = pos(outc.stdout, strings.concat("ok ", tree,
" [rootpkg, same-package]\n"));
let alphareport: i32 = pos(outc.stdout, strings.concat("ok ", tree,
"/alpha [alpha_test, external]\n"));
let innerreport: i32 = pos(outc.stdout, strings.concat("ok ", tree,
"/beta/inner [inner, same-package]\n"));
let gammareport: i32 = pos(outc.stdout, strings.concat("? ", tree,
"/gamma [no tests]\n"));
assert(rootreport >= 0 && rootreport < alphareport
&& alphareport < innerreport && innerreport < gammareport);
assert(occurrences(outc.stdout, strings.concat(tree, " [")) == 1);
assert(!has(outc.stdout, ".hidden"));
assert(!has(outc.stdout, "_skip"));
// Concurrent scheduling must not reorder the emitted byte stream.
let seq: str = strings.dup(outc.stdout);
let j4: []str = [driver("ww"), "test", "-j", "4", spec];
runcommand(root, "tree-j4", j4,
(30i64 * (time.second: i64)): time.duration, &outc);
expectexit(&outc, 0);
assert(same(outc.stdout, seq));
let j0: []str = [driver("ww"), "test", "-j", "0", spec];
runcommand(root, "tree-j0", j0, time.second, &outc);
expectexit(&outc, 2);
assert(has(outc.stderr, "usage: wwtest package"));
let patc: []str = [driver("ww"), "test", spec, "glob*"];
let patw: []str = [driver("ww_ww"), "test", spec, "glob*"];
runcommand(root, "tree-pattern-c", patc, time.second, &outc);
runcommand(root, "tree-pattern-ww", patw, time.second, &outw);
expectexit(&outc, 2);
expectexit(&outw, 2);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "ww test: pattern needs a single test file\n"));
let oc: []str = [driver("ww"), "test", "-o",
strings.concat(root, "/stem"), spec];
let ow: []str = [driver("ww_ww"), "test", "-o",
strings.concat(root, "/stem"), spec];
runcommand(root, "tree-o-c", oc, time.second, &outc);
runcommand(root, "tree-o-ww", ow, time.second, &outw);
expectexit(&outc, 2);
expectexit(&outw, 2);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr,
"ww test: -o needs -c for a package target\n"));
// -w on a package target forwards to the coordinator: one shared
// persistent driver workdir for the complete selected request,
// reuse owned by the driver's content-identity contract. The
// byte stream must match the plain run, cold and warm.
let wdroot: str = strings.concat(root, "/wd");
assert(os.mkdir(wdroot, 448i32) == 0);
let wdc: []str = [driver("ww"), "test", "-w", wdroot, spec];
let wdw: []str = [driver("ww_ww"), "test", "-w", wdroot, spec];
runcommand(root, "tree-w-c", wdc,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "tree-w-ww", wdw,
(30i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 0);
expectexit(&outw, 0);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stdout, seq));
runcommand(root, "tree-w-warm", wdc,
(30i64 * (time.second: i64)): time.duration, &outc);
expectexit(&outc, 0);
assert(same(outc.stdout, seq));
// -c publishes caller-owned artifacts; a persistent workdir is a
// different ownership contract — the coordinator rejects the mix.
let wcc: []str = [driver("ww"), "test", "-c", "-w", wdroot, spec];
let wcw: []str = [driver("ww_ww"), "test", "-c", "-w", wdroot, spec];
runcommand(root, "tree-wc-c", wcc, time.second, &outc);
runcommand(root, "tree-wc-ww", wcw, time.second, &outw);
expectexit(&outc, 2);
expectexit(&outw, 2);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "wwtest package: -w conflicts with -c\n"));
let bare: str = strings.concat(root, "/bare");
assert(os.mkdir(bare, 448i32) == 0);
assert(os.mkdir(strings.concat(bare, "/sub"), 448i32) == 0);
let barec: []str = [driver("ww"), "test",
strings.concat(bare, "/...")];
let barew: []str = [driver("ww_ww"), "test",
strings.concat(bare, "/...")];
runcommand(root, "tree-bare-c", barec,
(10i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "tree-bare-ww", barew,
(10i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "directory contains no WW package sources\n"));
clean(root);
};
@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");
assert(os.mkdir(tree, 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,
strings.concat(tree, "/...")];
let out: commandout;
runcommand(root, "workkey-cold", av,
(60i64 * (time.second: i64)): time.duration, &out);
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, "/__ww-test-000-same.unit.ww")));
assert(os.exists(strings.concat(key, "/__ww-test-001-same.unit.ww")));
runcommand(root, "workkey-warm", av,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(cold, out.stdout));
clean(root);
};
fn runtimepath(relative: str) str = {
return strings.concat(repo(), "/test/package/runtime/", relative);
};
// 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
// wiring honest; the runtime-internal classifications themselves are
// owned by the cases/* tests above.
@test fn singlefile_runtime_outcomes() void = {
let root: str = fresh();
let out: commandout;
let successav: []str = [driver("ww"), "test",
runtimepath("success_test.ww")];
runcommand(root, "sf-success", successav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "alpha_pass ... ok\n"));
assert(has(out.stdout,
"beta_skip ... SKIP: synthetic unavailable feature\n"));
assert(has(out.stdout, "gamma_expected_abort ... ok\n"));
assert(has(out.stdout, "delta_pass ... ok\n"));
assert(has(out.stdout,
"3 passed, 0 failed, 1 skipped, 0 harness errors\n"));
assert(has(out.stdout,
"4 discovered, 4 selected, 4 started, 4 completed\n"));
let failav: []str = [driver("ww"), "test",
runtimepath("fail_test.ww")];
runcommand(root, "sf-fail", failav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout, "assertion_failure ... FAIL (exit 1)\n"));
let multiav: []str = [driver("ww"), "test",
runtimepath("multiple_fail_test.ww")];
runcommand(root, "sf-multi", multiav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout,
"0 passed, 2 failed, 0 skipped, 0 harness errors\n"));
let unmetav: []str = [driver("ww"), "test",
runtimepath("expected_abort_return_test.ww")];
runcommand(root, "sf-unmet", unmetav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout,
"expected_abort_must_happen ... FAIL (expected abort)\n"));
let premav: []str = [driver("ww"), "test",
runtimepath("premature_exit_test.ww")];
runcommand(root, "sf-premature", premav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout,
"clean_exit_without_completion ... HARNESS (incomplete result)\n"));
let sigav: []str = [driver("ww"), "test",
runtimepath("signal_test.ww")];
runcommand(root, "sf-signal", sigav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout, "signal_is_not_exit ... FAIL (signal 15)\n"));
// Record-and-continue past every fault class: the runner reports
// hardware faults with their literal signal numbers and still
// reaches the trailing test (retired 911_attest_record).
let recav: []str = [driver("ww"), "test",
runtimepath("record_continue_test.ww")];
runcommand(root, "sf-record", recav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout, "rec_pass_a ... ok\n"));
assert(has(out.stdout, "rec_assert ... FAIL (exit 1)\n"));
assert(has(out.stdout, "rec_segv ... FAIL (signal 11)\n"));
assert(has(out.stdout, "rec_div0 ... FAIL (signal 8)\n"));
assert(has(out.stdout, "rec_pass_b ... ok\n"));
assert(has(out.stdout,
"2 passed, 3 failed, 0 skipped, 0 harness errors\n"));
assert(has(out.stdout,
"5 discovered, 5 selected, 5 started, 5 completed\n"));
clean(root);
};
// Explicit linker search/library flags are retained by the package builder
// and reach both native linkers in their accepted argv forms. This is a
// real manifest-free build/run check, not a parser-only simulation.
@test fn linker_flag_stage_parity() void = {
let root: str = fresh();
let pkg: str = strings.concat(root, "/mainpkg");
let extra: str = strings.concat(root, "/extra");
let linktrace: str = strings.concat(root, "/link.trace");
let cwrapper: str = strings.concat(root, "/trace-w6l.sh");
assert(os.mkdir(pkg, 448i32) == 0);
assert(os.mkdir(extra, 448i32) == 0);
writefile(linktrace, "");
writeexecutable(cwrapper, strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_LINK_FLAG_TRACE\"\n",
"exec \"$WW_LINK_FLAG_W6L\" \"$@\"\n"));
writefile(strings.concat(pkg, "/main.ww"),
"package main;\nfn main() void = {};\n");
writefile(strings.concat(extra, "/extra.ww"),
"package extra;\nexport fn marker() i32 = { return 7; };\n");
let extralib: str = strings.concat(root, "/libextra.a");
let libav: []str = [driver("ww"), "build", "-p", "-o", extralib,
extra];
let out: commandout;
runcommand(root, "link-flags-library", libav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let cbin: str = strings.concat(root, "/c-main");
let wwbin: str = strings.concat(root, "/ww-main");
let cav: []str = [driver("ww"), "build", "-L", root,
"-l", "extra", "-o", cbin, pkg];
let baseenv: []str = os.getenvs();
let cenv: []str = alloc([], (baseenv.len + 3): u64)!;
let ei: i32 = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_W6L=")
&& !strings.hasprefix(baseenv[ei], "WW_LINK_FLAG_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_LINK_FLAG_W6L=")) {
append(cenv, baseenv[ei]);
};
ei += 1;
};
append(cenv, strings.concat("WW_W6L=", cwrapper));
append(cenv, strings.concat("WW_LINK_FLAG_TRACE=", linktrace));
append(cenv, strings.concat("WW_LINK_FLAG_W6L=", driver("w6l")));
runcommandenv(root, "link-flags-c", cav, cenv,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let ctraced: str = readfile(linktrace);
assert(has(ctraced, strings.concat(" -L ", root, " -l extra")));
// 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);
let tracedriver: str = strings.concat(tracedir, "/ww_ww");
writeexecutable(tracedriver, readfile(driver("ww_ww")));
writeexecutable(strings.concat(tracedir, "/w6c_ww"),
readfile(driver("w6c_ww")));
writeexecutable(strings.concat(tracedir, "/w6a_ww"),
readfile(driver("w6a_ww")));
writeexecutable(strings.concat(tracedir, "/w6l_ww"), strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_LINK_FLAG_TRACE\"\n",
"exec \"$WW_LINK_FLAG_W6L_WW\" \"$@\"\n"));
let wenv: []str = alloc([], (baseenv.len + 2): u64)!;
ei = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_LINK_FLAG_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_LINK_FLAG_W6L_WW=")) {
append(wenv, baseenv[ei]);
};
ei += 1;
};
append(wenv, strings.concat("WW_LINK_FLAG_TRACE=", linktrace));
append(wenv, strings.concat("WW_LINK_FLAG_W6L_WW=", driver("w6l_ww")));
let twav: []str = [tracedriver, "build", "-L", root,
"-l", "extra", "-o", wwbin, pkg];
runcommandenv(root, "link-flags-ww", twav, wenv,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let wtraced: str = readfile(linktrace);
assert(has(wtraced, strings.concat(" -L", root, " -lextra")));
assert(same(readfile(cbin), readfile(wwbin)));
let crun: []str = [cbin];
let wrun: []str = [wwbin];
runcommand(root, "link-flags-c-run", crun,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
runcommand(root, "link-flags-ww-run", wrun,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
clean(tracedir);
clean(root);
};
// The published test binary's OWN command surface: repeated glob args,
// -list (with and without a glob), and -timeout-ms. Only a direct
// invocation of the `-c` artifact proves these; every driver route
// parses its flags before the binary sees them.
@test fn published_binary_cli() void = {
let root: str = fresh();
let out: commandout;
let stem: str = strings.concat(root, "/rtsuccess");
let cav: []str = [driver("ww"), "test", "-c", "-o", stem,
runtimepath("success_test.ww")];
runcommand(root, "publish", cav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let gav: []str = [stem, "alpha*", "delta*"];
runcommand(root, "globs", gav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "alpha_pass ... ok\n"));
assert(has(out.stdout, "delta_pass ... ok\n"));
assert(has(out.stdout,
"2 passed, 0 failed, 0 skipped, 0 harness errors\n"));
assert(has(out.stdout,
"4 discovered, 2 selected, 2 started, 2 completed\n"));
let lav: []str = [stem, "-list"];
runcommand(root, "list", lav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(out.stdout,
"alpha_pass\nbeta_skip\ngamma_expected_abort\ndelta_pass\n"));
let lgav: []str = [stem, "-list", "gamma*"];
runcommand(root, "list-glob", lgav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(out.stdout, "gamma_expected_abort\n"));
let tav: []str = [stem, "-timeout-ms=50", "alpha*"];
runcommand(root, "cli-timeout", tav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout,
"1 passed, 0 failed, 0 skipped, 0 harness errors\n"));
clean(root);
};
// Direct-binary timeout classification and descendant handling. The
// runcommand deadline bounds the no-hang claims: a runner waiting on a
// SIGTERM-blocking or process-group-escaped pipe writer would trip it.
@test fn direct_binary_timeout_and_descendants() void = {
let root: str = fresh();
let out: commandout;
let tstem: str = strings.concat(root, "/rttimeout");
let tcav: []str = [driver("ww"), "test", "-c", "-o", tstem,
runtimepath("timeout_test.ww")];
runcommand(root, "publish-timeout", tcav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let trun: []str = [tstem, "-timeout-ms=50"];
runcommand(root, "run-timeout", trun,
(20i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stdout, "hang_times_out ... FAIL(timeout)\n"));
let lstem: str = strings.concat(root, "/rtlinger");
let lcav: []str = [driver("ww"), "test", "-c", "-o", lstem,
runtimepath("lingering_descendant_test.ww")];
runcommand(root, "publish-linger", lcav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let lrun: []str = [lstem, "-timeout-ms=250"];
runcommand(root, "run-linger", lrun,
(20i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout,
"returning_test_clears_descendant ... ok\n"));
let estem: str = strings.concat(root, "/rtescaped");
let ecav: []str = [driver("ww"), "test", "-c", "-o", estem,
runtimepath("escaped_descendant_test.ww")];
runcommand(root, "publish-escaped", ecav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let erun: []str = [estem, "-timeout-ms=250"];
runcommand(root, "run-escaped", erun,
(20i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout,
"escaped_writer_does_not_hold_runner ... ok\n"));
clean(root);
};
// The package-level -o contract: -c -o names the single package's
// artifact in place of the fixed <package>.test stem; -o without -c
// has nothing to name (runs execute from the temp root); one name
// cannot fan out over multiple packages (Go's `go test -o` rule).
@test fn compile_artifact_naming() void = {
let root: str = fresh();
let pdir: str = strings.concat(root, "/pkg");
assert(os.mkdir(pdir, 493i32) == 0);
writefile(strings.concat(pdir, "/pkg.ww"),
"package pkg;\nexport fn v() i32 = { return 7; };\n");
writefile(strings.concat(pdir, "/pkg_test.ww"), strings.concat(
"package pkg_test;\nimport pkg;\n",
"@test fn seven() void = { assert(pkg.v() == 7); };\n"));
let adir: str = strings.concat(root, "/a");
assert(os.mkdir(adir, 493i32) == 0);
// '_'-prefixed: the tree walk skips it, so the artifacts and
// their .sepwork trees never pollute the multi-package discovery.
let outdir: str = strings.concat(root, "/_out");
assert(os.mkdir(outdir, 493i32) == 0);
writefile(strings.concat(adir, "/a.ww"),
"package a;\nexport fn v() i32 = { return 1; };\n");
writefile(strings.concat(adir, "/a_test.ww"), strings.concat(
"package a_test;\nimport a;\n",
"@test fn one() void = { assert(a.v() == 1); };\n"));
let out: commandout;
let drvs: []str = ["ww", "ww_ww"];
let i: i32 = 0;
for (i < 2) {
let named: str = strings.concat(outdir, "/out_", drvs[i],
".bin");
let coav: []str = [driver(drvs[i]), "test", "-c", "-o",
named, pdir];
runcommand(root, strings.concat("nameco_", drvs[i]), coav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let fi: os.filestat;
match (os.stat(&fi, named)) {
case void => void;
case let e: os.oserror => abort("-c -o artifact missing");
};
match (os.stat(&fi, strings.concat(pdir, "/pkg.test"))) {
case void => abort("-c -o still published the fixed stem");
case let e: os.oserror => void;
};
let runav: []str = [named];
runcommand(root, strings.concat("namerun_", drvs[i]), runav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "seven ... ok"));
let nocav: []str = [driver(drvs[i]), "test", "-o", named,
pdir];
runcommand(root, strings.concat("noc_", drvs[i]), nocav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 2);
assert(has(out.stderr, "-o needs -c for a package target"));
let mulav: []str = [driver(drvs[i]), "test", "-c", "-o",
named, strings.concat(root, "/...")];
runcommand(root, strings.concat("multi_", drvs[i]), mulav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 2);
assert(has(out.stderr,
"cannot use -o with multiple packages"));
i += 1;
};
clean(root);
};