Files
ww/test/package/package_test.ww

12638 lines
547 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package package_test;
// Make builds and invokes this one binary; discovery, subprocess ownership,
// output interpretation, and assertions remain WW code.
import crypto.sha256;
import hash;
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 rewritefile(path: str, content: str) void = {
let fd: i32 = os.open(path, os.flag.WRONLY | os.flag.TRUNC, 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 runcommanddir(root: str, name: str, dir: 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 = dir;
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 runcommandenvdir(root: str, name: str, argv: []str, env: []str,
dir: str, lifetime: time.duration, out: *commandout) void = {
let c: exec.command;
c.path = argv[0];
c.argv = argv;
c.env = env;
c.dir = dir;
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);
};
// A direct descriptor mapping keeps the caller's duplicate environment and cwd
// intact while giving the nested driver known nonempty input.
fn runcommandinputenvdir(root: str, name: str, argv: []str, env: []str,
dir: str, input: str, lifetime: time.duration, out: *commandout) void = {
let c: exec.command;
c.path = argv[0];
c.argv = argv;
c.env = env;
c.dir = dir;
c.stdinpath = input;
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 boundarypkgname(n: i32) str = {
assert(n >= 0 && n < 1000);
let out: []u8 = alloc([], 4u64)!;
append(out, 'p');
append(out, ('0': i32 + (n / 100)): u8);
append(out, ('0': i32 + ((n / 10) % 10)): u8);
append(out, ('0': i32 + (n % 10)): u8);
return strings.frombytes(out);
};
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);
};
fn localidentity(dir: str, declaredname: str) str = {
let out: []u8 = alloc([], (dir.len * 4 + 16): u64)!;
let prefix: str = "__wwlocal.p";
let i: i32 = 0;
for (i < prefix.len) { append(out, prefix[i]); i += 1; };
let hex: str = "0123456789abcdef";
i = 0;
for (i < dir.len) {
let c: u8 = dir[i];
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9')) {
append(out, c);
} else if (c == '_') {
append(out, '_'); append(out, 'u');
} else if (c == '/') {
append(out, '_'); append(out, 's');
} else {
let high: i32 = (c / 16u8): i32;
let low: i32 = (c % 16u8): i32;
append(out, '_'); append(out, 'x');
append(out, hex[high]); append(out, hex[low]);
};
i += 1;
};
return strings.frombytes(out);
};
fn digesthex(h: *hash.hash) str = {
let digest: [32]u8;
hash.sum(h, digest[0:32]);
let out: []u8 = alloc([], 65u64)!;
let digits: str = "0123456789abcdef";
let i: i32 = 0;
for (i < 32) {
let high: i32 = (digest[i] / 16u8): i32;
let low: i32 = (digest[i] % 16u8): i32;
append(out, digits[high]);
append(out, digits[low]);
i += 1;
};
return strings.frombytes(out);
};
fn packagestoragekeyfor(path: str, canon: str, variant: i32, role: i32,
for_test: str) str = {
let state: sha256.state = sha256.sha256();
let h: *hash.hash = (&state): *hash.hash;
hash.write(h, strings.toutf8("ww-package-storage-v3:"));
let tag: [4]u8;
tag[0] = ('0': i32 + variant): u8;
tag[1] = ':': u8;
tag[2] = ('0': i32 + role): u8;
tag[3] = ':': u8;
hash.write(h, tag[0:4]);
hash.write(h, strings.toutf8(path));
let zero: [1]u8;
zero[0] = 0u8;
hash.write(h, zero[0:1]);
hash.write(h, strings.toutf8(canon));
hash.write(h, zero[0:1]);
if (for_test.len != 0) {
hash.write(h, strings.toutf8(for_test));
};
let out: []u8 = alloc([], 81u64)!;
let prefix: str = "__wwpkg.v";
let i: i32 = 0;
for (i < prefix.len) { append(out, prefix[i]); i += 1; };
append(out, tag[0]); append(out, '.'); append(out, 'r');
append(out, tag[2]); append(out, '.'); append(out, 'h');
let hex: str = digesthex(h);
i = 0;
for (i < hex.len) { append(out, hex[i]); i += 1; };
return strings.frombytes(out);
};
fn packagestoragekey(path: str, canon: str, variant: i32, role: i32) str = {
return packagestoragekeyfor(path, canon, variant, role, "");
};
fn importrelative(path: str) str = {
let out: []u8 = alloc([], (path.len + 1): u64)!;
let i: i32 = 0;
for (i < path.len) {
if (path[i] == '.') { append(out, '/'); }
else { append(out, path[i]); };
i += 1;
};
return strings.frombytes(out);
};
fn longidentity(leaf: str) str = {
let out: []u8 = alloc([], 384u64)!;
let component: str = "segmentabcdefghijklmnop";
let n: i32 = 0;
for (n < 13) {
let i: i32 = 0;
for (i < component.len) { append(out, component[i]); i += 1; };
append(out, '.');
n += 1;
};
let i: i32 = 0;
for (i < leaf.len) { append(out, leaf[i]); i += 1; };
return strings.frombytes(out);
};
fn deeppunctuationpath(root: str, branch: str) str = {
let out: str = strings.concat(root, "/outside +% @ _/", branch);
let component: str = "/punctuation + percent% at@ under_score";
let n: i32 = 0;
for (n < 9) { out = strings.concat(out, component); n += 1; };
return out;
};
fn mkdirall(path: str) void = {
match (os.mkdirs(path, 448i32)) {
case void => void;
case let e: os.oserror => abort("mkdirs failed");
};
};
fn normalizedtrace(trace: str, work: str, output: str) str = {
let first: str;
match (strings.replace(trace, work, "$WORK/")) {
case let value: str => first = value;
case nomem => abort("trace normalization failed");
};
match (strings.replace(first, output, "$OUTPUT")) {
case let value: str => return value;
case nomem => abort("trace normalization failed");
};
};
fn directoryhasnew(path: str) bool = {
let fd: i32 = os.open(path, os.flag.RDONLY, 0i32);
assert(fd >= 0);
let buf: []u8 = alloc([], 16384u64)!;
buf.len = 16384;
let n: i64 = os.getdents64(fd, buf.ptr, buf.len: u64);
for (n > 0i64) {
let off: i32 = 0;
for (off < n: i32) {
let reclen: i32 = (buf[off + 16]: i32)
+ ((buf[off + 17]: i32) * 256);
assert(reclen >= 20 && off + reclen <= n: i32);
let len: i32 = 0;
for (buf[off + 19 + len] != 0u8) { len += 1; };
if (len >= 4 && buf[off + 19 + len - 4] == '.'
&& buf[off + 19 + len - 3] == 'n'
&& buf[off + 19 + len - 2] == 'e'
&& buf[off + 19 + len - 1] == 'w') {
assert(os.close(fd) == 0);
return true;
};
off += reclen;
};
n = os.getdents64(fd, buf.ptr, buf.len: u64);
};
assert(n == 0i64);
assert(os.close(fd) == 0);
return false;
};
fn directoryisempty(path: str) bool = {
let fd: i32 = os.open(path, os.flag.RDONLY, 0i32);
assert(fd >= 0);
let buf: []u8 = alloc([], 16384u64)!;
buf.len = 16384;
let n: i64 = os.getdents64(fd, buf.ptr, buf.len: u64);
for (n > 0i64) {
let off: i32 = 0;
for (off < n: i32) {
let reclen: i32 = (buf[off + 16]: i32)
+ ((buf[off + 17]: i32) * 256);
assert(reclen >= 20 && off + reclen <= n: i32);
let len: i32 = 0;
for (buf[off + 19 + len] != 0u8) { len += 1; };
let dot: bool = len == 1 && buf[off + 19] == '.';
let dotdot: bool = len == 2 && buf[off + 19] == '.'
&& buf[off + 20] == '.';
if (!dot && !dotdot) {
assert(os.close(fd) == 0);
return false;
};
off += reclen;
};
n = os.getdents64(fd, buf.ptr, buf.len: u64);
};
assert(n == 0i64);
assert(os.close(fd) == 0);
return true;
};
fn byteshasat(s: str, off: i32, want: str) bool = {
if (off < 0 || off + want.len > s.len) { return false; };
let i: i32 = 0;
for (i < want.len) {
if (s[off + i] != want[i]) { return false; };
i += 1;
};
return true;
};
fn archivememberend(ar: str, off: i32, name: str) i32 = {
assert(byteshasat(ar, off, name));
assert(byteshasat(ar, off + 58, "`\n"));
let size: i32 = 0;
let seen: bool = false;
let i: i32 = 0;
for (i < 10) {
let c: u8 = ar[off + 48 + i];
if (c >= '0' && c <= '9') {
seen = true;
size = size * 10 + ((c - '0'): i32);
} else { assert(c == ' '); };
i += 1;
};
assert(seen);
return off + 60 + size + (size & 1);
};
fn checkactionarchive(ar: str, hasinit: bool) void = {
assert(byteshasat(ar, 0, "!<arch>\n"));
let off: i32 = archivememberend(ar, 8, "pkg.o/");
if (hasinit) { off = archivememberend(ar, off, "init.o/"); };
assert(off == ar.len);
};
fn hexbytes(value: str) str = {
let out: []u8 = alloc([], (value.len * 2 + 1): u64)!;
let digits: str = "0123456789abcdef";
let i: i32 = 0;
for (i < value.len) {
let high: i32 = (value[i] / 16u8): i32;
let low: i32 = (value[i] % 16u8): i32;
append(out, digits[high]);
append(out, digits[low]);
i += 1;
};
return strings.frombytes(out);
};
fn cwdtestenv(stage: str) []str = {
let inherited: []str = os.getenvs();
let env: []str = alloc([], (inherited.len + 8): u64)!;
let i: i32 = 0;
for (i < inherited.len) {
if (!strings.hasprefix(inherited[i], "PWD=")
&& !strings.hasprefix(inherited[i], "WW_W6C=")
&& !strings.hasprefix(inherited[i], "WW_W6A=")
&& !strings.hasprefix(inherited[i], "WW_W6L=")
&& !strings.hasprefix(inherited[i], "WW_SRCLIB=")
&& !strings.hasprefix(inherited[i], "WW_CWD_")) {
append(env, inherited[i]);
};
i += 1;
};
append(env, "PWD=/ww-cwd-inherited-first");
if (same(stage, "ww")) {
append(env, strings.concat("WW_W6C=", driver("w6c")));
append(env, strings.concat("WW_W6A=", driver("w6a")));
append(env, strings.concat("WW_W6L=", driver("w6l")));
} else {
assert(same(stage, "ww_ww"));
append(env, strings.concat("WW_W6C=", driver("w6c_ww")));
append(env, strings.concat("WW_W6A=", driver("w6a_ww")));
append(env, strings.concat("WW_W6L=", driver("w6l_ww")));
};
append(env, strings.concat("WW_SRCLIB=", repo(), "/lib"));
append(env, "PWD=/ww-cwd-inherited-last");
return env;
};
fn cwdassertrecord(text: str, label: str, cwd: str, pwd: str,
pwdcount: str, pwdlast: str, data: str, testdata: str,
input: str) void = {
assert(has(text, strings.concat(label, " cwd=", cwd, "\n")));
assert(has(text, strings.concat(label, " PWD=", pwd, "\n")));
assert(has(text, strings.concat(label, " PWD-count=", pwdcount, "\n")));
assert(has(text, strings.concat(label, " PWD-last=", pwdlast, "\n")));
assert(has(text, strings.concat(label, " data=", data, "\n")));
assert(has(text, strings.concat(label, " testdata=", testdata, "\n")));
assert(has(text, strings.concat(label, " stdin=", input, "\n")));
assert(has(text, strings.concat(label, " create=ok\n")));
};
fn cwdassertmergedstreams(text: str, label: str, dir: str) void = {
let out1: str = strings.concat("STREAM ", label, " out-1 cwd=", dir, "\n");
let err1: str = strings.concat("STREAM ", label, " err-1 cwd=", dir, "\n");
let out2: str = strings.concat("STREAM ", label, " out-2 cwd=", dir, "\n");
let err2: str = strings.concat("STREAM ", label, " err-2 cwd=", dir, "\n");
let p0: i32 = pos(text, out1);
let p1: i32 = pos(text, err1);
let p2: i32 = pos(text, out2);
let p3: i32 = pos(text, err2);
assert(p0 >= 0 && p0 < p1 && p1 < p2 && p2 < p3);
assert(occurrences(text, out1) == 1 && occurrences(text, err1) == 1);
assert(occurrences(text, out2) == 1 && occurrences(text, err2) == 1);
};
fn cwdassertsplitstreams(stdout: str, stderr: str, label: str, dir: str) void = {
let out1: str = strings.concat("STREAM ", label, " out-1 cwd=", dir, "\n");
let err1: str = strings.concat("STREAM ", label, " err-1 cwd=", dir, "\n");
let out2: str = strings.concat("STREAM ", label, " out-2 cwd=", dir, "\n");
let err2: str = strings.concat("STREAM ", label, " err-2 cwd=", dir, "\n");
let p0: i32 = pos(stdout, out1);
let p2: i32 = pos(stdout, out2);
let p1: i32 = pos(stderr, err1);
let p3: i32 = pos(stderr, err2);
assert(p0 >= 0 && p0 < p2 && p1 >= 0 && p1 < p3);
assert(!has(stdout, err1) && !has(stdout, err2));
assert(!has(stderr, out1) && !has(stderr, out2));
};
fn cwdassertpackage(text: str, label: str, dir: str, data: str,
testdata: str) void = {
cwdassertrecord(text, label, dir, dir, "1", "yes", data, testdata,
"eof");
cwdassertmergedstreams(text, label, dir);
};
fn cwdwritedata(dir: str, label: str) void = {
let testdata: str = strings.concat(dir, "/testdata");
assert(os.mkdir(testdata, 448i32) == 0);
writefile(strings.concat(dir, "/data.txt"),
strings.concat(label, "-data\n"));
writefile(strings.concat(testdata, "/input.txt"),
strings.concat(label, "-testdata\n"));
};
@test fn deterministic_routing_and_filters() void = {
let root: str = fresh();
let target: str = packagepath("routing");
let sourceroot: str = strings.concat(repo(), "/test/package");
let av: []str = [driver("ww"), "test", "-I", sourceroot,
"-list", target];
let out: commandout;
runcommand(root, "list", av, (30i64 * (time.second: i64)): time.duration,
&out);
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.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.external_package\n") == 1);
let rav: []str = [driver("ww"), "test", "-I", sourceroot, 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.external_package ... ok\n"));
assert(has(out.stdout,
"3 passed, 0 failed, 0 skipped, 0 harness errors\n"));
assert(occurrences(out.stdout,
"3 passed, 0 failed, 0 skipped, 0 harness errors\n") == 1);
let fav: []str = [driver("ww"), "test", "-run",
"routing.private_helper_first", "-filter", "external_package",
"-I", sourceroot, 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.external_package ... ok\n"));
let nav: []str = [driver("ww"), "test", "-I", sourceroot,
"-run", "no-such-*", target];
runcommand(root, "nomatch", nav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(out.stdout, "[no matches]\n") == 1);
assert(occurrences(out.stdout,
"3 discovered, 0 selected, 0 started, 0 completed\n") == 1);
let lnav: []str = [driver("ww"), "test", "-list", "-run",
"no-such-*", "-I", sourceroot, target];
runcommand(root, "list-nomatch", lnav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(out.stdout, "[no matches]\n") == 1);
clean(root);
};
// Directory-package execution is one product-level runtime property. This
// fixture keeps every source tree disposable while covering the variant,
// dependency, routing, concurrency, persistence, and failure boundaries that
// could otherwise accidentally derive a cwd from an action or request name.
@test fn directory_test_execution_working_directory() void = {
let root: str = fresh();
let caller: str = strings.concat(root, "/caller");
let tree: str = strings.concat(root, "/tree");
let treelink: str = strings.concat(root, "/tree-link");
let failtree: str = strings.concat(root, "/failtree");
mkdirall(caller);
mkdirall(tree);
mkdirall(failtree);
cwdwritedata(caller, "caller");
writefile(strings.concat(caller, "/sentinel"), "parent-sentinel\n");
let stdinpath: str = strings.concat(root, "/stdin.txt");
let stdinbytes: []u8 = alloc([], 4096u64)!;
let inputi: i32 = 0;
for (inputi < 2048) {
append(stdinbytes, 'X');
append(stdinbytes, '\n');
inputi += 1;
};
writefile(stdinpath, strings.frombytes(stdinbytes));
let missingstdinout: str = strings.concat(root, "/missing-stdin.stdout");
let missingstdinerr: str = strings.concat(root, "/missing-stdin.stderr");
let missingstdinav: []str = ["/bin/true"];
let missingstdincmd: exec.command;
missingstdincmd.path = missingstdinav[0];
missingstdincmd.argv = missingstdinav;
missingstdincmd.env = os.getenvs();
missingstdincmd.dir = caller;
missingstdincmd.stdinpath = strings.concat(root, "/missing-stdin");
missingstdincmd.stdoutpath = missingstdinout;
missingstdincmd.stderrpath = missingstdinerr;
missingstdincmd.deadline.sec = 0i64;
missingstdincmd.deadline.nsec = 0i64;
missingstdincmd.grace = 0i64: time.duration;
let missingstdinresult: exec.result;
exec.run(&missingstdincmd, &missingstdinresult);
assert(missingstdinresult.termination == exec.termination.ERROR);
assert(missingstdinresult.errno == 2
&& missingstdinresult.cleanuperrno == 0);
assert(!os.exists(missingstdinout) && !os.exists(missingstdinerr));
// Create in reverse lexical order; discovery and product emission may not
// inherit filesystem or request order.
let names: []str = ["probe", "plain", "p6", "p5", "p4", "p3",
"p2", "p1", "testdep", "dep", "cmdno"];
let i: i32 = 0;
for (i < names.len) {
let dir: str = strings.concat(tree, "/", names[i]);
assert(os.mkdir(dir, 448i32) == 0);
cwdwritedata(dir, names[i]);
i += 1;
};
let probe: str = strings.concat(tree, "/probe");
let dep: str = strings.concat(tree, "/dep");
let testdep: str = strings.concat(tree, "/testdep");
let p1: str = strings.concat(tree, "/p1");
let p2: str = strings.concat(tree, "/p2");
let p3: str = strings.concat(tree, "/p3");
let p4: str = strings.concat(tree, "/p4");
let p5: str = strings.concat(tree, "/p5");
let p6: str = strings.concat(tree, "/p6");
let plain: str = strings.concat(tree, "/plain");
let cmdno: str = strings.concat(tree, "/cmdno");
let streamsource: str = strings.concat(
"fn putfd(fd: i32, value: str) void = {\n",
" match (os.writeall(fd, value.ptr, value.len: u64)) {\n",
" case let n: i64 => assert(n == value.len: i64);\n",
" case let e: os.oserror => abort(\"write failed\");\n",
" };\n",
"};\n",
"fn put(value: str) void = { putfd(os.STDOUT_FILENO, value); };\n",
"fn puterr(value: str) void = { putfd(os.STDERR_FILENO, value); };\n",
"export fn streams(label: str, context: str) void = {\n",
" put(strings.concat(\"STREAM \", label, \" out-1 cwd=\", context, \"\\n\"));\n",
" puterr(strings.concat(\"STREAM \", label, \" err-1 cwd=\", context, \"\\n\"));\n",
" put(strings.concat(\"STREAM \", label, \" out-2 cwd=\", context, \"\\n\"));\n",
" puterr(strings.concat(\"STREAM \", label, \" err-2 cwd=\", context, \"\\n\"));\n",
"};\n");
writefile(strings.concat(probe, "/probe.ww"), strings.concat(
"package probe;\n",
"import os;\n",
"import strings;\n",
streamsource,
"fn emitfile(label: str, key: str, path: str) void = {\n",
" put(label); put(\" \" ); put(key); put(\"=\");\n",
" let fd: i32 = os.open(path, os.flag.RDONLY, 0i32);\n",
" if (fd < 0) { put(\"<missing>\\n\"); return; };\n",
" let size: i64 = -1i64;\n",
" match (os.filesize(fd)) {\n",
" case let value: i64 => size = value;\n",
" case let e: os.oserror => void;\n",
" };\n",
" if (size < 0i64) { os.close(fd); put(\"<size-error>\\n\"); return; };\n",
" let bytes: []u8 = alloc([], size: u64)!; bytes.len = size: i32;\n",
" match (os.readall(fd, bytes.ptr, size: u64)) {\n",
" case let n: i64 => assert(n == size);\n",
" case let e: os.oserror => abort(\"read failed\");\n",
" }; os.close(fd);\n",
" let body: str; body.ptr = bytes.ptr; body.len = bytes.len; put(body);\n",
" if (body.len == 0 || body[body.len - 1] != '\\n') { put(\"\\n\"); };\n",
"};\n",
"export fn run(label: str) void = {\n",
" let buf: [4096]u8;\n",
" let n: i64 = os.getcwd(&buf[0], size([4096]u8)); assert(n > 1i64);\n",
" let cwd: str; cwd.ptr = &buf[0]; cwd.len = (n - 1i64): i32;\n",
" streams(label, cwd);\n",
" put(label); put(\" cwd=\"); put(cwd); put(\"\\n\");\n",
" put(label); put(\" PWD=\");\n",
" match (os.getenv(\"PWD\")) {\n",
" case let value: str => put(value); case void => put(\"<unset>\");\n",
" }; put(\"\\n\");\n",
" let env: []str = os.getenvs(); let count: i32 = 0; let last: i32 = -1;\n",
" let i: i32 = 0; for (i < env.len) {\n",
" if (strings.hasprefix(env[i], \"PWD=\")) { count += 1; last = i; };\n",
" i += 1;\n",
" };\n",
" put(label); put(\" PWD-count=\");\n",
" if (count == 0) { put(\"0\\n\"); } else { if (count == 1) {\n",
" put(\"1\\n\"); } else { if (count == 2) { put(\"2\\n\");\n",
" } else { put(\"many\\n\"); }; }; };\n",
" put(label); put(\" PWD-last=\");\n",
" if (last == env.len - 1) { put(\"yes\\n\"); } else { put(\"no\\n\"); };\n",
" emitfile(label, \"data\", \"data.txt\");\n",
" emitfile(label, \"testdata\", \"testdata/input.txt\");\n",
" let input: [1]u8;\n let inputn: i64 = os.read(os.STDIN_FILENO, &input[0], 1u64);\n put(label); put(\" stdin=\");\n if (inputn == 0i64) { put(\"eof\\n\"); } else {\n if (inputn == 1i64) { put(\"data\\n\"); } else { put(\"<error>\\n\"); };\n };\n",
" let fd: i32 = os.open(\"created.txt\", os.flag.WRONLY |\n",
" os.flag.CREATE | os.flag.TRUNC, 384i32);\n",
" put(label); put(\" create=\");\n",
" if (fd < 0) { put(\"<error>\\n\"); } else {\n",
" match (os.writeall(fd, label.ptr, label.len: u64)) {\n",
" case let wrote: i64 => assert(wrote == label.len: i64);\n",
" case let e: os.oserror => abort(\"create write failed\");\n",
" }; assert(os.close(fd) == 0); put(\"ok\\n\");\n",
" };\n",
"};\n"));
writefile(strings.concat(dep, "/dep.ww"), strings.concat(
"package dep;\nimport probe;\n",
"export fn value() i32 = { return 7; };\n",
"fn init() void = { probe.run(\"dep-init\"); };\n"));
writefile(strings.concat(dep, "/dep_test.ww"),
"package dep;\nimport probe;\n@test fn cwd() void = { probe.run(\"dep-test\"); };\n");
writefile(strings.concat(testdep, "/testdep.ww"), strings.concat(
"package testdep;\nimport probe;\n",
"export fn value() i32 = { return 8; };\n",
"fn init() void = { probe.run(\"testdep-init\"); };\n"));
writefile(strings.concat(testdep, "/testdep_test.ww"), strings.concat(
"package testdep;\nimport probe;\n",
"@test fn cwd() void = { probe.run(\"testdep-test\"); };\n"));
writefile(strings.concat(p1, "/p1.ww"),
"package p1;\nimport _ dep;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(p1, "/p1_test.ww"),
"package p1;\nimport probe;\n@test fn cwd() void = { probe.run(\"p1-internal\"); };\n");
writefile(strings.concat(p2, "/p2.ww"),
"package p2;\nimport _ dep;\nexport fn value() i32 = { return 2; };\n");
writefile(strings.concat(p2, "/p2_test.ww"), strings.concat(
"package p2_test;\nimport p2;\nimport probe;\n",
"@test fn cwd() void = { assert(p2.value() == 2); ",
"probe.run(\"p2-external\"); };\n"));
writefile(strings.concat(p3, "/p3.ww"),
"package p3;\nimport _ dep;\nexport fn value() i32 = { return 3; };\n");
writefile(strings.concat(p3, "/internal_test.ww"), strings.concat(
"package p3;\nimport _ testdep;\nimport probe;\n",
"export fn helper() i32 = { return 33; };\n",
"@test fn cwd_internal() void = { probe.run(\"p3-internal\"); };\n"));
writefile(strings.concat(p3, "/external_test.ww"), strings.concat(
"package p3_test;\nimport p3;\nimport probe;\n",
"@test fn cwd_external() void = { assert(p3.helper() == 33); ",
"probe.run(\"p3-external\"); };\n"));
writefile(strings.concat(p4, "/internal_test.ww"),
"package p4;\nimport probe;\n@test fn cwd() void = { probe.run(\"p4-internal-only\"); };\n");
writefile(strings.concat(p5, "/external_test.ww"),
"package p5_test;\nimport probe;\n@test fn cwd() void = { probe.run(\"p5-external-only\"); };\n");
writefile(strings.concat(p6, "/internal_test.ww"), strings.concat(
"package p6;\nimport probe;\nexport fn helper() i32 = { return 66; };\n",
"@test fn cwd_internal() void = { probe.run(\"p6-internal-only\"); };\n"));
writefile(strings.concat(p6, "/external_test.ww"), strings.concat(
"package p6_test;\nimport p6;\nimport probe;\n",
"@test fn cwd_external() void = { assert(p6.helper() == 66); ",
"probe.run(\"p6-external-only\"); };\n"));
writefile(strings.concat(plain, "/plain.ww"),
"package plain;\nimport probe;\nfn init() void = { probe.run(\"plain-init\"); };\n");
writefile(strings.concat(cmdno, "/main.ww"), strings.concat(
"package main;\nimport probe;\n",
"fn init() void = { probe.run(\"cmdno-init\"); };\n",
"fn main() void = { probe.run(\"cmdno-main\"); };\n"));
let failnames: []str = ["reject", "p9", "p8", "p7"];
i = 0;
for (i < failnames.len) {
let dir: str = strings.concat(failtree, "/", failnames[i]);
assert(os.mkdir(dir, 448i32) == 0);
cwdwritedata(dir, failnames[i]);
i += 1;
};
let p7: str = strings.concat(failtree, "/p7");
let p8: str = strings.concat(failtree, "/p8");
let p9: str = strings.concat(failtree, "/p9");
let reject: str = strings.concat(failtree, "/reject");
writefile(strings.concat(p7, "/p7_test.ww"), strings.concat(
"package p7;\nimport probe;\n@test fn fails() void = {\n",
" probe.run(\"p7-fail\"); assert(false);\n};\n"));
writefile(strings.concat(p8, "/p8_test.ww"), strings.concat(
"package p8;\nimport probe;\nimport time;\n@test fn timesout() void = {\n",
" probe.run(\"p8-timeout\");\n",
" time.sleep((2i64 * (time.second: i64)): time.duration, ",
"time.clock.monotonic);\n};\n"));
writefile(strings.concat(p9, "/p9_test.ww"), strings.concat(
"package p9;\nimport os;\nimport probe;\n@test fn signals() void = {\n",
" probe.run(\"p9-signal\"); os.kill(os.getpid(), os.SIGTERM);\n};\n"));
writefile(strings.concat(reject, "/reject.ww"),
"package reject;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(reject, "/bad_test.ww"),
"package unrelated;\n@test fn unreachable() void = { assert(false); };\n");
let out: commandout;
let lnav: []str = ["/bin/ln", "-s", tree, treelink];
runcommand(root, "cwd-link", lnav, time.second, &out);
expectexit(&out, 0);
// The first environment has hundreds of unrelated entries after two PWD
// entries. The product must dynamically clone it, remove both PWD entries,
// and append exactly one authoritative PWD last.
let cbase: []str = cwdtestenv("ww");
let cenv: []str = alloc([], (cbase.len + 300): u64)!;
i = 0;
for (i < cbase.len) { append(cenv, cbase[i]); i += 1; };
i = 0;
for (i < 300) {
append(cenv, strings.concat("WW_CWD_PADDING_", boundarypkgname(i),
"=abcdefghijklmnopqrstuvwxyz0123456789"));
i += 1;
};
let wenv: []str = cwdtestenv("ww_ww");
let forward: []str = [driver("ww"), "test", "-j", "1", "-I", tree,
dep, testdep, p1, p2, p3, p4, p5, p6];
let reverse: []str = [driver("ww_ww"), "test", "-j", "4", "-I", tree,
p6, p5, p4, p3, p2, p1, testdep, dep];
let outc: commandout;
let outw: commandout;
runcommandinputenvdir(root, "cwd-multi-c", forward, cenv, caller,
stdinpath,
(120i64 * (time.second: i64)): time.duration, &outc);
runcommandinputenvdir(root, "cwd-multi-ww", reverse, wenv, caller,
stdinpath,
(120i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 0);
expectexit(&outw, 0);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr) && outc.stderr.len == 0);
cwdassertpackage(outc.stdout, "dep-init", dep, "dep-data", "dep-testdata");
cwdassertpackage(outc.stdout, "dep-test", dep, "dep-data", "dep-testdata");
cwdassertpackage(outc.stdout, "testdep-init", testdep,
"testdep-data", "testdep-testdata");
cwdassertpackage(outc.stdout, "testdep-test", testdep,
"testdep-data", "testdep-testdata");
cwdassertpackage(outc.stdout, "dep-init", p1, "p1-data", "p1-testdata");
cwdassertpackage(outc.stdout, "p1-internal", p1,
"p1-data", "p1-testdata");
let multiout: str = strings.dup(outc.stdout);
let ran: []str = [dep, testdep, p1, p2, p3, p4, p5, p6];
i = 0;
for (i < ran.len) {
assert(os.exists(strings.concat(ran[i], "/created.txt")));
i += 1;
};
assert(!os.exists(strings.concat(caller, "/created.txt")));
assert(same(readfile(strings.concat(caller, "/sentinel")),
"parent-sentinel\n"));
// Filtering, listing, and a no-match filter all execute the same product
// binary. Package initialization therefore has the product cwd even when no
// selected test body runs.
let filterav: []str = [driver("ww"), "test", "-run", "cwd_external",
"-I", tree, p3];
runcommandinputenvdir(root, "cwd-filter", filterav, cenv, caller,
stdinpath,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
cwdassertpackage(out.stdout, "dep-init", p3, "p3-data", "p3-testdata");
cwdassertpackage(out.stdout, "testdep-init", p3,
"p3-data", "p3-testdata");
cwdassertpackage(out.stdout, "p3-external", p3,
"p3-data", "p3-testdata");
assert(!has(out.stdout, "p3-internal cwd="));
let listav: []str = [driver("ww_ww"), "test", "-list", "-I", tree, p3];
runcommandinputenvdir(root, "cwd-list", listav, wenv, caller,
stdinpath,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
cwdassertpackage(out.stdout, "dep-init", p3, "p3-data", "p3-testdata");
cwdassertpackage(out.stdout, "testdep-init", p3,
"p3-data", "p3-testdata");
assert(has(out.stdout, "p3.cwd_internal\n"));
assert(has(out.stdout, "p3.cwd_external\n"));
assert(!has(out.stdout, "p3-internal cwd="));
assert(!has(out.stdout, "p3-external cwd="));
let nomatchav: []str = [driver("ww"), "test", "-run", "no-such-test",
"-I", tree, p3];
runcommandinputenvdir(root, "cwd-no-match", nomatchav, cenv, caller,
stdinpath,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
cwdassertpackage(out.stdout, "dep-init", p3, "p3-data", "p3-testdata");
cwdassertpackage(out.stdout, "testdep-init", p3,
"p3-data", "p3-testdata");
assert(has(out.stdout, "[no matches]\n"));
assert(!has(out.stdout, "p3-internal cwd="));
assert(!has(out.stdout, "p3-external cwd="));
let failc: []str = [driver("ww"), "test", "-I", tree, "-I", failtree,
p7];
let failw: []str = [driver("ww_ww"), "test", "-I", tree, "-I",
failtree, p7];
runcommandinputenvdir(root, "cwd-fail-c", failc, cenv, caller,
stdinpath,
(60i64 * (time.second: i64)): time.duration, &outc);
runcommandinputenvdir(root, "cwd-fail-ww", failw, wenv, caller,
stdinpath,
(60i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
cwdassertpackage(outc.stdout, "p7-fail", p7, "p7-data", "p7-testdata");
assert(outc.stderr.len == 0);
assert(has(outc.stdout, strings.concat("FAIL ", p7,
" [p7] (test exit 1)\n")));
let timeoutc: []str = [driver("ww"), "test", "-timeout-ms=50", "-I",
tree, "-I", failtree, p8];
let timeoutw: []str = [driver("ww_ww"), "test", "-timeout-ms=50", "-I",
tree, "-I", failtree, p8];
runcommandinputenvdir(root, "cwd-timeout-c", timeoutc, cenv, caller,
stdinpath,
(60i64 * (time.second: i64)): time.duration, &outc);
runcommandinputenvdir(root, "cwd-timeout-ww", timeoutw, wenv, caller,
stdinpath,
(60i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
cwdassertpackage(outc.stdout, "p8-timeout", p8,
"p8-data", "p8-testdata");
assert(has(outc.stdout, "FAIL(timeout)\n"));
assert(outc.stderr.len == 0);
assert(has(outc.stdout, strings.concat("FAIL ", p8,
" [p8] (test exit 1)\n")));
let signalc: []str = [driver("ww"), "test", "-I", tree, "-I",
failtree, p9];
let signalw: []str = [driver("ww_ww"), "test", "-I", tree, "-I",
failtree, p9];
runcommandinputenvdir(root, "cwd-signal-c", signalc, cenv, caller,
stdinpath, (60i64 * (time.second: i64)): time.duration, &outc);
runcommandinputenvdir(root, "cwd-signal-ww", signalw, wenv, caller,
stdinpath, (60i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
cwdassertpackage(outc.stdout, "p9-signal", p9,
"p9-data", "p9-testdata");
assert(has(outc.stdout, "FAIL (signal 15)\n"));
assert(outc.stderr.len == 0);
assert(has(outc.stdout, strings.concat("FAIL ", p9,
" [p9] (test exit 1)\n")));
// Source-class rejection precedes every captured build or test child, so a
// nonempty caller input cannot create a partial persistent generation.
let rejectcwork: str = strings.concat(root, "/stdin-reject-c");
let rejectwwork: str = strings.concat(root, "/stdin-reject-ww");
assert(os.mkdir(rejectcwork, 448i32) == 0);
assert(os.mkdir(rejectwwork, 448i32) == 0);
let rejectcav: []str = [driver("ww"), "test", "-w", rejectcwork,
"-I", failtree, reject];
let rejectwav: []str = [driver("ww_ww"), "test", "-w", rejectwwork,
"-I", failtree, reject];
runcommandinputenvdir(root, "stdin-reject-c", rejectcav, cenv, caller,
stdinpath, (60i64 * (time.second: i64)): time.duration, &outc);
runcommandinputenvdir(root, "stdin-reject-ww", rejectwav, wenv, caller,
stdinpath, (60i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(outc.stdout.len == 0 && outw.stdout.len == 0);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr,
"test package must match production package or <package>_test\n"));
assert(directoryisempty(rejectcwork));
assert(directoryisempty(rejectwwork));
// Packages without selected test sources and `ww build` never start a test
// process, even if production initialization would make that visible.
let notestav: []str = [driver("ww_ww"), "test", "-I", tree,
plain, cmdno];
runcommandinputenvdir(root, "cwd-no-tests", notestav, wenv, caller,
stdinpath,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(!has(out.stdout, "plain-init"));
assert(!has(out.stdout, "cmdno-init"));
assert(!has(out.stdout, "cmdno-main"));
assert(!os.exists(strings.concat(plain, "/created.txt")));
assert(!os.exists(strings.concat(cmdno, "/created.txt")));
let commandbin: str = strings.concat(root, "/cmdno.bin");
let buildav: []str = [driver("ww"), "build", "-I", tree, "-o",
commandbin, cmdno];
runcommandinputenvdir(root, "cwd-build", buildav, cenv, caller,
stdinpath,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(os.exists(commandbin));
assert(!has(out.stdout, "cmdno-init") && !has(out.stdout, "cmdno-main"));
assert(!os.exists(strings.concat(cmdno, "/created.txt")));
// Compile-only paths do not run. A published binary has no embedded cwd or
// wrapper: direct invocation keeps the caller's cwd and duplicate PWDs.
assert(os.remove(strings.concat(p2, "/created.txt")) == 0);
let defaultcompile: []str = [driver("ww"), "test", "-c", "-I", tree, p2];
runcommandinputenvdir(root, "cwd-compile-default", defaultcompile, cenv,
caller, stdinpath,
(90i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let defaultbin: str = strings.concat(caller, "/p2.test");
assert(os.exists(defaultbin));
assert(!os.exists(strings.concat(p2, "/p2.test")));
assert(!os.exists(strings.concat(p2, "/created.txt")));
assert(!has(out.stdout, "dep-init") && !has(out.stdout, "p2-external"));
assert(os.remove(defaultbin) == 0);
assert(os.remove(strings.concat(p1, "/created.txt")) == 0);
let p1cbin: str = strings.concat(root, "/p1-c.test");
let p1wbin: str = strings.concat(root, "/p1-ww.test");
let compilec: []str = [driver("ww"), "test", "-c", "-o", p1cbin,
"-I", tree, p1];
let compilew: []str = [driver("ww_ww"), "test", "-c", "-o", p1wbin,
"-I", tree, p1];
runcommandinputenvdir(root, "cwd-compile-c", compilec, cenv, caller,
stdinpath,
(90i64 * (time.second: i64)): time.duration, &outc);
runcommandinputenvdir(root, "cwd-compile-ww", compilew, wenv, caller,
stdinpath,
(90i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 0);
expectexit(&outw, 0);
assert(!os.exists(strings.concat(p1, "/created.txt")));
assert(same(readfile(p1cbin), readfile(p1wbin)));
assert(!has(outc.stdout, "dep-init") && !has(outw.stdout, "dep-init"));
let directbin: []str = [p1cbin, "-package=p1"];
runcommandinputenvdir(root, "cwd-published-direct", directbin, cenv,
caller, stdinpath,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
cwdassertrecord(out.stdout, "dep-init", caller,
"/ww-cwd-inherited-first", "2", "no", "caller-data",
"caller-testdata", "data");
cwdassertrecord(out.stdout, "p1-internal", caller,
"/ww-cwd-inherited-first", "2", "no", "caller-data",
"caller-testdata", "data");
cwdassertsplitstreams(out.stdout, out.stderr, "dep-init", caller);
cwdassertsplitstreams(out.stdout, out.stderr, "p1-internal", caller);
assert(os.exists(strings.concat(caller, "/created.txt")));
assert(os.remove(strings.concat(caller, "/created.txt")) == 0);
// Raw single-file compatibility is deliberately outside the directory
// coordinator rule and retains its caller execution context.
let rawc: []str = [driver("ww"), "test", "-I", tree,
strings.concat(p4, "/internal_test.ww")];
let raww: []str = [driver("ww_ww"), "test", "-I", tree,
strings.concat(p4, "/internal_test.ww")];
runcommandinputenvdir(root, "cwd-raw-c", rawc, cbase, caller,
stdinpath,
(60i64 * (time.second: i64)): time.duration, &outc);
assert(os.remove(strings.concat(caller, "/created.txt")) == 0);
runcommandinputenvdir(root, "cwd-raw-ww", raww, wenv, caller,
stdinpath,
(60i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 0);
expectexit(&outw, 0);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
cwdassertrecord(outc.stdout, "p4-internal-only", caller,
"/ww-cwd-inherited-first", "2", "yes", "caller-data",
"caller-testdata", "data");
cwdassertsplitstreams(outc.stdout, outc.stderr,
"p4-internal-only", caller);
assert(os.remove(strings.concat(caller, "/created.txt")) == 0);
cwdassertpackage(multiout, "dep-init", p2, "p2-data", "p2-testdata");
cwdassertpackage(multiout, "p2-external", p2,
"p2-data", "p2-testdata");
cwdassertpackage(multiout, "dep-init", p3, "p3-data", "p3-testdata");
cwdassertpackage(multiout, "testdep-init", p3,
"p3-data", "p3-testdata");
cwdassertpackage(multiout, "p3-internal", p3,
"p3-data", "p3-testdata");
cwdassertpackage(multiout, "p3-external", p3,
"p3-data", "p3-testdata");
cwdassertpackage(multiout, "p4-internal-only", p4,
"p4-data", "p4-testdata");
cwdassertpackage(multiout, "p5-external-only", p5,
"p5-data", "p5-testdata");
cwdassertpackage(multiout, "p6-internal-only", p6,
"p6-data", "p6-testdata");
cwdassertpackage(multiout, "p6-external-only", p6,
"p6-data", "p6-testdata");
let realrec: []str = [driver("ww"), "test", "-j", "1", "-I", tree,
strings.concat(tree, "/...")];
let linkrec: []str = [driver("ww_ww"), "test", "-j", "4", "-I",
"../tree-link", "../tree-link/..."];
runcommandinputenvdir(root, "cwd-recursive-real", realrec, cenv, caller,
stdinpath,
(120i64 * (time.second: i64)): time.duration, &outc);
runcommandinputenvdir(root, "cwd-recursive-link", linkrec, wenv, caller,
stdinpath,
(120i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 0);
expectexit(&outw, 0);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr) && outc.stderr.len == 0);
assert(has(outc.stdout, strings.concat("? ", plain, " [no tests]\n")));
assert(has(outc.stdout, strings.concat("? ", cmdno, " [no tests]\n")));
assert(!has(outc.stdout, "plain-init"));
assert(!has(outc.stdout, "cmdno-init"));
assert(!has(outc.stdout, "cmdno-main"));
cwdassertpackage(outc.stdout, "p6-external-only", p6,
"p6-data", "p6-testdata");
let direct: []str = [driver("ww"), "test", "-I", tree, p1];
let equivalent: []str = [driver("ww_ww"), "test", "-j", "3", "-I",
"../tree-link", "../tree/p1", p1, "../tree/./p1/../p1",
"../tree-link/p1"];
runcommandinputenvdir(root, "cwd-direct", direct, cenv, caller,
stdinpath,
(60i64 * (time.second: i64)): time.duration, &outc);
runcommandinputenvdir(root, "cwd-equivalent", equivalent, wenv, caller,
stdinpath,
(60i64 * (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(occurrences(outc.stdout,
strings.concat("ok ", p1, " [p1]\n")) == 1);
cwdassertpackage(outc.stdout, "dep-init", p1, "p1-data", "p1-testdata");
cwdassertpackage(outc.stdout, "p1-internal", p1,
"p1-data", "p1-testdata");
// Tool wrappers observe the established build-tool context. Only the
// generated product binary gets the package cwd; compiler, assembler, and
// linker cwd/argv/locale/TMPDIR remain owned by the build plan.
let tooltrace: str = strings.concat(root, "/cwd-tools.trace");
let cw: str = strings.concat(root, "/cwd-w6c.sh");
let aw: str = strings.concat(root, "/cwd-w6a.sh");
let lw: str = strings.concat(root, "/cwd-w6l.sh");
writefile(tooltrace, "");
writeexecutable(cw, strings.concat(
"#!/bin/sh\n",
"printf 'compiler cwd=' >> \"$WW_CWD_TOOL_TRACE\"\n",
"/bin/pwd >> \"$WW_CWD_TOOL_TRACE\"\n",
"printf 'compiler env=LC_ALL:%s TMPDIR:%s\\n' \"$LC_ALL\" ",
"\"$TMPDIR\" >> \"$WW_CWD_TOOL_TRACE\"\n",
"if IFS= read -r WW_CWD_STDIN; then\n",
" printf 'compiler stdin=data\\n' >> \"$WW_CWD_TOOL_TRACE\"\n",
"else printf 'compiler stdin=eof\\n' >> \"$WW_CWD_TOOL_TRACE\"; fi\n",
"printf 'compiler argv' >> \"$WW_CWD_TOOL_TRACE\"\n",
"for arg in \"$@\"; do printf ' <%s>' \"$arg\" >> ",
"\"$WW_CWD_TOOL_TRACE\"; done\n",
"printf '\\n' >> \"$WW_CWD_TOOL_TRACE\"\n",
"exec \"$WW_CWD_REAL_W6C\" \"$@\"\n"));
writeexecutable(aw, strings.concat(
"#!/bin/sh\n",
"printf 'assembler cwd=' >> \"$WW_CWD_TOOL_TRACE\"\n",
"/bin/pwd >> \"$WW_CWD_TOOL_TRACE\"\n",
"printf 'assembler env=LC_ALL:%s TMPDIR:%s\\n' \"$LC_ALL\" ",
"\"$TMPDIR\" >> \"$WW_CWD_TOOL_TRACE\"\n",
"if IFS= read -r WW_CWD_STDIN; then\n",
" printf 'assembler stdin=data\\n' >> \"$WW_CWD_TOOL_TRACE\"\n",
"else printf 'assembler stdin=eof\\n' >> \"$WW_CWD_TOOL_TRACE\"; fi\n",
"printf 'assembler argv' >> \"$WW_CWD_TOOL_TRACE\"\n",
"for arg in \"$@\"; do printf ' <%s>' \"$arg\" >> ",
"\"$WW_CWD_TOOL_TRACE\"; done\n",
"printf '\\n' >> \"$WW_CWD_TOOL_TRACE\"\n",
"exec \"$WW_CWD_REAL_W6A\" \"$@\"\n"));
writeexecutable(lw, strings.concat(
"#!/bin/sh\n",
"printf 'linker cwd=' >> \"$WW_CWD_TOOL_TRACE\"\n",
"/bin/pwd >> \"$WW_CWD_TOOL_TRACE\"\n",
"printf 'linker env=LC_ALL:%s TMPDIR:%s\\n' \"$LC_ALL\" ",
"\"$TMPDIR\" >> \"$WW_CWD_TOOL_TRACE\"\n",
"if IFS= read -r WW_CWD_STDIN; then\n",
" printf 'linker stdin=data\\n' >> \"$WW_CWD_TOOL_TRACE\"\n",
"else printf 'linker stdin=eof\\n' >> \"$WW_CWD_TOOL_TRACE\"; fi\n",
"printf 'linker argv' >> \"$WW_CWD_TOOL_TRACE\"\n",
"for arg in \"$@\"; do printf ' <%s>' \"$arg\" >> ",
"\"$WW_CWD_TOOL_TRACE\"; done\n",
"printf '\\n' >> \"$WW_CWD_TOOL_TRACE\"\n",
"exec \"$WW_CWD_REAL_W6L\" \"$@\"\n"));
let tracebase: []str = cwdtestenv("ww");
let traceenv: []str = alloc([], (tracebase.len + 7): u64)!;
i = 0;
for (i < tracebase.len) {
if (!strings.hasprefix(tracebase[i], "WW_W6C=")
&& !strings.hasprefix(tracebase[i], "WW_W6A=")
&& !strings.hasprefix(tracebase[i], "WW_W6L=")) {
append(traceenv, tracebase[i]);
};
i += 1;
};
append(traceenv, strings.concat("WW_W6C=", cw));
append(traceenv, strings.concat("WW_W6A=", aw));
append(traceenv, strings.concat("WW_W6L=", lw));
append(traceenv, strings.concat("WW_CWD_REAL_W6C=", driver("w6c")));
append(traceenv, strings.concat("WW_CWD_REAL_W6A=", driver("w6a")));
append(traceenv, strings.concat("WW_CWD_REAL_W6L=", driver("w6l")));
append(traceenv, strings.concat("WW_CWD_TOOL_TRACE=", tooltrace));
let work: str = strings.concat(root, "/cwd-work");
assert(os.mkdir(work, 448i32) == 0);
let persistav: []str = [driver("ww"), "test", "-w", work, "-I", tree,
p1];
runcommandinputenvdir(root, "cwd-persist-cold", persistav, traceenv,
caller, stdinpath,
(120i64 * (time.second: i64)): time.duration, &outc);
expectexit(&outc, 0);
cwdassertpackage(outc.stdout, "dep-init", p1, "p1-data", "p1-testdata");
cwdassertpackage(outc.stdout, "p1-internal", p1,
"p1-data", "p1-testdata");
let coldtrace: str = readfile(tooltrace);
assert(has(coldtrace, strings.concat("compiler cwd=", caller, "\n")));
assert(has(coldtrace, strings.concat("assembler cwd=", caller, "\n")));
assert(has(coldtrace, strings.concat("linker cwd=", caller, "\n")));
assert(!has(coldtrace, strings.concat("cwd=", p1, "\n")));
assert(has(coldtrace, "compiler env=LC_ALL:C TMPDIR:/tmp/"));
assert(has(coldtrace, "assembler env=LC_ALL:C TMPDIR:/tmp/"));
assert(has(coldtrace, "linker env=LC_ALL:C TMPDIR:/tmp/"));
assert(has(coldtrace, "compiler stdin=eof\n"));
assert(has(coldtrace, "assembler stdin=eof\n"));
assert(has(coldtrace, "linker stdin=eof\n"));
assert(!has(coldtrace, "stdin=data\n"));
assert(has(coldtrace, "compiler argv <"));
assert(has(coldtrace, ".unit.new>"));
assert(has(coldtrace, "assembler argv <"));
assert(has(coldtrace, "linker argv <"));
assert(has(coldtrace, ".a.new>"));
let artifactpaths: []str = [
strings.concat(work, "/p1-internal-test.unit.ww"),
strings.concat(work, "/p1-internal-test.wwi"),
strings.concat(work, "/p1-internal-test.s"),
strings.concat(work, "/p1-internal-test.o"),
strings.concat(work, "/p1-internal-test.a"),
strings.concat(work, "/p1-test-main.unit.ww"),
strings.concat(work, "/p1-test-main.init.unit.ww"),
strings.concat(work, "/p1-test-main.wwi"),
strings.concat(work, "/p1-test-main.s"),
strings.concat(work, "/p1-test-main.init.s"),
strings.concat(work, "/p1-test-main.o"),
strings.concat(work, "/p1-test-main.init.o"),
strings.concat(work, "/p1-test-main.a"),
strings.concat(work, "/dep.wwi"),
strings.concat(work, "/dep.a"),
strings.concat(work, "/probe.wwi"),
strings.concat(work, "/probe.a")
];
let artifacts: []str = alloc([], artifactpaths.len: u64)!;
i = 0;
for (i < artifactpaths.len) {
append(artifacts, strings.dup(readfile(artifactpaths[i])));
i += 1;
};
rewritefile(tooltrace, "");
runcommandinputenvdir(root, "cwd-persist-warm", persistav, traceenv,
caller, stdinpath,
(120i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outw, 0);
assert(same(outc.stdout, outw.stdout));
let warmtrace: str = readfile(tooltrace);
assert(!has(warmtrace, "compiler cwd="));
assert(!has(warmtrace, "assembler cwd="));
assert(occurrences(warmtrace, "linker cwd=") == 1);
assert(has(warmtrace, strings.concat("linker cwd=", caller, "\n")));
assert(has(warmtrace, "linker stdin=eof\n"));
assert(!has(warmtrace, "stdin=data\n"));
// Non-source data does not enter graph/action/storage bytes. The established
// warm final relink remains one invocation, while the next uncached runtime
// observes the new relative data immediately.
rewritefile(strings.concat(p1, "/data.txt"), "p1-data-v2\n");
rewritefile(strings.concat(p1, "/testdata/input.txt"),
"p1-testdata-v2\n");
let changedstdin: []u8 = alloc([], 4096u64)!;
inputi = 0;
for (inputi < 2048) {
append(changedstdin, 'Y');
append(changedstdin, '\n');
inputi += 1;
};
rewritefile(stdinpath, strings.frombytes(changedstdin));
rewritefile(tooltrace, "");
runcommandinputenvdir(root, "cwd-persist-data", persistav, traceenv,
caller, stdinpath,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
cwdassertpackage(out.stdout, "dep-init", p1,
"p1-data-v2", "p1-testdata-v2");
cwdassertpackage(out.stdout, "p1-internal", p1,
"p1-data-v2", "p1-testdata-v2");
let datatrace: str = readfile(tooltrace);
assert(!has(datatrace, "compiler cwd="));
assert(!has(datatrace, "assembler cwd="));
assert(occurrences(datatrace, "linker cwd=") == 1);
assert(has(datatrace, strings.concat("linker cwd=", caller, "\n")));
assert(has(datatrace, "linker stdin=eof\n"));
assert(!has(datatrace, "stdin=data\n"));
i = 0;
for (i < artifactpaths.len) {
assert(same(artifacts[i], readfile(artifactpaths[i])));
i += 1;
};
assert(!directoryhasnew(work));
assert(!os.exists(strings.concat(work, "/p1.result")));
assert(!os.exists(strings.concat(work, "/p1.output")));
assert(!os.exists(strings.concat(work, "/p1.status")));
assert(!os.exists(strings.concat(work, "/p1.voucher")));
let p1after: str = strings.concat(root, "/p1-after-data.test");
let afterav: []str = [driver("ww_ww"), "test", "-c", "-o", p1after,
"-I", tree, p1];
runcommandinputenvdir(root, "cwd-after-data-binary", afterav, wenv,
caller, stdinpath,
(90i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(readfile(p1cbin), readfile(p1after)));
// The builder wrapper creates a deterministic post-build/pre-run boundary.
// Removing one owned source directory there must be a child setup error;
// the sibling still runs from its own directory and both stages agree.
let hidewrapper: str = strings.concat(root, "/build-then-hide.sh");
writeexecutable(hidewrapper, strings.concat(
"#!/bin/sh\n",
"\"$WW_CWD_REAL_DRIVER\" \"$@\"\n",
"status=$?\n",
"if [ \"$status\" -eq 0 ]; then\n",
" mv -- \"$WW_CWD_HIDE_DIR\" \"$WW_CWD_HIDE_DIR.gone\" || exit 125\n",
" printf 'wrapper-hidden=%s\\n' \"$WW_CWD_HIDE_DIR\" >&2\n",
"fi\n",
"exit \"$status\"\n"));
let hidestages: []str = ["ww", "ww_ww"];
let hidestdout: []str = ["", ""];
let hidestderr: []str = ["", ""];
i = 0;
for (i < hidestages.len) {
let base: []str = cwdtestenv(hidestages[i]);
let hideenv: []str = alloc([], (base.len + 2): u64)!;
let j: i32 = 0;
for (j < base.len) { append(hideenv, base[j]); j += 1; };
append(hideenv, strings.concat("WW_CWD_REAL_DRIVER=",
driver(hidestages[i])));
append(hideenv, strings.concat("WW_CWD_HIDE_DIR=", p1));
let hideav: []str = [driver("wwtest"), "package", "--ww-driver",
hidewrapper, "-j", "2", "-I", tree, p1, p2];
runcommandinputenvdir(root, strings.concat("cwd-hide-", hidestages[i]),
hideav, hideenv, caller, stdinpath,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, strings.concat("wrapper-hidden=", p1, "\n")));
assert(has(out.stdout, strings.concat("FAIL ", p1,
" [p1] (test harness error 2)\n")));
assert(!has(out.stdout, "p1-internal cwd="));
cwdassertpackage(out.stdout, "dep-init", p2,
"p2-data", "p2-testdata");
cwdassertpackage(out.stdout, "p2-external", p2,
"p2-data", "p2-testdata");
assert(os.rename(strings.concat(p1, ".gone"), p1) == 0);
assert(!os.exists(strings.concat(p1, ".gone")));
hidestdout[i] = strings.dup(out.stdout);
hidestderr[i] = strings.dup(out.stderr);
i += 1;
};
assert(same(hidestdout[0], hidestdout[1]));
assert(same(hidestderr[0], hidestderr[1]));
assert(!directoryhasnew(work));
assert(same(readfile(strings.concat(caller, "/sentinel")),
"parent-sentinel\n"));
assert(!os.exists(strings.concat(caller, "/created.txt")));
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"));
// Package declarations are validation/kind data, not fixed driver storage.
// A 256-byte selector must reach both stages intact and run under the same
// reversible outside-root identity instead of preserving the old slot cap.
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"));
writefile(strings.concat(longdir, "/long_test.ww"), strings.concat(
"package ", longname, ";\n",
"@test fn long_package_runs() void = { value(); };\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, 0);
expectexit(&outw, 0);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
assert(outc.stderr.len == 0);
assert(has(outc.stdout, strings.concat(longname,
".long_package_runs ... ok\n")));
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, "ok "));
assert(!has(out.stdout, " [no tests]\n"));
assert(!has(out.stdout, "phantom"));
// Go's complete empty-package matrix: production-only, internal-only,
// external-only, combined, test-only same, test-only external, and honest
// mixed test-only directories are each one directory-owned result.
let prodonly: str = strings.concat(root, "/shapeprod");
let internalonly: str = strings.concat(root, "/shapeinternal");
let externalonly: str = strings.concat(root, "/shapeexternal");
let both: str = strings.concat(root, "/shapeboth");
let testonlysame: str = strings.concat(root, "/tosame");
let testonlyexternal: str = strings.concat(root,
"/toexternal");
let testonlymixed: str = strings.concat(root, "/tomixed");
let shapes: []str = [prodonly, internalonly, externalonly, both,
testonlysame, testonlyexternal, testonlymixed];
let shi: i32 = 0;
for (shi < shapes.len) {
assert(os.mkdir(shapes[shi], 448i32) == 0);
shi += 1;
};
writefile(strings.concat(prodonly, "/prod.ww"),
"package shapeprod;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(internalonly, "/prod.ww"),
"package shapeinternal;\nfn value() i32 = { return 1; };\n");
writefile(strings.concat(internalonly, "/same_test.ww"), strings.concat(
"package shapeinternal;\n",
"@test fn internal_runs() void = { assert(value() == 1); };\n"));
writefile(strings.concat(externalonly, "/prod.ww"),
"package shapeexternal;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(externalonly, "/external_test.ww"), strings.concat(
"package shapeexternal_test;\nimport shapeexternal;\n",
"@test fn external_runs() void = { assert(shapeexternal.value() == 1); };\n"));
writefile(strings.concat(both, "/prod.ww"),
"package shapeboth;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(both, "/same_test.ww"), strings.concat(
"package shapeboth;\n",
"export fn helper() i32 = { return 2; };\n",
"@test fn same_runs() void = { assert(value() == 1); };\n"));
writefile(strings.concat(both, "/external_test.ww"), strings.concat(
"package shapeboth_test;\nimport shapeboth;\n",
"@test fn external_runs() void = { assert(shapeboth.helper() == 2); };\n"));
writefile(strings.concat(testonlysame, "/same_test.ww"),
"package tosame;\n@test fn same_only() void = { assert(true); };\n");
writefile(strings.concat(testonlyexternal, "/external_test.ww"),
"package toexternal_test;\n@test fn external_only() void = { assert(true); };\n");
writefile(strings.concat(testonlymixed, "/same_test.ww"), strings.concat(
"package tomixed;\nexport fn helper() i32 = { return 3; };\n",
"@test fn same_test_only() void = { assert(helper() == 3); };\n"));
writefile(strings.concat(testonlymixed, "/external_test.ww"), strings.concat(
"package tomixed_test;\nimport tomixed;\n",
"@test fn external_test_only() void = { assert(tomixed.helper() == 3); };\n"));
let shaperefs: []str = ["", "", "", "", "", "", ""];
shi = 0;
for (shi < shapes.len) {
let stagei: i32 = 0;
for (stagei < stages.len) {
let shapeav: []str = [driver(stages[stagei]), "test", "-I", root,
shapes[shi]];
runcommand(root, strings.concat("shape-", stages[stagei], "-",
boundarypkgname(shi)), shapeav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
if (stagei == 0) { shaperefs[shi] = strings.dup(out.stdout); }
else { assert(same(shaperefs[shi], out.stdout)); };
assert(out.stderr.len == 0);
stagei += 1;
};
shi += 1;
};
assert(has(shaperefs[0], " [no tests]\n"));
assert(occurrences(shaperefs[0], strings.concat(
"? ", prodonly, " [no tests]\n")) == 1);
assert(has(shaperefs[1], "shapeinternal.internal_runs ... ok\n"));
assert(has(shaperefs[2], "shapeexternal.external_runs ... ok\n"));
assert(occurrences(shaperefs[3], " ... ok\n") == 2);
assert(has(shaperefs[4], "tosame.same_only ... ok\n"));
assert(has(shaperefs[5], "toexternal.external_only ... ok\n"));
assert(has(shaperefs[6], "tomixed.same_test_only ... ok\n"));
assert(has(shaperefs[6], "tomixed.external_test_only ... ok\n"));
let shapefamilies: []str = ["shapeprod", "shapeinternal",
"shapeexternal", "shapeboth", "tosame", "toexternal", "tomixed"];
shi = 1;
for (shi < shapes.len) {
assert(occurrences(shaperefs[shi], strings.concat(
"ok ", shapes[shi], " [", shapefamilies[shi], "]\n")) == 1);
shi += 1;
};
// The five non-combined real-test shapes have one structural product in
// both stages. The combined case is proved in full by the graph observer.
let shapecompilerwrapper: str = strings.concat(root,
"/shape-w6c-wrapper.sh");
let shapelinkerwrapper: str = strings.concat(root,
"/shape-w6l-wrapper.sh");
writeexecutable(shapecompilerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_SHAPE_COMPILER_TRACE\"\n",
"exec \"$WW_SHAPE_REAL_COMPILER\" \"$@\"\n"));
writeexecutable(shapelinkerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_SHAPE_LINKER_TRACE\"\n",
"exec \"$WW_SHAPE_REAL_LINKER\" \"$@\"\n"));
let shapeindices: []i32 = [1, 2, 4, 5, 6];
let shapemains: []str = ["shapeinternal-test-main",
"shapeexternal-test-main", "tosame-test-main",
"toexternal-test-main", "tomixed-test-main"];
let shapeordinary: []str = ["shapeinternal", "shapeexternal", "tosame",
"toexternal", "tomixed"];
let shapeordinarypresent: []bool = [false, true, false, false, false];
let shapeinternal: []str = ["shapeinternal-internal-test",
"shapeexternal-internal-test", "tosame-internal-test",
"toexternal-internal-test", "tomixed-internal-test"];
let shapeinternalpresent: []bool = [true, false, true, false, true];
let shapeexternal: []str = ["shapeinternal_test-external-test",
"shapeexternal_test-external-test", "tosame_test-external-test",
"toexternal_test-external-test", "tomixed_test-external-test"];
let shapeexternalpresent: []bool = [false, true, false, true, true];
let shapetargetfirst: []str = ["shapeinternal", "shapeexternal", "tosame",
"toexternal_test", "tomixed"];
let shapetargetsecond: []str = ["", "shapeexternal_test", "", "",
"tomixed_test"];
let shapeproductionselector: []str = ["shapeinternal", "shapeexternal",
"-", "-", "-"];
let shapeinternalselector: []str = ["shapeinternal", "-", "tosame",
"-", "tomixed"];
let shapeexternalselector: []str = ["-", "shapeexternal_test", "-",
"toexternal_test", "tomixed_test"];
let shapecompilerrefs: []str = ["", "", "", "", ""];
let shapelinkerrefs: []str = ["", "", "", "", ""];
let shapemainrefs: []str = ["", "", "", "", ""];
let shapebinrefs: []str = ["", "", "", "", ""];
let shapecompilers: []str = ["w6c", "w6c_ww"];
let shapelinkers: []str = ["w6l", "w6l_ww"];
let shapebaseenv: []str = os.getenvs();
let sj: i32 = 0;
for (sj < shapeindices.len) {
let index: i32 = shapeindices[sj];
let shapebin: str = strings.concat(root, "/shape-product-",
boundarypkgname(sj), ".test");
let shapework: str = strings.concat(shapebin, ".sepwork");
let shapestatus: str = strings.concat(shapebin, ".status");
let ctracepath: str = strings.concat(root, "/shape-compiler-",
boundarypkgname(sj), ".trace");
let ltracepath: str = strings.concat(root, "/shape-linker-",
boundarypkgname(sj), ".trace");
writefile(ctracepath, "");
writefile(ltracepath, "");
let stagei: i32 = 0;
for (stagei < stages.len) {
assert(os.mkdir(shapework, 448i32) == 0);
if (stagei != 0) {
rewritefile(ctracepath, "");
rewritefile(ltracepath, "");
};
let env: []str = alloc([], (shapebaseenv.len + 6): u64)!;
let ei: i32 = 0;
for (ei < shapebaseenv.len) {
if (!strings.hasprefix(shapebaseenv[ei], "WW_W6C=")
&& !strings.hasprefix(shapebaseenv[ei], "WW_W6L=")
&& !strings.hasprefix(shapebaseenv[ei],
"WW_SHAPE_COMPILER_TRACE=")
&& !strings.hasprefix(shapebaseenv[ei],
"WW_SHAPE_LINKER_TRACE=")
&& !strings.hasprefix(shapebaseenv[ei],
"WW_SHAPE_REAL_COMPILER=")
&& !strings.hasprefix(shapebaseenv[ei],
"WW_SHAPE_REAL_LINKER=")) {
append(env, shapebaseenv[ei]);
};
ei += 1;
};
append(env, strings.concat("WW_W6C=", shapecompilerwrapper));
append(env, strings.concat("WW_W6L=", shapelinkerwrapper));
append(env, strings.concat("WW_SHAPE_COMPILER_TRACE=", ctracepath));
append(env, strings.concat("WW_SHAPE_LINKER_TRACE=", ltracepath));
append(env, strings.concat("WW_SHAPE_REAL_COMPILER=",
driver(shapecompilers[stagei])));
append(env, strings.concat("WW_SHAPE_REAL_LINKER=",
driver(shapelinkers[stagei])));
let shapeav: []str = [driver(stages[stagei]), "test", "-c", "-w",
shapework, "-I", root,
"--ww-package-test", "test", shapefamilies[index],
shapeproductionselector[sj], shapeinternalselector[sj],
shapeexternalselector[sj], shapes[index], shapebin, "-",
shapestatus, shapes[index]];
runcommandenv(root, strings.concat("shape-structure-",
stages[stagei], "-", boundarypkgname(sj)), shapeav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stderr.len == 0);
assert(os.exists(shapebin));
assert(!os.exists(strings.concat(shapes[index], "/",
shapefamilies[index], ".test")));
let ctrace: str = readfile(ctracepath);
let ltrace: str = readfile(ltracepath);
assert(occurrences(ctrace, "-test-main.unit.new") == 1);
let mainline: str = linecontaining(ctrace,
strings.concat("/", shapemains[sj], ".unit.new"));
let targetcount: i32 = 1;
if (shapetargetsecond[sj].len != 0) { targetcount = 2; };
assert(occurrences(mainline, "--test-target-package")
== targetcount);
assert(has(mainline, strings.concat("--test-target-package ",
shapetargetfirst[sj], " ")));
if (shapetargetsecond[sj].len != 0) {
assert(pos(mainline, strings.concat("--test-target-package ",
shapetargetfirst[sj], " ")) < pos(mainline, strings.concat(
"--test-target-package ", shapetargetsecond[sj], " ")));
};
assert(occurrences(ltrace, "\n") == 1);
let linkline: str = linecontaining(ltrace,
strings.concat("-o ", shapebin, ".new "));
assert(occurrences(linkline, "-test-main.a") == 1);
assert(has(linkline, strings.concat("/", shapemains[sj],
".a")));
assert(!has(linkline, ".wwi"));
assert(os.exists(strings.concat(shapework, "/", shapemains[sj],
".unit.ww")));
let actionnames: []str = [shapeordinary[sj], shapeinternal[sj],
shapeexternal[sj]];
let actionpresent: []bool = [shapeordinarypresent[sj],
shapeinternalpresent[sj], shapeexternalpresent[sj]];
let actioni: i32 = 0;
for (actioni < actionnames.len) {
assert(os.exists(strings.concat(shapework, "/",
actionnames[actioni], ".unit.ww"))
== actionpresent[actioni]);
assert(has(linkline, strings.concat("/", actionnames[actioni],
".a")) == actionpresent[actioni]);
actioni += 1;
};
let nc: str = normalizedtrace(ctrace,
strings.concat(shapework, "/"), shapebin);
let nl: str = normalizedtrace(ltrace,
strings.concat(shapework, "/"), shapebin);
let mainbytes: str = readfile(strings.concat(shapework, "/",
shapemains[sj], ".unit.ww"));
let binbytes: str = readfile(shapebin);
if (stagei == 0) {
shapecompilerrefs[sj] = nc;
shapelinkerrefs[sj] = nl;
shapemainrefs[sj] = mainbytes;
shapebinrefs[sj] = binbytes;
} else {
assert(same(shapecompilerrefs[sj], nc));
assert(same(shapelinkerrefs[sj], nl));
assert(same(shapemainrefs[sj], mainbytes));
assert(same(shapebinrefs[sj], binbytes));
};
clean(shapework);
clean(shapebin);
clean(shapestatus);
stagei += 1;
};
sj += 1;
};
clean(root);
};
@test fn symlink_package_root_reuses_canonical_directory() void = {
let root: str = fresh();
let real: str = deeppunctuationpath(root, "symlink target");
let link: str = strings.concat(root, "/link");
let wrapper: str = strings.concat(root, "/compiler wrapper.sh");
mkdirall(real);
writefile(strings.concat(real, "/real.ww"),
"package real;\nexport fn value() int = { return 1; };\n");
writefile(strings.concat(real, "/real_test.ww"),
"package real;\n@test fn value_is_one() void = { assert(value() == 1); };\n");
let lav: []str = ["/bin/ln", "-s", real, link];
let out: commandout;
runcommand(root, "link", lav, time.second, &out);
expectexit(&out, 0);
writeexecutable(wrapper, strings.concat(
"#!/bin/sh\n",
"printf 'BEGIN' >> \"$WW_SYMLINK_COMPILER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_SYMLINK_COMPILER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_SYMLINK_COMPILER_TRACE\"\n",
"exec \"$WW_SYMLINK_REAL_COMPILER\" \"$@\"\n"));
let actionid: str = localidentity(real, "real");
assert(actionid.len > 255);
let action: str = packagestoragekey(actionid, real, 1, 0);
assert(action.len + 9 <= 255);
let stages: []str = ["ww", "ww_ww"];
let compilers: []str = ["w6c", "w6c_ww"];
let references: []str = ["", "", ""];
let baseenv: []str = os.getenvs();
let si: i32 = 0;
for (si < stages.len) {
let work: str = strings.concat(root, "/work-", stages[si]);
let trace: str = strings.concat(root, "/trace-", stages[si]);
assert(os.mkdir(work, 448i32) == 0);
writefile(trace, "");
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_SYMLINK_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_SYMLINK_REAL_COMPILER=")) {
append(env, baseenv[ei]);
};
ei += 1;
};
append(env, strings.concat("WW_W6C=", wrapper));
append(env, strings.concat("WW_SYMLINK_COMPILER_TRACE=", trace));
append(env, strings.concat("WW_SYMLINK_REAL_COMPILER=",
driver(compilers[si])));
let av: []str = [driver(stages[si]), "test", "-w", work, real];
runcommandenv(root, strings.concat("real-cold-", stages[si]), av, env,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "real.value_is_one ... ok\n"));
let coldtrace: str = readfile(trace);
assert(coldtrace.len > 0);
assert(has(coldtrace, strings.concat("<--import><", actionid, "><")));
let key: str = work;
assert(os.exists(key));
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
let xi: i32 = 0;
for (xi < suffixes.len) {
let artifact: str = readfile(strings.concat(key, "/", action,
suffixes[xi]));
if (xi == 0) {
assert(has(artifact, strings.concat("//ww:module-reset ",
actionid, "\n")));
} else { if (xi == 1) {
assert(strings.hasprefix(artifact, strings.concat("//ww:module ",
actionid, "\n")));
}; };
if (si == 0) { references[xi] = strings.dup(artifact); }
else { assert(same(references[xi], artifact)); };
xi += 1;
};
let linkav: []str = [driver(stages[si]), "test", "-w", work, link];
runcommandenv(root, strings.concat("symlink-warm-", stages[si]),
linkav, env, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "real.value_is_one ... ok\n"));
assert(same(coldtrace, readfile(trace)));
xi = 0;
for (xi < suffixes.len) {
assert(same(references[xi], readfile(strings.concat(key, "/",
action, suffixes[xi]))));
xi += 1;
};
let relative: str = strings.concat(".",
strings.sub(real, root.len, real.len));
let relativeav: []str = [driver(stages[si]), "test", "-w", work,
relative];
runcommandenvdir(root, strings.concat("relative-warm-", stages[si]),
relativeav, env, root,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "real.value_is_one ... ok\n"));
assert(same(coldtrace, readfile(trace)));
xi = 0;
for (xi < suffixes.len) {
assert(same(references[xi], readfile(strings.concat(key, "/",
action, suffixes[xi]))));
xi += 1;
};
si += 1;
};
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.alpha_pass ... ok\n"));
assert(has(out.stdout,
"pass.beta_skip ... SKIP: synthetic unavailable feature\n"));
assert(has(out.stdout, "pass.gamma_expected_abort ... ok\n"));
assert(has(out.stdout, "pass.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, strings.concat(
"assert_failure.assertion_failure ... synthetic assertion failure",
"FAIL (exit 1)\n")));
assert(out.stderr.len == 0);
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.deliberate_nonzero_exit ... FAIL (exit 7)\n"));
assert(out.stderr.len == 0);
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.clean_exit_without_completion ... HARNESS (incomplete result)\n"));
assert(out.stderr.len == 0);
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.signal_is_not_exit ... FAIL (signal 15)\n"));
assert(out.stderr.len == 0);
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"));
assert(out.stderr.len == 0);
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.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.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();
let route: str = strings.concat(root, "/route");
assert(os.mkdir(route, 448i32) == 0);
writefile(strings.concat(route, "/route.ww"),
"package route;\nexport fn value() int = { return 7; };\n");
writefile(strings.concat(route, "/a_test.ww"),
"package route;\n@test fn white() void = { assert(value() == 7); };\n");
writefile(strings.concat(route, "/z_test.ww"),
"package route_test;\nimport route;\n@test fn external() void = { assert(route.value() == 7); };\n");
let outc: commandout;
let outw: commandout;
let listc: []str = [driver("ww"), "test", "-I", root, "-list", route];
let listw: []str = [driver("ww_ww"), "test", "-I", root, "-list", route];
runcommand(root, "list-c", listc,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "list-ww", listw,
(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", "-I", root, route];
let timeoutw: []str = [driver("ww_ww"), "test",
"-timeout-ms=4000000", "-I", root, route];
runcommand(root, "timeout-misuse-c", timeoutc, time.second, &outc);
runcommand(root, "timeout-misuse-ww", timeoutw, time.second, &outw);
expectexit(&outc, 2);
expectexit(&outw, 2);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "usage: wwtest package"));
let cwork: str = strings.concat(root, "/compile-c-work");
let wwork: str = strings.concat(root, "/compile-ww-work");
let cbinarypath: str = strings.concat(root, "/route-c.test");
let wbinarypath: str = strings.concat(root, "/route-ww.test");
let cc: []str = [driver("ww"), "test", "-w", cwork, "-o",
cbinarypath, "-I", root, route];
runcommand(root, "compile-c", cc,
(30i64 * (time.second: i64)): time.duration, &outc);
expectexit(&outc, 0);
assert(has(outc.stdout, "route.white ... ok\n"));
assert(has(outc.stdout, "route.external ... ok\n"));
let cwhite: str = readfile(strings.concat(cwork,
"/route-internal-test.s"));
let cexternal: str = readfile(strings.concat(cwork,
"/route_test-external-test.s"));
let cmain: str = readfile(strings.concat(cwork,
"/route-test-main.s"));
let cbinary: str = readfile(cbinarypath);
let wc: []str = [driver("ww_ww"), "test", "-w", wwork, "-o",
wbinarypath, "-I", root, route];
runcommand(root, "compile-ww", wc,
(30i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outw, 0);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
assert(same(cwhite, readfile(strings.concat(wwork,
"/route-internal-test.s"))));
assert(same(cexternal, readfile(strings.concat(wwork,
"/route_test-external-test.s"))));
assert(same(cmain, readfile(strings.concat(wwork,
"/route-test-main.s"))));
assert(same(cbinary, readfile(wbinarypath)));
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 samedep: str = strings.concat(root, "/__same");
let external: str = strings.concat(root, "/__external");
let bridge: str = strings.concat(root, "/bridge");
let pkg: str = strings.concat(root, "/pkg");
let dirs: []str = [implementation, api, samedep, external, bridge, pkg];
let di: i32 = 0;
for (di < dirs.len) {
assert(os.mkdir(dirs[di], 448i32) == 0);
di += 1;
};
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, "/ignored_test.ww"), strings.concat(
"package api;\n",
"TEST_DEPENDENCY_MUST_NOT_COMPILE\n"));
writefile(strings.concat(samedep, "/same.ww"),
"package __same;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(external, "/external.ww"),
"package __external;\nexport 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(bridge, "/bridge.ww"), strings.concat(
"package bridge;\nimport pkg;\n",
"// TRANSITIVE_TEST_IMPORTER\n",
"export fn helper() i32 = { return pkg.internal_helper(); };\n"));
let samebody: str = strings.concat(
"package pkg;\nimport __same;\n",
"// SAME_TEST_SOURCE\n",
"export fn internal_helper() i32 = { return 6; };\n",
"@test fn same_graph() void = {\n",
" assert(value() + __same.value() == 42);\n",
" assert(secret() == 6);\n",
"};\n");
let samebodychanged: str = strings.concat(
"package pkg;\nimport __same;\n",
"// SAME_TEST_SOURCE_BODY_CHANGED\n",
"export fn internal_helper() i32 = { return 7; };\n",
"@test fn same_graph() void = {\n",
" assert(value() + __same.value() == 42);\n",
" assert(secret() == 6);\n",
"};\n");
let samebodyexported: str = strings.concat(
"package pkg;\nimport __same;\n",
"// SAME_TEST_SOURCE_EXPORT_CHANGED\n",
"export fn internal_helper() i32 = { return 7; };\n",
"export fn second_helper() i32 = { return 8; };\n",
"@test fn same_graph() void = {\n",
" assert(value() + __same.value() == 42);\n",
" assert(secret() == 6);\n",
"};\n");
let externalbody: str = strings.concat(
"package pkg_test;\nimport __external;\nimport bridge;\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",
" assert(pkg.internal_helper() >= 6);\n",
" assert(bridge.helper() >= 6);\n",
"};\n");
let externalbodychanged: str = strings.concat(
"package pkg_test;\nimport __external;\nimport bridge;\nimport pkg;\n",
"// EXTERNAL_TEST_SOURCE_BODY_CHANGED\n",
"@test fn external_graph() void = {\n",
" assert(pkg.value() + __external.value() == 42);\n",
" assert(pkg.second() == 9);\n",
" assert(pkg.internal_helper() >= 7);\n",
" assert(bridge.helper() >= 7);\n",
"};\n");
let externalbodyreadded: str = strings.concat(
"package pkg_test;\nimport __external;\nimport bridge;\nimport pkg;\n",
"// EXTERNAL_TEST_SOURCE_READDED\n",
"@test fn external_graph() void = {\n",
" assert(pkg.value() + __external.value() == 42);\n",
" assert(pkg.second() == 9);\n",
" assert(pkg.internal_helper() >= 7);\n",
" assert(bridge.helper() >= 7);\n",
" assert(__external.value() == 1);\n",
"};\n");
let samefile: str = strings.concat(pkg, "/same_test.ww");
let externalfile: str = strings.concat(pkg, "/external_test.ww");
writefile(samefile, samebody);
writefile(externalfile, externalbody);
// Ordinary builds neither parse nor load any test-only source or dependency.
let prodout: str = strings.concat(root, "/production.a");
let prodav: []str = [driver("ww"), "build", "-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, "PACKAGE_PRODUCTION_A"));
assert(has(produnit, "PACKAGE_PRODUCTION_Z"));
assert(!has(produnit, "SAME_TEST_SOURCE"));
assert(!has(produnit, "internal_helper"));
assert(!os.exists(strings.concat(prodwork, "__same.unit.ww")));
assert(!os.exists(strings.concat(prodwork, "__external.unit.ww")));
assert(!os.exists(strings.concat(prodwork, "bridge.unit.ww")));
assert(!has(readfile(strings.concat(prodwork, "api.unit.ww")),
"TEST_DEPENDENCY_MUST_NOT_COMPILE"));
let compilerwrapper: str = strings.concat(root, "/trace-w6c.sh");
let assemblerwrapper: str = strings.concat(root, "/trace-w6a.sh");
let linkerwrapper: str = strings.concat(root, "/trace-w6l.sh");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_GRAPH_COMPILER_TRACE\"\n",
"exec \"$WW_GRAPH_REAL_COMPILER\" \"$@\"\n"));
writeexecutable(assemblerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_GRAPH_ASSEMBLER_TRACE\"\n",
"exec \"$WW_GRAPH_REAL_ASSEMBLER\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_GRAPH_LINKER_TRACE\"\n",
"exec \"$WW_GRAPH_REAL_LINKER\" \"$@\"\n"));
let stages: []str = ["ww", "ww_ww"];
let compilers: []str = ["w6c", "w6c_ww"];
let assemblers: []str = ["w6a", "w6a_ww"];
let linkers: []str = ["w6l", "w6l_ww"];
let works: []str = [strings.concat(root, "/c-work"),
strings.concat(root, "/ww-work")];
let bins: []str = [strings.concat(root, "/c-pkg.test"),
strings.concat(root, "/ww-pkg.test")];
let statuses: []str = [strings.concat(root, "/c-pkg.status"),
strings.concat(root, "/ww-pkg.status")];
let compilertraces: []str = [strings.concat(root, "/c-w6c.trace"),
strings.concat(root, "/ww-w6c.trace")];
let assemblertraces: []str = [strings.concat(root, "/c-w6a.trace"),
strings.concat(root, "/ww-w6a.trace")];
let linkertraces: []str = [strings.concat(root, "/c-w6l.trace"),
strings.concat(root, "/ww-w6l.trace")];
let bridgeowner: str = strings.concat("pkg#", pkg);
let bridgeaction: str = packagestoragekeyfor(
"bridge", bridge, 4, 0, bridgeowner);
assert(strings.hasprefix(bridgeaction, "__wwpkg.v4.r0.h"));
let actions: []str = ["implementation", "api", "__same", "__external",
bridgeaction, "test", "pkg-internal-test", "pkg_test-external-test",
"pkg-test-main"];
let suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"];
let references: []str = alloc([],
(actions.len * suffixes.len): u64)!;
let ai: i32 = 0;
for (ai < actions.len * suffixes.len) {
append(references, "");
ai += 1;
};
let referencebin: str = "";
let referenceout: str = "";
let referenceerr: str = "";
let referencecompiler: str = "";
let referenceassembler: str = "";
let referencelinker: str = "";
let bodycompiler: str = "";
let bodyassembler: str = "";
let bodylinker: str = "";
let externalcompiler: str = "";
let externalassembler: str = "";
let externallinker: str = "";
let exportcompiler: str = "";
let exportassembler: str = "";
let exportlinker: str = "";
let exportbridge: []str = ["", "", "", "", ""];
let removecompiler: str = "";
let removeassembler: str = "";
let removelinker: str = "";
let removebin: str = "";
let removeout: str = "";
let removeerr: str = "";
let readdcompiler: str = "";
let readdassembler: str = "";
let readdlinker: str = "";
let readdbin: str = "";
let readdout: str = "";
let readderr: str = "";
let baseenv: []str = os.getenvs();
let si: i32 = 0;
for (si < stages.len) {
assert(os.mkdir(works[si], 448i32) == 0);
writefile(compilertraces[si], "");
writefile(assemblertraces[si], "");
writefile(linkertraces[si], "");
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_GRAPH_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_GRAPH_ASSEMBLER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_GRAPH_LINKER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_GRAPH_REAL_COMPILER=")
&& !strings.hasprefix(baseenv[ei],
"WW_GRAPH_REAL_ASSEMBLER=")
&& !strings.hasprefix(baseenv[ei],
"WW_GRAPH_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_GRAPH_COMPILER_TRACE=",
compilertraces[si]));
append(env, strings.concat("WW_GRAPH_ASSEMBLER_TRACE=",
assemblertraces[si]));
append(env, strings.concat("WW_GRAPH_LINKER_TRACE=",
linkertraces[si]));
append(env, strings.concat("WW_GRAPH_REAL_COMPILER=",
driver(compilers[si])));
append(env, strings.concat("WW_GRAPH_REAL_ASSEMBLER=",
driver(assemblers[si])));
append(env, strings.concat("WW_GRAPH_REAL_LINKER=",
driver(linkers[si])));
let av: []str = [driver(stages[si]), "test", "-c", "-w", works[si],
"-I", root, "--ww-package-test", "test", "pkg", "pkg", "pkg",
"pkg_test", pkg, bins[si], "-", statuses[si], pkg];
runcommandenv(root, strings.concat("graph-cold-", stages[si]), av,
env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(os.exists(bins[si]));
assert(same(readfile(statuses[si]), "ok\n"));
assert(!os.exists(strings.concat(pkg, "/pkg_test.test")));
assert(!os.exists(strings.concat(works[si], "/pkg.unit.ww")));
assert(!os.exists(strings.concat(works[si], "/bridge.unit.ww")));
let ptestunit: str = readfile(strings.concat(works[si],
"/pkg-internal-test.unit.ww"));
let pxtestunit: str = readfile(strings.concat(works[si],
"/pkg_test-external-test.unit.ww"));
let mainunit: str = readfile(strings.concat(works[si],
"/pkg-test-main.unit.ww"));
assert(has(ptestunit, "PACKAGE_PRODUCTION_A"));
assert(has(ptestunit, "PACKAGE_PRODUCTION_Z"));
assert(has(ptestunit, "SAME_TEST_SOURCE"));
assert(has(ptestunit, "export fn internal_helper"));
assert(!has(ptestunit, "EXTERNAL_TEST_SOURCE"));
assert(has(pxtestunit, "EXTERNAL_TEST_SOURCE"));
assert(!has(pxtestunit, "PACKAGE_PRODUCTION_A"));
assert(!has(pxtestunit, "SAME_TEST_SOURCE"));
assert(strings.hasprefix(mainunit, strings.concat(
"//ww:module-reset __wwtestmain.pkg.main\n",
"package main;\nimport pkg;\nimport pkg_test;\nimport test;\n")));
let ctrace: str = readfile(compilertraces[si]);
let atrace: str = readfile(assemblertraces[si]);
let ltrace: str = readfile(linkertraces[si]);
assert(occurrences(ctrace, "pkg-internal-test.unit.new") == 1);
assert(occurrences(ctrace,
"pkg_test-external-test.unit.new") == 1);
assert(occurrences(ctrace, "pkg-test-main.unit.new") == 1);
assert(occurrences(ctrace,
"--test-target-package pkg --test-target-package pkg_test") == 1);
assert(!has(ctrace,
"--package-init-symbol __ww..pkg.p.pkg.v0.r0.init"));
let ptestcompile: str = linecontaining(ctrace,
"pkg-internal-test.unit.new");
assert(has(ptestcompile,
"--package-init-symbol __ww..pkg.p.pkg.v1.r0.init"));
assert(pos(ptestcompile, "--import __same ")
< pos(ptestcompile, "--import api "));
let bridgecompile: str = linecontaining(ctrace,
"--package-init-symbol __ww..pkg.p.bridge.v4.r0.init");
assert(has(bridgecompile, "--import pkg "));
assert(has(bridgecompile, "/pkg-internal-test.wwi.new"));
assert(!has(ctrace,
"--package-init-symbol __ww..pkg.p.bridge.v0.r0.init"));
let externalcompile: str = linecontaining(ctrace,
"pkg_test-external-test.unit.new");
assert(pos(externalcompile, "--import __external ")
< pos(externalcompile, "--import bridge "));
assert(pos(externalcompile, "--import bridge ")
< pos(externalcompile, "--import pkg "));
assert(has(externalcompile, "/pkg-internal-test.wwi.new"));
assert(!has(externalcompile, "/pkg.wwi"));
let maincompile: str = linecontaining(ctrace,
"pkg-test-main.unit.new");
assert(has(maincompile, strings.concat(
"-T --entry --test-support-module test ",
"--test-target-package pkg --test-target-package pkg_test ",
"--package-init-symbol ",
"__ww..pkg.p.__wwtestmain.pkg.main.v3.r2.init ")));
assert(pos(maincompile, "--import pkg ")
< pos(maincompile, "--import pkg_test "));
assert(pos(maincompile, "--import pkg_test ")
< pos(maincompile, "--import test "));
let workprefix: str = strings.concat(works[si], "/");
assert(same(ptestcompile, strings.concat(
"--test-package --package-init-symbol ",
"__ww..pkg.p.pkg.v1.r0.init -c --import __same ", workprefix,
"__same.wwi.new --import api ", workprefix,
"api.wwi.new -I ", workprefix,
"pkg-internal-test.wwi.new -o ", workprefix,
"pkg-internal-test.s.new ", workprefix,
"pkg-internal-test.unit.new")));
assert(same(bridgecompile, strings.concat(
"--package-init-symbol __ww..pkg.p.bridge.v4.r0.init -c ",
"--import pkg ", workprefix,
"pkg-internal-test.wwi.new -I ", workprefix, bridgeaction,
".wwi.new -o ", workprefix, bridgeaction, ".s.new ", workprefix,
bridgeaction, ".unit.new")));
assert(same(externalcompile, strings.concat(
"--test-package --package-init-symbol ",
"__ww..pkg.p.pkg_test.v2.r0.init -c --import __external ",
workprefix, "__external.wwi.new --import bridge ", workprefix,
bridgeaction, ".wwi.new --import pkg ", workprefix,
"pkg-internal-test.wwi.new -I ", workprefix,
"pkg_test-external-test.wwi.new -o ", workprefix,
"pkg_test-external-test.s.new ", workprefix,
"pkg_test-external-test.unit.new")));
assert(same(maincompile, strings.concat(
"-T --entry --test-support-module test --test-target-package pkg ",
"--test-target-package pkg_test --package-init-symbol ",
"__ww..pkg.p.__wwtestmain.pkg.main.v3.r2.init ",
"--init-dispatch-symbol __ww..dispatch -c --import pkg ",
workprefix, "pkg-internal-test.wwi.new --import pkg_test ",
workprefix, "pkg_test-external-test.wwi.new --import test ",
workprefix, "test.wwi.new -I ", workprefix,
"pkg-test-main.wwi.new -o ", workprefix,
"pkg-test-main.s.new ", workprefix, "pkg-test-main.unit.new")));
let supportcompile: str = linecontaining(ctrace,
"--test-support-module test --package-init-symbol");
assert(same(supportcompile, strings.concat(
"--test-support-module test --package-init-symbol ",
"__ww..pkg.p.test.v0.r0.init -c --import fnmatch ", workprefix,
"fnmatch.wwi.new --import os ", workprefix,
"os.wwi.new --import time ", workprefix,
"time.wwi.new -I ", workprefix, "test.wwi.new -o ", workprefix,
"test.s.new ", workprefix, "test.unit.new")));
assert(same(linecontaining(atrace, "/pkg-internal-test.o.new"),
strings.concat("-o ", works[si],
"/pkg-internal-test.o.new ", works[si],
"/pkg-internal-test.s.new")));
assert(same(linecontaining(atrace, "/pkg-test-main.init.o.new"),
strings.concat("-o ", works[si],
"/pkg-test-main.init.o.new ", works[si],
"/pkg-test-main.init.s.new")));
let exactassembled: []str = [bridgeaction,
"pkg_test-external-test", "pkg-test-main", "test"];
let exacti: i32 = 0;
for (exacti < exactassembled.len) {
assert(same(linecontaining(atrace, strings.concat("/",
exactassembled[exacti], ".o.new")), strings.concat("-o ",
workprefix, exactassembled[exacti], ".o.new ", workprefix,
exactassembled[exacti], ".s.new")));
exacti += 1;
};
assert(occurrences(ltrace, "\n") == 1);
let link: str = linecontaining(ltrace,
strings.concat("-o ", bins[si], ".new "));
assert(has(link, "/pkg-test-main.a.new"));
assert(has(link, "/pkg-internal-test.a.new"));
assert(has(link, "/pkg_test-external-test.a.new"));
assert(has(link, "/__same.a.new"));
assert(has(link, "/__external.a.new"));
assert(has(link, "/api.a.new"));
assert(has(link, "/implementation.a.new"));
assert(has(link, "/test.a.new"));
assert(has(link, strings.concat("/", bridgeaction, ".a.new")));
assert(!has(link, strings.concat(works[si], "/pkg.a")));
assert(!has(link, ".wwi"));
assert(same(link, strings.concat("-o ", bins[si], ".new ",
workprefix, "pkg-test-main.a.new ", workprefix, "test.a.new ",
workprefix, "fnmatch.a.new ", workprefix, "ascii.a.new ",
workprefix, "strings.a.new ", workprefix, "os.a.new ",
workprefix, "time.a.new ", workprefix, "encoding.utf8.a.new ",
workprefix, "bytes.a.new ", workprefix, "types.a.new ",
workprefix, "pkg_test-external-test.a.new ", workprefix,
bridgeaction, ".a.new ", workprefix, "__external.a.new ",
workprefix, "pkg-internal-test.a.new ", workprefix, "api.a.new ",
workprefix, "implementation.a.new ", workprefix, "__same.a.new ",
repo(), "/out/bin/../lib/libwwrt.a")));
ai = 0;
for (ai < actions.len) {
let archive: str = readfile(strings.concat(works[si], "/",
actions[ai], ".a"));
checkactionarchive(archive,
strings.compare(actions[ai], "pkg-test-main") == 0);
let xi: i32 = 0;
for (xi < suffixes.len) {
let bytes: str = readfile(strings.concat(works[si], "/",
actions[ai], suffixes[xi]));
let index: i32 = ai * suffixes.len + xi;
if (si == 0) { references[index] = strings.dup(bytes); }
else { assert(same(references[index], bytes)); };
xi += 1;
};
ai += 1;
};
let normalizedcompiler: str = normalizedtrace(ctrace,
strings.concat(works[si], "/"), bins[si]);
let normalizedassembler: str = normalizedtrace(atrace,
strings.concat(works[si], "/"), bins[si]);
let normalizedlinker: str = normalizedtrace(ltrace,
strings.concat(works[si], "/"), bins[si]);
if (si == 0) {
referencebin = readfile(bins[si]);
referenceout = strings.dup(out.stdout);
referenceerr = strings.dup(out.stderr);
referencecompiler = normalizedcompiler;
referenceassembler = normalizedassembler;
referencelinker = normalizedlinker;
} else {
assert(same(referencebin, readfile(bins[si])));
assert(same(referenceout, out.stdout));
assert(same(referenceerr, out.stderr));
assert(same(referencecompiler, normalizedcompiler));
assert(same(referenceassembler, normalizedassembler));
assert(same(referencelinker, normalizedlinker));
};
let runav: []str = [bins[si]];
runcommand(root, strings.concat("graph-run-", stages[si]), runav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(out.stdout, "same_graph ... ok\n") == 1);
assert(occurrences(out.stdout, "external_graph ... ok\n") == 1);
// Warm action reuse is exact; linking republishes the requested output.
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
runcommandenv(root, strings.concat("graph-warm-", stages[si]), av,
env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(occurrences(readfile(linkertraces[si]), "\n") == 1);
si += 1;
};
// An internal helper body edit recompiles only ptest; its stable export
// stops reverse compilation of pxtest, the transitive clone, and pmain.
rewritefile(samefile, samebodychanged);
si = 0;
for (si < stages.len) {
let oldptestwwi: str = readfile(strings.concat(works[si],
"/pkg-internal-test.wwi"));
let oldptesta: str = readfile(strings.concat(works[si],
"/pkg-internal-test.a"));
let oldpxtestwwi: str = readfile(strings.concat(works[si],
"/pkg_test-external-test.wwi"));
let oldpxtesta: str = readfile(strings.concat(works[si],
"/pkg_test-external-test.a"));
let oldmainwwi: str = readfile(strings.concat(works[si],
"/pkg-test-main.wwi"));
let oldmaina: str = readfile(strings.concat(works[si],
"/pkg-test-main.a"));
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let env: []str = os.getenvs();
let tracedenv: []str = alloc([], (env.len + 9): u64)!;
let ei: i32 = 0;
for (ei < env.len) {
if (!strings.hasprefix(env[ei], "WW_W6C=")
&& !strings.hasprefix(env[ei], "WW_W6A=")
&& !strings.hasprefix(env[ei], "WW_W6L=")) {
append(tracedenv, env[ei]);
};
ei += 1;
};
append(tracedenv, strings.concat("WW_W6C=", compilerwrapper));
append(tracedenv, strings.concat("WW_W6A=", assemblerwrapper));
append(tracedenv, strings.concat("WW_W6L=", linkerwrapper));
append(tracedenv, strings.concat("WW_GRAPH_COMPILER_TRACE=",
compilertraces[si]));
append(tracedenv, strings.concat("WW_GRAPH_ASSEMBLER_TRACE=",
assemblertraces[si]));
append(tracedenv, strings.concat("WW_GRAPH_LINKER_TRACE=",
linkertraces[si]));
append(tracedenv, strings.concat("WW_GRAPH_REAL_COMPILER=",
driver(compilers[si])));
append(tracedenv, strings.concat("WW_GRAPH_REAL_ASSEMBLER=",
driver(assemblers[si])));
append(tracedenv, strings.concat("WW_GRAPH_REAL_LINKER=",
driver(linkers[si])));
let av: []str = [driver(stages[si]), "test", "-c", "-w", works[si],
"-I", root, "--ww-package-test", "test", "pkg", "pkg", "pkg",
"pkg_test", pkg, bins[si], "-", statuses[si], pkg];
runcommandenv(root, strings.concat("graph-body-", stages[si]), av,
tracedenv, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let ct: str = readfile(compilertraces[si]);
let at: str = readfile(assemblertraces[si]);
let lt: str = readfile(linkertraces[si]);
assert(occurrences(ct, "\n") == 1);
assert(has(ct, "pkg-internal-test.unit.new"));
assert(!has(ct, "pkg_test-external-test.unit.new"));
assert(!has(ct, "pkg-test-main.unit.new"));
assert(!has(ct, ".bridge.v4.r0.init"));
assert(occurrences(at, "\n") == 1);
assert(has(at, "pkg-internal-test.o.new"));
assert(occurrences(lt, "\n") == 1);
assert(same(oldptestwwi, readfile(strings.concat(works[si],
"/pkg-internal-test.wwi"))));
assert(!same(oldptesta, readfile(strings.concat(works[si],
"/pkg-internal-test.a"))));
assert(same(oldpxtestwwi, readfile(strings.concat(works[si],
"/pkg_test-external-test.wwi"))));
assert(same(oldpxtesta, readfile(strings.concat(works[si],
"/pkg_test-external-test.a"))));
assert(same(oldmainwwi, readfile(strings.concat(works[si],
"/pkg-test-main.wwi"))));
assert(same(oldmaina, readfile(strings.concat(works[si],
"/pkg-test-main.a"))));
let nc: str = normalizedtrace(ct, strings.concat(works[si], "/"),
bins[si]);
let na: str = normalizedtrace(at, strings.concat(works[si], "/"),
bins[si]);
let nl: str = normalizedtrace(lt, strings.concat(works[si], "/"),
bins[si]);
if (si == 0) {
bodycompiler = nc; bodyassembler = na; bodylinker = nl;
} else {
assert(same(bodycompiler, nc));
assert(same(bodyassembler, na));
assert(same(bodylinker, nl));
assert(same(readfile(bins[0]), readfile(bins[1])));
};
si += 1;
};
// An external test body edit is confined to pxtest when its export is stable.
rewritefile(externalfile, externalbodychanged);
si = 0;
for (si < stages.len) {
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let env: []str = os.getenvs();
let tracedenv: []str = alloc([], (env.len + 9): u64)!;
let ei: i32 = 0;
for (ei < env.len) {
if (!strings.hasprefix(env[ei], "WW_W6C=")
&& !strings.hasprefix(env[ei], "WW_W6A=")
&& !strings.hasprefix(env[ei], "WW_W6L=")) {
append(tracedenv, env[ei]);
};
ei += 1;
};
append(tracedenv, strings.concat("WW_W6C=", compilerwrapper));
append(tracedenv, strings.concat("WW_W6A=", assemblerwrapper));
append(tracedenv, strings.concat("WW_W6L=", linkerwrapper));
append(tracedenv, strings.concat("WW_GRAPH_COMPILER_TRACE=",
compilertraces[si]));
append(tracedenv, strings.concat("WW_GRAPH_ASSEMBLER_TRACE=",
assemblertraces[si]));
append(tracedenv, strings.concat("WW_GRAPH_LINKER_TRACE=",
linkertraces[si]));
append(tracedenv, strings.concat("WW_GRAPH_REAL_COMPILER=",
driver(compilers[si])));
append(tracedenv, strings.concat("WW_GRAPH_REAL_ASSEMBLER=",
driver(assemblers[si])));
append(tracedenv, strings.concat("WW_GRAPH_REAL_LINKER=",
driver(linkers[si])));
let av: []str = [driver(stages[si]), "test", "-c", "-w", works[si],
"-I", root, "--ww-package-test", "test", "pkg", "pkg", "pkg",
"pkg_test", pkg, bins[si], "-", statuses[si], pkg];
runcommandenv(root, strings.concat("graph-external-", stages[si]), av,
tracedenv, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let ct: str = readfile(compilertraces[si]);
let at: str = readfile(assemblertraces[si]);
let lt: str = readfile(linkertraces[si]);
assert(occurrences(ct, "\n") == 1);
assert(has(ct, "pkg_test-external-test.unit.new"));
assert(!has(ct, "pkg-internal-test.unit.new"));
assert(!has(ct, "pkg-test-main.unit.new"));
assert(!has(ct, ".bridge.v4.r0.init"));
assert(occurrences(at, "\n") == 1);
assert(has(at, "pkg_test-external-test.o.new"));
assert(occurrences(lt, "\n") == 1);
let nc: str = normalizedtrace(ct, strings.concat(works[si], "/"),
bins[si]);
let na: str = normalizedtrace(at, strings.concat(works[si], "/"),
bins[si]);
let nl: str = normalizedtrace(lt, strings.concat(works[si], "/"),
bins[si]);
if (si == 0) {
externalcompiler = nc; externalassembler = na;
externallinker = nl;
} else {
assert(same(externalcompiler, nc));
assert(same(externalassembler, na));
assert(same(externallinker, nl));
assert(same(readfile(bins[0]), readfile(bins[1])));
};
si += 1;
};
// An internal exported-helper interface edit reaches the variant-4
// importer, pxtest, and pmain, but still never introduces ordinary p.
rewritefile(samefile, samebodyexported);
si = 0;
for (si < stages.len) {
let oldwwi: str = readfile(strings.concat(works[si],
"/pkg-internal-test.wwi"));
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let env: []str = os.getenvs();
let tracedenv: []str = alloc([], (env.len + 9): u64)!;
let ei: i32 = 0;
for (ei < env.len) {
if (!strings.hasprefix(env[ei], "WW_W6C=")
&& !strings.hasprefix(env[ei], "WW_W6A=")
&& !strings.hasprefix(env[ei], "WW_W6L=")) {
append(tracedenv, env[ei]);
};
ei += 1;
};
append(tracedenv, strings.concat("WW_W6C=", compilerwrapper));
append(tracedenv, strings.concat("WW_W6A=", assemblerwrapper));
append(tracedenv, strings.concat("WW_W6L=", linkerwrapper));
append(tracedenv, strings.concat("WW_GRAPH_COMPILER_TRACE=",
compilertraces[si]));
append(tracedenv, strings.concat("WW_GRAPH_ASSEMBLER_TRACE=",
assemblertraces[si]));
append(tracedenv, strings.concat("WW_GRAPH_LINKER_TRACE=",
linkertraces[si]));
append(tracedenv, strings.concat("WW_GRAPH_REAL_COMPILER=",
driver(compilers[si])));
append(tracedenv, strings.concat("WW_GRAPH_REAL_ASSEMBLER=",
driver(assemblers[si])));
append(tracedenv, strings.concat("WW_GRAPH_REAL_LINKER=",
driver(linkers[si])));
let av: []str = [driver(stages[si]), "test", "-c", "-w", works[si],
"-I", root, "--ww-package-test", "test", "pkg", "pkg", "pkg",
"pkg_test", pkg, bins[si], "-", statuses[si], pkg];
runcommandenv(root, strings.concat("graph-export-", stages[si]), av,
tracedenv, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let ct: str = readfile(compilertraces[si]);
let at: str = readfile(assemblertraces[si]);
let lt: str = readfile(linkertraces[si]);
assert(!same(oldwwi, readfile(strings.concat(works[si],
"/pkg-internal-test.wwi"))));
assert(occurrences(ct, "pkg-internal-test.unit.new") == 1);
assert(occurrences(ct,
"--package-init-symbol __ww..pkg.p.bridge.v4.r0.init") == 1);
assert(occurrences(ct,
"pkg_test-external-test.unit.new") == 1);
assert(occurrences(ct, "pkg-test-main.unit.new") == 1);
assert(!has(ct,
"--package-init-symbol __ww..pkg.p.pkg.v0.r0.init"));
assert(occurrences(lt, "\n") == 1);
let nc: str = normalizedtrace(ct, strings.concat(works[si], "/"),
bins[si]);
let na: str = normalizedtrace(at, strings.concat(works[si], "/"),
bins[si]);
let nl: str = normalizedtrace(lt, strings.concat(works[si], "/"),
bins[si]);
if (si == 0) {
exportcompiler = nc; exportassembler = na; exportlinker = nl;
} else {
assert(same(exportcompiler, nc));
assert(same(exportassembler, na));
assert(same(exportlinker, nl));
assert(same(readfile(bins[0]), readfile(bins[1])));
};
let xi: i32 = 0;
for (xi < suffixes.len) {
let bytes: str = readfile(strings.concat(works[si], "/",
bridgeaction, suffixes[xi]));
if (si == 0) { exportbridge[xi] = strings.dup(bytes); }
else { assert(same(exportbridge[xi], bytes)); };
xi += 1;
};
let runav: []str = [bins[si]];
runcommand(root, strings.concat("graph-export-run-", stages[si]),
runav, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(out.stdout, "same_graph ... ok\n") == 1);
assert(occurrences(out.stdout, "external_graph ... ok\n") == 1);
si += 1;
};
// Removing the external variant changes only the directory main's target
// set. The now-unreachable pxtest and transitive clone remain intact in the
// persistent store, while the linked process runs the internal target once.
assert(os.remove(externalfile) == 0);
si = 0;
for (si < stages.len) {
let oldptest: str = readfile(strings.concat(works[si],
"/pkg-internal-test.a"));
let oldpxtest: str = readfile(strings.concat(works[si],
"/pkg_test-external-test.a"));
let oldbridge: str = readfile(strings.concat(works[si], "/",
bridgeaction, ".a"));
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
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_GRAPH_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_GRAPH_ASSEMBLER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_GRAPH_LINKER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_GRAPH_REAL_COMPILER=")
&& !strings.hasprefix(baseenv[ei],
"WW_GRAPH_REAL_ASSEMBLER=")
&& !strings.hasprefix(baseenv[ei],
"WW_GRAPH_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_GRAPH_COMPILER_TRACE=",
compilertraces[si]));
append(env, strings.concat("WW_GRAPH_ASSEMBLER_TRACE=",
assemblertraces[si]));
append(env, strings.concat("WW_GRAPH_LINKER_TRACE=",
linkertraces[si]));
append(env, strings.concat("WW_GRAPH_REAL_COMPILER=",
driver(compilers[si])));
append(env, strings.concat("WW_GRAPH_REAL_ASSEMBLER=",
driver(assemblers[si])));
append(env, strings.concat("WW_GRAPH_REAL_LINKER=",
driver(linkers[si])));
let av: []str = [driver(stages[si]), "test", "-c", "-w", works[si],
"-I", root, "--ww-package-test", "test", "pkg", "pkg", "pkg",
"-", pkg, bins[si], "-", statuses[si], pkg];
runcommandenv(root, strings.concat("graph-remove-external-", stages[si]),
av, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(same(readfile(statuses[si]), "ok\n"));
let ct: str = readfile(compilertraces[si]);
let at: str = readfile(assemblertraces[si]);
let lt: str = readfile(linkertraces[si]);
assert(occurrences(ct, "\n") == 1);
assert(has(ct, "pkg-test-main.unit.new"));
assert(!has(ct, "pkg-internal-test.unit.new"));
assert(!has(ct, "pkg_test-external-test.unit.new"));
assert(!has(ct, strings.concat("/", bridgeaction, ".unit.new")));
let maincompile: str = linecontaining(ct,
"pkg-test-main.unit.new");
assert(occurrences(maincompile, "--test-target-package") == 1);
assert(has(maincompile, "--test-target-package pkg "));
assert(!has(maincompile, "--test-target-package pkg_test "));
assert(occurrences(at, "\n") == 2);
assert(has(at, "/pkg-test-main.o.new"));
assert(has(at, "/pkg-test-main.init.o.new"));
assert(occurrences(lt, "\n") == 1);
let link: str = linecontaining(lt,
strings.concat("-o ", bins[si], ".new "));
assert(has(link, "/pkg-test-main.a.new"));
assert(has(link, "/pkg-internal-test.a"));
assert(!has(link, "/pkg_test-external-test.a"));
assert(!has(link, strings.concat("/", bridgeaction, ".a")));
assert(!has(link, "/__external.a"));
assert(same(oldptest, readfile(strings.concat(works[si],
"/pkg-internal-test.a"))));
assert(same(oldpxtest, readfile(strings.concat(works[si],
"/pkg_test-external-test.a"))));
assert(same(oldbridge, readfile(strings.concat(works[si], "/",
bridgeaction, ".a"))));
let runav: []str = [bins[si]];
runcommand(root, strings.concat("graph-remove-run-", stages[si]),
runav, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(out.stdout, "same_graph ... ok\n") == 1);
assert(!has(out.stdout, "external_graph ... ok\n"));
let nc: str = normalizedtrace(ct, strings.concat(works[si], "/"),
bins[si]);
let na: str = normalizedtrace(at, strings.concat(works[si], "/"),
bins[si]);
let nl: str = normalizedtrace(lt, strings.concat(works[si], "/"),
bins[si]);
if (si == 0) {
removecompiler = nc; removeassembler = na; removelinker = nl;
removebin = readfile(bins[si]);
removeout = strings.dup(out.stdout);
removeerr = strings.dup(out.stderr);
} else {
assert(same(removecompiler, nc));
assert(same(removeassembler, na));
assert(same(removelinker, nl));
assert(same(removebin, readfile(bins[si])));
assert(same(removeout, out.stdout));
assert(same(removeerr, out.stderr));
};
si += 1;
};
// Re-adding the external variant with a body-only edit rebuilds pxtest and
// the target-set main. Its stable export stops at the unchanged ptest and
// transitive clone, whose complete persisted bytes remain identical.
writefile(externalfile, externalbodyreadded);
si = 0;
for (si < stages.len) {
let oldptest: str = readfile(strings.concat(works[si],
"/pkg-internal-test.a"));
let oldpxtestwwi: str = readfile(strings.concat(works[si],
"/pkg_test-external-test.wwi"));
let oldpxtesta: str = readfile(strings.concat(works[si],
"/pkg_test-external-test.a"));
let oldbridge: []str = ["", "", "", "", ""];
let xi: i32 = 0;
for (xi < suffixes.len) {
oldbridge[xi] = readfile(strings.concat(works[si], "/",
bridgeaction, suffixes[xi]));
xi += 1;
};
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
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_GRAPH_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_GRAPH_ASSEMBLER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_GRAPH_LINKER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_GRAPH_REAL_COMPILER=")
&& !strings.hasprefix(baseenv[ei],
"WW_GRAPH_REAL_ASSEMBLER=")
&& !strings.hasprefix(baseenv[ei],
"WW_GRAPH_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_GRAPH_COMPILER_TRACE=",
compilertraces[si]));
append(env, strings.concat("WW_GRAPH_ASSEMBLER_TRACE=",
assemblertraces[si]));
append(env, strings.concat("WW_GRAPH_LINKER_TRACE=",
linkertraces[si]));
append(env, strings.concat("WW_GRAPH_REAL_COMPILER=",
driver(compilers[si])));
append(env, strings.concat("WW_GRAPH_REAL_ASSEMBLER=",
driver(assemblers[si])));
append(env, strings.concat("WW_GRAPH_REAL_LINKER=",
driver(linkers[si])));
let av: []str = [driver(stages[si]), "test", "-c", "-w", works[si],
"-I", root, "--ww-package-test", "test", "pkg", "pkg", "pkg",
"pkg_test", pkg, bins[si], "-", statuses[si], pkg];
runcommandenv(root, strings.concat("graph-readd-external-", stages[si]),
av, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let ct: str = readfile(compilertraces[si]);
let at: str = readfile(assemblertraces[si]);
let lt: str = readfile(linkertraces[si]);
assert(occurrences(ct, "\n") == 2);
assert(occurrences(ct,
"pkg_test-external-test.unit.new") == 1);
assert(occurrences(ct, "pkg-test-main.unit.new") == 1);
assert(!has(ct, "pkg-internal-test.unit.new"));
assert(!has(ct, strings.concat("/", bridgeaction, ".unit.new")));
let maincompile: str = linecontaining(ct,
"pkg-test-main.unit.new");
assert(occurrences(maincompile, "--test-target-package") == 2);
assert(pos(maincompile, "--test-target-package pkg ")
< pos(maincompile, "--test-target-package pkg_test "));
let externalcompile: str = linecontaining(ct,
"pkg_test-external-test.unit.new");
assert(has(externalcompile, "/pkg-internal-test.wwi"));
assert(has(externalcompile, strings.concat("/", bridgeaction,
".wwi")));
assert(occurrences(at, "\n") == 3);
assert(occurrences(lt, "\n") == 1);
let link: str = linecontaining(lt,
strings.concat("-o ", bins[si], ".new "));
assert(has(link, "/pkg-test-main.a.new"));
assert(has(link, "/pkg_test-external-test.a.new"));
assert(has(link, "/pkg-internal-test.a"));
assert(has(link, strings.concat("/", bridgeaction, ".a")));
assert(same(oldptest, readfile(strings.concat(works[si],
"/pkg-internal-test.a"))));
assert(same(oldpxtestwwi, readfile(strings.concat(works[si],
"/pkg_test-external-test.wwi"))));
assert(!same(oldpxtesta, readfile(strings.concat(works[si],
"/pkg_test-external-test.a"))));
xi = 0;
for (xi < suffixes.len) {
assert(same(oldbridge[xi], readfile(strings.concat(works[si], "/",
bridgeaction, suffixes[xi]))));
xi += 1;
};
let runav: []str = [bins[si]];
runcommand(root, strings.concat("graph-readd-run-", stages[si]),
runav, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(out.stdout, "same_graph ... ok\n") == 1);
assert(occurrences(out.stdout, "external_graph ... ok\n") == 1);
let nc: str = normalizedtrace(ct, strings.concat(works[si], "/"),
bins[si]);
let na: str = normalizedtrace(at, strings.concat(works[si], "/"),
bins[si]);
let nl: str = normalizedtrace(lt, strings.concat(works[si], "/"),
bins[si]);
if (si == 0) {
readdcompiler = nc; readdassembler = na; readdlinker = nl;
readdbin = readfile(bins[si]);
readdout = strings.dup(out.stdout);
readderr = strings.dup(out.stderr);
} else {
assert(same(readdcompiler, nc));
assert(same(readdassembler, na));
assert(same(readdlinker, nl));
assert(same(readdbin, readfile(bins[si])));
assert(same(readdout, out.stdout));
assert(same(readderr, out.stderr));
};
si += 1;
};
// The public coordinator accepts one explicit output for the combined
// directory in both stages because variants are actions, not products.
let directbin: str = strings.concat(root, "/direct.test");
let directbytes: str = "";
let directout: str = "";
let directerr: str = "";
si = 0;
for (si < stages.len) {
let directav: []str = [driver(stages[si]), "test", "-c", "-o",
directbin, "-I", root, pkg];
runcommand(root, strings.concat("graph-direct-product-", stages[si]),
directav, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0);
assert(os.exists(directbin));
if (si == 0) {
directbytes = readfile(directbin);
directout = strings.dup(out.stdout);
directerr = strings.dup(out.stderr);
} else {
assert(same(directbytes, readfile(directbin)));
assert(same(directout, out.stdout));
assert(same(directerr, out.stderr));
};
clean(strings.concat(directbin, ".sepwork"));
clean(directbin);
si += 1;
};
clean(root);
};
@test fn multi_directory_shared_package_plan() void = {
let root: str = fresh();
let suite: str = strings.concat(root, "/suite");
let leaf: str = strings.concat(root, "/leaf");
let common: str = strings.concat(root, "/common");
let alpha: str = strings.concat(suite, "/alpha");
let beta: str = strings.concat(suite, "/beta");
let gamma: str = strings.concat(suite, "/gamma");
let alphasame: str = strings.concat(suite, "/_alpha_same");
let alphaexternal: str = strings.concat(suite, "/_alpha_external");
let betasame: str = strings.concat(suite, "/_beta_same");
let betaexternal: str = strings.concat(suite, "/_beta_external");
let dirs: []str = [suite, leaf, common, alpha, beta, gamma,
alphasame, alphaexternal, betasame, betaexternal];
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() + 1; };\n"));
writefile(strings.concat(alphasame, "/dep.ww"),
"package _alpha_same;\nexport fn value() i32 = { return 0; };\n");
writefile(strings.concat(alphaexternal, "/dep.ww"),
"package _alpha_external;\nexport fn value() i32 = { return 0; };\n");
writefile(strings.concat(betasame, "/dep.ww"),
"package _beta_same;\nexport fn value() i32 = { return 0; };\n");
writefile(strings.concat(betaexternal, "/dep.ww"),
"package _beta_external;\nexport fn value() i32 = { return 0; };\n");
writefile(strings.concat(alpha, "/a.ww"), strings.concat(
"package alpha;\nimport common;\n// MULTIDIR_ALPHA\n",
"export fn value() i32 = { return common.value() + 1; };\n"));
writefile(strings.concat(alpha, "/same_test.ww"), strings.concat(
"package alpha;\nimport _alpha_same;\n// MULTIDIR_ALPHA_SAME\n",
"export fn test_helper() i32 = { return 1; };\n",
"@test fn alpha_same_runs() void = {\n",
" assert(value() + _alpha_same.value() == 42);\n",
"};\n"));
writefile(strings.concat(alpha, "/external_test.ww"), strings.concat(
"package alpha_test;\nimport _alpha_external;\nimport alpha;\n",
"// MULTIDIR_ALPHA_EXTERNAL\n",
"@test fn alpha_external_runs() void = {\n",
" assert(alpha.value() + _alpha_external.value() == 42);\n",
" assert(alpha.test_helper() == 1);\n",
"};\n"));
writefile(strings.concat(gamma, "/gamma.ww"), strings.concat(
"package gamma;\n// MULTIDIR_GAMMA\n",
"export fn value() i32 = { return 0; };\n"));
writefile(strings.concat(beta, "/beta.ww"), strings.concat(
"package beta;\nimport alpha;\nimport gamma;\n// MULTIDIR_BETA\n",
"export fn value() i32 = { return alpha.value() + gamma.value(); };\n"));
writefile(strings.concat(beta, "/same_test.ww"), strings.concat(
"package beta;\nimport _beta_same;\n// MULTIDIR_BETA_SAME\n",
"export fn test_helper() i32 = { return 2; };\n",
"@test fn beta_same_runs() void = {\n",
" assert(value() + _beta_same.value() == 42);\n",
"};\n"));
writefile(strings.concat(beta, "/external_test.ww"), strings.concat(
"package beta_test;\nimport _beta_external;\nimport beta;\n",
"// MULTIDIR_BETA_EXTERNAL\n",
"@test fn beta_external_runs() void = {\n",
" assert(beta.value() + _beta_external.value() == 42);\n",
" assert(beta.test_helper() == 2);\n",
"};\n"));
let compilerwrapper: str = strings.concat(root, "/trace-w6c.sh");
let assemblerwrapper: str = strings.concat(root, "/trace-w6a.sh");
let linkerwrapper: str = strings.concat(root, "/trace-w6l.sh");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_MULTI_COMPILER_TRACE\"\n",
"exec \"$WW_MULTI_REAL_COMPILER\" \"$@\"\n"));
writeexecutable(assemblerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_MULTI_ASSEMBLER_TRACE\"\n",
"exec \"$WW_MULTI_REAL_ASSEMBLER\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_MULTI_LINKER_TRACE\"\n",
"exec \"$WW_MULTI_REAL_LINKER\" \"$@\"\n"));
let stages: []str = ["ww", "ww_ww"];
let compilers: []str = ["w6c", "w6c_ww"];
let assemblers: []str = ["w6a", "w6a_ww"];
let linkers: []str = ["w6l", "w6l_ww"];
let works: []str = [strings.concat(root, "/c-work"),
strings.concat(root, "/ww-work")];
let compilertraces: []str = [strings.concat(root, "/c-w6c.trace"),
strings.concat(root, "/ww-w6c.trace")];
let assemblertraces: []str = [strings.concat(root, "/c-w6a.trace"),
strings.concat(root, "/ww-w6a.trace")];
let linkertraces: []str = [strings.concat(root, "/c-w6l.trace"),
strings.concat(root, "/ww-w6l.trace")];
let bins: []str = [strings.concat(root, "/alpha-product.test"),
strings.concat(root, "/beta-product.test")];
let statuses: []str = [strings.concat(root, "/alpha.status"),
strings.concat(root, "/beta.status"),
strings.concat(root, "/gamma.status")];
let gammabin: str = strings.concat(root, "/gamma-product.test");
let actions: []str = ["leaf", "common", "alpha", "gamma",
"_alpha_same", "_alpha_external", "_beta_same", "_beta_external",
"test", "alpha-internal-test", "alpha_test-external-test",
"alpha-test-main", "beta-internal-test",
"beta_test-external-test", "beta-test-main"];
let suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"];
let references: []str = alloc([],
(actions.len * suffixes.len): u64)!;
let ri: i32 = 0;
for (ri < actions.len * suffixes.len) {
append(references, "");
ri += 1;
};
let referencealpha: str = "";
let referencebeta: str = "";
let referencecompiler: str = "";
let referenceassembler: str = "";
let referencelinker: str = "";
let baseenv: []str = os.getenvs();
let out: commandout;
let si: i32 = 0;
for (si < stages.len) {
assert(os.mkdir(works[si], 448i32) == 0);
writefile(compilertraces[si], "");
writefile(assemblertraces[si], "");
writefile(linkertraces[si], "");
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_MULTI_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_MULTI_ASSEMBLER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_MULTI_LINKER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_MULTI_REAL_COMPILER=")
&& !strings.hasprefix(baseenv[ei],
"WW_MULTI_REAL_ASSEMBLER=")
&& !strings.hasprefix(baseenv[ei],
"WW_MULTI_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_MULTI_COMPILER_TRACE=",
compilertraces[si]));
append(env, strings.concat("WW_MULTI_ASSEMBLER_TRACE=",
assemblertraces[si]));
append(env, strings.concat("WW_MULTI_LINKER_TRACE=",
linkertraces[si]));
append(env, strings.concat("WW_MULTI_REAL_COMPILER=",
driver(compilers[si])));
append(env, strings.concat("WW_MULTI_REAL_ASSEMBLER=",
driver(assemblers[si])));
append(env, strings.concat("WW_MULTI_REAL_LINKER=",
driver(linkers[si])));
let forward: []str = [driver(stages[si]), "test", "-c", "-w",
works[si], "-I", suite, "-I", root,
"--ww-package-test", "test", "alpha", "alpha", "alpha",
"alpha_test", alpha, bins[0], "-", statuses[0],
"--ww-package-test", "test", "beta", "beta", "beta",
"beta_test", beta, bins[1], "-", statuses[1],
"--ww-package-test", "test", "gamma", "gamma", "-", "-",
gamma, gammabin, "-", statuses[2], alpha];
let reverse: []str = [driver(stages[si]), "test", "-c", "-w",
works[si], "-I", suite, "-I", root,
"--ww-package-test", "test", "gamma", "gamma", "-", "-",
gamma, gammabin, "-", statuses[2],
"--ww-package-test", "test", "beta", "beta", "beta",
"beta_test", beta, bins[1], "-", statuses[1],
"--ww-package-test", "test", "alpha", "alpha", "alpha",
"alpha_test", alpha, bins[0], "-", statuses[0], alpha];
if (si == 0) {
runcommandenv(root, "multi-forward-c", forward, env,
(180i64 * (time.second: i64)): time.duration, &out);
} else {
runcommandenv(root, "multi-reverse-ww", reverse, env,
(180i64 * (time.second: i64)): time.duration, &out);
};
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(os.exists(bins[0]) && os.exists(bins[1]));
assert(!os.exists(gammabin));
assert(same(readfile(statuses[0]), "ok\n"));
assert(same(readfile(statuses[1]), "ok\n"));
assert(same(readfile(statuses[2]), "ok\n"));
assert(!os.exists(strings.concat(works[si], "/beta.unit.ww")));
assert(!os.exists(strings.concat(works[si], "/gamma-main.unit.ww")));
assert(!os.exists(strings.concat(works[si],
"/alpha-internal-test-main.unit.ww")));
assert(!os.exists(strings.concat(works[si],
"/alpha_test-external-test-main.unit.ww")));
let ctrace: str = readfile(compilertraces[si]);
let atrace: str = readfile(assemblertraces[si]);
let ltrace: str = readfile(linkertraces[si]);
assert(occurrences(ctrace, "/alpha.unit.new") == 1);
assert(occurrences(ctrace, "/gamma.unit.new") == 1);
assert(occurrences(ctrace, "/beta.unit.new") == 0);
assert(occurrences(ctrace,
"/alpha-internal-test.unit.new") == 1);
assert(occurrences(ctrace,
"/alpha_test-external-test.unit.new") == 1);
assert(occurrences(ctrace, "/alpha-test-main.unit.new") == 1);
assert(occurrences(ctrace,
"/beta-internal-test.unit.new") == 1);
assert(occurrences(ctrace,
"/beta_test-external-test.unit.new") == 1);
assert(occurrences(ctrace, "/beta-test-main.unit.new") == 1);
assert(occurrences(ctrace, "--test-target-package") == 4);
let alphamain: str = linecontaining(ctrace,
"/alpha-test-main.unit.new");
assert(occurrences(alphamain, "--test-target-package") == 2);
assert(pos(alphamain, "--test-target-package alpha ")
< pos(alphamain, "--test-target-package alpha_test "));
let betamain: str = linecontaining(ctrace,
"/beta-test-main.unit.new");
assert(occurrences(betamain, "--test-target-package") == 2);
assert(pos(betamain, "--test-target-package beta ")
< pos(betamain, "--test-target-package beta_test "));
assert(occurrences(ltrace, "\n") == 2);
let alink: str = linecontaining(ltrace,
strings.concat("-o ", bins[0], ".new "));
assert(has(alink, "/alpha-test-main.a.new"));
assert(has(alink, "/alpha-internal-test.a.new"));
assert(has(alink, "/alpha_test-external-test.a.new"));
assert(!has(alink, strings.concat(works[si], "/alpha.a")));
assert(!has(alink, "/beta-internal-test.a.new"));
assert(!has(alink, "/gamma.a.new"));
assert(!has(alink, ".wwi"));
let blink: str = linecontaining(ltrace,
strings.concat("-o ", bins[1], ".new "));
assert(has(blink, "/beta-test-main.a.new"));
assert(has(blink, "/beta-internal-test.a.new"));
assert(has(blink, "/beta_test-external-test.a.new"));
assert(!has(blink, strings.concat(works[si], "/beta.a")));
assert(has(blink, strings.concat(works[si], "/alpha.a.new")));
assert(has(blink, strings.concat(works[si], "/gamma.a.new")));
assert(!has(blink, "/alpha-internal-test.a.new"));
assert(!has(blink, "/alpha_test-external-test.a.new"));
assert(!has(blink, ".wwi"));
let runav: []str = [bins[0]];
runcommand(root, strings.concat("multi-alpha-run-", stages[si]),
runav, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(out.stdout, "alpha_same_runs ... ok\n") == 1);
assert(occurrences(out.stdout, "alpha_external_runs ... ok\n") == 1);
let betarunav: []str = [bins[1]];
runcommand(root, strings.concat("multi-beta-run-", stages[si]),
betarunav, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(out.stdout, "beta_same_runs ... ok\n") == 1);
assert(occurrences(out.stdout, "beta_external_runs ... ok\n") == 1);
ri = 0;
for (ri < actions.len) {
let xi: i32 = 0;
for (xi < suffixes.len) {
let bytes: str = readfile(strings.concat(works[si], "/",
actions[ri], suffixes[xi]));
let index: i32 = ri * suffixes.len + xi;
if (si == 0) { references[index] = strings.dup(bytes); }
else { assert(same(references[index], bytes)); };
xi += 1;
};
ri += 1;
};
let nc: str = normalizedtrace(ctrace,
strings.concat(works[si], "/"), bins[0]);
let na: str = normalizedtrace(atrace,
strings.concat(works[si], "/"), bins[0]);
let nl: str = normalizedtrace(ltrace,
strings.concat(works[si], "/"), bins[0]);
if (si == 0) {
referencealpha = readfile(bins[0]);
referencebeta = readfile(bins[1]);
referencecompiler = nc;
referenceassembler = na;
referencelinker = nl;
} else {
assert(same(referencealpha, readfile(bins[0])));
assert(same(referencebeta, readfile(bins[1])));
assert(same(referencecompiler, nc));
assert(same(referenceassembler, na));
assert(same(referencelinker, nl));
};
// Every unchanged action is warm-reused. Only the two requested
// directory binaries are linked again; gamma remains compile-only.
// The opposite descriptor order is warm in each stage, so product
// order cannot enter action identity or invalidation.
let warmalpha: str = readfile(bins[0]);
let warmbeta: str = readfile(bins[1]);
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
if (si == 0) {
runcommandenv(root, "multi-warm-reverse-c", reverse, env,
(180i64 * (time.second: i64)): time.duration, &out);
} else {
runcommandenv(root, "multi-warm-forward-ww", forward, env,
(180i64 * (time.second: i64)): time.duration, &out);
};
expectexit(&out, 0);
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(occurrences(readfile(linkertraces[si]), "\n") == 2);
assert(same(warmalpha, readfile(bins[0])));
assert(same(warmbeta, readfile(bins[1])));
si += 1;
};
// Public root order is presentation-only. Default -c destinations are in
// the invocation cwd, and the selected no-test package publishes nothing.
let publicalpha: str = strings.concat(root, "/alpha.test");
let publicbeta: str = strings.concat(root, "/beta.test");
let publicgamma: str = strings.concat(root, "/gamma.test");
let publicout: str = "";
let publicerr: str = "";
let publicalphabytes: str = "";
let publicbetabytes: str = "";
let publiclabels: []str = ["c-forward", "c-reverse",
"ww-forward", "ww-reverse"];
let pi: i32 = 0;
for (pi < 4) {
let publicdriver: str = driver("ww");
if (pi >= 2) { publicdriver = driver("ww_ww"); };
let publicav: []str = alloc([], 16u64)!;
append(publicav, publicdriver);
append(publicav, "test"); append(publicav, "-c");
append(publicav, "-j"); append(publicav, "1");
append(publicav, "-I"); append(publicav, suite);
append(publicav, "-I"); append(publicav, root);
if (pi % 2 == 0) {
append(publicav, alpha); append(publicav, beta);
append(publicav, gamma);
} else {
append(publicav, gamma); append(publicav, beta);
append(publicav, alpha);
};
runcommanddir(root, strings.concat("multi-public-order-",
publiclabels[pi]), root, publicav,
(180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(out.stdout, "built ") == 0);
assert(has(out.stdout, strings.concat(
"? ", gamma, " [no tests]\n")));
assert(os.exists(publicalpha) && os.exists(publicbeta));
assert(!os.exists(publicgamma));
assert(!os.exists(strings.concat(alpha, "/alpha_test.test")));
assert(!os.exists(strings.concat(beta, "/beta_test.test")));
if (pi == 0) {
publicout = strings.dup(out.stdout);
publicerr = strings.dup(out.stderr);
publicalphabytes = readfile(publicalpha);
publicbetabytes = readfile(publicbeta);
} else {
assert(same(publicout, out.stdout));
assert(same(publicerr, out.stderr));
assert(same(publicalphabytes, readfile(publicalpha)));
assert(same(publicbetabytes, readfile(publicbeta)));
};
clean(publicalpha); clean(publicbeta); clean(publicgamma);
pi += 1;
};
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 tooltrace: str = strings.concat(root, "/context-tool.trace");
let compilerwrapper: str = strings.concat(root, "/context-w6c.sh");
let linkerwrapper: str = strings.concat(root, "/context-w6l.sh");
writefile(tooltrace, "");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\nprintf 'compile\\n' >> \"$WW_CONTEXT_TRACE\"\n",
"exec \"$WW_CONTEXT_W6C\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\nprintf 'link\\n' >> \"$WW_CONTEXT_TRACE\"\n",
"exec \"$WW_CONTEXT_W6L\" \"$@\"\n"));
let baseenv: []str = os.getenvs();
let traceenv: []str = alloc([], (baseenv.len + 5): u64)!;
let ei: i32 = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_W6L=")
&& !strings.hasprefix(baseenv[ei], "WW_CONTEXT_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_CONTEXT_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_CONTEXT_W6L=")) {
append(traceenv, baseenv[ei]);
};
ei += 1;
};
append(traceenv, strings.concat("WW_W6C=", compilerwrapper));
append(traceenv, strings.concat("WW_W6L=", linkerwrapper));
append(traceenv, strings.concat("WW_CONTEXT_TRACE=", tooltrace));
append(traceenv, strings.concat("WW_CONTEXT_W6C=", driver("w6c")));
append(traceenv, strings.concat("WW_CONTEXT_W6L=", driver("w6l")));
let stages: []str = ["ww", "ww_ww"];
let jobs: []str = ["1", "4"];
let diagnostics: []str = ["", ""];
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, "/...")];
let stageenv: []str = traceenv;
if (i == 1) {
let wwenv: []str = alloc([], (baseenv.len + 5): u64)!;
stageenv = wwenv;
ei = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_W6L=")
&& !strings.hasprefix(baseenv[ei], "WW_CONTEXT_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_CONTEXT_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_CONTEXT_W6L=")) {
append(stageenv, baseenv[ei]);
};
ei += 1;
};
append(stageenv, strings.concat("WW_W6C=", compilerwrapper));
append(stageenv, strings.concat("WW_W6L=", linkerwrapper));
append(stageenv, strings.concat("WW_CONTEXT_TRACE=", tooltrace));
append(stageenv, strings.concat("WW_CONTEXT_W6C=", driver("w6c_ww")));
append(stageenv, strings.concat("WW_CONTEXT_W6L=", driver("w6l_ww")));
};
runcommandenv(root, strings.concat("context-conflict-", stages[i]), av,
stageenv, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, strings.concat(
"ww: package _leaf resolves to directories ", aleaf,
" and ", bleaf, "\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,
" [good] (build exit 1)\n")));
assert(!has(out.stdout, "unrelated_runs"));
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]));
assert(readfile(tooltrace).len == 0);
clean(root);
};
@test fn mixed_named_test_and_toolchain_test_actions_do_not_collide() void = {
let root: str = fresh();
let suite: str = strings.concat(root, "/suite");
let named: str = strings.concat(suite, "/test");
let consumer: str = strings.concat(suite, "/zconsumer");
assert(os.mkdir(suite, 448i32) == 0);
assert(os.mkdir(named, 448i32) == 0);
assert(os.mkdir(consumer, 448i32) == 0);
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 zconsumer;\n",
"// MIXED_GENERATED_TOOLCHAIN_TEST_SUPPORT\n",
"export fn value() i32 = { return 42; };\n"));
writefile(strings.concat(consumer, "/same_test.ww"), strings.concat(
"package zconsumer;\n@test fn consumer_same_runs() void = {",
" assert(value() == 42); };\n"));
writefile(strings.concat(consumer, "/external_test.ww"), strings.concat(
"package zconsumer_test;\nimport zconsumer;\n",
"@test fn consumer_external_runs() void = {",
" assert(zconsumer.value() == 42); };\n"));
let linktrace: str = strings.concat(root, "/mixed-link.trace");
let linkwrapper: str = strings.concat(root, "/mixed-w6l.sh");
writefile(linktrace, "");
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(consumer, "/zconsumer.test")];
let statuses: []str = [strings.concat(root, "/mixed-test.status"),
strings.concat(root, "/mixed-zconsumer.status")];
let keys: []str = ["test-internal-test", "test_test-external-test",
"test-test-main", "zconsumer-internal-test",
"zconsumer_test-external-test", "zconsumer-test-main"];
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) {
assert(os.mkdir(workroot, 448i32) == 0);
let av: []str = [driver(stages[si]), "test", "-c", "-w", workroot,
"-I", suite,
"--ww-package-test", "test", "test", "test", "test",
"test_test", named, bins[0], "-", statuses[0],
"--ww-package-test", "test", "zconsumer", "zconsumer",
"zconsumer", "zconsumer_test", consumer, bins[1], "-",
statuses[1], named];
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);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let namedprod: str = readfile(strings.concat(work,
"test-internal-test.unit.ww"));
let support: str = readfile(strings.concat(work, "__wwtest.unit.ww"));
assert(has(namedprod, "MIXED_USER_TEST_PRODUCTION"));
assert(has(namedprod, "//ww:module-reset test\n"));
assert(has(support, "//ww:module-reset __wwtest\n"));
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
let actions: []str = ["__wwtest", "test-internal-test",
"test_test-external-test", "test-test-main",
"zconsumer-internal-test", "zconsumer_test-external-test",
"zconsumer-test-main"];
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 "));
if (si == 0) { referenceunits[ri] = strings.dup(unit); }
else { assert(same(referenceunits[ri], unit)); };
ri += 1;
};
let namedrun: []str = [bins[0]];
runcommand(root, strings.concat("mixed-run-", stages[si], "-named"),
namedrun, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "named_same_runs ... ok\n"));
assert(has(out.stdout, "named_external_runs ... ok\n"));
let consumerrun: []str = [bins[1]];
runcommand(root, strings.concat("mixed-run-", stages[si], "-consumer"),
consumerrun, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "consumer_same_runs ... ok\n"));
assert(has(out.stdout, "consumer_external_runs ... ok\n"));
if (si == 0) {
let links: str = readfile(linktrace);
assert(occurrences(links, "\n") == 2);
let namedlink: str = linecontaining(links,
strings.concat("-o ", bins[0], ".new "));
let consumerlink: str = linecontaining(links,
strings.concat("-o ", bins[1], ".new "));
assert(has(namedlink, strings.concat(work, "__wwtest.a")));
assert(has(namedlink, strings.concat(work,
"test-test-main.a")));
assert(has(namedlink, strings.concat(work,
"test-internal-test.a")));
assert(has(namedlink, strings.concat(work,
"test_test-external-test.a")));
assert(!has(namedlink, strings.concat(work, "test.a")));
assert(has(consumerlink, strings.concat(work, "__wwtest.a")));
assert(has(consumerlink, strings.concat(work,
"zconsumer-test-main.a")));
assert(has(consumerlink, strings.concat(work,
"zconsumer-internal-test.a")));
assert(has(consumerlink, strings.concat(work,
"zconsumer_test-external-test.a")));
assert(!has(consumerlink, strings.concat(work, "test.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");
let chainroot: str = strings.concat(d3, "/chain");
assert(os.mkdir(d1, 448i32) == 0);
assert(os.mkdir(d2, 448i32) == 0);
assert(os.mkdir(d3, 448i32) == 0);
assert(os.mkdir(target, 448i32) == 0);
assert(os.mkdir(chainroot, 448i32) == 0);
let packagecount: i32 = 300;
let i: i32 = 0;
for (i < packagecount) {
let name: str = boundarypkgname(i);
let dir: str = strings.concat(root, "/", name);
assert(os.mkdir(dir, 448i32) == 0);
let a: str = "";
if (i + 1 < packagecount) {
let next: str = boundarypkgname(i + 1);
a = strings.concat("package ", name, ";\nimport ", next,
";\n// OWNER_A_", name,
"\nexport fn value() i32 = { return ", next,
".value(); };\n");
} else {
a = strings.concat("package ", name, ";\n// OWNER_A_", name,
"\nexport fn value() i32 = { return 42; };\n");
};
let z: str = strings.concat("package ", name, ";\n// OWNER_Z_",
name, "\nfn private_value() i32 = { return value(); };\n");
writefile(strings.concat(dir, "/a.ww"), a);
writefile(strings.concat(dir, "/z.ww"), z);
i += 1;
};
let roota: str = "package main;\n// ROOT_A\n";
i = 0;
for (i < packagecount) {
if (i != 150) {
roota = strings.concat(roota, "import ", boundarypkgname(i), ";\n");
};
i += 1;
};
i = 0;
for (i < packagecount) {
if (i != 150) {
let name: str = boundarypkgname(i);
roota = strings.concat(roota, "fn use_", name,
"() i32 = { return ", name, ".value(); };\n");
};
i += 1;
};
let rootz: str = strings.concat("package main;\nimport p150;\n",
"// ROOT_Z\nfn main() i32 = { return p150.value() - 42; };\n");
writefile(strings.concat(target, "/a.ww"), roota);
writefile(strings.concat(target, "/z.ww"), rootz);
let chainsource: str = strings.concat("package main;\nimport p000;\n",
"// CHAIN_ROOT\nfn main() i32 = { return p000.value() - 42; };\n");
writefile(strings.concat(chainroot, "/main.ww"), chainsource);
let rootaction: str = "target";
let chainaction: str = "chain";
let compilerwrapper: str = strings.concat(root, "/boundary-w6c.sh");
let assemblerwrapper: str = strings.concat(root, "/boundary-w6a.sh");
let linkerwrapper: str = strings.concat(root, "/boundary-w6l.sh");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_BOUNDARY_COMPILER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_BOUNDARY_COMPILER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_BOUNDARY_COMPILER_TRACE\"\n",
"exec \"$WW_BOUNDARY_W6C\" \"$@\"\n"));
writeexecutable(assemblerwrapper, strings.concat(
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_BOUNDARY_ASSEMBLER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_BOUNDARY_ASSEMBLER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_BOUNDARY_ASSEMBLER_TRACE\"\n",
"exec \"$WW_BOUNDARY_W6A\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_BOUNDARY_LINKER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_BOUNDARY_LINKER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_BOUNDARY_LINKER_TRACE\"\n",
"exec \"$WW_BOUNDARY_W6L\" \"$@\"\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 works: []str = [strings.concat(root, "/boundary-c-work"),
strings.concat(root, "/boundary-ww-work")];
let bins: []str = [strings.concat(root, "/boundary-c-bin"),
strings.concat(root, "/boundary-ww-bin")];
let chainbins: []str = [strings.concat(root, "/boundary-c-chain-bin"),
strings.concat(root, "/boundary-ww-chain-bin")];
let compilertraces: []str = [strings.concat(root, "/boundary-c-compiler"),
strings.concat(root, "/boundary-ww-compiler")];
let assemblertraces: []str = [strings.concat(root, "/boundary-c-assembler"),
strings.concat(root, "/boundary-ww-assembler")];
let linkertraces: []str = [strings.concat(root, "/boundary-c-linker"),
strings.concat(root, "/boundary-ww-linker")];
let baseenv: []str = os.getenvs();
let environments: [][]str = alloc([], stages.len: u64)!;
let out: commandout;
let si: i32 = 0;
for (si < stages.len) {
assert(os.mkdir(works[si], 448i32) == 0);
writefile(compilertraces[si], "");
writefile(assemblertraces[si], "");
writefile(linkertraces[si], "");
let env: []str = alloc([], (baseenv.len + 11): 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_BOUNDARY_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_BOUNDARY_ASSEMBLER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_BOUNDARY_LINKER_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_BOUNDARY_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_BOUNDARY_W6A=")
&& !strings.hasprefix(baseenv[ei], "WW_BOUNDARY_W6L=")
&& !strings.hasprefix(baseenv[ei], "WW_LIB=")
&& !strings.hasprefix(baseenv[ei], "WW_SRCLIB=")) {
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_BOUNDARY_COMPILER_TRACE=",
compilertraces[si]));
append(env, strings.concat("WW_BOUNDARY_ASSEMBLER_TRACE=",
assemblertraces[si]));
append(env, strings.concat("WW_BOUNDARY_LINKER_TRACE=",
linkertraces[si]));
append(env, strings.concat("WW_BOUNDARY_W6C=",
driver(compilers[si])));
append(env, strings.concat("WW_BOUNDARY_W6A=",
driver(assemblers[si])));
append(env, strings.concat("WW_BOUNDARY_W6L=",
driver(linkers[si])));
append(env, strings.concat("WW_LIB=", repo(), "/out/bin/../lib"));
append(env, strings.concat("WW_SRCLIB=", repo(), "/lib"));
append(environments, env);
let av: []str = [driver(stages[si]), "build", "-w", works[si],
"-I", d3, "-I", root, "-o", bins[si], target];
runcommandenv(root, strings.concat("boundary-cold-", stages[si]), av,
env, (600i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let runav: []str = [bins[si]];
runcommand(root, strings.concat("boundary-run-", stages[si]), runav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let ctrace: str = readfile(compilertraces[si]);
let atrace: str = readfile(assemblertraces[si]);
let ltrace: str = readfile(linkertraces[si]);
assert(occurrences(ctrace, "\n") == packagecount + 1);
assert(occurrences(atrace, "\n") == packagecount + 2);
assert(occurrences(ltrace, "\n") == 1);
let rootline: str = linecontaining(ctrace,
strings.concat("/", rootaction, ".unit.new"));
assert(occurrences(rootline, "<--import>") == packagecount);
let expectedroot: str = strings.concat(
"BEGIN<--entry><--package-init-symbol><__ww..pkg.p.",
rootaction, ".v0.r0.init><--init-dispatch-symbol>",
"<__ww..dispatch><-c>");
i = 0;
for (i < packagecount) {
let name: str = boundarypkgname(i);
expectedroot = strings.concat(expectedroot, "<--import><", name,
"><", works[si], "/", name, ".wwi.new>");
assert(occurrences(rootline, strings.concat("<", name, "><",
works[si], "/", name, ".wwi.new>")) == 1);
i += 1;
};
expectedroot = strings.concat(expectedroot, "<-I><", works[si], "/",
rootaction, ".wwi.new><-o><", works[si], "/", rootaction,
".s.new><", works[si], "/", rootaction, ".unit.new>");
assert(same(rootline, expectedroot));
i = 0;
for (i < packagecount) {
let name: str = boundarypkgname(i);
let expectedcompile: str = strings.concat(
"BEGIN<--package-init-symbol><__ww..pkg.p.", name,
".v0.r0.init><-c>");
if (i + 1 < packagecount) {
let next: str = boundarypkgname(i + 1);
expectedcompile = strings.concat(expectedcompile,
"<--import><", next, "><", works[si], "/", next,
".wwi.new>");
};
expectedcompile = strings.concat(expectedcompile, "<-I><",
works[si], "/", name, ".wwi.new><-o><", works[si], "/",
name, ".s.new><", works[si], "/", name, ".unit.new>");
assert(same(linecontaining(ctrace,
strings.concat("/", name, ".unit.new")), expectedcompile));
let expectedassemble: str = strings.concat("BEGIN<-o><", works[si],
"/", name, ".o.new><", works[si], "/", name, ".s.new>");
assert(same(linecontaining(atrace,
strings.concat("/", name, ".o.new")), expectedassemble));
assert(occurrences(ltrace, strings.concat("<", works[si], "/",
name, ".a.new>")) == 1);
assert(os.exists(strings.concat(works[si], "/", name, ".wwi")));
assert(os.exists(strings.concat(works[si], "/", name, ".s")));
assert(os.exists(strings.concat(works[si], "/", name, ".o")));
assert(os.exists(strings.concat(works[si], "/", name, ".a")));
let a: str = "";
if (i + 1 < packagecount) {
let next: str = boundarypkgname(i + 1);
a = strings.concat("package ", name, ";\nimport ", next,
";\n// OWNER_A_", name,
"\nexport fn value() i32 = { return ", next,
".value(); };\n");
} else {
a = strings.concat("package ", name, ";\n// OWNER_A_", name,
"\nexport fn value() i32 = { return 42; };\n");
};
let z: str = strings.concat("package ", name, ";\n// OWNER_Z_",
name, "\nfn private_value() i32 = { return value(); };\n");
let unit: str = readfile(strings.concat(works[si], "/", name,
".unit.ww"));
assert(strings.hasprefix(unit, strings.concat("//ww:module-reset ",
name, "\n", a, "\n//ww:module-reset ", name, "\n", z, "\n")));
if (i + 1 < packagecount) {
assert(has(unit, strings.concat("//ww:direct-export ",
boundarypkgname(i + 1), " ")));
};
assert(strings.hasprefix(readfile(strings.concat(works[si], "/",
name, ".wwi")), strings.concat("//ww:module ", name, "\n")));
i += 1;
};
assert(occurrences(ltrace, strings.concat("<", works[si], "/",
rootaction, ".a.new>")) == 1);
assert(!has(ltrace, ".wwi>"));
let expectedlink: str = strings.concat("BEGIN<-o><", bins[si], ".new><",
works[si], "/", rootaction, ".a.new>");
i = 0;
for (i < packagecount) {
expectedlink = strings.concat(expectedlink, "<", works[si], "/",
boundarypkgname(i), ".a.new>");
i += 1;
};
expectedlink = strings.concat(expectedlink, "<", repo(),
"/out/bin/../lib/libwwrt.a>\n");
assert(same(ltrace, expectedlink));
let rootunit: str = readfile(strings.concat(works[si], "/", rootaction,
".unit.ww"));
assert(strings.hasprefix(rootunit,
strings.concat("//ww:module-reset target\n", roota,
"\n//ww:module-reset target\n", rootz, "\n")));
assert(occurrences(rootunit, "//ww:direct-export p") == packagecount);
let rootassemble: str = strings.concat("BEGIN<-o><", works[si], "/",
rootaction, ".o.new><", works[si], "/", rootaction, ".s.new>");
assert(same(linecontaining(atrace,
strings.concat("/", rootaction, ".o.new")), rootassemble));
let dispatchassemble: str = strings.concat("BEGIN<-o><", works[si],
"/", rootaction, ".init.o.new><", works[si], "/", rootaction,
".init.s.new>");
assert(same(linecontaining(atrace,
strings.concat("/", rootaction, ".init.o.new")), dispatchassemble));
// Repeating the same semantic request in the persistent work root may
// relink the requested binary, but must not compile or assemble any action.
let cbefore: i32 = ctrace.len;
let abefore: i32 = atrace.len;
runcommandenv(root, strings.concat("boundary-warm-", stages[si]), av,
env, (600i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(readfile(compilertraces[si]).len == cbefore);
assert(readfile(assemblertraces[si]).len == abefore);
// A second root importing only p000 proves that link closure expansion,
// not the wide root's direct import list, reaches every archive beyond 256.
let chaincbefore: i32 = readfile(compilertraces[si]).len;
let chainabefore: i32 = readfile(assemblertraces[si]).len;
let chainlbefore: i32 = readfile(linkertraces[si]).len;
let chainav: []str = [driver(stages[si]), "build", "-w", works[si],
"-I", d3, "-I", root, "-o", chainbins[si], chainroot];
runcommandenv(root, strings.concat("boundary-chain-", stages[si]), chainav,
env, (600i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let chainctrace: str = readfile(compilertraces[si]);
let chainatrace: str = readfile(assemblertraces[si]);
let chainltrace: str = readfile(linkertraces[si]);
let cdelta: str = strings.sub(chainctrace, chaincbefore, chainctrace.len);
let adelta: str = strings.sub(chainatrace, chainabefore, chainatrace.len);
let ldelta: str = strings.sub(chainltrace, chainlbefore, chainltrace.len);
assert(occurrences(cdelta, "\n") == 1);
assert(occurrences(adelta, "\n") == 2);
assert(occurrences(ldelta, "\n") == 1);
assert(same(cdelta, strings.concat(
"BEGIN<--entry><--package-init-symbol><__ww..pkg.p.",
chainaction, ".v0.r0.init><--init-dispatch-symbol>",
"<__ww..dispatch><-c><--import><p000><",
works[si], "/p000.wwi><-I><", works[si], "/", chainaction,
".wwi.new><-o><", works[si], "/", chainaction, ".s.new><",
works[si], "/", chainaction, ".unit.new>\n")));
assert(same(adelta, strings.concat("BEGIN<-o><", works[si], "/",
chainaction, ".o.new><", works[si], "/", chainaction, ".s.new>\n",
"BEGIN<-o><", works[si], "/", chainaction, ".init.o.new><",
works[si], "/", chainaction, ".init.s.new>\n")));
let expectedchainlink: str = strings.concat("BEGIN<-o><", chainbins[si],
".new><", works[si], "/", chainaction, ".a.new>");
i = 0;
for (i < packagecount) {
expectedchainlink = strings.concat(expectedchainlink, "<", works[si],
"/", boundarypkgname(i), ".a>");
i += 1;
};
expectedchainlink = strings.concat(expectedchainlink, "<", repo(),
"/out/bin/../lib/libwwrt.a>\n");
assert(same(ldelta, expectedchainlink));
assert(!has(ldelta, ".wwi>"));
let chainunit: str = readfile(strings.concat(works[si], "/", chainaction,
".unit.ww"));
assert(strings.hasprefix(chainunit, strings.concat(
"//ww:module-reset chain\n", chainsource, "\n")));
assert(has(chainunit, "//ww:direct-export p000 "));
let chainrun: []str = [chainbins[si]];
runcommand(root, strings.concat("boundary-chain-run-", stages[si]),
chainrun, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
si += 1;
};
let suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"];
i = 0;
for (i < packagecount) {
let name: str = boundarypkgname(i);
let xi: i32 = 0;
for (xi < suffixes.len) {
assert(same(readfile(strings.concat(works[0], "/", name,
suffixes[xi])), readfile(strings.concat(works[1], "/", name,
suffixes[xi]))));
xi += 1;
};
i += 1;
};
let xi: i32 = 0;
for (xi < suffixes.len) {
assert(same(readfile(strings.concat(works[0], "/", rootaction,
suffixes[xi])), readfile(strings.concat(works[1], "/", rootaction,
suffixes[xi]))));
xi += 1;
};
assert(same(readfile(bins[0]), readfile(bins[1])));
xi = 0;
for (xi < suffixes.len) {
assert(same(readfile(strings.concat(works[0], "/", chainaction,
suffixes[xi])), readfile(strings.concat(works[1], "/", chainaction,
suffixes[xi]))));
xi += 1;
};
assert(same(readfile(chainbins[0]), readfile(chainbins[1])));
// p257 is inserted beyond the former 256-action boundary. A changed
// export recompiles that package, its direct importer p256, and the root
// (which directly imports every package), then stops at p255 because the
// regenerated p256 export is byte-identical.
let changed: str = strings.concat(root, "/p257/a.ww");
rewritefile(changed, strings.concat(
"package p257;\nimport p258;\n// OWNER_A_p257_CHANGED\n",
"export fn value() i32 = { return p258.value(); };\n",
"export fn changed() i32 = { return 257; };\n"));
si = 0;
for (si < stages.len) {
let before: str = readfile(compilertraces[si]);
let av: []str = [driver(stages[si]), "build", "-w", works[si],
"-I", d3, "-I", root, "-o", bins[si], target];
runcommandenv(root, strings.concat("boundary-change-", stages[si]), av,
environments[si],
(600i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let after: str = readfile(compilertraces[si]);
let delta: str = strings.sub(after, before.len, after.len);
assert(occurrences(delta, "\n") == 3);
assert(occurrences(delta, "/p257.unit.new") == 1);
assert(occurrences(delta, "/p256.unit.new") == 1);
assert(occurrences(delta, strings.concat("/", rootaction,
".unit.new")) == 1);
assert(!has(delta, "/p255.unit.new"));
assert(!has(delta, "/p258.unit.new"));
let runav: []str = [bins[si]];
runcommand(root, strings.concat("boundary-change-run-", stages[si]),
runav, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
si += 1;
};
assert(same(readfile(strings.concat(works[0], "/p257.wwi")),
readfile(strings.concat(works[1], "/p257.wwi"))));
assert(same(readfile(bins[0]), readfile(bins[1])));
// Close the 300-node chain into a cycle. Both graph implementations must
// emit the complete deterministic path before compiler, assembler, or linker.
rewritefile(strings.concat(root, "/p299/a.ww"), strings.concat(
"package p299;\nimport p000;\n// OWNER_A_p299_CYCLE\n",
"export fn value() i32 = { return p000.value(); };\n"));
let wantcycle: str = "ww: dependency cycle: ";
i = 0;
for (i < packagecount) {
if (i != 0) { wantcycle = strings.concat(wantcycle, " -> "); };
wantcycle = strings.concat(wantcycle, boundarypkgname(i));
i += 1;
};
wantcycle = strings.concat(wantcycle, " -> p000\n");
let referencecycle: str = "";
si = 0;
for (si < stages.len) {
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let cyclework: str = strings.concat(root, "/cycle-work-", stages[si]);
assert(os.mkdir(cyclework, 448i32) == 0);
let cyclebin: str = strings.concat(root, "/cycle-bin-", stages[si]);
let av: []str = [driver(stages[si]), "build", "-w", cyclework,
"-I", d3, "-I", root, "-o", cyclebin, target];
runcommandenv(root, strings.concat("boundary-cycle-", stages[si]), av,
environments[si],
(600i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0);
assert(same(out.stderr, wantcycle));
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(readfile(linkertraces[si]).len == 0);
if (si == 0) { referencecycle = strings.dup(out.stderr); }
else { assert(same(referencecycle, out.stderr)); };
si += 1;
};
clean(root);
};
@test fn dynamic_package_universe_crosses_former_boundary() void = {
let root: str = fresh();
let suite: str = strings.concat(root, "/suite");
assert(os.mkdir(suite, 448i32) == 0);
let testcount: i32 = 52;
let notestcount: i32 = 205;
let productcount: i32 = testcount + notestcount;
let actioncount: i32 = testcount * 3 + notestcount + 9;
let assemblycount: i32 = actioncount + testcount;
let i: i32 = 0;
for (i < productcount) {
let name: str = boundarypkgname(i);
let dir: str = strings.concat(suite, "/", name);
assert(os.mkdir(dir, 448i32) == 0);
writefile(strings.concat(dir, "/prod.ww"), strings.concat(
"package ", name, ";\n// DYNAMIC_PRODUCTION_", name,
"\nexport fn value() i32 = { return 42; };\n"));
if (i < testcount) {
writefile(strings.concat(dir, "/same_test.ww"), strings.concat(
"package ", name, ";\n// DYNAMIC_INTERNAL_", name,
"\n@test fn same_value() void = { assert(value() == 42); };\n"));
writefile(strings.concat(dir, "/external_test.ww"), strings.concat(
"package ", name, "_test;\nimport ", name,
";\n// DYNAMIC_EXTERNAL_", name,
"\n@test fn external_value() void = { assert(", name,
".value() == 42); };\n"));
};
i += 1;
};
let compilerwrapper: str = strings.concat(root, "/universe-w6c.sh");
let assemblerwrapper: str = strings.concat(root, "/universe-w6a.sh");
let linkerwrapper: str = strings.concat(root, "/universe-w6l.sh");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> ",
"\"$WW_UNIVERSE_COMPILER_TRACE\"\n",
"exec \"$WW_UNIVERSE_W6C\" \"$@\"\n"));
writeexecutable(assemblerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> ",
"\"$WW_UNIVERSE_ASSEMBLER_TRACE\"\n",
"exec \"$WW_UNIVERSE_W6A\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> ",
"\"$WW_UNIVERSE_LINKER_TRACE\"\n",
"exec \"$WW_UNIVERSE_W6L\" \"$@\"\n"));
let coordinatorproxy: str = strings.concat(root,
"/universe-coordinator.sh");
let driverwrapper: str = strings.concat(root, "/universe-driver.sh");
writeexecutable(coordinatorproxy, strings.concat(
"#!/bin/sh\n",
"if [ \"$1\" != package ] || [ \"$2\" != --ww-driver ] || ",
"[ \"$#\" -lt 3 ]; then exit 97; fi\n",
"shift 3\nexec \"$WW_UNIVERSE_WWTEST\" package --ww-driver ",
"\"$WW_UNIVERSE_DRIVER_WRAPPER\" \"$@\"\n"));
writeexecutable(driverwrapper, strings.concat(
"#!/bin/sh\ncount=0\n",
"for arg in \"$@\"; do\n",
" if [ \"$arg\" = --ww-package-test ]; then count=$((count + 1)); fi\n",
"done\nprintf '%s\\n' \"$count\" >> ",
"\"$WW_UNIVERSE_BUILDER_TRACE\"\n",
"exec \"$WW_UNIVERSE_DRIVER\" \"$@\"\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 works: []str = [strings.concat(root, "/universe-c-work"),
strings.concat(root, "/universe-ww-work")];
let compilertraces: []str = [strings.concat(root, "/universe-c-w6c"),
strings.concat(root, "/universe-ww-w6c")];
let assemblertraces: []str = [strings.concat(root, "/universe-c-w6a"),
strings.concat(root, "/universe-ww-w6a")];
let linkertraces: []str = [strings.concat(root, "/universe-c-w6l"),
strings.concat(root, "/universe-ww-w6l")];
let buildertraces: []str = [strings.concat(root, "/universe-c-builder"),
strings.concat(root, "/universe-ww-builder")];
let referencecompiler: str = "";
let referenceassembler: str = "";
let referencelinker: str = "";
let referencebinary: str = "";
let referenceartifacts: []str = ["", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", ""];
let coordinatoroutputs: []str = ["", ""];
let baseenv: []str = os.getenvs();
let out: commandout;
let si: i32 = 0;
for (si < stages.len) {
assert(os.mkdir(works[si], 448i32) == 0);
writefile(compilertraces[si], "");
writefile(assemblertraces[si], "");
writefile(linkertraces[si], "");
writefile(buildertraces[si], "");
let env: []str = alloc([], (baseenv.len + 17): 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_UNIVERSE_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_UNIVERSE_ASSEMBLER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_UNIVERSE_LINKER_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_UNIVERSE_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_UNIVERSE_W6A=")
&& !strings.hasprefix(baseenv[ei], "WW_UNIVERSE_W6L=")
&& !strings.hasprefix(baseenv[ei], "WW_UNIVERSE_WWTEST=")
&& !strings.hasprefix(baseenv[ei],
"WW_UNIVERSE_DRIVER_WRAPPER=")
&& !strings.hasprefix(baseenv[ei], "WW_UNIVERSE_DRIVER=")
&& !strings.hasprefix(baseenv[ei],
"WW_UNIVERSE_BUILDER_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_WWTEST=")
&& !strings.hasprefix(baseenv[ei], "WW_LIB=")
&& !strings.hasprefix(baseenv[ei], "WW_SRCLIB=")) {
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_UNIVERSE_COMPILER_TRACE=",
compilertraces[si]));
append(env, strings.concat("WW_UNIVERSE_ASSEMBLER_TRACE=",
assemblertraces[si]));
append(env, strings.concat("WW_UNIVERSE_LINKER_TRACE=",
linkertraces[si]));
append(env, strings.concat("WW_UNIVERSE_W6C=",
driver(compilers[si])));
append(env, strings.concat("WW_UNIVERSE_W6A=",
driver(assemblers[si])));
append(env, strings.concat("WW_UNIVERSE_W6L=",
driver(linkers[si])));
append(env, strings.concat("WW_LIB=", repo(), "/out/bin/../lib"));
append(env, strings.concat("WW_SRCLIB=", repo(), "/lib"));
append(env, strings.concat("WW_WWTEST=", coordinatorproxy));
append(env, strings.concat("WW_UNIVERSE_WWTEST=", repo(),
"/out/bin/wwtest"));
append(env, strings.concat("WW_UNIVERSE_DRIVER_WRAPPER=",
driverwrapper));
append(env, strings.concat("WW_UNIVERSE_DRIVER=", driver(stages[si])));
append(env, strings.concat("WW_UNIVERSE_BUILDER_TRACE=",
buildertraces[si]));
let av: []str = alloc([], (8 + productcount * 10): u64)!;
append(av, driver(stages[si]));
append(av, "test"); append(av, "-c");
append(av, "-w"); append(av, works[si]);
append(av, "-I"); append(av, suite);
if (si == 0) {
i = 0;
for (i < productcount) {
let name: str = boundarypkgname(i);
let dir: str = strings.concat(suite, "/", name);
append(av, "--ww-package-test"); append(av, "test");
append(av, name); append(av, name);
if (i < testcount) {
append(av, name);
append(av, strings.concat(name, "_test"));
} else {
append(av, "-"); append(av, "-");
};
append(av, dir);
append(av, strings.concat(root, "/product-", name, ".test"));
append(av, "-");
append(av, strings.concat(root, "/product-", name, ".status"));
i += 1;
};
} else {
i = productcount - 1;
for (i >= 0) {
let name: str = boundarypkgname(i);
let dir: str = strings.concat(suite, "/", name);
append(av, "--ww-package-test"); append(av, "test");
append(av, name); append(av, name);
if (i < testcount) {
append(av, name);
append(av, strings.concat(name, "_test"));
} else {
append(av, "-"); append(av, "-");
};
append(av, dir);
append(av, strings.concat(root, "/product-", name, ".test"));
append(av, "-");
append(av, strings.concat(root, "/product-", name, ".status"));
i -= 1;
};
};
append(av, strings.concat(suite, "/p000"));
assert(av.len == 8 + productcount * 10);
runcommandenv(root, strings.concat("dynamic-universe-", stages[si]), av,
env, (1200i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let ctrace: str = readfile(compilertraces[si]);
let atrace: str = readfile(assemblertraces[si]);
let ltrace: str = readfile(linkertraces[si]);
assert(occurrences(ctrace, "\n") == actioncount);
assert(occurrences(atrace, "\n") == assemblycount);
assert(occurrences(ltrace, "\n") == testcount);
assert(!has(ltrace, ".wwi"));
assert(occurrences(ctrace, "/test.unit.new") == 1);
i = 0;
for (i < productcount) {
let name: str = boundarypkgname(i);
if (i < testcount) {
assert(occurrences(ctrace, strings.concat("/", name,
"-internal-test.unit.new")) == 1);
assert(occurrences(ctrace, strings.concat("/", name,
"_test-external-test.unit.new")) == 1);
assert(occurrences(ctrace, strings.concat("/", name,
"-test-main.unit.new")) == 1);
assert(occurrences(ctrace, strings.concat("/", name,
".unit.new")) == 0);
assert(os.exists(strings.concat(root, "/product-", name,
".test")));
} else {
assert(occurrences(ctrace, strings.concat("/", name,
".unit.new")) == 1);
assert(occurrences(ctrace, strings.concat("/", name,
"-test-main.unit.new")) == 0);
assert(!os.exists(strings.concat(root, "/product-", name,
".test")));
};
assert(same(readfile(strings.concat(root, "/product-", name,
".status")), "ok\n"));
i += 1;
};
let samplemain: str = linecontaining(ctrace,
"/p051-test-main.unit.new");
assert(has(samplemain,
"--test-target-package p051 --test-target-package p051_test"));
let sampleexternal: str = linecontaining(ctrace,
"/p051_test-external-test.unit.new");
assert(has(sampleexternal,
strings.concat("--import p051 ", works[si],
"/p051-internal-test.wwi.new")));
let samplelink: str = linecontaining(ltrace,
strings.concat("-o ", root, "/product-p051.test.new "));
assert(has(samplelink, "/p051-test-main.a.new"));
assert(has(samplelink, "/p051-internal-test.a.new"));
assert(has(samplelink, "/p051_test-external-test.a.new"));
assert(!has(samplelink, strings.concat(works[si], "/p051.a")));
assert(!has(samplelink, ".wwi"));
let runav: []str = [strings.concat(root, "/product-p051.test")];
runcommand(root, strings.concat("dynamic-run-", stages[si]), runav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "same_value ... ok\n"));
assert(has(out.stdout, "external_value ... ok\n"));
let samples: []str = ["p051-internal-test",
"p051_test-external-test", "p051-test-main", "p256"];
let suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"];
let sri: i32 = 0;
for (sri < samples.len) {
let xi: i32 = 0;
for (xi < suffixes.len) {
let bytes: str = readfile(strings.concat(works[si], "/",
samples[sri], suffixes[xi]));
let index: i32 = sri * suffixes.len + xi;
if (si == 0) {
referenceartifacts[index] = strings.dup(bytes);
} else {
assert(same(referenceartifacts[index], bytes));
};
xi += 1;
};
sri += 1;
};
let impossible: str = strings.concat(root, "/not-an-output");
let nc: str = normalizedtrace(ctrace,
strings.concat(works[si], "/"), impossible);
let na: str = normalizedtrace(atrace,
strings.concat(works[si], "/"), impossible);
let nl: str = normalizedtrace(ltrace,
strings.concat(works[si], "/"), impossible);
if (si == 0) {
referencecompiler = nc;
referenceassembler = na;
referencelinker = nl;
referencebinary = readfile(strings.concat(root,
"/product-p051.test"));
} else {
assert(same(referencecompiler, nc));
assert(same(referenceassembler, na));
assert(same(referencelinker, nl));
assert(same(referencebinary, readfile(strings.concat(root,
"/product-p051.test"))));
};
// The complete >256 action universe is reused on an unchanged request.
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
runcommandenv(root, strings.concat("dynamic-warm-", stages[si]), av,
env, (1200i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(occurrences(readfile(linkertraces[si]), "\n") == testcount);
// The public recursive coordinator emits the same 257 canonical
// directory products in one delegated request, runs 52 binaries, and
// takes the no-real-run path for all remaining directories.
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let coordinatorav: []str = [driver(stages[si]), "test", "-j", "1",
"-w", works[si], "-I", suite, strings.concat(suite, "/...")];
runcommandenv(root, strings.concat("dynamic-coordinator-", stages[si]),
coordinatorav, env,
(1200i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stderr.len == 0);
coordinatoroutputs[si] = strings.dup(out.stdout);
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(occurrences(readfile(linkertraces[si]), "\n") == testcount);
assert(same(readfile(buildertraces[si]), "257\n"));
assert(occurrences(out.stdout, "ok ") == testcount);
assert(occurrences(out.stdout, "? ") == notestcount);
assert(has(out.stdout, strings.concat("ok ", suite,
"/p051 [p051]\n")));
assert(has(out.stdout, strings.concat("? ", suite,
"/p256 [no tests]\n")));
let beforecompiler: i32 = readfile(compilertraces[si]).len;
runcommandenv(root, strings.concat("dynamic-coordinator-warm-",
stages[si]), coordinatorav, env,
(1200i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(coordinatoroutputs[si], out.stdout));
assert(readfile(compilertraces[si]).len == beforecompiler);
assert(same(readfile(buildertraces[si]), "257\n257\n"));
si += 1;
};
assert(same(coordinatoroutputs[0], coordinatoroutputs[1]));
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(out.stdout.len == 0);
assert(has(out.stderr, "has no exported declaration 'hidden'"));
assert(has(out.stderr, strings.concat("FAIL ", alpha,
" [alpha] (build exit 1)\n")));
assert(has(out.stderr, strings.concat("FAIL ", beta,
" [beta] (build exit 1)\n")));
assert(occurrences(out.stderr, strings.concat("FAIL ", alpha)) == 1);
assert(occurrences(out.stderr, strings.concat("FAIL ", beta)) == 1);
assert(!has(out.stderr, "[alpha_test]"));
assert(!has(out.stderr, "[beta_test]"));
let alphapos: i32 = pos(out.stderr, strings.concat("FAIL ", alpha,
" [alpha] (build exit 1)\n"));
let betapos: i32 = pos(out.stderr, strings.concat("FAIL ", beta,
" [beta] (build exit 1)\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);
};
// Roots remain independently diagnosed and may be staged in parallel, but one
// failing product rejects publication and execution of the entire request.
@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(out.stdout.len == 0);
assert(has(out.stderr,
"has no exported declaration 'hidden'"));
assert(has(out.stderr,
strings.concat("FAIL ", badexternal,
" [badexternal] (build exit 1)\n")));
assert(occurrences(out.stderr,
strings.concat("FAIL ", badexternal)) == 1);
assert(!has(out.stderr, "[badexternal_test]"));
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(out.stdout.len == 0);
assert(has(out.stderr, "undefined: missing"));
assert(has(out.stderr, strings.concat("FAIL ", badsame,
" [badsame] (build exit 1)\n")));
assert(occurrences(out.stderr, strings.concat("FAIL ", badsame)) == 1);
assert(!has(out.stderr, "[badsame_test]"));
samediagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
i += 1;
};
assert(same(externaldiagnostics[0], externaldiagnostics[1]));
assert(same(samediagnostics[0], samediagnostics[1]));
// A persistent request is one publication transaction. A rejection leaves
// no reusable generation, so every staged action is reconsidered next time.
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,
"/badexternal-internal-test.unit.new") == 1);
assert(occurrences(firsttrace,
"/badexternal_test-external-test.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,
"/badexternal-internal-test.unit.new") == 2);
assert(occurrences(secondtrace,
"/badexternal_test-external-test.unit.new") == 2);
assert(!os.exists(strings.concat(warmroot,
"/badexternal-internal-test.unit.ww")));
assert(!os.exists(strings.concat(warmroot,
"/badexternal_test-external-test.unit.ww")));
assert(!os.exists(strings.concat(warmroot, "/.wwtool.stamp")));
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,
"/badexternal-internal-test.unit.new") == 1);
assert(occurrences(wwfirst,
"/badexternal_test-external-test.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,
"/badexternal-internal-test.unit.new") == 2);
assert(occurrences(wwsecond,
"/badexternal_test-external-test.unit.new") == 2);
assert(!os.exists(strings.concat(wwwarmroot,
"/badexternal-internal-test.unit.ww")));
assert(!os.exists(strings.concat(wwwarmroot,
"/badexternal_test-external-test.unit.ww")));
assert(!os.exists(strings.concat(wwwarmroot, "/.wwtool.stamp")));
clean(wwtracebin);
// Late failures are request-wide transactions. Start from a committed
// combined product, stage a changed dependency first, and then fail each
// family action or the linker twice. Every retry must reconsider the same
// work and the committed generation must remain byte-identical.
let latedep: str = strings.concat(root, "/late_dep");
let latebridge: str = strings.concat(root, "/late_bridge");
let late: str = strings.concat(root, "/late");
assert(os.mkdir(latedep, 448i32) == 0);
assert(os.mkdir(latebridge, 448i32) == 0);
assert(os.mkdir(late, 448i32) == 0);
let depfile: str = strings.concat(latedep, "/dep.ww");
let latefile: str = strings.concat(late, "/late.ww");
let latebridgefile: str = strings.concat(latebridge, "/bridge.ww");
let latesamefile: str = strings.concat(late, "/same_test.ww");
let lateexternalfile: str = strings.concat(late, "/external_test.ww");
let depbase: str = strings.concat("package late_dep;\n",
"export fn value() i32 = { return 40; };\n");
let depchanged: str = strings.concat("package late_dep;\n",
"export fn value() i32 = { return 39 + 1; };\n");
let samebase: str = strings.concat("package late;\n",
"export fn internal_helper() i32 = { return 41; };\n",
"@test fn internal_base() void = { assert(value() == 41); };\n");
let samechanged: str = strings.concat("package late;\n",
"export fn internal_helper() i32 = { return 40 + 1; };\n",
"@test fn internal_base() void = { assert(value() == 41); };\n");
let externalbase: str = strings.concat(
"package late_test;\nimport late;\nimport late_bridge;\n",
"@test fn external_base() void = {\n",
" assert(late.internal_helper() == 41);\n",
" assert(late_bridge.helper() == 41);\n};\n");
let externalchanged: str = strings.concat(
"package late_test;\nimport late;\nimport late_bridge;\n",
"@test fn external_base() void = {\n",
" assert(late.internal_helper() >= 41);\n",
" assert(late_bridge.helper() >= 41);\n};\n");
let externalmainchanged: str = strings.concat(
"package late_test;\nimport late;\nimport late_bridge;\n",
"@test fn external_renamed() void = {\n",
" assert(late.internal_helper() == 41);\n",
" assert(late_bridge.helper() == 41);\n};\n");
writefile(depfile, depbase);
writefile(latefile, strings.concat("package late;\nimport late_dep;\n",
"export fn value() i32 = { return late_dep.value() + 1; };\n"));
writefile(latebridgefile, strings.concat(
"package late_bridge;\nimport late;\n",
"export fn helper() i32 = { return late.internal_helper(); };\n"));
writefile(latesamefile, samebase);
writefile(lateexternalfile, externalbase);
let latecompilerwrapper: str = strings.concat(root, "/late-w6c.sh");
let lateassemblerwrapper: str = strings.concat(root, "/late-w6a.sh");
let latelinkerwrapper: str = strings.concat(root, "/late-w6l.sh");
writeexecutable(latecompilerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_LATE_COMPILER_TRACE\"\n",
"if test -n \"$WW_LATE_FAIL_FRAGMENT\"; then\n",
" for arg do case \"$arg\" in *\"$WW_LATE_FAIL_FRAGMENT\"*)\n",
" printf 'injected w6c failure: %s\\n' ",
"\"$WW_LATE_FAIL_FRAGMENT\" >&2\n exit 97;; esac; done\nfi\n",
"exec \"$WW_LATE_REAL_COMPILER\" \"$@\"\n"));
writeexecutable(lateassemblerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_LATE_ASSEMBLER_TRACE\"\n",
"exec \"$WW_LATE_REAL_ASSEMBLER\" \"$@\"\n"));
writeexecutable(latelinkerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_LATE_LINKER_TRACE\"\n",
"if test \"$WW_LATE_FAIL_LINK\" = 1; then\n",
" printf 'injected w6l failure\\n' >&2\n exit 97\nfi\n",
"exec \"$WW_LATE_REAL_LINKER\" \"$@\"\n"));
let lateworks: []str = [strings.concat(root, "/late-c-work"),
strings.concat(root, "/late-ww-work")];
let latebins: []str = [strings.concat(root, "/late-c.test"),
strings.concat(root, "/late-ww.test")];
let latestatuses: []str = [strings.concat(root, "/late-c.status"),
strings.concat(root, "/late-ww.status")];
let latecompilers: []str = ["w6c", "w6c_ww"];
let lateassemblers: []str = ["w6a", "w6a_ww"];
let latelinkers: []str = ["w6l", "w6l_ww"];
let latebridgeowner: str = strings.concat("late#", late);
let latebridgeaction: str = packagestoragekeyfor(
"late_bridge", latebridge, 4, 0, latebridgeowner);
let laterelative: []str = [".wwtool.ww", ".wwtool.w6c", ".wwtool.w6a",
".wwtool.stamp", "late_dep.unit.ww", "late_dep.wwi", "late_dep.s",
"late_dep.o", "late_dep.a",
strings.concat(latebridgeaction, ".unit.ww"),
strings.concat(latebridgeaction, ".wwi"),
strings.concat(latebridgeaction, ".s"),
strings.concat(latebridgeaction, ".o"),
strings.concat(latebridgeaction, ".a"),
"late-internal-test.unit.ww", "late-internal-test.wwi",
"late-internal-test.s", "late-internal-test.o", "late-internal-test.a",
"late_test-external-test.unit.ww", "late_test-external-test.wwi",
"late_test-external-test.s", "late_test-external-test.o",
"late_test-external-test.a", "late-test-main.unit.ww",
"late-test-main.wwi", "late-test-main.s", "late-test-main.o",
"late-test-main.a", "late-test-main.init.unit.ww",
"late-test-main.init.s", "late-test-main.init.o", "test.unit.ww",
"test.wwi", "test.s", "test.o", "test.a"];
let latesnapshots: []str = alloc([],
(stages.len * laterelative.len): u64)!;
let snapshoti: i32 = 0;
for (snapshoti < stages.len * laterelative.len) {
append(latesnapshots, ""); snapshoti += 1;
};
let latebinrefs: []str = ["", ""];
let latestatusrefs: []str = ["", ""];
let lateseedbaseenv: []str = os.getenvs();
i = 0;
for (i < stages.len) {
assert(os.mkdir(lateworks[i], 448i32) == 0);
let seedctrace: str = strings.concat(root, "/late-seed-", tags[i],
"-w6c.trace");
let seedatrace: str = strings.concat(root, "/late-seed-", tags[i],
"-w6a.trace");
let seedltrace: str = strings.concat(root, "/late-seed-", tags[i],
"-w6l.trace");
writefile(seedctrace, ""); writefile(seedatrace, "");
writefile(seedltrace, "");
let seedenv: []str = alloc([], (lateseedbaseenv.len + 11): u64)!;
ei = 0;
for (ei < lateseedbaseenv.len) {
if (!strings.hasprefix(lateseedbaseenv[ei], "WW_W6C=")
&& !strings.hasprefix(lateseedbaseenv[ei], "WW_W6A=")
&& !strings.hasprefix(lateseedbaseenv[ei], "WW_W6L=")
&& !strings.hasprefix(lateseedbaseenv[ei],
"WW_LATE_COMPILER_TRACE=")
&& !strings.hasprefix(lateseedbaseenv[ei],
"WW_LATE_ASSEMBLER_TRACE=")
&& !strings.hasprefix(lateseedbaseenv[ei],
"WW_LATE_LINKER_TRACE=")
&& !strings.hasprefix(lateseedbaseenv[ei],
"WW_LATE_REAL_COMPILER=")
&& !strings.hasprefix(lateseedbaseenv[ei],
"WW_LATE_REAL_ASSEMBLER=")
&& !strings.hasprefix(lateseedbaseenv[ei],
"WW_LATE_REAL_LINKER=")
&& !strings.hasprefix(lateseedbaseenv[ei],
"WW_LATE_FAIL_FRAGMENT=")
&& !strings.hasprefix(lateseedbaseenv[ei],
"WW_LATE_FAIL_LINK=")) {
append(seedenv, lateseedbaseenv[ei]);
};
ei += 1;
};
append(seedenv, strings.concat("WW_W6C=", latecompilerwrapper));
append(seedenv, strings.concat("WW_W6A=", lateassemblerwrapper));
append(seedenv, strings.concat("WW_W6L=", latelinkerwrapper));
append(seedenv, strings.concat("WW_LATE_COMPILER_TRACE=", seedctrace));
append(seedenv, strings.concat("WW_LATE_ASSEMBLER_TRACE=", seedatrace));
append(seedenv, strings.concat("WW_LATE_LINKER_TRACE=", seedltrace));
append(seedenv, strings.concat("WW_LATE_REAL_COMPILER=",
driver(latecompilers[i])));
append(seedenv, strings.concat("WW_LATE_REAL_ASSEMBLER=",
driver(lateassemblers[i])));
append(seedenv, strings.concat("WW_LATE_REAL_LINKER=",
driver(latelinkers[i])));
append(seedenv, "WW_LATE_FAIL_FRAGMENT=");
append(seedenv, "WW_LATE_FAIL_LINK=0");
let seedav: []str = [driver(stages[i]), "test", "-c",
"-w", lateworks[i], "-I", root, "--ww-package-test", "test",
"late", "late", "late", "late_test", late, latebins[i],
"-", latestatuses[i], late];
runcommandenv(root, strings.concat("late-seed-", tags[i]), seedav,
seedenv, (180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(same(readfile(latestatuses[i]), "ok\n"));
let runav: []str = [latebins[i]];
runcommand(root, strings.concat("late-seed-run-", tags[i]), runav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(out.stdout, "internal_base ... ok\n") == 1);
assert(occurrences(out.stdout, "external_base ... ok\n") == 1);
latebinrefs[i] = readfile(latebins[i]);
latestatusrefs[i] = readfile(latestatuses[i]);
snapshoti = 0;
for (snapshoti < laterelative.len) {
latesnapshots[i * laterelative.len + snapshoti] = readfile(
strings.concat(lateworks[i], "/", laterelative[snapshoti]));
snapshoti += 1;
};
i += 1;
};
assert(same(latebinrefs[0], latebinrefs[1]));
let phaselabels: []str = ["internal", "external", "main", "link"];
let phasefragments: []str = ["/late-internal-test.unit.new",
"/late_test-external-test.unit.new", "/late-test-main.unit.new", ""];
let phaseowners: []str = ["late", "late_test",
"__wwtestmain.late.main", ""];
let phasecompiles: []i32 = [2, 2, 3, 2];
let phaseassembles: []i32 = [1, 1, 2, 2];
let phaselinks: []i32 = [0, 0, 0, 1];
let phasectrefs: []str = ["", "", "", ""];
let phaseatrefs: []str = ["", "", "", ""];
let phaseltrefs: []str = ["", "", "", ""];
let phasediagnosticrefs: []str = ["", "", "", ""];
let lateactions: []str = ["late_dep", latebridgeaction,
"late-internal-test", "late_test-external-test", "late-test-main",
"test"];
let latestagesuffixes: []str = [".unit.new", ".wwi.new", ".s.new",
".o.new", ".a.new", ".init.unit.new", ".init.s.new",
".init.o.new"];
let latebaseenv: []str = os.getenvs();
let phasei: i32 = 0;
for (phasei < phaselabels.len) {
rewritefile(depfile, depchanged);
if (phasei == 0 || phasei == 3) {
rewritefile(latesamefile, samechanged);
} else {
rewritefile(latesamefile, samebase);
};
if (phasei == 1) {
rewritefile(lateexternalfile, externalchanged);
} else { if (phasei == 2) {
rewritefile(lateexternalfile, externalmainchanged);
} else {
rewritefile(lateexternalfile, externalbase);
}; };
i = 0;
for (i < stages.len) {
let retry: i32 = 0;
for (retry < 2) {
let retrylabel: str = "first";
if (retry != 0) { retrylabel = "second"; };
let ctracepath: str = strings.concat(root, "/late-",
phaselabels[phasei], "-", tags[i], "-", retrylabel,
"-w6c.trace");
let atracepath: str = strings.concat(root, "/late-",
phaselabels[phasei], "-", tags[i], "-", retrylabel,
"-w6a.trace");
let ltracepath: str = strings.concat(root, "/late-",
phaselabels[phasei], "-", tags[i], "-", retrylabel,
"-w6l.trace");
writefile(ctracepath, ""); writefile(atracepath, "");
writefile(ltracepath, "");
let attemptbin: str = strings.concat(root, "/late-attempt-",
phaselabels[phasei], "-", tags[i], "-", retrylabel,
".test");
let attemptstatus: str = strings.concat(root, "/late-attempt-",
phaselabels[phasei], "-", tags[i], "-", retrylabel,
".status");
let env: []str = alloc([], (latebaseenv.len + 11): u64)!;
ei = 0;
for (ei < latebaseenv.len) {
if (!strings.hasprefix(latebaseenv[ei], "WW_W6C=")
&& !strings.hasprefix(latebaseenv[ei], "WW_W6A=")
&& !strings.hasprefix(latebaseenv[ei], "WW_W6L=")
&& !strings.hasprefix(latebaseenv[ei],
"WW_LATE_COMPILER_TRACE=")
&& !strings.hasprefix(latebaseenv[ei],
"WW_LATE_ASSEMBLER_TRACE=")
&& !strings.hasprefix(latebaseenv[ei],
"WW_LATE_LINKER_TRACE=")
&& !strings.hasprefix(latebaseenv[ei],
"WW_LATE_REAL_COMPILER=")
&& !strings.hasprefix(latebaseenv[ei],
"WW_LATE_REAL_ASSEMBLER=")
&& !strings.hasprefix(latebaseenv[ei],
"WW_LATE_REAL_LINKER=")
&& !strings.hasprefix(latebaseenv[ei],
"WW_LATE_FAIL_FRAGMENT=")
&& !strings.hasprefix(latebaseenv[ei],
"WW_LATE_FAIL_LINK=")) {
append(env, latebaseenv[ei]);
};
ei += 1;
};
append(env, strings.concat("WW_W6C=", latecompilerwrapper));
append(env, strings.concat("WW_W6A=", lateassemblerwrapper));
append(env, strings.concat("WW_W6L=", latelinkerwrapper));
append(env, strings.concat("WW_LATE_COMPILER_TRACE=", ctracepath));
append(env, strings.concat("WW_LATE_ASSEMBLER_TRACE=", atracepath));
append(env, strings.concat("WW_LATE_LINKER_TRACE=", ltracepath));
append(env, strings.concat("WW_LATE_REAL_COMPILER=",
driver(latecompilers[i])));
append(env, strings.concat("WW_LATE_REAL_ASSEMBLER=",
driver(lateassemblers[i])));
append(env, strings.concat("WW_LATE_REAL_LINKER=",
driver(latelinkers[i])));
append(env, strings.concat("WW_LATE_FAIL_FRAGMENT=",
phasefragments[phasei]));
let faillink: str = "0";
if (phasei == 3) { faillink = "1"; };
append(env, strings.concat("WW_LATE_FAIL_LINK=", faillink));
let failav: []str = [driver(stages[i]), "test", "-c",
"-w", lateworks[i], "-I", root, "--ww-package-test", "test",
"late", "late", "late", "late_test", late, attemptbin,
"-", attemptstatus, late];
runcommandenv(root, strings.concat("late-failure-",
phaselabels[phasei], "-", tags[i], "-", retrylabel), failav,
env, (180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0);
if (phasei == 3) {
assert(has(out.stderr, "injected w6l failure\n"));
assert(has(out.stderr, "ww: w6l failed\n"));
} else {
assert(has(out.stderr, strings.concat(
"injected w6c failure: ", phasefragments[phasei], "\n")));
assert(has(out.stderr, strings.concat(
"ww: w6c failed for ", phaseowners[phasei], "\n")));
};
assert(!os.exists(attemptbin));
assert(!os.exists(strings.concat(attemptbin, ".new")));
assert(!os.exists(strings.concat(attemptbin, ".result")));
assert(!os.exists(strings.concat(attemptbin, ".result.new")));
assert(!os.exists(attemptstatus));
assert(!os.exists(strings.concat(attemptstatus, ".new")));
let ct: str = readfile(ctracepath);
let at: str = readfile(atracepath);
let lt: str = readfile(ltracepath);
assert(occurrences(ct, "\n") == phasecompiles[phasei]);
assert(occurrences(at, "\n") == phaseassembles[phasei]);
assert(occurrences(lt, "\n") == phaselinks[phasei]);
assert(pos(ct, "/late_dep.unit.new") >= 0);
if (phasei != 3) {
assert(pos(ct, "/late_dep.unit.new")
< pos(ct, phasefragments[phasei]));
};
assert(!directoryhasnew(lateworks[i]));
let actioni: i32 = 0;
for (actioni < lateactions.len) {
let suffixi: i32 = 0;
for (suffixi < latestagesuffixes.len) {
assert(!os.exists(strings.concat(lateworks[i], "/",
lateactions[actioni], latestagesuffixes[suffixi])));
suffixi += 1;
};
actioni += 1;
};
snapshoti = 0;
for (snapshoti < laterelative.len) {
assert(same(latesnapshots[i * laterelative.len + snapshoti],
readfile(strings.concat(lateworks[i], "/",
laterelative[snapshoti]))));
snapshoti += 1;
};
assert(same(latebinrefs[i], readfile(latebins[i])));
assert(same(latestatusrefs[i], readfile(latestatuses[i])));
let nc: str = normalizedtrace(ct,
strings.concat(lateworks[i], "/"), attemptbin);
let na: str = normalizedtrace(at,
strings.concat(lateworks[i], "/"), attemptbin);
let nl: str = normalizedtrace(lt,
strings.concat(lateworks[i], "/"), attemptbin);
let nd: str = normalizedtrace(out.stderr,
strings.concat(lateworks[i], "/"), attemptbin);
if (i == 0 && retry == 0) {
phasectrefs[phasei] = nc; phaseatrefs[phasei] = na;
phaseltrefs[phasei] = nl;
phasediagnosticrefs[phasei] = nd;
} else {
assert(same(phasectrefs[phasei], nc));
assert(same(phaseatrefs[phasei], na));
assert(same(phaseltrefs[phasei], nl));
assert(same(phasediagnosticrefs[phasei], nd));
};
retry += 1;
};
i += 1;
};
phasei += 1;
};
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", "-w", workroot,
"-I", root, "-o", bin, pkg];
runcommand(root, strings.concat("named-test-build-", stages[i]), av,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let rootunit: str = readfile(strings.concat(work,
"test_test-external-test.unit.ww"));
let produnit: str = readfile(strings.concat(work,
"test.unit.ww"));
let supportunit: str = readfile(strings.concat(work,
"__wwtest.unit.ww"));
assert(!has(rootunit, "//ww:module "));
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,
"test.wwi")));
assert(os.exists(strings.concat(work,
"test.a")));
assert(!os.exists(strings.concat(work,
"__ww-test-000-external-production.unit.ww")));
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 internal_package_import_visibility() void = {
let root: str = fresh();
let source: str = strings.concat(root, "/host/internal/source");
let runtime: str = strings.concat(root, "/runtime");
let tools: str = strings.concat(root, "/tools");
let domain: str = strings.concat(source, "/domain");
let leaf: str = strings.concat(domain, "/leaf");
let secret: str = strings.concat(domain, "/internal/secret");
let client: str = strings.concat(domain, "/client");
let outsider: str = strings.concat(source, "/outsider");
let prefixclient: str = strings.concat(source, "/domainx/client");
let deep: str = strings.concat(domain,
"/internal/outer/internal/deep");
let deepclient: str = strings.concat(domain, "/internal/outer/client");
let nestedoutsider: str = strings.concat(domain, "/nestedclient");
let internalx: str = strings.concat(domain, "/internalx/visible");
let internalxclient: str = strings.concat(source, "/internalxclient");
let testclient: str = strings.concat(domain, "/testclient");
let outsame: str = strings.concat(source, "/outsame");
let outexternal: str = strings.concat(source, "/outexternal");
let physical: str = strings.concat(root, "/physical/domain");
let linkedsecret: str = strings.concat(physical, "/internal/secret");
let linkedclient: str = strings.concat(physical, "/client");
let rawallowed: str = strings.concat(source, "/alias/rawclient.ww");
let rawalias: str = strings.concat(domain, "/rawalias.ww");
let rawescape: str = strings.concat(domain, "/rawescape.ww");
let aliasinternal: str = strings.concat(source, "/alias/internal");
let aliasclient: str = strings.concat(source, "/alias/client");
let aliasownedclient: str = strings.concat(source,
"/alias/owned-client");
let aliasoutsider: str = strings.concat(source, "/alias/outsider");
let shapedomain: str = strings.concat(source, "/shape/domain");
let shapeinternal: str = strings.concat(shapedomain, "/internal");
let shapeclient: str = strings.concat(shapedomain, "/client");
let shapeoutsider: str = strings.concat(source, "/shape/outsider");
let shapevault: str = strings.concat(root, "/vault");
mkdirall(leaf); mkdirall(secret); mkdirall(client); mkdirall(outsider);
mkdirall(prefixclient); mkdirall(deep); mkdirall(deepclient);
mkdirall(nestedoutsider); mkdirall(internalx); mkdirall(internalxclient);
mkdirall(testclient); mkdirall(outsame); mkdirall(outexternal);
mkdirall(linkedsecret); mkdirall(linkedclient); mkdirall(aliasinternal);
mkdirall(aliasownedclient); mkdirall(shapeinternal); mkdirall(shapeclient);
mkdirall(shapeoutsider); mkdirall(shapevault); mkdirall(runtime);
mkdirall(tools);
writefile(strings.concat(runtime, "/libwwrt.a"),
readfile(strings.concat(repo(), "/out/lib/libwwrt.a")));
let leafbody: str = strings.concat(
"package leaf;\n",
"export fn value() i32 = { return 20; };\n");
let secreta: str = strings.concat(
"package secret;\n",
"import domain.leaf;\n",
"export fn value() i32 = { return leaf.value() + 22; };\n");
let secretz: str = strings.concat(
"package secret;\n",
"fn private_value() i32 = { return 99; };\n");
let clientbody: str = strings.concat(
"package main;\n",
"import domain.internal.secret;\n",
"fn main() i32 = { return secret.value(); };\n");
writefile(strings.concat(leaf, "/leaf.ww"), leafbody);
writefile(strings.concat(secret, "/a.ww"), secreta);
writefile(strings.concat(secret, "/z.ww"), secretz);
writefile(strings.concat(client, "/main.ww"), clientbody);
writefile(strings.concat(outsider, "/main.ww"), strings.concat(
"package main;\nimport domain.internal.secret;\n",
"fn main() i32 = { return secret.value(); };\n"));
writefile(strings.concat(prefixclient, "/main.ww"), strings.concat(
"package main;\nimport domain.internal.secret;\n",
"fn main() i32 = { return secret.value(); };\n"));
writefile(strings.concat(deep, "/deep.ww"), strings.concat(
"package deep;\n",
"export fn value() i32 = { return 7; };\n"));
writefile(strings.concat(deepclient, "/main.ww"), strings.concat(
"package main;\n",
"import domain.internal.outer.internal.deep;\n",
"fn main() i32 = { return deep.value(); };\n"));
writefile(strings.concat(nestedoutsider, "/main.ww"), strings.concat(
"package main;\n",
"import domain.internal.outer.internal.deep;\n",
"fn main() i32 = { return deep.value(); };\n"));
writefile(strings.concat(internalx, "/visible.ww"), strings.concat(
"package visible;\n",
"export fn value() i32 = { return 9; };\n"));
writefile(strings.concat(internalxclient, "/main.ww"), strings.concat(
"package main;\nimport domain.internalx.visible;\n",
"fn main() i32 = { return visible.value(); };\n"));
writefile(strings.concat(linkedsecret, "/secret.ww"), strings.concat(
"package secret;\n",
"export fn value() i32 = { return 31; };\n"));
writefile(strings.concat(linkedclient, "/main.ww"), strings.concat(
"package main;\nimport alias.internal.secret;\n",
"fn main() i32 = { return secret.value(); };\n"));
writefile(rawallowed, strings.concat(
"package main;\nimport alias.internal.secret;\n",
"fn main() i32 = { return secret.value(); };\n"));
assert(os.symlink(rawallowed, rawalias) == 0);
assert(os.symlink(strings.concat(outsider, "/main.ww"), rawescape) == 0);
assert(os.symlink(linkedsecret,
strings.concat(aliasinternal, "/secret")) == 0);
writefile(strings.concat(aliasownedclient, "/main.ww"), strings.concat(
"package main;\nimport alias.internal.secret;\n",
"fn main() i32 = { return secret.value(); };\n"));
assert(os.symlink(aliasownedclient, aliasclient) == 0);
assert(os.symlink(linkedclient, aliasoutsider) == 0);
writefile(strings.concat(shapevault, "/secret.ww"), strings.concat(
"package secret;\n",
"export fn value() i32 = { return 17; };\n"));
assert(os.symlink(shapevault,
strings.concat(shapeinternal, "/secret")) == 0);
writefile(strings.concat(shapeclient, "/main.ww"), strings.concat(
"package main;\nimport shape.domain.internal.secret;\n",
"fn main() i32 = { return secret.value(); };\n"));
writefile(strings.concat(shapeoutsider, "/main.ww"), strings.concat(
"package main;\nimport shape.domain.internal.secret;\n",
"fn main() i32 = { return secret.value(); };\n"));
writefile(strings.concat(testclient, "/testclient.ww"), strings.concat(
"package testclient;\n",
"export fn value() i32 = { return 1; };\n"));
writefile(strings.concat(testclient, "/same_test.ww"), strings.concat(
"package testclient;\nimport domain.internal.secret;\n",
"@test fn allowed_same() void = {\n",
" assert(secret.value() == 42);\n};\n"));
writefile(strings.concat(testclient, "/external_test.ww"), strings.concat(
"package testclient_test;\nimport domain.internal.secret;\n",
"import domain.testclient;\n",
"@test fn allowed_external() void = {\n",
" assert(secret.value() + testclient.value() == 43);\n};\n"));
writefile(strings.concat(outsame, "/outsame.ww"),
"package outsame;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(outsame, "/same_test.ww"), strings.concat(
"package outsame;\nimport domain.internal.secret;\n",
"@test fn forbidden_same() void = { assert(false); };\n"));
writefile(strings.concat(outexternal, "/outexternal.ww"),
"package outexternal;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(outexternal, "/external_test.ww"), strings.concat(
"package outexternal_test;\nimport domain.internal.secret;\n",
"@test fn forbidden_external() void = { assert(false); };\n"));
let compilerwrapper: str = strings.concat(tools, "/w6c.sh");
let assemblerwrapper: str = strings.concat(tools, "/w6a.sh");
let linkerwrapper: str = strings.concat(tools, "/w6l.sh");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_INTERNAL_COMPILER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_INTERNAL_COMPILER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_INTERNAL_COMPILER_TRACE\"\n",
"exec \"$WW_INTERNAL_REAL_COMPILER\" \"$@\"\n"));
writeexecutable(assemblerwrapper, strings.concat(
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_INTERNAL_ASSEMBLER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_INTERNAL_ASSEMBLER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_INTERNAL_ASSEMBLER_TRACE\"\n",
"exec \"$WW_INTERNAL_REAL_ASSEMBLER\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_INTERNAL_LINKER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_INTERNAL_LINKER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_INTERNAL_LINKER_TRACE\"\n",
"exec \"$WW_INTERNAL_REAL_LINKER\" \"$@\"\n"));
let stages: []str = ["ww", "ww_ww"];
let compilers: []str = ["w6c", "w6c_ww"];
let assemblers: []str = ["w6a", "w6a_ww"];
let linkers: []str = ["w6l", "w6l_ww"];
let labels: []str = ["0", "1", "2", "3", "4"];
let works: []str = [strings.concat(root, "/c-work"),
strings.concat(root, "/ww-work")];
let bins: []str = [strings.concat(root, "/c-bin"),
strings.concat(root, "/ww-bin")];
let compilertraces: []str = [strings.concat(root, "/c-compiler"),
strings.concat(root, "/ww-compiler")];
let assemblertraces: []str = [strings.concat(root, "/c-assembler"),
strings.concat(root, "/ww-assembler")];
let linkertraces: []str = [strings.concat(root, "/c-linker"),
strings.concat(root, "/ww-linker")];
let artifacts: []str = ["domain.leaf", "domain.internal.secret",
"domain.client"];
let suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"];
let references: []str = alloc([], (artifacts.len * suffixes.len): u64)!;
let ri: i32 = 0;
for (ri < artifacts.len * suffixes.len) {
append(references, ""); ri += 1;
};
let referencebin: str = "";
let referencecompiler: str = "";
let referenceassembler: str = "";
let referencelinker: str = "";
let referencediagnostic: str = "";
let referencetestout: str = "";
let referencetesterr: str = "";
let referencetestartifacts: []str = alloc([], 9u64)!;
ri = 0;
for (ri < 9) { append(referencetestartifacts, ""); ri += 1; };
let allowedreferences: []str = ["", "", "", ""];
let testrejectreferences: []str = ["", ""];
let orderreference: str = "";
let baseenv: []str = os.getenvs();
let si: i32 = 0;
for (si < stages.len) {
assert(os.mkdir(works[si], 448i32) == 0);
writefile(compilertraces[si], ""); writefile(assemblertraces[si], "");
writefile(linkertraces[si], "");
let env: []str = alloc([], (baseenv.len + 11): 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_INTERNAL_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_INTERNAL_ASSEMBLER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_INTERNAL_LINKER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_INTERNAL_REAL_COMPILER=")
&& !strings.hasprefix(baseenv[ei],
"WW_INTERNAL_REAL_ASSEMBLER=")
&& !strings.hasprefix(baseenv[ei],
"WW_INTERNAL_REAL_LINKER=")
&& !strings.hasprefix(baseenv[ei], "WW_LIB=")) {
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_INTERNAL_COMPILER_TRACE=",
compilertraces[si]));
append(env, strings.concat("WW_INTERNAL_ASSEMBLER_TRACE=",
assemblertraces[si]));
append(env, strings.concat("WW_INTERNAL_LINKER_TRACE=",
linkertraces[si]));
append(env, strings.concat("WW_INTERNAL_REAL_COMPILER=",
driver(compilers[si])));
append(env, strings.concat("WW_INTERNAL_REAL_ASSEMBLER=",
driver(assemblers[si])));
append(env, strings.concat("WW_INTERNAL_REAL_LINKER=",
driver(linkers[si])));
append(env, strings.concat("WW_LIB=", runtime));
let av: []str = [driver(stages[si]), "build", "-w", works[si],
"-I", source, "-o", bins[si], client];
let out: commandout;
runcommandenv(root, strings.concat("internal-cold-", stages[si]), av,
env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let wantsecret: str = strings.concat(
"//ww:module-reset domain.internal.secret\n", secreta,
"\n//ww:module-reset domain.internal.secret\n", secretz, "\n");
let secretunit: str = readfile(strings.concat(works[si],
"/domain.internal.secret.unit.ww"));
assert(strings.hasprefix(secretunit, wantsecret));
assert(has(secretunit, "//ww:direct-export domain.leaf "));
let ai: i32 = 0;
for (ai < artifacts.len) {
let xi: i32 = 0;
for (xi < suffixes.len) {
let bytes: str = readfile(strings.concat(works[si], "/",
artifacts[ai], suffixes[xi]));
let index: i32 = ai * suffixes.len + xi;
if (si == 0) { references[index] = strings.dup(bytes); }
else { assert(same(references[index], bytes)); };
xi += 1;
};
ai += 1;
};
let ctrace: str = readfile(compilertraces[si]);
let atrace: str = readfile(assemblertraces[si]);
let ltrace: str = readfile(linkertraces[si]);
assert(occurrences(ctrace, "\n") == 3);
assert(occurrences(atrace, "\n") == 4);
assert(occurrences(ltrace, "\n") == 1);
let dispatchline: str = strings.concat("BEGIN<-o><", works[si],
"/domain.client.init.o.new><", works[si],
"/domain.client.init.s.new>");
assert(same(linecontaining(atrace, "/domain.client.init.o.new"),
dispatchline));
let secretline: str = linecontaining(ctrace,
"domain.internal.secret.unit.new");
assert(occurrences(secretline, "domain.leaf.wwi") == 1);
assert(!has(secretline, "domain.client.wwi"));
let clientline: str = linecontaining(ctrace,
"domain.client.unit.new");
assert(occurrences(clientline,
"domain.internal.secret.wwi") == 1);
assert(!has(clientline, "domain.leaf.wwi"));
assert(occurrences(ltrace, strings.concat(works[si],
"/domain.client.a")) == 1);
assert(occurrences(ltrace, strings.concat(works[si],
"/domain.internal.secret.a")) == 1);
assert(occurrences(ltrace, strings.concat(works[si],
"/domain.leaf.a")) == 1);
assert(!has(ltrace, ".wwi"));
let normalizedcompiler: str = normalizedtrace(ctrace,
strings.concat(works[si], "/"), bins[si]);
let normalizedassembler: str = normalizedtrace(atrace,
strings.concat(works[si], "/"), bins[si]);
let normalizedlinker: str = normalizedtrace(ltrace,
strings.concat(works[si], "/"), bins[si]);
if (si == 0) {
referencecompiler = strings.dup(normalizedcompiler);
referenceassembler = strings.dup(normalizedassembler);
referencelinker = strings.dup(normalizedlinker);
referencebin = strings.dup(readfile(bins[si]));
} else {
assert(same(referencecompiler, normalizedcompiler));
assert(same(referenceassembler, normalizedassembler));
assert(same(referencelinker, normalizedlinker));
assert(same(referencebin, readfile(bins[si])));
};
let runav: []str = [bins[si]];
runcommand(root, strings.concat("internal-run-", stages[si]), runav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 42);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let voucher: str = readfile(strings.concat(works[si],
"/domain.internal.secret.unit.ww"));
let toolww: str = readfile(strings.concat(works[si], "/.wwtool.ww"));
let toolc: str = readfile(strings.concat(works[si], "/.wwtool.w6c"));
let toola: str = readfile(strings.concat(works[si], "/.wwtool.w6a"));
let toolstamp: str = readfile(strings.concat(works[si],
"/.wwtool.stamp"));
rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
runcommandenv(root, strings.concat("internal-warm-", stages[si]), av,
env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(occurrences(readfile(linkertraces[si]), "\n") == 1);
assert(same(voucher, readfile(strings.concat(works[si],
"/domain.internal.secret.unit.ww"))));
rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let badout: str = strings.concat(root, "/warm-forbidden-", stages[si]);
let badav: []str = [driver(stages[si]), "build", "-w", works[si],
"-I", source, "-o", badout, outsider];
runcommandenv(root, strings.concat("internal-warm-forbidden-",
stages[si]), badav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let wantdiag: str = strings.concat(outsider,
"/main.ww:2:1: error: use of internal package ",
"domain.internal.secret not allowed\n");
assert(same(out.stderr, wantdiag));
if (si == 0) { referencediagnostic = strings.dup(out.stderr); }
else { assert(same(referencediagnostic, out.stderr)); };
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(readfile(linkertraces[si]).len == 0);
assert(!os.exists(badout));
assert(!os.exists(strings.concat(works[si], "/outsider.unit.ww")));
assert(same(voucher, readfile(strings.concat(works[si],
"/domain.internal.secret.unit.ww"))));
assert(same(toolww, readfile(strings.concat(works[si], "/.wwtool.ww"))));
assert(same(toolc, readfile(strings.concat(works[si], "/.wwtool.w6c"))));
assert(same(toola, readfile(strings.concat(works[si], "/.wwtool.w6a"))));
assert(same(toolstamp, readfile(strings.concat(works[si],
"/.wwtool.stamp"))));
let coldreject: str = strings.concat(root, "/cold-reject-", stages[si]);
assert(os.mkdir(coldreject, 448i32) == 0);
rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let coldav: []str = [driver(stages[si]), "build", "-w", coldreject,
"-I", source, "-o", strings.concat(coldreject, ".bin"), outsider];
runcommandenv(root, strings.concat("internal-cold-forbidden-",
stages[si]), coldav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(same(out.stderr, wantdiag));
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(readfile(linkertraces[si]).len == 0);
assert(!os.exists(strings.concat(coldreject, "/.wwtool.ww")));
assert(!os.exists(strings.concat(coldreject, "/.wwtool.w6c")));
assert(!os.exists(strings.concat(coldreject, "/.wwtool.w6a")));
assert(!os.exists(strings.concat(coldreject, "/.wwtool.stamp")));
assert(!os.exists(strings.concat(coldreject, ".bin")));
assert(!os.exists(strings.concat(coldreject,
"/domain.internal.secret.unit.ww")));
assert(!os.exists(strings.concat(coldreject,
"/domain.internal.secret.a")));
assert(!os.exists(strings.concat(coldreject, "/outsider.unit.ww")));
let allowedtargets: []str = [deepclient, internalxclient, aliasclient,
shapeclient];
let allowedcodes: []i32 = [7, 9, 31, 17];
let allowedi: i32 = 0;
for (allowedi < allowedtargets.len) {
let allowedout: str = strings.concat(root, "/allowed-", stages[si],
"-", labels[allowedi]);
let allowedav: []str = [driver(stages[si]), "build", "-I", source,
"-o", allowedout, allowedtargets[allowedi]];
runcommandenv(root, strings.concat("internal-allowed-", stages[si],
"-", labels[allowedi]), allowedav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let allowedrun: []str = [allowedout];
runcommand(root, strings.concat("internal-allowed-run-", stages[si],
"-", labels[allowedi]), allowedrun,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, allowedcodes[allowedi]);
if (si == 0) {
allowedreferences[allowedi] = strings.dup(readfile(allowedout));
} else {
assert(same(allowedreferences[allowedi], readfile(allowedout)));
};
allowedi += 1;
};
let rawout: str = strings.concat(root, "/raw-allowed-", stages[si]);
let rawav: []str = [driver(stages[si]), "build", "-I", source,
"-o", rawout, rawalias];
runcommandenv(root, strings.concat("internal-raw-allowed-", stages[si]),
rawav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let rawrun: []str = [rawout];
runcommand(root, strings.concat("internal-raw-run-", stages[si]), rawrun,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 31);
let directout: str = strings.concat(root, "/direct-", stages[si], ".a");
let directav: []str = [driver(stages[si]), "build", "-I", source,
"-o", directout, secret];
runcommandenv(root, strings.concat("internal-direct-", stages[si]),
directav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(references[1 * suffixes.len + 4], readfile(directout)));
assert(same(references[1 * suffixes.len + 1],
readfile(strings.concat(directout, ".wwi"))));
let rejecttargets: []str = [prefixclient, nestedoutsider, aliasoutsider,
rawescape, shapeoutsider];
let rejectimports: []str = ["domain.internal.secret",
"domain.internal.outer.internal.deep", "alias.internal.secret",
"domain.internal.secret", "shape.domain.internal.secret"];
let rejecti: i32 = 0;
for (rejecti < rejecttargets.len) {
let rejectwork: str = strings.concat(root, "/reject-", stages[si],
"-", labels[rejecti]);
assert(os.mkdir(rejectwork, 448i32) == 0);
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let rejectav: []str = [driver(stages[si]), "build", "-w",
rejectwork, "-I", source, "-o", strings.concat(rejectwork,
".bin"), rejecttargets[rejecti]];
runcommandenv(root, strings.concat("internal-reject-", stages[si],
"-", labels[rejecti]), rejectav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let rejectsource: str = strings.concat(rejecttargets[rejecti],
"/main.ww");
if (rejecti == 3) { rejectsource = rawescape; };
let rejectdiag: str = strings.concat(rejectsource,
":2:1: error: use of internal package ",
rejectimports[rejecti], " not allowed\n");
assert(same(out.stderr, rejectdiag));
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(readfile(linkertraces[si]).len == 0);
assert(!os.exists(strings.concat(rejectwork, "/.wwtool.ww")));
assert(!os.exists(strings.concat(rejectwork, "/.wwtool.w6c")));
assert(!os.exists(strings.concat(rejectwork, "/.wwtool.w6a")));
assert(!os.exists(strings.concat(rejectwork, "/.wwtool.stamp")));
assert(!os.exists(strings.concat(rejectwork, ".bin")));
rejecti += 1;
};
let testworkroot: str = strings.concat(root, "/test-work-", stages[si]);
assert(os.mkdir(testworkroot, 448i32) == 0);
rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let testav: []str = [driver(stages[si]), "test", "-w", testworkroot,
"-I", source, testclient];
runcommandenv(root, strings.concat("internal-test-allowed-", stages[si]),
testav, env, (180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "allowed_same ... ok\n"));
assert(has(out.stdout, "allowed_external ... ok\n"));
if (si == 0) {
referencetestout = strings.dup(out.stdout);
referencetesterr = strings.dup(out.stderr);
} else {
assert(same(referencetestout, out.stdout));
assert(same(referencetesterr, out.stderr));
};
let testwork: str = strings.concat(testworkroot, "/");
let testactions: []str = ["domain.testclient-internal-test",
"domain.testclient_test-external-test",
"domain.testclient-test-main"];
ai = 0;
for (ai < testactions.len) {
let testsuffixes: []str = [".unit.ww", ".wwi", ".a"];
let xi: i32 = 0;
for (xi < testsuffixes.len) {
let bytes: str = readfile(strings.concat(testwork,
testactions[ai], testsuffixes[xi]));
let index: i32 = ai * testsuffixes.len + xi;
if (si == 0) {
referencetestartifacts[index] = strings.dup(bytes);
} else {
assert(same(referencetestartifacts[index], bytes));
};
xi += 1;
};
ai += 1;
};
let testcompiletrace: str = readfile(compilertraces[si]);
let sameline: str = linecontaining(testcompiletrace,
"domain.testclient-internal-test.unit");
let externalline: str = linecontaining(testcompiletrace,
"domain.testclient_test-external-test.unit");
assert(occurrences(sameline, "domain.internal.secret.wwi") == 1);
assert(occurrences(externalline,
"domain.internal.secret.wwi") == 1);
assert(!has(sameline, "domain.leaf.wwi"));
assert(!has(externalline, "domain.leaf.wwi"));
assert(has(externalline, strings.concat("<--import>",
"<domain.testclient><", testwork,
"domain.testclient-internal-test.wwi.new>")));
let mainline: str = linecontaining(testcompiletrace,
"domain.testclient-test-main.unit");
assert(!has(mainline, "domain.internal.secret.wwi"));
assert(occurrences(mainline, "<--test-target-package>") == 2);
assert(pos(mainline,
"<--test-target-package><domain.testclient>")
< pos(mainline,
"<--test-target-package><domain.testclient_test>"));
assert(has(mainline, strings.concat("<--import><domain.testclient><",
testwork, "domain.testclient-internal-test.wwi.new>")));
assert(has(mainline, strings.concat(
"<--import><domain.testclient_test><", testwork,
"domain.testclient_test-external-test.wwi.new>")));
assert(occurrences(testcompiletrace, "--test-package") == 2);
assert(occurrences(testcompiletrace,
"<-T><--entry><--test-support-module>") == 1);
assert(occurrences(readfile(linkertraces[si]), "\n") == 1);
assert(!has(readfile(linkertraces[si]), ".wwi"));
let testrejects: []str = [outsame, outexternal];
let testfiles: []str = ["/same_test.ww", "/external_test.ww"];
let tri: i32 = 0;
for (tri < testrejects.len) {
let tw: str = strings.concat(root, "/test-reject-", stages[si],
"-", labels[tri]);
assert(os.mkdir(tw, 448i32) == 0);
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let tav: []str = [driver(stages[si]), "test", "-w", tw,
"-I", source, testrejects[tri]];
runcommandenv(root, strings.concat("internal-test-reject-",
stages[si], "-", labels[tri]), tav, env,
(180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let testdiag: str = strings.concat(testrejects[tri], testfiles[tri],
":2:1: error: use of internal package ",
"domain.internal.secret not allowed\n");
assert(has(out.stderr, testdiag));
if (si == 0) {
testrejectreferences[tri] = strings.dup(out.stderr);
} else {
assert(same(testrejectreferences[tri], out.stderr));
};
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(readfile(linkertraces[si]).len == 0);
tri += 1;
};
let orderwork: str = strings.concat(root, "/order-work-", stages[si]);
assert(os.mkdir(orderwork, 448i32) == 0);
let orderforward: []str = [driver(stages[si]), "test", "-c", "-w",
orderwork, "-I", source,
"--ww-package-test", "test", "main", "main", "-", "-", client,
strings.concat(root, "/order-client-", stages[si]),
"-",
strings.concat(root, "/order-client-", stages[si], ".status"),
"--ww-package-test", "test", "main", "main", "-", "-", outsider,
strings.concat(root, "/order-outsider-", stages[si]),
"-",
strings.concat(root, "/order-outsider-", stages[si], ".status"),
client];
let orderreverse: []str = [driver(stages[si]), "test", "-c", "-w",
orderwork, "-I", source,
"--ww-package-test", "test", "main", "main", "-", "-", outsider,
strings.concat(root, "/order-outsider-", stages[si]),
"-",
strings.concat(root, "/order-outsider-", stages[si], ".status"),
"--ww-package-test", "test", "main", "main", "-", "-", client,
strings.concat(root, "/order-client-", stages[si]),
"-",
strings.concat(root, "/order-client-", stages[si], ".status"),
client];
let orderrequests: [][]str = [orderforward, orderreverse];
let orderdiags: []str = ["", ""];
let oi: i32 = 0;
for (oi < 2) {
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
runcommandenv(root, strings.concat("internal-order-", stages[si],
"-", labels[oi]), orderrequests[oi], env,
(180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
orderdiags[oi] = strings.dup(out.stderr);
assert(same(out.stderr, wantdiag));
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(readfile(linkertraces[si]).len == 0);
oi += 1;
};
assert(same(orderdiags[0], orderdiags[1]));
if (si == 0) { orderreference = strings.dup(orderdiags[0]); }
else { assert(same(orderreference, orderdiags[0])); };
si += 1;
};
clean(root);
};
@test fn exact_package_tool_argv_stage_parity() void = {
let root: str = fresh();
let source: str = strings.concat(root, "/source tree");
let runtime: str = strings.concat(root, "/runtime library");
let baseidentity: str = longidentity("paritybase");
let leftidentity: str = longidentity("parityleft");
let rightidentity: str = longidentity("parityright");
let rootidentity: str = longidentity("paritycommand");
assert(baseidentity.len > 255 && rootidentity.len > 255);
let base: str = strings.concat(source, "/", importrelative(baseidentity));
let left: str = strings.concat(source, "/", importrelative(leftidentity));
let right: str = strings.concat(source, "/", importrelative(rightidentity));
let target: str = strings.concat(source, "/", importrelative(rootidentity));
let tools: str = strings.concat(root, "/tool wrappers");
assert(os.mkdir(source, 448i32) == 0);
assert(os.mkdir(runtime, 448i32) == 0);
writefile(strings.concat(runtime, "/libwwrt.a"),
readfile(strings.concat(repo(), "/out/lib/libwwrt.a")));
mkdirall(base);
mkdirall(left);
mkdirall(right);
mkdirall(target);
assert(os.mkdir(tools, 448i32) == 0);
let basea: str = strings.concat(
"package paritybase;\n",
"export fn value() i32 = { return 20; };\n");
let basez: str = strings.concat(
"package paritybase;\n",
"fn private_value() i32 = { return 99; };\n");
let leftbody: str = strings.concat(
"package parityleft;\n",
"import ", baseidentity, ";\n",
"export fn value() i32 = { return ",
"paritybase.value(); };\n");
let leftz: str = strings.concat(
"package parityleft;\n",
"import ", baseidentity, ";\n",
"export fn repeated_binding() i32 = { return ",
"paritybase.value(); };\n");
let rightbody: str = strings.concat(
"package parityright;\n",
"import ", baseidentity, ";\n",
"export fn value() i32 = { return ",
"paritybase.value() + 1; };\n");
let rootbody: str = strings.concat(
"package main;\n",
"import ", rightidentity, ";\n",
"import ", leftidentity, ";\n",
"fn main() i32 = { return parityleft.value() + ",
"parityright.value() + 1; };\n");
writefile(strings.concat(base, "/a.ww"), basea);
writefile(strings.concat(base, "/z.ww"), basez);
writefile(strings.concat(left, "/a.ww"), leftbody);
writefile(strings.concat(left, "/z.ww"), leftz);
writefile(strings.concat(right, "/right.ww"), rightbody);
writefile(strings.concat(target, "/main.ww"), rootbody);
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",
"owner=\n",
"for arg in \"$@\"; do if [ \"$arg\" = ",
"\"$WW_ARGV_MISSING_OWNER\" ]; then owner=1; fi; done\n",
"if [ -n \"$owner\" ]; then\n",
" mv -- \"$WW_ARGV_MISSING_EXPORT\" ",
"\"$WW_ARGV_MISSING_EXPORT.saved\" || exit 24\n",
" \"$WW_ARGV_REAL_COMPILER\" \"$@\"\n",
" rc=$?\n",
" mv -- \"$WW_ARGV_MISSING_EXPORT.saved\" ",
"\"$WW_ARGV_MISSING_EXPORT\" || exit 25\n",
" exit $rc\n",
"fi\n",
"exec \"$WW_ARGV_REAL_COMPILER\" \"$@\"\n"));
let stages: []str = ["ww", "ww", "ww_ww", "ww_ww"];
let compilers: []str = ["w6c", "w6c", "w6c_ww", "w6c_ww"];
let assemblers: []str = ["w6a", "w6a", "w6a_ww", "w6a_ww"];
let linkers: []str = ["w6l", "w6l", "w6l_ww", "w6l_ww"];
let tags: []str = ["c1", "c2", "ww1", "ww2"];
let bin: str = strings.concat(root, "/published binary");
let workroot: str = strings.concat(bin, ".sepwork");
let work: str = strings.concat(workroot, "/");
let identities: []str = [baseidentity, leftidentity, rightidentity,
rootidentity];
let artifacts: []str = [packagestoragekey(baseidentity, base, 0, 0),
packagestoragekey(leftidentity, left, 0, 0),
packagestoragekey(rightidentity, right, 0, 0),
packagestoragekey(rootidentity, target, 0, 0)];
let unitartifacts: []str = artifacts;
let aki: i32 = 0;
for (aki < artifacts.len) {
assert(strings.hasprefix(artifacts[aki], "__wwpkg.v0.r0.h"));
assert(artifacts[aki].len <= 246);
aki += 1;
};
let wantunits: []str = [strings.concat(
"//ww:module-reset ", baseidentity, "\n", basea,
"\n//ww:module-reset ", baseidentity, "\n", basez, "\n"),
strings.concat("//ww:module-reset ", leftidentity, "\n",
leftbody, "\n//ww:module-reset ", leftidentity, "\n",
leftz, "\n"),
strings.concat("//ww:module-reset ", rightidentity, "\n",
rightbody, "\n"),
strings.concat("//ww:module-reset ", rootidentity, "\n", rootbody,
"\n")];
let referenceunits: []str = ["", "", "", ""];
let referenceexports: []str = ["", "", "", ""];
let referencearchives: []str = ["", "", "", ""];
let referencebin: str = "";
let referencecompiler: str = "";
let referenceassembler: str = "";
let referencelinker: str = "";
let referenceout: str = "";
let referenceerr: str = "";
let referencefailure: str = "";
let referencecollision: 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 + 11): u64)!;
let ei: i32 = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_SRCLIB=")
&& !strings.hasprefix(baseenv[ei], "WW_LIB=")
&& !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=")
&& !strings.hasprefix(baseenv[ei],
"WW_ARGV_FAILURE_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_ARGV_MISSING_EXPORT=")
&& !strings.hasprefix(baseenv[ei],
"WW_ARGV_MISSING_OWNER=")) {
append(env, baseenv[ei]);
};
ei += 1;
};
append(env, strings.concat("WW_SRCLIB=", source));
append(env, strings.concat("WW_LIB=", runtime));
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 request: str = target;
if (si == 1 || si == 3) { request = rootidentity; };
let av: []str = [driver(stages[si]), "build", "-o", bin,
request];
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 ui: i32 = 0;
for (ui < unitartifacts.len) {
let unit: str = readfile(strings.concat(work, unitartifacts[ui],
".unit.ww"));
assert(strings.hasprefix(unit, wantunits[ui]));
if (ui == 1 || ui == 2) {
assert(has(unit, strings.concat("//ww:direct-export ",
baseidentity, " ")));
} else { if (ui == 3) {
assert(has(unit, strings.concat("//ww:direct-export ",
leftidentity, " ")));
assert(has(unit, strings.concat("//ww:direct-export ",
rightidentity, " ")));
}; };
assert(!has(unit, "//ww:module "));
if (si == 0) { referenceunits[ui] = strings.dup(unit); }
else { assert(same(referenceunits[ui], unit)); };
ui += 1;
};
let ai: i32 = 0;
for (ai < artifacts.len) {
let exportf: str = readfile(strings.concat(work, artifacts[ai],
".wwi"));
let assembly: str = readfile(strings.concat(work, artifacts[ai],
".s"));
let archive: str = readfile(strings.concat(work, artifacts[ai],
".a"));
assert(strings.hasprefix(exportf, strings.concat("//ww:module ",
identities[ai], "\n")));
if (ai < 3) {
assert(has(assembly, strings.concat(identities[ai], ".value")));
};
if (ai == 3) {
assert(has(exportf, "\npackage main;\n"));
assert(!has(exportf, "\npackage paritycommand;\n"));
};
if (si == 0) {
referenceexports[ai] = strings.dup(exportf);
referencearchives[ai] = strings.dup(archive);
} else {
assert(same(referenceexports[ai], exportf));
assert(same(referencearchives[ai], archive));
};
ai += 1;
};
assert(os.exists(bin));
let ctrace: str = readfile(compilertrace);
let atrace: str = readfile(assemblertrace);
let ltrace: str = readfile(linkertrace);
assert(occurrences(ctrace, "\n") == 4);
let baseline: str = strings.concat(
"BEGIN<--package-init-symbol><__ww..pkg.p.", baseidentity,
".v0.r0.init><-c><-I><", work,
artifacts[0], ".wwi><-o><", work,
artifacts[0], ".s><", work,
artifacts[0], ".unit.ww>");
let leftline: str = strings.concat(
"BEGIN<--package-init-symbol><__ww..pkg.p.", leftidentity,
".v0.r0.init><-c><--import>",
"<", baseidentity, "><", work,
artifacts[0], ".wwi><-I><", work,
artifacts[1], ".wwi><-o><", work,
artifacts[1], ".s><", work,
artifacts[1], ".unit.ww>");
let rightline: str = strings.concat(
"BEGIN<--package-init-symbol><__ww..pkg.p.", rightidentity,
".v0.r0.init><-c><--import>",
"<", baseidentity, "><", work,
artifacts[0], ".wwi><-I><", work,
artifacts[2], ".wwi><-o><", work,
artifacts[2], ".s><", work,
artifacts[2], ".unit.ww>");
let rootline: str = strings.concat(
"BEGIN<--entry><--package-init-symbol><__ww..pkg.p.",
rootidentity, ".v0.r0.init><--init-dispatch-symbol>",
"<__ww..dispatch><-c><--import>",
"<", leftidentity, "><", work,
artifacts[1], ".wwi><--import>",
"<", rightidentity, "><", work,
artifacts[2], ".wwi><-I><", work,
artifacts[3], ".wwi><-o><", work,
artifacts[3], ".s><", work, artifacts[3], ".unit.ww>");
assert(same(linecontaining(ctrace,
strings.concat(artifacts[0], ".unit.ww")), baseline));
assert(same(linecontaining(ctrace,
strings.concat(artifacts[1], ".unit.ww")), leftline));
assert(same(linecontaining(ctrace,
strings.concat(artifacts[2], ".unit.ww")), rightline));
assert(same(linecontaining(ctrace, strings.concat(artifacts[3],
".unit.ww")), rootline));
assert(!has(rootline, strings.concat(artifacts[0], ".wwi")));
// Canonical owner and declared name stay independent even in a raw
// package compile. --entry selects link-root code generation; it is not
// permission to replace canonical owner with the declared name.
let rejectwwi: str = strings.concat(root, "/reject-", tags[si], ".wwi");
let rejectasm: str = strings.concat(root, "/reject-", tags[si], ".s");
let rejectav: []str = [driver(compilers[si]), "-c", "--import",
leftidentity,
strings.concat(work, artifacts[1], ".wwi"),
"--import", rightidentity,
strings.concat(work, artifacts[2], ".wwi"),
"-I", rejectwwi, "-o", rejectasm,
strings.concat(work, artifacts[3], ".unit.ww")];
runcommand(root, strings.concat("command-without-entry-", tags[si]),
rejectav, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(os.exists(rejectwwi) && os.exists(rejectasm));
let ownerrejectwwi: str = strings.concat(root, "/owner-reject-",
tags[si], ".wwi");
let ownerrejectasm: str = strings.concat(root, "/owner-reject-",
tags[si], ".s");
let ownerrejectav: []str = [driver(compilers[si]), "-c", "--import",
leftidentity, strings.concat(work, artifacts[0], ".wwi"), "-I",
ownerrejectwwi, "-o", ownerrejectasm,
strings.concat(work, artifacts[1], ".unit.ww")];
runcommand(root, strings.concat("export-owner-reject-", tags[si]),
ownerrejectav, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(same(out.stderr, strings.concat("w6c: import ", leftidentity,
": export owner mismatch in ", work, artifacts[0], ".wwi\n")));
assert(occurrences(atrace, "\n") == 5);
ai = 0;
for (ai < artifacts.len) {
let assemblerline: str = strings.concat("BEGIN<-o><", work,
artifacts[ai], ".o><", work, artifacts[ai], ".s>");
assert(same(linecontaining(atrace, strings.concat(work,
artifacts[ai], ".o")), assemblerline));
ai += 1;
};
let dispatcherline: str = strings.concat("BEGIN<-o><", work,
artifacts[3], ".init.o><", work, artifacts[3], ".init.s>");
assert(same(linecontaining(atrace, strings.concat(work,
artifacts[3], ".init.o")), dispatcherline));
assert(occurrences(ltrace, "\n") == 1);
assert(has(ltrace, strings.concat("BEGIN<-o><", bin, ".new><", work,
artifacts[3], ".a>")));
ai = 0;
for (ai < artifacts.len) {
assert(occurrences(ltrace, strings.concat("<", work, artifacts[ai],
".a>")) == 1);
ai += 1;
};
assert(has(ltrace, strings.concat("<", runtime, "/libwwrt.a>")));
assert(!has(ltrace, strings.concat("<", repo(),
"/out/lib/libwwrt.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, 42);
assert(out.stdout.len == 0 && out.stderr.len == 0);
if (si == 0) {
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(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));
};
// Select the same long ordinary directory as both an explicit product
// root and the dependency of another product in one command. Then build
// it alone through logical and literal spellings. All routes must intern
// one production action and emit the dependency-built bytes above.
let combinedbase: str = strings.concat(root, "/combined-base-", tags[si]);
let combinedleft: str = strings.concat(root, "/combined-left-", tags[si]);
let combinedbasestatus: str = strings.concat(combinedbase, ".status");
let combinedleftstatus: str = strings.concat(combinedleft, ".status");
clean(compilertrace); writefile(compilertrace, "");
clean(assemblertrace); writefile(assemblertrace, "");
clean(linkertrace); writefile(linkertrace, "");
let combinedav: []str = [driver(stages[si]), "test", "-c", "-I",
source, "--ww-package-build",
"--ww-package-test", "build", "paritybase", "paritybase",
"-", "-", base,
combinedbase, "-", combinedbasestatus,
"--ww-package-test", "build", "parityleft", "parityleft",
"-", "-", left,
combinedleft, "-", combinedleftstatus, left];
runcommandenv(root, strings.concat("long-combined-", tags[si]),
combinedav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let combinedtrace: str = readfile(compilertrace);
assert(occurrences(combinedtrace, strings.concat(artifacts[0],
".unit.ww>")) == 1);
let combinedwork: str = strings.concat(combinedbase, ".sepwork/");
let combinedunit: str = readfile(strings.concat(combinedwork,
artifacts[0], ".unit.ww"));
let combinedwwi: str = readfile(strings.concat(combinedwork,
artifacts[0], ".wwi"));
let combinedarchive: str = readfile(strings.concat(combinedwork,
artifacts[0], ".a"));
assert(same(referenceunits[0], combinedunit));
assert(same(referenceexports[0], combinedwwi));
assert(same(referencearchives[0], combinedarchive));
let rootspellings: []str = [baseidentity, base];
let rootlabels: []str = ["logical", "literal"];
let ri: i32 = 0;
for (ri < rootspellings.len) {
let rootout: str = strings.concat(root, "/long-root-",
rootlabels[ri], "-", tags[si], ".a");
clean(compilertrace); writefile(compilertrace, "");
let rootav: []str = [driver(stages[si]), "build", "-I",
source, "-o", rootout, rootspellings[ri]];
runcommandenv(root, strings.concat("long-root-", rootlabels[ri],
"-", tags[si]), rootav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(readfile(compilertrace), strings.concat(
artifacts[0], ".unit.ww>")) == 1);
let rootwork: str = strings.concat(rootout, ".sepwork/");
assert(same(combinedunit, readfile(strings.concat(rootwork,
artifacts[0], ".unit.ww"))));
assert(same(combinedwwi, readfile(strings.concat(rootwork,
artifacts[0], ".wwi"))));
assert(same(combinedarchive, readfile(strings.concat(rootwork,
artifacts[0], ".a"))));
clean(strings.concat(rootout, ".sepwork"));
clean(rootout); clean(strings.concat(rootout, ".wwi"));
ri += 1;
};
clean(strings.concat(combinedbase, ".sepwork"));
clean(combinedbase); clean(combinedleft);
clean(combinedbasestatus); clean(combinedleftstatus);
let seedav: []str = [driver(stages[si]), "build", "-w", workroot,
"-o", bin, request];
runcommandenv(root, strings.concat("persistent-seed-", tags[si]),
seedav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(os.remove(compilertrace) == 0);
assert(os.remove(assemblertrace) == 0);
writefile(compilertrace, "");
writefile(assemblertrace, "");
let equivalent: str = rootidentity;
if (same(request, rootidentity)) { equivalent = target; };
let warmav: []str = [driver(stages[si]), "build", "-w", workroot,
"-o", bin, equivalent];
runcommandenv(root, strings.concat("persistent-equivalent-", tags[si]),
warmav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(readfile(compilertrace).len == 0);
assert(readfile(assemblertrace).len == 0);
let baseafile: str = strings.concat(base, "/a.ww");
assert(os.remove(baseafile) == 0);
writefile(baseafile, strings.concat(basea,
"export fn marker() i32 = { return 7; };\n"));
runcommandenv(root, strings.concat("persistent-export-", tags[si]),
warmav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let changedtrace: str = readfile(compilertrace);
assert(occurrences(changedtrace, "\n") == 3);
assert(has(changedtrace, strings.concat(artifacts[0], ".unit.new")));
assert(has(changedtrace, strings.concat(artifacts[1], ".unit.new")));
assert(has(changedtrace, strings.concat(artifacts[2], ".unit.new")));
assert(!has(changedtrace, strings.concat(artifacts[3], ".unit.new")));
let badunit: str = strings.concat(work, artifacts[0], ".unit.ww");
assert(os.remove(badunit) == 0);
writefile(badunit, "//ww:module-reset wrong.owner\n");
assert(os.remove(compilertrace) == 0);
assert(os.remove(assemblertrace) == 0);
assert(os.remove(linkertrace) == 0);
writefile(compilertrace, "");
writefile(assemblertrace, "");
writefile(linkertrace, "");
let collisionav: []str = [driver(stages[si]), "build", "-w",
workroot, "-o", bin, request];
runcommandenv(root, strings.concat("storage-owner-", tags[si]),
collisionav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let collisiondiag: str = strings.concat(
"ww: package storage owner mismatch at ", artifacts[0],
" for ", baseidentity, "\n");
assert(same(out.stderr, collisiondiag));
assert(readfile(compilertrace).len == 0);
assert(readfile(assemblertrace).len == 0);
assert(readfile(linkertrace).len == 0);
if (si == 0) { referencecollision = strings.dup(out.stderr); }
else { assert(same(referencecollision, out.stderr)); };
assert(os.remove(baseafile) == 0);
writefile(baseafile, basea);
clean(workroot);
clean(bin);
let failenv: []str = alloc([], (env.len + 4): 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));
append(failenv, strings.concat("WW_ARGV_MISSING_EXPORT=", work,
artifacts[0], ".wwi"));
append(failenv, strings.concat("WW_ARGV_MISSING_OWNER=", work,
artifacts[1], ".unit.ww"));
runcommandenv(root, strings.concat("exact-argv-fail-", tags[si]), av,
failenv, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let wantfailure: str = strings.concat(
"w6c: import ", baseidentity, ": cannot read ", work,
artifacts[0], ".wwi\n",
"ww: w6c failed for ", leftidentity, "\n");
assert(same(out.stderr, wantfailure));
assert(has(readfile(failuretrace), strings.concat(
"<--import><", baseidentity, "><", work,
artifacts[0], ".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 command_package_test_variants_keep_canonical_identity() void = {
let root: str = fresh();
let source: str = strings.concat(root, "/source");
let commandid: str = longidentity("cmdtool");
assert(commandid.len > 255);
let target: str = strings.concat(source, "/", importrelative(commandid));
let importer: str = strings.concat(source, "/importer");
let wrapper: str = strings.concat(root, "/command-w6c.sh");
assert(os.mkdir(source, 448i32) == 0);
mkdirall(target);
assert(os.mkdir(importer, 448i32) == 0);
writefile(strings.concat(target, "/main.ww"), strings.concat(
"package main;\n",
"export fn value() i32 = { return 41; };\n",
"fn main() i32 = { return 0; };\n"));
writefile(strings.concat(target, "/internal_test.ww"), strings.concat(
"package main;\n",
"@test fn command_internal() void = { assert(value() == 41); };\n"));
writefile(strings.concat(target, "/external_test.ww"), strings.concat(
"package main_test;\n",
"import ", commandid, ";\n",
"@test fn command_external() void = { ",
"assert(main.value() == 41); };\n"));
writefile(strings.concat(importer, "/importer.ww"), strings.concat(
"package importer;\n",
"import ", commandid, ";\n",
"export fn value() i32 = { return main.value(); };\n"));
writeexecutable(wrapper, strings.concat(
"#!/bin/sh\n",
"printf 'BEGIN' >> \"$WW_COMMAND_COMPILER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_COMMAND_COMPILER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_COMMAND_COMPILER_TRACE\"\n",
"exec \"$WW_COMMAND_REAL_COMPILER\" \"$@\"\n"));
let stages: []str = ["ww", "ww_ww"];
let compilers: []str = ["w6c", "w6c_ww"];
let internalid: str = commandid;
let externalid: str = strings.concat(commandid, "_test");
let mainid: str = strings.concat("__wwtestmain.", commandid, ".main");
let actionids: []str = [internalid, externalid, mainid];
let ordinaryartifact: str = packagestoragekey(commandid, target, 0, 0);
let artifacts: []str = [packagestoragekey(internalid, target, 1, 0),
packagestoragekey(externalid, target, 2, 0),
packagestoragekey(mainid,
strings.concat(target, "#directory-test-main"), 3, 2)];
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
let reference: []str = ["", "", "", "", "", "", "", "", ""];
let baseenv: []str = os.getenvs();
let si: i32 = 0;
for (si < stages.len) {
let workroot: str = strings.concat(root, "/command-work-", stages[si]);
assert(os.mkdir(workroot, 448i32) == 0);
let work: str = strings.concat(workroot, "/");
let trace: str = strings.concat(root, "/", stages[si], ".trace");
writefile(trace, "");
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_COMMAND_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_COMMAND_REAL_COMPILER=")) {
append(env, baseenv[ei]);
};
ei += 1;
};
append(env, strings.concat("WW_W6C=", wrapper));
append(env, strings.concat("WW_COMMAND_COMPILER_TRACE=", trace));
append(env, strings.concat("WW_COMMAND_REAL_COMPILER=",
driver(compilers[si])));
let av: []str = [driver(stages[si]), "test", "-w", workroot,
"-I", source, target];
let out: commandout;
runcommandenv(root, strings.concat("command-variants-", stages[si]), av,
env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stderr.len == 0);
assert(has(out.stdout, "main.command_internal ... ok\n"));
assert(has(out.stdout, "main.command_external ... ok\n"));
let ctrace: str = readfile(trace);
let ai: i32 = 0;
for (ai < artifacts.len) {
let line: str = linecontaining(ctrace,
strings.concat(artifacts[ai], ".unit.new"));
if (ai < 2) { assert(has(line, "<--command-package>")); }
else { assert(has(line, "<-T><--entry>")); };
let sj: i32 = 0;
for (sj < suffixes.len) {
let body: str = readfile(strings.concat(work, artifacts[ai],
suffixes[sj]));
if (sj == 0) {
assert(has(body, strings.concat("//ww:module-reset ",
actionids[ai], "\n")));
} else { if (sj == 1) {
assert(strings.hasprefix(body, strings.concat("//ww:module ",
actionids[ai], "\n")));
}; };
let ri: i32 = ai * suffixes.len + sj;
if (si == 0) { reference[ri] = strings.dup(body); }
else { assert(same(reference[ri], body)); };
sj += 1;
};
ai += 1;
};
let externalline: str = linecontaining(ctrace,
strings.concat(artifacts[1], ".unit.new"));
assert(has(externalline, strings.concat("<--import><", commandid,
"><", work, artifacts[0], ".wwi.new>")));
let mainline: str = linecontaining(ctrace,
strings.concat(artifacts[2], ".unit.new"));
assert(has(mainline, strings.concat("<--import><", internalid,
"><", work, artifacts[0], ".wwi.new>")));
assert(has(mainline, strings.concat("<--import><", externalid,
"><", work, artifacts[1], ".wwi.new>")));
assert(has(mainline, strings.concat(
"<--test-target-package><", internalid, ">")));
assert(has(mainline, strings.concat(
"<--test-target-package><", externalid, ">")));
assert(pos(mainline, strings.concat("<--test-target-package><",
internalid, ">")) < pos(mainline, strings.concat(
"<--test-target-package><", externalid, ">")));
assert(!os.exists(strings.concat(work, ordinaryartifact, ".unit.ww")));
assert(has(readfile(strings.concat(work, artifacts[0], ".s")),
strings.concat(commandid, ".value")));
assert(has(readfile(strings.concat(work, artifacts[0], ".s")),
strings.concat(commandid, ".command_internal")));
assert(has(readfile(strings.concat(work, artifacts[1], ".s")),
strings.concat(externalid, ".command_external")));
let warmrefs: []str = alloc([], reference.len: u64)!;
warmrefs.len = reference.len;
ai = 0;
for (ai < artifacts.len) {
let sj: i32 = 0;
for (sj < suffixes.len) {
warmrefs[ai * suffixes.len + sj] = strings.dup(readfile(
strings.concat(work, artifacts[ai], suffixes[sj])));
sj += 1;
};
ai += 1;
};
runcommandenv(root, strings.concat("command-warm-", stages[si]), av,
env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "main.command_internal ... ok\n"));
assert(has(out.stdout, "main.command_external ... ok\n"));
assert(same(ctrace, readfile(trace)));
ai = 0;
for (ai < artifacts.len) {
let sj: i32 = 0;
for (sj < suffixes.len) {
assert(same(warmrefs[ai * suffixes.len + sj], readfile(
strings.concat(work, artifacts[ai], suffixes[sj]))));
sj += 1;
};
ai += 1;
};
// The same command action is not generally source-importable. It is
// classified from its declaration so this Go-like diagnostic is stable,
// and graph failure occurs before any compiler invocation.
clean(trace);
writefile(trace, "");
let importout: str = strings.concat(root, "/importer-", stages[si], ".a");
let importav: []str = [driver(stages[si]), "build", "-I", source,
"-o", importout, importer];
runcommandenv(root, strings.concat("command-import-", stages[si]),
importav, env, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, strings.concat("package ", commandid,
" is a program, not an importable package\n")));
assert(readfile(trace).len == 0);
clean(workroot);
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 identityroot: str = strings.concat(root, "/identityroot");
let identityactual: str = strings.concat(root, "/identityactual");
let identityalias: str = strings.concat(root, "/identityalias");
let reserved: str = strings.concat(root, "/reservedprobe");
let foldsource: str = strings.concat(root, "/foldsource");
let foldupper: str = strings.concat(foldsource, "/domain/Foo");
let foldlower: str = strings.concat(foldsource, "/domain/foo");
let folddirect: str = strings.concat(foldsource, "/cmd/direct");
let foldbackward: str = strings.concat(foldsource, "/cmd/backward");
let foldindirect: str = strings.concat(foldsource, "/cmd/indirect");
let foldleft: str = strings.concat(foldsource, "/parent/left");
let foldright: str = strings.concat(foldsource, "/parent/right");
let foldrepeat: str = strings.concat(foldsource, "/cmd/repeat");
let foldaliasroot: str = strings.concat(foldsource, "/aliasroot");
let foldaliasactual: str = strings.concat(foldsource, "/alias/Foo");
let foldalias: str = strings.concat(foldsource, "/alias/foo");
let foldrootleft: str = strings.concat(foldsource, "/roots/left");
let foldrootright: str = strings.concat(foldsource, "/roots/right");
let foldrecursive: str = strings.concat(root, "/foldrecursive");
let foldrecursiveupper: str = strings.concat(foldrecursive, "/domain/Foo");
let foldrecursivelower: str = strings.concat(foldrecursive, "/domain/foo");
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(identityroot, 448i32) == 0);
assert(os.mkdir(identityactual, 448i32) == 0);
assert(os.mkdir(reserved, 448i32) == 0);
mkdirall(foldupper); mkdirall(foldlower); mkdirall(folddirect);
mkdirall(foldbackward); mkdirall(foldindirect); mkdirall(foldleft);
mkdirall(foldright); mkdirall(foldrepeat); mkdirall(foldaliasroot);
mkdirall(foldaliasactual); mkdirall(foldrootleft); mkdirall(foldrootright);
mkdirall(foldrecursiveupper); mkdirall(foldrecursivelower);
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(identityactual, "/identityactual.ww"),
"package identityactual;\nexport fn value() i32 = { return 1; };\n");
let linkout: commandout;
let linkav: []str = ["/bin/ln", "-s", identityactual, identityalias];
runcommand(root, "identity-alias", linkav, time.second, &linkout);
expectexit(&linkout, 0);
writefile(strings.concat(identityroot, "/identityroot.ww"), strings.concat(
"package identityroot;\nimport identityactual;\n",
"import identityalias;\nexport fn value() i32 = { return 1; };\n"));
writefile(strings.concat(reserved, "/reservedprobe.ww"), strings.concat(
"package reservedprobe;\nimport __wwlocal.fake;\n",
"export fn value() i32 = { return 1; };\n"));
writefile(strings.concat(foldupper, "/pkg.ww"),
"package upperdecl;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(foldlower, "/pkg.ww"),
"package lowerdecl;\nexport fn value() i32 = { return 2; };\n");
// File creation and import order deliberately disagree with byte order.
writefile(strings.concat(folddirect, "/z.ww"), strings.concat(
"package main;\nimport Lower domain.foo;\n",
"fn main() i32 = { return 0; };\n"));
writefile(strings.concat(folddirect, "/a.ww"),
"package main;\nimport Upper domain.Foo;\n");
writefile(strings.concat(foldbackward, "/a.ww"),
"package main;\nimport Lower domain.foo;\n");
writefile(strings.concat(foldbackward, "/z.ww"), strings.concat(
"package main;\nimport Upper domain.Foo;\n",
"fn main() i32 = { return 0; };\n"));
writefile(strings.concat(foldleft, "/pkg.ww"), strings.concat(
"package left;\nimport _ domain.Foo;\n",
"export fn value() i32 = { return 1; };\n"));
writefile(strings.concat(foldright, "/pkg.ww"), strings.concat(
"package right;\nimport _ domain.foo;\n",
"export fn value() i32 = { return 2; };\n"));
writefile(strings.concat(foldindirect, "/main.ww"), strings.concat(
"package main;\nimport _ parent.left;\nimport _ parent.right;\n",
"fn main() i32 = { return 0; };\n"));
writefile(strings.concat(foldrepeat, "/a.ww"),
"package main;\nimport _ domain.Foo;\n");
writefile(strings.concat(foldrepeat, "/z.ww"), strings.concat(
"package main;\nimport _ domain.Foo;\n",
"fn main() i32 = { return 0; };\n"));
writefile(strings.concat(foldaliasactual, "/pkg.ww"),
"package aliasdecl;\nexport fn value() i32 = { return 1; };\n");
assert(os.symlink(foldaliasactual, foldalias) == 0);
writefile(strings.concat(foldaliasroot, "/main.ww"), strings.concat(
"package main;\nimport _ alias.Foo;\nimport _ alias.foo;\n",
"fn main() i32 = { return 0; };\n"));
writefile(strings.concat(foldrootleft, "/pkg.ww"),
"package leftroot;\nimport _ domain.Foo;\n");
writefile(strings.concat(foldrootright, "/pkg.ww"),
"package rightroot;\nimport _ domain.foo;\n");
writefile(strings.concat(foldrecursiveupper, "/pkg.ww"),
"package upper;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(foldrecursivelower, "/pkg.ww"),
"package lower;\nexport fn value() i32 = { return 2; };\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 stages: []str = ["ww", "ww_ww"];
let tooltrace: str = strings.concat(root, "/identity-tool.trace");
let compilerwrapper: str = strings.concat(root, "/identity-w6c.sh");
let assemblerwrapper: str = strings.concat(root, "/identity-w6a.sh");
let linkerwrapper: str = strings.concat(root, "/identity-w6l.sh");
writefile(tooltrace, "");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\nprintf 'compile' >> \"$WW_IDENTITY_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_IDENTITY_TRACE\"; done\nprintf '\\n' >> ",
"\"$WW_IDENTITY_TRACE\"\n",
"exec \"$WW_IDENTITY_W6C\" \"$@\"\n"));
writeexecutable(assemblerwrapper, strings.concat(
"#!/bin/sh\nprintf 'assemble' >> \"$WW_IDENTITY_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_IDENTITY_TRACE\"; done\nprintf '\\n' >> ",
"\"$WW_IDENTITY_TRACE\"\n",
"exec \"$WW_IDENTITY_W6A\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\nprintf 'link' >> \"$WW_IDENTITY_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_IDENTITY_TRACE\"; done\nprintf '\\n' >> ",
"\"$WW_IDENTITY_TRACE\"\n",
"exec \"$WW_IDENTITY_W6L\" \"$@\"\n"));
let baseenv: []str = os.getenvs();
let traceenv: []str = alloc([], (baseenv.len + 4): 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_IDENTITY_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_IDENTITY_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_IDENTITY_W6A=")
&& !strings.hasprefix(baseenv[ei], "WW_IDENTITY_W6L=")) {
append(traceenv, baseenv[ei]);
};
ei += 1;
};
append(traceenv, strings.concat("WW_W6C=", compilerwrapper));
append(traceenv, strings.concat("WW_W6A=", assemblerwrapper));
append(traceenv, strings.concat("WW_W6L=", linkerwrapper));
append(traceenv, strings.concat("WW_IDENTITY_TRACE=", tooltrace));
let out: commandout;
let i: i32 = 0;
let identitydiagnostics: []str = ["", ""];
i = 0;
for (i < stages.len) {
let av: []str = [driver(stages[i]), "build", "-I", root,
"-o", strings.concat(root, "/bad-identity-", stages[i], ".a"),
identityroot];
runcommandenv(root, strings.concat("duplicate-directory-identity-",
stages[i]), av, traceenv,
(60i64 * (time.second: i64)): time.duration, &out);
assert(out.termination == exec.termination.EXIT && out.code != 0);
assert(has(out.stderr, strings.concat("ww: package directory ",
identityactual, " has import identities identityactual and ",
"identityalias\n")));
identitydiagnostics[i] = strings.dup(out.stderr);
i += 1;
};
assert(same(identitydiagnostics[0], identitydiagnostics[1]));
// A canonical directory acquiring two import identities rejects before
// compiler or linker invocation. The converse is covered by the shared
// multi-context resolution test above.
assert(readfile(tooltrace).len == 0);
let foldexpected: str =
"ww: case-insensitive import collision: \"domain.Foo\" and \"domain.foo\"\n";
let aliasexpected: str =
"ww: case-insensitive import collision: \"alias.Foo\" and \"alias.foo\"\n";
let foldtargets: []str = [folddirect, foldbackward, foldindirect,
foldaliasroot];
let foldlabels: []str = ["direct", "backward", "indirect", "one-dir"];
let foldwant: []str = [foldexpected, foldexpected, foldexpected,
aliasexpected];
let compilers: []str = ["w6c", "w6c_ww"];
let assemblers: []str = ["w6a", "w6a_ww"];
let linkers: []str = ["w6l", "w6l_ww"];
let foldrefs: []str = ["", "", "", "", "", "", ""];
let repeatref: str = "";
i = 0;
for (i < stages.len) {
let foldenv: []str = alloc([], (traceenv.len + 3): u64)!;
let tei: i32 = 0;
for (tei < traceenv.len) {
append(foldenv, traceenv[tei]); tei += 1;
};
append(foldenv, strings.concat("WW_IDENTITY_W6C=",
driver(compilers[i])));
append(foldenv, strings.concat("WW_IDENTITY_W6A=",
driver(assemblers[i])));
append(foldenv, strings.concat("WW_IDENTITY_W6L=",
driver(linkers[i])));
let fi: i32 = 0;
for (fi < foldtargets.len) {
rewritefile(tooltrace, "");
let work: str = strings.concat(root, "/fold-", foldlabels[fi],
"-", stages[i], "-work");
assert(os.mkdir(work, 448i32) == 0);
let output: str = strings.concat(root, "/fold-", foldlabels[fi],
"-", stages[i]);
let av: []str = [driver(stages[i]), "build", "-w", work,
"-I", foldsource, "-o", output, foldtargets[fi]];
runcommandenv(root, strings.concat("case-fold-", foldlabels[fi],
"-", stages[i]), av, foldenv,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && same(out.stderr, foldwant[fi]));
assert(readfile(tooltrace).len == 0);
assert(!os.exists(output));
assert(!os.exists(strings.concat(output, ".new")));
assert(!os.exists(strings.concat(output, ".sepwork")));
assert(!os.exists(strings.concat(work, "/.wwtool.stamp")));
assert(directoryisempty(work));
if (i == 0) { foldrefs[fi] = strings.dup(out.stderr); }
else { assert(same(foldrefs[fi], out.stderr)); };
fi += 1;
};
// The coordinator canonicalizes product order, so reversing roots cannot
// choose a different representative or diagnostic.
let rootfirst: []str = [foldrootleft, foldrootright];
let rootsecond: []str = [foldrootright, foldrootleft];
let oi: i32 = 0;
for (oi < rootfirst.len) {
rewritefile(tooltrace, "");
let work: str = strings.concat(root, "/fold-roots-", stages[i],
"-", foldlabels[oi], "-work");
assert(os.mkdir(work, 448i32) == 0);
let av: []str = [driver(stages[i]), "build", "-w", work,
"-I", foldsource, rootfirst[oi], rootsecond[oi]];
runcommandenv(root, strings.concat("case-fold-roots-", stages[i],
"-", foldlabels[oi]), av, foldenv,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && has(out.stderr, foldexpected));
assert(readfile(tooltrace).len == 0);
assert(!os.exists(strings.concat(work, "/.wwtool.stamp")));
assert(directoryisempty(work));
let refindex: i32 = foldtargets.len + oi;
if (i == 0) { foldrefs[refindex] = strings.dup(out.stderr); }
else { assert(same(foldrefs[refindex], out.stderr)); };
oi += 1;
};
assert(same(foldrefs[4], foldrefs[5]));
rewritefile(tooltrace, "");
let recursivework: str = strings.concat(root, "/fold-recursive-",
stages[i], "-work");
assert(os.mkdir(recursivework, 448i32) == 0);
let recursiveav: []str = [driver(stages[i]), "build", "-w",
recursivework, "-I", foldrecursive,
strings.concat(foldrecursive, "/...")];
runcommandenv(root, strings.concat("case-fold-recursive-", stages[i]),
recursiveav, foldenv,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && has(out.stderr, foldexpected));
assert(readfile(tooltrace).len == 0);
assert(!os.exists(strings.concat(recursivework, "/.wwtool.stamp")));
assert(directoryisempty(recursivework));
if (i == 0) { foldrefs[6] = strings.dup(out.stderr); }
else { assert(same(foldrefs[6], out.stderr)); };
// Exact repeated occurrences retain one canonical action and accepted
// compiler input, rather than being merged by the folded key.
rewritefile(tooltrace, "");
let repeatwork: str = strings.concat(root, "/fold-repeat-", stages[i],
"-work");
let repeatout: str = strings.concat(root, "/fold-repeat-", stages[i]);
assert(os.mkdir(repeatwork, 448i32) == 0);
let repeatav: []str = [driver(stages[i]), "build", "-w", repeatwork,
"-I", foldsource, "-o", repeatout, foldrepeat];
runcommandenv(root, strings.concat("case-fold-repeat-", stages[i]),
repeatav, foldenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let repeattrace: str = readfile(tooltrace);
assert(occurrences(repeattrace,
"/domain.Foo.unit.new>") == 1);
let repeatline: str = linecontaining(repeattrace,
"/cmd.repeat.unit.new>");
assert(occurrences(repeatline, "<--import><domain.Foo>") == 1);
assert(occurrences(repeatline, "/domain.Foo.wwi.new>") == 1);
assert(os.exists(strings.concat(repeatwork, "/.wwtool.stamp")));
let repeatpaths: []str = ["/.wwtool.ww", "/.wwtool.w6c",
"/.wwtool.w6a", "/.wwtool.stamp", "/cmd.repeat.unit.ww",
"/cmd.repeat.wwi", "/cmd.repeat.s", "/cmd.repeat.o",
"/cmd.repeat.a", "/cmd.repeat.init.unit.ww",
"/cmd.repeat.init.s", "/cmd.repeat.init.o",
"/domain.Foo.unit.ww", "/domain.Foo.wwi", "/domain.Foo.s",
"/domain.Foo.o", "/domain.Foo.a"];
let repeatbytes: []str = alloc([], repeatpaths.len: u64)!;
let rsi: i32 = 0;
for (rsi < repeatpaths.len) {
append(repeatbytes, strings.dup(readfile(strings.concat(repeatwork,
repeatpaths[rsi]))));
rsi += 1;
};
let repeatoutput: str = strings.dup(readfile(repeatout));
if (i == 0) { repeatref = strings.dup(repeatoutput); }
else { assert(same(repeatref, repeatoutput)); };
let repeatcollision: str = strings.concat(foldrepeat, "/m.ww");
writefile(repeatcollision,
"package main;\nimport _ domain.foo;\n");
rewritefile(tooltrace, "");
runcommandenv(root, strings.concat("case-fold-repeat-added-", stages[i]),
repeatav, foldenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && same(out.stderr, foldexpected));
assert(readfile(tooltrace).len == 0);
rsi = 0;
for (rsi < repeatpaths.len) {
assert(same(repeatbytes[rsi], readfile(strings.concat(repeatwork,
repeatpaths[rsi]))));
rsi += 1;
};
assert(!directoryhasnew(repeatwork));
assert(same(repeatoutput, readfile(repeatout)));
assert(!os.exists(strings.concat(repeatout, ".new")));
assert(!os.exists(strings.concat(repeatout, ".sepwork")));
assert(!os.exists(strings.concat(repeatwork, "/domain.foo.unit.ww")));
assert(!os.exists(strings.concat(repeatwork, "/domain.foo.wwi")));
assert(!os.exists(strings.concat(repeatwork, "/domain.foo.a")));
assert(os.remove(repeatcollision) == 0);
rewritefile(tooltrace, "");
runcommandenv(root, strings.concat("case-fold-repeat-removed-", stages[i]),
repeatav, foldenv,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(occurrences(readfile(tooltrace), "compile") == 0);
assert(occurrences(readfile(tooltrace), "assemble") == 0);
assert(occurrences(readfile(tooltrace), "link") == 1);
rsi = 0;
for (rsi < repeatpaths.len) {
assert(same(repeatbytes[rsi], readfile(strings.concat(repeatwork,
repeatpaths[rsi]))));
rsi += 1;
};
assert(!directoryhasnew(repeatwork));
assert(same(repeatoutput, readfile(repeatout)));
assert(!os.exists(strings.concat(repeatout, ".new")));
assert(!os.exists(strings.concat(repeatout, ".sepwork")));
i += 1;
};
rewritefile(tooltrace, "");
let reserveddiagnostics: []str = ["", ""];
i = 0;
for (i < stages.len) {
let av: []str = [driver(stages[i]), "build", "-I", root,
"-o", strings.concat(root, "/bad-reserved-", stages[i], ".a"),
reserved];
runcommandenv(root, strings.concat("reserved-local-import-", stages[i]),
av, traceenv, (60i64 * (time.second: i64)): time.duration, &out);
assert(out.termination == exec.termination.EXIT && out.code != 0);
assert(has(out.stderr, "package path __wwlocal.fake is reserved"));
reserveddiagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
i += 1;
};
assert(same(reserveddiagnostics[0], reserveddiagnostics[1]));
assert(readfile(tooltrace).len == 0);
clean(root);
};
@test fn platform_filename_source_selection() void = {
let root: str = fresh();
let source: str = strings.concat(root, "/source");
let app: str = strings.concat(source, "/app");
let good: str = strings.concat(source, "/dep/good");
let pkg: str = strings.concat(source, "/pkg");
let testgood: str = strings.concat(source, "/test/good");
let wrongonly: str = strings.concat(source, "/wrongonly");
let notests: str = strings.concat(source, "/notests");
let internal: str = strings.concat(source, "/foreign/internal/secret");
let command: str = strings.concat(source, "/command");
let vendored: str = strings.concat(app, "/vendor/vendored");
let order: str = strings.concat(root, "/order");
let tools: str = strings.concat(root, "/tools");
let foldfiles: str = strings.concat(root, "/foldfiles");
let foldunicode: str = strings.concat(foldfiles, "/unicode");
let foldinvalid: str = strings.concat(foldfiles, "/invalid");
let foldnonormal: str = strings.concat(foldfiles, "/nonormal");
let foldinternal: str = strings.concat(foldfiles, "/internal");
let foldexternal: str = strings.concat(foldfiles, "/external");
let foldsameonly: str = strings.concat(foldfiles, "/sameonly");
let foldexternalonly: str = strings.concat(foldfiles, "/externalonly");
let foldmixed: str = strings.concat(foldfiles, "/mixed");
let foldcross: str = strings.concat(foldfiles, "/cross");
let foldcreationroot: str = strings.concat(root, "/fold-creation-order");
let foldcreation: str = strings.concat(foldcreationroot, "/prod");
mkdirall(app); mkdirall(good); mkdirall(pkg); mkdirall(testgood);
mkdirall(wrongonly); mkdirall(notests); mkdirall(internal);
mkdirall(command); mkdirall(vendored); mkdirall(order); mkdirall(tools);
mkdirall(foldunicode); mkdirall(foldinvalid); mkdirall(foldnonormal);
mkdirall(foldinternal); mkdirall(foldexternal); mkdirall(foldsameonly);
mkdirall(foldexternalonly); mkdirall(foldmixed); mkdirall(foldcross);
mkdirall(foldcreation);
let good5: str = strings.concat("package good;\n",
"export fn value() i32 = { return 5; };\n");
let good6: str = strings.concat("package good;\n",
"export fn value() i32 = { return 6; };\n");
let good7: str = strings.concat("package good;\n",
"export fn value() i32 = { return 7; };\n");
let appmain: str = strings.concat(
"package main;\nimport dep.good;\n",
"fn main() i32 = { return good.value() + wholelinux() + ",
"afterdot() + arch() + reversed() + future() + osname() + pair(); };\n");
let wholelinux: str =
"package main;\nfn wholelinux() i32 = { return 1; };\n";
let afterdot: str =
"package main;\nfn afterdot() i32 = { return 1; };\n";
let arch: str =
"package main;\nfn arch() i32 = { return 1; };\n";
let reversed: str =
"package main;\nfn reversed() i32 = { return 1; };\n";
let future: str =
"package main;\nfn future() i32 = { return 1; };\n";
let osname: str = strings.concat(
"package main;\nimport _ dep.good;\n",
"fn osname() i32 = { return 1; };\n");
let pair: str =
"package main;\nfn pair() i32 = { return 1; };\n";
let ignoredparse: str =
"this wrong-target source is deliberately malformed\n";
let ignoredparseedit: str =
"a different malformed wrong-target edit {\n";
let ignoreddep: str = strings.concat(
"package main;\nimport dep.wrong;\n",
"fn wrong_dep() i32 = { return wrong.value(); };\n");
let ignoredinternal: str = strings.concat(
"package main;\nimport foreign.internal.secret;\n",
"fn wrong_internal() i32 = { return secret.value(); };\n");
let ignoredmain: str = strings.concat(
"package main;\nimport command;\n",
"fn wrong_main() i32 = { return 0; };\n");
let ignoredvendor: str = strings.concat(
"package main;\nimport vendored;\n",
"fn wrong_vendor() i32 = { return vendored.value(); };\n");
writefile(strings.concat(good, "/good.ww"), good5);
writefile(strings.concat(app, "/main.ww"), appmain);
writefile(strings.concat(app, "/linux.ww"), wholelinux);
writefile(strings.concat(app, "/platform.extra_windows.ww"), afterdot);
writefile(strings.concat(app, "/platform_amd64.ww"), arch);
writefile(strings.concat(app, "/platform_amd64_linux.ww"), reversed);
writefile(strings.concat(app, "/platform_future.ww"), future);
writefile(strings.concat(app, "/platform_linux.ww"), osname);
writefile(strings.concat(app, "/platform_linux_amd64.ww"), pair);
writefile(strings.concat(app, "/badparse_windows.ww"), ignoredparse);
writefile(strings.concat(app, "/baddep_arm64.ww"), ignoreddep);
writefile(strings.concat(app, "/badinternal_windows_amd64.ww"),
ignoredinternal);
writefile(strings.concat(app, "/badmain_linux_arm64.ww"), ignoredmain);
writefile(strings.concat(app, "/badvendor_windows.ww"), ignoredvendor);
writefile(strings.concat(app, "/.Fold.ww"), ignoredparse);
writefile(strings.concat(app, "/.fold.ww"), ignoredparseedit);
writefile(strings.concat(app, "/_Fold.ww"), ignoredparse);
writefile(strings.concat(app, "/_fold.ww"), ignoredparseedit);
writefile(strings.concat(app, "/Fold_windows.ww"), ignoredparse);
writefile(strings.concat(app, "/fold_windows.ww"), ignoredparseedit);
writefile(strings.concat(internal, "/secret.ww"), strings.concat(
"package secret;\n",
"export fn value() i32 = { return 19; };\n"));
writefile(strings.concat(command, "/main.ww"),
"package main;\nfn main() i32 = { return 0; };\n");
writefile(strings.concat(vendored, "/vendored.ww"), strings.concat(
"package vendored;\n",
"export fn value() i32 = { return 23; };\n"));
let pkgbase: str = strings.concat("package pkg;\n",
"export fn value() i32 = { return 7; };\n");
let samepair: str = strings.concat(
"package pkg;\nimport test.good;\n",
"@test fn selected_internal_pair() void = { ",
"assert(value() + good.value() == 18); };\n");
let samewhole: str = strings.concat(
"package pkg;\n",
"@test fn selected_whole_plan9_name() void = { assert(value() == 7); };\n");
let samereversed: str = strings.concat(
"package pkg;\n",
"@test fn selected_reversed_suffix() void = { assert(value() == 7); };\n");
let externalpair: str = strings.concat(
"package pkg_test;\nimport pkg;\nimport test.good;\n",
"@test fn selected_external_pair() void = { ",
"assert(pkg.value() + good.value() == 18); };\n");
let externaldot: str = strings.concat(
"package pkg_test;\nimport pkg;\n",
"@test fn selected_external_after_dot() void = { ",
"assert(pkg.value() == 7); };\n");
let wrongtest: str = strings.concat(
"package pkg;\nimport test.wrong;\n",
"@test fn wrong_target_test() void = { abort(\"wrong test ran\"); };\n");
let wrongtestedit: str =
"this edited wrong-target test remains deliberately malformed\n";
writefile(strings.concat(pkg, "/base.ww"), pkgbase);
writefile(strings.concat(pkg, "/internal_linux_amd64_test.ww"), samepair);
writefile(strings.concat(pkg, "/plan9_test.ww"), samewhole);
writefile(strings.concat(pkg, "/reverse_amd64_linux_test.ww"),
samereversed);
writefile(strings.concat(pkg, "/external_linux_amd64_test.ww"),
externalpair);
writefile(strings.concat(pkg, "/external.extra_windows_test.ww"),
externaldot);
writefile(strings.concat(pkg, "/internal_windows_amd64_test.ww"),
wrongtest);
writefile(strings.concat(pkg, "/external_linux_arm64_test.ww"),
wrongtest);
writefile(strings.concat(pkg, "/x_plan9_test.ww"), wrongtest);
writefile(strings.concat(testgood, "/good.ww"), strings.concat(
"package good;\n",
"export fn value() i32 = { return 11; };\n"));
writefile(strings.concat(wrongonly, "/only_windows.ww"), ignoredparse);
writefile(strings.concat(notests, "/base.ww"),
"package notests;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(notests, "/only_windows_test.ww"), ignoredparse);
writefile(strings.concat(pkg, "/.Fold_test.ww"), ignoredparse);
writefile(strings.concat(pkg, "/.fold_test.ww"), ignoredparseedit);
writefile(strings.concat(pkg, "/_Fold_test.ww"), ignoredparse);
writefile(strings.concat(pkg, "/_fold_test.ww"), ignoredparseedit);
writefile(strings.concat(pkg, "/Fold_windows_test.ww"), ignoredparse);
writefile(strings.concat(pkg, "/fold_windows_test.ww"), ignoredparseedit);
writefile(strings.concat(foldunicode, "/K.ww"),
"package main;\nfn latin() i32 = { return 1; };\n");
writefile(strings.concat(foldunicode, "/.ww"),
"package main;\nfn kelvin() i32 = { return 2; };\n");
writefile(strings.concat(foldunicode, "/main.ww"),
"package main;\nfn main() i32 = { return 0; };\n");
let invalidupperbytes: []u8 = alloc([], 6u64)!;
append(invalidupperbytes, 'A'); append(invalidupperbytes, '-');
append(invalidupperbytes, 255u8); append(invalidupperbytes, '.');
append(invalidupperbytes, 'w'); append(invalidupperbytes, 'w');
let invalidlowerbytes: []u8 = alloc([], 6u64)!;
append(invalidlowerbytes, 'a'); append(invalidlowerbytes, '-');
append(invalidlowerbytes, 254u8); append(invalidlowerbytes, '.');
append(invalidlowerbytes, 'w'); append(invalidlowerbytes, 'w');
writefile(strings.concat(foldinvalid, "/",
strings.frombytes(invalidupperbytes)),
"package main;\nfn invalidupper() i32 = { return 1; };\n");
writefile(strings.concat(foldinvalid, "/",
strings.frombytes(invalidlowerbytes)),
"package main;\nfn invalidlower() i32 = { return 2; };\n");
writefile(strings.concat(foldinvalid, "/main.ww"),
"package main;\nfn main() i32 = { return 0; };\n");
writefile(strings.concat(foldnonormal, "/É.ww"),
"package main;\nfn composed() i32 = { return 1; };\n");
writefile(strings.concat(foldnonormal, "/É.ww"),
"package main;\nfn decomposed() i32 = { return 2; };\n");
writefile(strings.concat(foldnonormal, "/main.ww"),
"package main;\nfn main() i32 = { return 0; };\n");
writefile(strings.concat(foldinternal, "/base.ww"),
"package sample;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(foldinternal, "/File_test.ww"),
"package sample;\n@test fn upper() void = { assert(true); };\n");
writefile(strings.concat(foldinternal, "/file_test.ww"),
"package sample;\n@test fn lower() void = { assert(true); };\n");
writefile(strings.concat(foldexternal, "/base.ww"),
"package sample;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(foldexternal, "/File_test.ww"),
"package sample_test;\n@test fn upper() void = { assert(true); };\n");
writefile(strings.concat(foldexternal, "/file_test.ww"),
"package sample_test;\n@test fn lower() void = { assert(true); };\n");
writefile(strings.concat(foldsameonly, "/File_test.ww"),
"package sample;\n@test fn upper() void = { assert(true); };\n");
writefile(strings.concat(foldsameonly, "/file_test.ww"),
"package sample;\n@test fn lower() void = { assert(true); };\n");
writefile(strings.concat(foldexternalonly, "/File_test.ww"),
"package sample_test;\n@test fn upper() void = { assert(true); };\n");
writefile(strings.concat(foldexternalonly, "/file_test.ww"),
"package sample_test;\n@test fn lower() void = { assert(true); };\n");
writefile(strings.concat(foldmixed, "/File_test.ww"),
"package sample;\n@test fn upper() void = { assert(true); };\n");
writefile(strings.concat(foldmixed, "/file_test.ww"),
"package sample_test;\n@test fn lower() void = { assert(true); };\n");
writefile(strings.concat(foldcross, "/X_TEST.ww"),
"package cross;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(foldcross, "/x_test.ww"),
"package cross;\n@test fn lower() void = { assert(value() == 1); };\n");
// The lower spelling is created first to prove getdents creation order is
// irrelevant to both direct and recursive collision diagnostics.
writefile(strings.concat(foldcreation, "/file.ww"),
"package main;\nfn lower() i32 = { return 1; };\n");
writefile(strings.concat(foldcreation, "/File.ww"), strings.concat(
"package main;\nfn upper() i32 = { return 2; };\n",
"fn main() i32 = { return 0; };\n"));
// Creation order is deliberately the inverse of byte order.
writefile(strings.concat(order, "/z_linux.ww"),
"package order;\n@test fn z() void = { };\n");
writefile(strings.concat(order, "/a_linux.ww"),
"package order;\n@test fn a() void = { };\n");
let compilerwrapper: str = strings.concat(tools, "/w6c.sh");
let assemblerwrapper: str = strings.concat(tools, "/w6a.sh");
let linkerwrapper: str = strings.concat(tools, "/w6l.sh");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_PLATFORM_COMPILER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_PLATFORM_COMPILER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_PLATFORM_COMPILER_TRACE\"\n",
"exec \"$WW_PLATFORM_REAL_COMPILER\" \"$@\"\n"));
writeexecutable(assemblerwrapper, strings.concat(
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_PLATFORM_ASSEMBLER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_PLATFORM_ASSEMBLER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_PLATFORM_ASSEMBLER_TRACE\"\n",
"exec \"$WW_PLATFORM_REAL_ASSEMBLER\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_PLATFORM_LINKER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_PLATFORM_LINKER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_PLATFORM_LINKER_TRACE\"\n",
"exec \"$WW_PLATFORM_REAL_LINKER\" \"$@\"\n"));
let stages: []str = ["ww", "ww_ww"];
let compilers: []str = ["w6c", "w6c_ww"];
let assemblers: []str = ["w6a", "w6a_ww"];
let linkers: []str = ["w6l", "w6l_ww"];
let labels: []str = ["c", "ww"];
let artifactnames: []str = ["app.unit.ww", "app.wwi", "app.s",
"app.o", "app.a", "app.init.unit.ww", "app.init.s", "app.init.o",
"dep.good.unit.ww", "dep.good.wwi", "dep.good.s", "dep.good.o",
"dep.good.a"];
let artifactrefs: []str = ["", "", "", "", "", "", "", "", "",
"", "", "", ""];
let testartifactnames: []str = ["pkg-internal-test.unit.ww",
"pkg-internal-test.wwi",
"pkg-internal-test.a", "pkg_test-external-test.unit.ww",
"pkg_test-external-test.wwi", "pkg_test-external-test.a",
"pkg-test-main.unit.ww", "pkg-test-main.wwi", "pkg-test-main.a"];
let testartifactrefs: []str = ["", "", "", "", "", "", "", "",
""];
let binref: str = "";
let compilerref: str = "";
let assemblerref: str = "";
let linkerref: str = "";
let prodarchiveref: str = "";
let prodwwiref: str = "";
let testoutref: str = "";
let testerrref: str = "";
let faildiagref: str = "";
let recursiveoutref: str = "";
let recursiveerrref: str = "";
let foldfilerefs: []str = ["", "", "", "", "", "", "", ""];
let crossref: str = "";
let nonormalref: str = "";
let nonormalunitref: str = "";
let foldcreationref: str = "";
let foldcreationrecursiveref: str = "";
let baseenv: []str = os.getenvs();
let si: i32 = 0;
for (si < stages.len) {
rewritefile(strings.concat(good, "/good.ww"), good5);
rewritefile(strings.concat(app, "/platform_future.ww"), future);
rewritefile(strings.concat(app, "/badparse_windows.ww"), ignoredparse);
rewritefile(strings.concat(pkg, "/internal_windows_amd64_test.ww"),
wrongtest);
let work: str = strings.concat(root, "/", labels[si], "-work");
let reversework: str = strings.concat(root, "/", labels[si],
"-reverse-work");
let outdir: str = strings.concat(root, "/", labels[si], "-out");
let reverseout: str = strings.concat(root, "/", labels[si],
"-reverse-out");
let compilertrace: str = strings.concat(root, "/", labels[si],
"-compiler");
let assemblertrace: str = strings.concat(root, "/", labels[si],
"-assembler");
let linkertrace: str = strings.concat(root, "/", labels[si],
"-linker");
assert(os.mkdir(work, 448i32) == 0);
assert(os.mkdir(reversework, 448i32) == 0);
assert(os.mkdir(outdir, 448i32) == 0);
assert(os.mkdir(reverseout, 448i32) == 0);
writefile(compilertrace, ""); writefile(assemblertrace, "");
writefile(linkertrace, "");
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_PLATFORM_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_PLATFORM_ASSEMBLER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_PLATFORM_LINKER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_PLATFORM_REAL_COMPILER=")
&& !strings.hasprefix(baseenv[ei],
"WW_PLATFORM_REAL_ASSEMBLER=")
&& !strings.hasprefix(baseenv[ei],
"WW_PLATFORM_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_PLATFORM_COMPILER_TRACE=", compilertrace));
append(env, strings.concat("WW_PLATFORM_ASSEMBLER_TRACE=", assemblertrace));
append(env, strings.concat("WW_PLATFORM_LINKER_TRACE=", linkertrace));
append(env, strings.concat("WW_PLATFORM_REAL_COMPILER=",
driver(compilers[si])));
append(env, strings.concat("WW_PLATFORM_REAL_ASSEMBLER=",
driver(assemblers[si])));
append(env, strings.concat("WW_PLATFORM_REAL_LINKER=",
driver(linkers[si])));
let forward: []str = [driver(stages[si]), "build", "-w", work,
"-I", source, "-o", strings.concat(outdir, "/"), app, good];
let reverse: []str = [driver(stages[si]), "build", "-w", reversework,
"-I", source, "-o", strings.concat(reverseout, "/"), good, app];
let out: commandout;
runcommandenv(root, strings.concat("platform-cold-", labels[si]),
forward, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let ctrace: str = readfile(compilertrace);
let atrace: str = readfile(assemblertrace);
let ltrace: str = readfile(linkertrace);
assert(occurrences(ctrace, "\n") == 2);
assert(occurrences(atrace, "\n") == 3);
assert(occurrences(ltrace, "\n") == 1);
let appline: str = linecontaining(ctrace, "/app.unit.new");
assert(occurrences(appline, "<--import><dep.good>") == 1);
assert(occurrences(appline, "/dep.good.wwi.new>") == 1);
assert(!has(ctrace, "dep.wrong"));
assert(!has(ctrace, "foreign.internal.secret"));
assert(!has(ctrace, "vendored"));
assert(!has(ctrace, "command.wwi"));
assert(occurrences(ltrace, strings.concat(work, "/app.a.new")) == 1);
assert(occurrences(ltrace, strings.concat(work,
"/dep.good.a.new")) == 1);
assert(!has(ltrace, ".wwi"));
assert(!has(ltrace, "dep.wrong"));
let unitprefix: str = strings.concat(
"//ww:module-reset app\n", wholelinux, "\n",
"//ww:module-reset app\n", appmain, "\n",
"//ww:module-reset app\n", afterdot, "\n",
"//ww:module-reset app\n", arch, "\n",
"//ww:module-reset app\n", reversed, "\n",
"//ww:module-reset app\n", future, "\n",
"//ww:module-reset app\n", osname, "\n",
"//ww:module-reset app\n", pair, "\n");
let appunit: str = readfile(strings.concat(work, "/app.unit.ww"));
assert(strings.hasprefix(appunit, unitprefix));
assert(has(appunit, "//ww:direct-export dep.good "));
assert(!has(appunit, "wrong_dep"));
assert(!has(appunit, "wrong_internal"));
assert(!has(appunit, "wrong_main"));
assert(!has(appunit, "wrong_vendor"));
assert(!os.exists(strings.concat(work, "/dep.wrong.unit.ww")));
let bin: str = strings.concat(outdir, "/app");
let runav: []str = [bin];
runcommand(root, strings.concat("platform-run-", labels[si]), runav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 12);
let ai: i32 = 0;
for (ai < artifactnames.len) {
let bytes: str = readfile(strings.concat(work, "/",
artifactnames[ai]));
if (si == 0) { artifactrefs[ai] = strings.dup(bytes); }
else { assert(same(artifactrefs[ai], bytes)); };
ai += 1;
};
let normalizedcompiler: str = normalizedtrace(ctrace,
strings.concat(work, "/"), outdir);
let normalizedassembler: str = normalizedtrace(atrace,
strings.concat(work, "/"), outdir);
let normalizedlinker: str = normalizedtrace(ltrace,
strings.concat(work, "/"), outdir);
if (si == 0) {
compilerref = strings.dup(normalizedcompiler);
assemblerref = strings.dup(normalizedassembler);
linkerref = strings.dup(normalizedlinker);
binref = strings.dup(readfile(bin));
} else {
assert(same(compilerref, normalizedcompiler));
assert(same(assemblerref, normalizedassembler));
assert(same(linkerref, normalizedlinker));
assert(same(binref, readfile(bin)));
};
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
runcommandenv(root, strings.concat("platform-reverse-", labels[si]),
reverse, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(readfile(bin), readfile(strings.concat(reverseout, "/app"))));
assert(same(normalizedcompiler, normalizedtrace(readfile(compilertrace),
strings.concat(reversework, "/"), reverseout)));
assert(same(normalizedassembler, normalizedtrace(readfile(assemblertrace),
strings.concat(reversework, "/"), reverseout)));
assert(same(normalizedlinker, normalizedtrace(readfile(linkertrace),
strings.concat(reversework, "/"), reverseout)));
ai = 0;
for (ai < artifactnames.len) {
assert(same(readfile(strings.concat(work, "/", artifactnames[ai])),
readfile(strings.concat(reversework, "/", artifactnames[ai]))));
ai += 1;
};
let stableunit: str = strings.dup(readfile(strings.concat(work,
"/app.unit.ww")));
let stablewwi: str = strings.dup(readfile(strings.concat(work,
"/app.wwi")));
let stablearchive: str = strings.dup(readfile(strings.concat(work,
"/app.a")));
let stabledepwwi: str = strings.dup(readfile(strings.concat(work,
"/dep.good.wwi")));
let stablebin: str = strings.dup(readfile(bin));
let stablestamp: str = strings.dup(readfile(strings.concat(work,
"/.wwtool.stamp")));
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
runcommandenv(root, strings.concat("platform-warm-", labels[si]),
forward, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(readfile(compilertrace).len == 0);
assert(readfile(assemblertrace).len == 0);
assert(occurrences(readfile(linkertrace), "\n") == 1);
rewritefile(strings.concat(app, "/badparse_windows.ww"),
ignoredparseedit);
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
runcommandenv(root, strings.concat("platform-ignored-edit-", labels[si]),
forward, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(readfile(compilertrace).len == 0);
assert(readfile(assemblertrace).len == 0);
assert(occurrences(readfile(linkertrace), "\n") == 1);
assert(same(stableunit, readfile(strings.concat(work, "/app.unit.ww"))));
assert(same(stablewwi, readfile(strings.concat(work, "/app.wwi"))));
assert(same(stablearchive, readfile(strings.concat(work, "/app.a"))));
assert(same(stabledepwwi, readfile(strings.concat(work,
"/dep.good.wwi"))));
assert(same(stablebin, readfile(bin)));
assert(same(stablestamp, readfile(strings.concat(work,
"/.wwtool.stamp"))));
rewritefile(strings.concat(good, "/good.ww"), good6);
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
runcommandenv(root, strings.concat("platform-private-edit-", labels[si]),
forward, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(readfile(compilertrace), "\n") == 1);
assert(has(readfile(compilertrace), "/dep.good.unit.new"));
assert(!has(readfile(compilertrace), "/app.unit.new"));
assert(occurrences(readfile(assemblertrace), "\n") == 1);
assert(occurrences(readfile(linkertrace), "\n") == 1);
assert(same(stabledepwwi, readfile(strings.concat(work,
"/dep.good.wwi"))));
assert(same(stableunit, readfile(strings.concat(work, "/app.unit.ww"))));
assert(same(stablewwi, readfile(strings.concat(work, "/app.wwi"))));
assert(same(stablearchive, readfile(strings.concat(work, "/app.a"))));
assert(!same(stablebin, readfile(bin)));
let runchanged: []str = [bin];
runcommand(root, strings.concat("platform-run-edited-", labels[si]),
runchanged, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 13);
let committeddepunit: str = strings.dup(readfile(strings.concat(work,
"/dep.good.unit.ww")));
let committeddepa: str = strings.dup(readfile(strings.concat(work,
"/dep.good.a")));
let committedbin: str = strings.dup(readfile(bin));
rewritefile(strings.concat(good, "/good.ww"), good7);
rewritefile(strings.concat(app, "/platform_future.ww"),
"package main;\nfn future() i32 = { return missing_name; };\n");
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
runcommandenv(root, strings.concat("platform-late-failure-", labels[si]),
forward, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "undefined: missing_name"));
let normalizedfailure: str = normalizedtrace(out.stderr,
strings.concat(work, "/"), bin);
if (si == 0) { faildiagref = strings.dup(normalizedfailure); }
else { assert(same(faildiagref, normalizedfailure)); };
assert(occurrences(readfile(compilertrace), "\n") == 2);
assert(occurrences(readfile(assemblertrace), "\n") == 1);
assert(readfile(linkertrace).len == 0);
assert(same(committeddepunit, readfile(strings.concat(work,
"/dep.good.unit.ww"))));
assert(same(committeddepa, readfile(strings.concat(work,
"/dep.good.a"))));
assert(same(committedbin, readfile(bin)));
assert(same(stablestamp, readfile(strings.concat(work,
"/.wwtool.stamp"))));
assert(!os.exists(strings.concat(work, "/dep.good.unit.new")));
assert(!os.exists(strings.concat(work, "/dep.good.wwi.new")));
assert(!os.exists(strings.concat(work, "/dep.good.a.new")));
assert(!os.exists(strings.concat(work, "/app.unit.new")));
assert(!os.exists(strings.concat(work, "/app.wwi.new")));
assert(!os.exists(strings.concat(work, "/app.a.new")));
rewritefile(strings.concat(good, "/good.ww"), good6);
rewritefile(strings.concat(app, "/platform_future.ww"), future);
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
runcommandenv(root, strings.concat("platform-restored-", labels[si]),
forward, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(readfile(compilertrace).len == 0);
assert(readfile(assemblertrace).len == 0);
assert(occurrences(readfile(linkertrace), "\n") == 1);
assert(same(committedbin, readfile(bin)));
rewritefile(strings.concat(good, "/good.ww"), good5);
rewritefile(strings.concat(app, "/badparse_windows.ww"), ignoredparse);
let prodwork: str = strings.concat(root, "/", labels[si], "-prod-work");
let prodout: str = strings.concat(root, "/", labels[si], "-pkg.a");
assert(os.mkdir(prodwork, 448i32) == 0);
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
let prodav: []str = [driver(stages[si]), "build", "-w", prodwork,
"-I", source, "-o", prodout, pkg];
runcommandenv(root, strings.concat("platform-production-", labels[si]),
prodav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(readfile(compilertrace), "\n") == 1);
assert(!has(readfile(compilertrace), "test.good"));
assert(!has(readfile(strings.concat(prodwork, "/pkg.unit.ww")),
"selected_internal"));
if (si == 0) {
prodarchiveref = strings.dup(readfile(prodout));
prodwwiref = strings.dup(readfile(strings.concat(prodout, ".wwi")));
} else {
assert(same(prodarchiveref, readfile(prodout)));
assert(same(prodwwiref, readfile(strings.concat(prodout, ".wwi"))));
};
let testwork: str = strings.concat(root, "/", labels[si], "-test-work");
assert(os.mkdir(testwork, 448i32) == 0);
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
let testav: []str = [driver(stages[si]), "test", "-w", testwork,
"-I", source, pkg];
runcommandenv(root, strings.concat("platform-test-", labels[si]), testav,
env, (180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "selected_internal_pair ... ok\n"));
assert(has(out.stdout, "selected_whole_plan9_name ... ok\n"));
assert(has(out.stdout, "selected_reversed_suffix ... ok\n"));
assert(has(out.stdout, "selected_external_pair ... ok\n"));
assert(has(out.stdout, "selected_external_after_dot ... ok\n"));
assert(!has(out.stdout, "wrong_target_test"));
assert(!has(out.stderr, "wrong-target"));
let testctrace: str = readfile(compilertrace);
let testltrace: str = readfile(linkertrace);
assert(!has(testctrace, "test.wrong"));
let sameline: str = linecontaining(testctrace,
"/pkg-internal-test.unit.new");
let externalline: str = linecontaining(testctrace,
"/pkg_test-external-test.unit.new");
assert(occurrences(sameline, "<--import><test.good>") == 1);
assert(occurrences(externalline, "<--import><pkg>") == 1);
assert(occurrences(externalline, "<--import><test.good>") == 1);
assert(has(externalline, strings.concat("<--import><pkg><", testwork,
"/pkg-internal-test.wwi.new>")));
let mainline: str = linecontaining(testctrace,
"/pkg-test-main.unit.new");
assert(occurrences(mainline, "<--test-target-package>") == 2);
assert(pos(mainline, "<--test-target-package><pkg>")
< pos(mainline, "<--test-target-package><pkg_test>"));
assert(occurrences(testltrace, "\n") == 1);
assert(has(testltrace, "/pkg-test-main.a.new>"));
assert(has(testltrace, "/pkg-internal-test.a.new>"));
assert(has(testltrace, "/pkg_test-external-test.a.new>"));
assert(!has(testltrace, ".wwi"));
assert(!os.exists(strings.concat(testwork, "/pkg.unit.ww")));
let sameunit: str = readfile(strings.concat(testwork,
"/pkg-internal-test.unit.ww"));
let externalunit: str = readfile(strings.concat(testwork,
"/pkg_test-external-test.unit.ww"));
assert(has(sameunit, "selected_internal_pair"));
assert(has(sameunit, "selected_whole_plan9_name"));
assert(has(sameunit, "selected_reversed_suffix"));
assert(!has(sameunit, "wrong_target_test"));
assert(has(externalunit, "selected_external_pair"));
assert(has(externalunit, "selected_external_after_dot"));
assert(!has(externalunit, "wrong_target_test"));
ai = 0;
for (ai < testartifactnames.len) {
let bytes: str = readfile(strings.concat(testwork, "/",
testartifactnames[ai]));
if (si == 0) { testartifactrefs[ai] = strings.dup(bytes); }
else { assert(same(testartifactrefs[ai], bytes)); };
ai += 1;
};
if (si == 0) {
testoutref = strings.dup(out.stdout);
testerrref = strings.dup(out.stderr);
} else {
assert(same(testoutref, out.stdout));
assert(same(testerrref, out.stderr));
};
let stabletestunit: str = strings.dup(sameunit);
rewritefile(strings.concat(pkg, "/internal_windows_amd64_test.ww"),
wrongtestedit);
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
runcommandenv(root, strings.concat("platform-test-warm-", labels[si]),
testav, env, (180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(testoutref, out.stdout));
assert(readfile(compilertrace).len == 0);
assert(readfile(assemblertrace).len == 0);
assert(occurrences(readfile(linkertrace), "\n") == 1);
assert(same(stabletestunit, readfile(strings.concat(testwork,
"/pkg-internal-test.unit.ww"))));
rewritefile(strings.concat(pkg, "/internal_windows_amd64_test.ww"),
wrongtest);
let onlywork: str = strings.concat(root, "/", labels[si], "-only-work");
let onlyout: str = strings.concat(root, "/", labels[si], "-only-bin");
assert(os.mkdir(onlywork, 448i32) == 0);
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
let onlyav: []str = [driver(stages[si]), "build", "-w", onlywork,
"-o", onlyout, wrongonly];
runcommandenv(root, strings.concat("platform-only-", labels[si]), onlyav,
env, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(same(out.stderr, strings.concat("ww: ", wrongonly,
": directory contains no WW package sources\n")));
assert(readfile(compilertrace).len == 0);
assert(readfile(assemblertrace).len == 0);
assert(readfile(linkertrace).len == 0);
assert(!os.exists(onlyout));
assert(!os.exists(strings.concat(onlywork, "/.wwtool.stamp")));
let orderwork: str = strings.concat(root, "/", labels[si],
"-order-work");
assert(os.mkdir(orderwork, 448i32) == 0);
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
let orderav: []str = [driver(stages[si]), "build", "-w", orderwork,
"-o", strings.concat(root, "/", labels[si], "-order.a"), order];
runcommandenv(root, strings.concat("platform-order-", labels[si]),
orderav, env, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(same(out.stderr, strings.concat("ww: ", order,
"/a_linux.ww: @test declaration outside *_test.ww\n")));
assert(readfile(compilertrace).len == 0);
assert(readfile(assemblertrace).len == 0);
assert(readfile(linkertrace).len == 0);
assert(!os.exists(strings.concat(orderwork, "/.wwtool.stamp")));
let recursivework: str = strings.concat(root, "/", labels[si],
"-recursive-work");
let recursiveout: str = strings.concat(root, "/", labels[si],
"-recursive-out");
assert(os.mkdir(recursivework, 448i32) == 0);
assert(os.mkdir(recursiveout, 448i32) == 0);
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
let recursiveav: []str = [driver(stages[si]), "build", "-w",
recursivework, "-I", source, "-o", strings.concat(recursiveout,
"/"), strings.concat(source, "/...")];
runcommandenv(root, strings.concat("platform-recursive-build-",
labels[si]), recursiveav, env,
(180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(!has(readfile(compilertrace), "wrongonly"));
assert(!has(readfile(compilertrace), "dep.wrong"));
let recbin: str = strings.concat(recursiveout, "/app");
let recrun: []str = [recbin];
runcommand(root, strings.concat("platform-recursive-run-", labels[si]),
recrun, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 12);
assert(same(binref, readfile(recbin)));
let recursivetestwork: str = strings.concat(root, "/", labels[si],
"-recursive-test-work");
assert(os.mkdir(recursivetestwork, 448i32) == 0);
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
let recursivetestav: []str = [driver(stages[si]), "test", "-w",
recursivetestwork, "-I", source, strings.concat(source, "/...")];
runcommandenv(root, strings.concat("platform-recursive-test-",
labels[si]), recursivetestav, env,
(240i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "selected_internal_pair ... ok\n"));
assert(has(out.stdout, "selected_external_pair ... ok\n"));
assert(has(out.stdout, strings.concat("? ", notests,
" [no tests]\n")));
assert(!has(out.stdout, "wrong_target_test"));
assert(!has(out.stderr, "only_windows"));
assert(!has(readfile(compilertrace), "dep.wrong"));
if (si == 0) {
recursiveoutref = strings.dup(out.stdout);
recursiveerrref = strings.dup(out.stderr);
} else {
assert(same(recursiveoutref, out.stdout));
assert(same(recursiveerrref, out.stderr));
};
// An upper-case TEST suffix is production source, while its lower-case
// twin is test source. Ordinary build stays isolated; test selects both
// categories into one directory-owned filename-collision scope.
let crosswork: str = strings.concat(root, "/", labels[si],
"-fold-cross-build-work");
let crossout: str = strings.concat(root, "/", labels[si],
"-fold-cross.a");
assert(os.mkdir(crosswork, 448i32) == 0);
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
let crossbuildav: []str = [driver(stages[si]), "build", "-w",
crosswork, "-I", foldfiles, "-o", crossout, foldcross];
runcommandenv(root, strings.concat("fold-cross-build-", labels[si]),
crossbuildav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(!has(readfile(strings.concat(crosswork, "/cross.unit.ww")),
"@test fn lower"));
if (si == 0) { crossref = strings.dup(readfile(crossout)); }
else { assert(same(crossref, readfile(crossout))); };
let foldtargets: []str = [foldunicode, foldinvalid, foldinternal,
foldexternal, foldsameonly, foldexternalonly, foldmixed, foldcross];
let foldmodes: []str = ["build", "build", "test", "test", "test",
"test", "test", "test"];
let foldpackages: []str = ["", "", "sample", "sample", "sample",
"sample", "sample", "cross"];
let foldlabels: []str = ["unicode", "invalid", "internal", "external",
"same-only", "external-only", "mixed", "cross"];
let foldwants: []str = [
"ww: case-insensitive file name collision: \"K.ww\" and \".ww\"\n",
"ww: case-insensitive file name collision: \"A-\\xff.ww\" and \"a-\\xfe.ww\"\n",
"ww: case-insensitive file name collision: \"File_test.ww\" and \"file_test.ww\"\n",
"ww: case-insensitive file name collision: \"File_test.ww\" and \"file_test.ww\"\n",
"ww: case-insensitive file name collision: \"File_test.ww\" and \"file_test.ww\"\n",
"ww: case-insensitive file name collision: \"File_test.ww\" and \"file_test.ww\"\n",
"ww: case-insensitive file name collision: \"File_test.ww\" and \"file_test.ww\"\n",
"ww: case-insensitive file name collision: \"X_TEST.ww\" and \"x_test.ww\"\n",
];
let fi: i32 = 0;
for (fi < foldtargets.len) {
let foldwork: str = strings.concat(root, "/", labels[si],
"-fold-", foldlabels[fi], "-work");
let foldoutput: str = strings.concat(root, "/", labels[si],
"-fold-", foldlabels[fi]);
assert(os.mkdir(foldwork, 448i32) == 0);
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
let foldbuildav: []str = [driver(stages[si]), "build", "-w",
foldwork, "-I", foldfiles, "-o", foldoutput, foldtargets[fi]];
let foldtestav: []str = [driver(stages[si]), "test", "-w",
foldwork, "-I", foldfiles, foldtargets[fi]];
let foldav: []str = foldtestav;
if (same(foldmodes[fi], "build")) { foldav = foldbuildav; };
runcommandenv(root, strings.concat("filename-fold-", labels[si],
"-", foldlabels[fi]), foldav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let foldfullwant: str = foldwants[fi];
if (same(foldmodes[fi], "test")) {
foldfullwant = strings.concat(foldwants[fi], "FAIL ",
foldtargets[fi], " [", foldpackages[fi],
"] (build exit 1)\n");
};
assert(out.stdout.len == 0 && same(out.stderr, foldfullwant));
assert(readfile(compilertrace).len == 0);
assert(readfile(assemblertrace).len == 0);
assert(readfile(linkertrace).len == 0);
assert(!os.exists(foldoutput));
assert(!os.exists(strings.concat(foldoutput, ".new")));
assert(!os.exists(strings.concat(foldoutput, ".sepwork")));
assert(!os.exists(strings.concat(foldwork, "/.wwtool.stamp")));
assert(directoryisempty(foldwork));
if (si == 0) { foldfilerefs[fi] = strings.dup(out.stderr); }
else { assert(same(foldfilerefs[fi], out.stderr)); };
fi += 1;
};
let creationmodes: []str = ["direct", "recursive"];
let creationfull: []str = ["", ""];
let creationwant: str =
"ww: case-insensitive file name collision: \"File.ww\" and \"file.ww\"\n";
let ci: i32 = 0;
for (ci < creationmodes.len) {
let creationwork: str = strings.concat(root, "/", labels[si],
"-fold-creation-", creationmodes[ci], "-work");
let creationout: str = strings.concat(root, "/", labels[si],
"-fold-creation-", creationmodes[ci]);
assert(os.mkdir(creationwork, 448i32) == 0);
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
let directav: []str = [driver(stages[si]), "build", "-w",
creationwork, "-I", foldcreationroot, "-o", creationout,
foldcreation];
if (ci != 0) { assert(os.mkdir(creationout, 448i32) == 0); };
let recursiveav: []str = [driver(stages[si]), "build", "-w",
creationwork, "-I", foldcreationroot, "-o",
strings.concat(creationout, "/"),
strings.concat(foldcreationroot, "/...")];
let creationav: []str = directav;
if (ci != 0) { creationav = recursiveav; };
runcommandenv(root, strings.concat("filename-fold-creation-",
labels[si], "-", creationmodes[ci]), creationav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0);
let creationfullwant: str = creationwant;
if (ci != 0) {
creationfullwant = strings.concat(creationwant, "FAIL ",
foldcreation, " [main] (build exit 1)\n");
};
assert(same(out.stderr, creationfullwant));
assert(readfile(compilertrace).len == 0);
assert(readfile(assemblertrace).len == 0);
assert(readfile(linkertrace).len == 0);
if (ci == 0) { assert(!os.exists(creationout)); }
else { assert(directoryisempty(creationout)); };
assert(!os.exists(strings.concat(creationout, ".new")));
assert(!os.exists(strings.concat(creationout, ".sepwork")));
assert(directoryisempty(creationwork));
creationfull[ci] = strings.dup(out.stderr);
ci += 1;
};
if (si == 0) {
foldcreationref = strings.dup(creationfull[0]);
foldcreationrecursiveref = strings.dup(creationfull[1]);
} else {
assert(same(foldcreationref, creationfull[0]));
assert(same(foldcreationrecursiveref, creationfull[1]));
};
// Canonically equivalent Unicode normalization forms remain distinct.
let nonormalwork: str = strings.concat(root, "/", labels[si],
"-fold-nonormal-work");
let nonormalout: str = strings.concat(root, "/", labels[si],
"-fold-nonormal");
assert(os.mkdir(nonormalwork, 448i32) == 0);
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
let nonormalav: []str = [driver(stages[si]), "build", "-w",
nonormalwork, "-I", foldfiles, "-o", nonormalout, foldnonormal];
runcommandenv(root, strings.concat("filename-no-normalization-",
labels[si]), nonormalav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let nonormalunit: str = readfile(strings.concat(nonormalwork,
"/nonormal.unit.ww"));
assert(has(nonormalunit, "fn composed() i32"));
assert(has(nonormalunit, "fn decomposed() i32"));
if (si == 0) { nonormalref = strings.dup(readfile(nonormalout)); }
else { assert(same(nonormalref, readfile(nonormalout))); };
if (si == 0) { nonormalunitref = strings.dup(nonormalunit); }
else { assert(same(nonormalunitref, nonormalunit)); };
// A collision introduced after a committed generation is pre-tool and
// cannot mutate any successful action, stamp, or published output. Its
// removal restores exact warm reuse (only the normal relink remains).
let warmname: str = strings.concat("warm", labels[si]);
let warmdir: str = strings.concat(foldfiles, "/", warmname);
mkdirall(warmdir);
writefile(strings.concat(warmdir, "/File.ww"), strings.concat(
"package main;\nfn upper() i32 = { return 1; };\n"));
writefile(strings.concat(warmdir, "/main.ww"), strings.concat(
"package main;\nfn main() i32 = { return upper() - 1; };\n"));
let warmwork: str = strings.concat(root, "/", labels[si],
"-fold-warm-work");
let warmout: str = strings.concat(root, "/", labels[si],
"-fold-warm");
assert(os.mkdir(warmwork, 448i32) == 0);
let warmav: []str = [driver(stages[si]), "build", "-w", warmwork,
"-I", foldfiles, "-o", warmout, warmdir];
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
runcommandenv(root, strings.concat("filename-fold-warm-cold-",
labels[si]), warmav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let warmsuffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a",
".init.unit.ww", ".init.s", ".init.o"];
let warmrefs: []str = ["", "", "", "", "", "", "", ""];
let wi: i32 = 0;
for (wi < warmsuffixes.len) {
warmrefs[wi] = strings.dup(readfile(strings.concat(warmwork, "/",
warmname, warmsuffixes[wi])));
wi += 1;
};
let warmbinref: str = strings.dup(readfile(warmout));
let warmstampref: str = strings.dup(readfile(strings.concat(warmwork,
"/.wwtool.stamp")));
let warmtoolpaths: []str = ["/.wwtool.ww", "/.wwtool.w6c",
"/.wwtool.w6a"];
let warmtoolrefs: []str = alloc([], warmtoolpaths.len: u64)!;
wi = 0;
for (wi < warmtoolpaths.len) {
append(warmtoolrefs, strings.dup(readfile(strings.concat(warmwork,
warmtoolpaths[wi]))));
wi += 1;
};
let collidingfile: str = strings.concat(warmdir, "/file.ww");
writefile(collidingfile,
"package main;\nfn lower() i32 = { return 2; };\n");
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
runcommandenv(root, strings.concat("filename-fold-warm-added-",
labels[si]), warmav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && same(out.stderr,
"ww: case-insensitive file name collision: \"File.ww\" and \"file.ww\"\n"));
assert(readfile(compilertrace).len == 0);
assert(readfile(assemblertrace).len == 0);
assert(readfile(linkertrace).len == 0);
wi = 0;
for (wi < warmsuffixes.len) {
assert(same(warmrefs[wi], readfile(strings.concat(warmwork, "/",
warmname, warmsuffixes[wi]))));
wi += 1;
};
wi = 0;
for (wi < warmtoolpaths.len) {
assert(same(warmtoolrefs[wi], readfile(strings.concat(warmwork,
warmtoolpaths[wi]))));
wi += 1;
};
assert(!directoryhasnew(warmwork));
assert(same(warmbinref, readfile(warmout)));
assert(!os.exists(strings.concat(warmout, ".new")));
assert(!os.exists(strings.concat(warmout, ".sepwork")));
assert(same(warmstampref, readfile(strings.concat(warmwork,
"/.wwtool.stamp"))));
assert(os.remove(collidingfile) == 0);
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
rewritefile(linkertrace, "");
runcommandenv(root, strings.concat("filename-fold-warm-removed-",
labels[si]), warmav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(readfile(compilertrace).len == 0);
assert(readfile(assemblertrace).len == 0);
assert(occurrences(readfile(linkertrace), "\n") == 1);
wi = 0;
for (wi < warmsuffixes.len) {
assert(same(warmrefs[wi], readfile(strings.concat(warmwork, "/",
warmname, warmsuffixes[wi]))));
wi += 1;
};
wi = 0;
for (wi < warmtoolpaths.len) {
assert(same(warmtoolrefs[wi], readfile(strings.concat(warmwork,
warmtoolpaths[wi]))));
wi += 1;
};
assert(!directoryhasnew(warmwork));
assert(same(warmbinref, readfile(warmout)));
assert(!os.exists(strings.concat(warmout, ".new")));
assert(!os.exists(strings.concat(warmout, ".sepwork")));
assert(same(warmstampref, readfile(strings.concat(warmwork,
"/.wwtool.stamp"))));
si += 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 local-pattern parity: "..." walks below the prefix preceding its first
// occurrence. Dot-, underscore-, and testdata-prefixed trees are excluded;
// vendor is traversed but a wildcard cannot consume a non-terminal vendor.
// Excluded sentinels fail so a wrong descent turns the whole run red.
@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, "/app"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/app/vendor"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/app/vendor/lib"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/app/vendor/lib/math"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/domain"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/domain/app"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/domain/vendor"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/domain/vendor/dep"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/.hidden"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/.hidden/deep"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/_skip"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/testdata"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/testdata/bad"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/vendor"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/vendor/bad"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/vendor/bad/vendor"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/vendor/bad/vendor/deep"), 448i32) == 0);
assert(os.mkdir(strings.concat(tree, "/vendorx"), 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"),
strings.concat("package alpha_test;\nimport alpha;\n",
"@test fn treealpha() void = { assert(alpha.value() == 7);",
" assert(alpha.linked() == 11); };\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, "/app/app.ww"), strings.concat(
"package app;\nimport lib.math;\n",
"export fn value() int = { return math.value(); };\n"));
writefile(strings.concat(tree, "/app/app_test.ww"), strings.concat(
"package app;\n@test fn vendored_dependency() void = {",
" assert(value() == 17); };\n"));
writefile(strings.concat(tree, "/app/vendor/lib/math/math.ww"),
"package math;\nexport fn value() int = { return 17; };\n");
writefile(strings.concat(tree, "/domain/app/app.ww"), strings.concat(
"package app;\nimport dep;\n",
"fn value() int = { return dep.value(); };\n"));
writefile(strings.concat(tree, "/domain/app/app_test.ww"), strings.concat(
"package app;\n@test fn ancestor_vendor() void = {",
" assert(value() == 29); };\n"));
writefile(strings.concat(tree, "/domain/vendor/dep/dep.ww"),
"package dep;\nexport fn value() int = { return 29; };\n");
writefile(strings.concat(tree, "/gamma/.ignored.ww"),
"this hidden source must not make package loading fail\n");
writefile(strings.concat(tree, "/gamma/_ignored.ww"),
"this underscore source must not make package loading fail\n");
writefile(strings.concat(tree, "/.hidden/hid_test.ww"),
"package hid;\n@test fn hidden_direct() void = { assert(true); };\n");
writefile(strings.concat(tree, "/.hidden/deep/bad.ww"),
"this excluded malformed directory must not be selected\n");
writefile(strings.concat(tree, "/_skip/skip_test.ww"),
"package _skip;\n@test fn underscore_direct() void = { assert(true); };\n");
writefile(strings.concat(tree, "/testdata/bad/bad_test.ww"),
"package bad;\n@test fn testdata_direct() void = { assert(true); };\n");
writefile(strings.concat(tree, "/vendor/vendor.ww"),
"package vendor;\nexport fn value() int = { return 1; };\n");
writefile(strings.concat(tree, "/vendor/bad/bad.ww"),
"package bad;\nexport fn value() int = { return 2; };\n");
writefile(strings.concat(tree, "/vendor/bad/bad_test.ww"),
"package bad;\n@test fn explicit_vendor() void = { assert(value() == 2); };\n");
writefile(strings.concat(tree, "/vendor/bad/vendor/deep/deep_test.ww"),
"package deep;\n@test fn nested_vendor_must_not_run() void = { assert(false); };\n");
writefile(strings.concat(tree, "/vendorx/vendorx.ww"),
"package vendorx;\nexport fn value() int = { return 3; };\n");
let outside: str = strings.concat(root, "/outside");
let alias: str = strings.concat(root, "/tree-alias");
assert(os.mkdir(outside, 448i32) == 0);
writefile(strings.concat(outside, "/outside.ww"),
"package outside;\nexport fn value() int = { return 23; };\n");
writefile(strings.concat(outside, "/outside_test.ww"), strings.concat(
"package outside;\n@test fn explicit_root_symlink() void = {",
" assert(value() == 23); };\n"));
let linkout: commandout;
let linkedsource: str = strings.concat(root, "/alpha-linked-source");
writefile(linkedsource,
"package alpha;\nexport fn linked() int = { return 11; };\n");
let linkedav: []str = ["/bin/ln", "-s", linkedsource,
strings.concat(tree, "/alpha/linked.ww")];
runcommand(root, "recursive-source-link", linkedav, time.second, &linkout);
expectexit(&linkout, 0);
let linkeddirectory: str = strings.concat(root, "/source-directory");
assert(os.mkdir(linkeddirectory, 448i32) == 0);
let linkeddirav: []str = ["/bin/ln", "-s", linkeddirectory,
strings.concat(tree, "/alpha/directory.ww")];
runcommand(root, "recursive-source-directory-link", linkeddirav,
time.second, &linkout);
expectexit(&linkout, 0);
let aliasav: []str = ["/bin/ln", "-s", tree, alias];
runcommand(root, "recursive-root-alias", aliasav, time.second, &linkout);
expectexit(&linkout, 0);
let escapeav: []str = ["/bin/ln", "-s", outside,
strings.concat(tree, "/escape")];
runcommand(root, "recursive-child-escape", escapeav, time.second, &linkout);
expectexit(&linkout, 0);
let cycleav: []str = ["/bin/ln", "-s", tree,
strings.concat(tree, "/cycle")];
runcommand(root, "recursive-child-cycle", cycleav, time.second, &linkout);
expectexit(&linkout, 0);
let spec: str = strings.concat(tree, "/...");
let outc: commandout;
let outw: commandout;
let treec: []str = [driver("ww"), "test", "-I", tree, spec];
let treew: []str = [driver("ww_ww"), "test", "-I", tree, 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));
let seq: str = strings.dup(outc.stdout);
// A directory -o publishes every selected command by directory basename.
// Non-command production roots remain graph roots but have no named output.
let commands: str = strings.concat(root, "/commands");
let commandalpha: str = strings.concat(commands, "/cmd-alpha");
let commandzeta: str = strings.concat(commands, "/cmd-zeta");
let commandlib: str = strings.concat(commands, "/library");
assert(os.mkdir(commands, 448i32) == 0);
assert(os.mkdir(commandalpha, 448i32) == 0);
assert(os.mkdir(commandzeta, 448i32) == 0);
assert(os.mkdir(commandlib, 448i32) == 0);
writefile(strings.concat(commandalpha, "/main.ww"), strings.concat(
"package main;\nimport library;\n",
"fn main() i32 = { return library.value(); };\n"));
writefile(strings.concat(commandzeta, "/main.ww"),
"package main;\nfn main() i32 = { return 0; };\n");
writefile(strings.concat(commandlib, "/library.ww"),
"package library;\nexport fn value() i32 = { return 0; };\n");
let commandalias: str = strings.concat(root, "/commands-alias");
let commandaliasav: []str = ["/bin/ln", "-s", commands, commandalias];
runcommand(root, "recursive-command-alias", commandaliasav, time.second,
&linkout);
expectexit(&linkout, 0);
let dashselector: str = "-dash-command";
let dashselectorpath: str = strings.concat(root, "/", dashselector);
let dashselectorav: []str = ["/bin/ln", "-s", commandalpha,
dashselectorpath];
runcommand(root, "recursive-dash-selector", dashselectorav, time.second,
&linkout);
expectexit(&linkout, 0);
let commandalphaid: str = localidentity(commandalpha, "main");
let commandzetaid: str = localidentity(commandzeta, "main");
let binc: str = strings.concat(root, "/bin-c");
let binw: str = strings.concat(root, "/bin-ww");
let reversebinc: str = strings.concat(root, "/reverse-bin-c");
let reversebinw: str = strings.concat(root, "/reverse-bin-ww");
assert(os.mkdir(binc, 448i32) == 0);
assert(os.mkdir(binw, 448i32) == 0);
let commandspec: str = strings.concat(commands, "/...");
let commandaliasspec: str = strings.concat(commandalias, "/...");
let commandworks: []str = [strings.concat(root, "/command-work-c"),
strings.concat(root, "/command-work-ww")];
let commandreverseworks: []str = [strings.concat(root,
"/command-reverse-work-c"), strings.concat(root,
"/command-reverse-work-ww")];
let commandbins: []str = [binc, binw];
let commandreversebins: []str = [reversebinc, reversebinw];
let commandreverseoutputs: []str = [strings.concat(reversebinc, "/"),
strings.concat(reversebinw, "/")];
let commandcompilertraces: []str = [strings.concat(root,
"/command-compiler-c"), strings.concat(root, "/command-compiler-ww")];
let commandassemblertraces: []str = [strings.concat(root,
"/command-assembler-c"), strings.concat(root, "/command-assembler-ww")];
let commandlinkertraces: []str = [strings.concat(root,
"/command-linker-c"), strings.concat(root, "/command-linker-ww")];
let commandasmworks: []str = [strings.concat(root, "/asm-work-c"),
strings.concat(root, "/asm-work-ww")];
let commandtools: str = strings.concat(root, "/command-tools");
assert(os.mkdir(commandtools, 448i32) == 0);
let commandcompilerwrapper: str = strings.concat(commandtools, "/w6c.sh");
let commandassemblerwrapper: str = strings.concat(commandtools, "/w6a.sh");
let commandlinkerwrapper: str = strings.concat(commandtools, "/w6l.sh");
writeexecutable(commandcompilerwrapper, strings.concat(
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_PATTERN_COMPILER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_PATTERN_COMPILER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_PATTERN_COMPILER_TRACE\"\n",
"exec \"$WW_PATTERN_REAL_COMPILER\" \"$@\"\n"));
writeexecutable(commandassemblerwrapper, strings.concat(
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_PATTERN_ASSEMBLER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_PATTERN_ASSEMBLER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_PATTERN_ASSEMBLER_TRACE\"\n",
"exec \"$WW_PATTERN_REAL_ASSEMBLER\" \"$@\"\n"));
writeexecutable(commandlinkerwrapper, strings.concat(
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_PATTERN_LINKER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_PATTERN_LINKER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_PATTERN_LINKER_TRACE\"\n",
"exec \"$WW_PATTERN_REAL_LINKER\" \"$@\"\n"));
let collisions: str = strings.concat(root, "/collisions");
let collisionleft: str = strings.concat(collisions, "/left");
let collisionright: str = strings.concat(collisions, "/right");
let collisionleftcmd: str = strings.concat(collisionleft, "/same");
let collisionrightcmd: str = strings.concat(collisionright, "/same");
assert(os.mkdir(collisions, 448i32) == 0);
assert(os.mkdir(collisionleft, 448i32) == 0);
assert(os.mkdir(collisionright, 448i32) == 0);
assert(os.mkdir(collisionleftcmd, 448i32) == 0);
assert(os.mkdir(collisionrightcmd, 448i32) == 0);
writefile(strings.concat(collisionleftcmd, "/main.ww"),
"package main;\nfn main() i32 = { return 0; };\n");
writefile(strings.concat(collisionrightcmd, "/main.ww"),
"package main;\nfn main() i32 = { return 0; };\n");
let collisionspec: str = strings.concat(collisions, "/...");
let collisionout: str = strings.concat(root, "/collision-bin");
assert(os.mkdir(collisionout, 448i32) == 0);
let collisionworks: []str = [strings.concat(root, "/collision-work-c"),
strings.concat(root, "/collision-work-ww")];
let commandstages: []str = ["ww", "ww_ww"];
let commandcompilers: []str = ["w6c", "w6c_ww"];
let commandassemblers: []str = ["w6a", "w6a_ww"];
let commandlinkers: []str = ["w6l", "w6l_ww"];
let commandbaseenv: []str = os.getenvs();
let referencecommandcompiler: str = "";
let referencecommandassembler: str = "";
let referencecommandlinker: str = "";
let referenceasmcompiler: str = "";
let referenceasmrejectdiag: str = "";
let referencecollisiondiag: str = "";
let referencefanoutpathdiag: str = "";
let referencescratchpathdiag: str = "";
let referenceworkpathdiag: str = "";
// Raw -o/-w spellings still fit the public PATH_MAX contract. The
// directory fan-out, cold scratch, and persistent tool-record spellings
// derived from them do not, and must be rejected before any producer.
let longoutputbytes: []u8 = alloc([], os.PATH_MAX: u64)!;
let longpathi: i32 = 0;
for (longpathi < root.len) {
append(longoutputbytes, root[longpathi]); longpathi += 1;
};
append(longoutputbytes, '/': u8);
for (longoutputbytes.len < os.PATH_MAX - 2) {
append(longoutputbytes, 'o': u8);
};
append(longoutputbytes, '/': u8);
assert(longoutputbytes.len == os.PATH_MAX - 1);
let longoutputdir: str = strings.frombytes(longoutputbytes);
let longscratchbytes: []u8 = alloc([], os.PATH_MAX: u64)!;
longpathi = 0;
for (longpathi < root.len) {
append(longscratchbytes, root[longpathi]); longpathi += 1;
};
append(longscratchbytes, '/': u8);
for (longscratchbytes.len < os.PATH_MAX - 1) {
append(longscratchbytes, 's': u8);
};
assert(longscratchbytes.len == os.PATH_MAX - 1);
let longscratchout: str = strings.frombytes(longscratchbytes);
let longworkbytes: []u8 = alloc([], os.PATH_MAX: u64)!;
longpathi = 0;
for (longpathi < root.len) {
append(longworkbytes, root[longpathi]); longpathi += 1;
};
for (longworkbytes.len < os.PATH_MAX - 8) {
append(longworkbytes, '/': u8);
let segmentbytes: i32 = 0;
for (segmentbytes < 120 && longworkbytes.len < os.PATH_MAX - 8) {
append(longworkbytes, 'w': u8); segmentbytes += 1;
};
};
let longworkdir: str = strings.frombytes(longworkbytes);
mkdirall(longworkdir);
let commandworkpaths: []str = ["", ""];
let commandstage: i32 = 0;
for (commandstage < commandstages.len) {
writefile(commandcompilertraces[commandstage], "");
writefile(commandassemblertraces[commandstage], "");
writefile(commandlinkertraces[commandstage], "");
let commandenv: []str = alloc([], (commandbaseenv.len + 9): u64)!;
let commandei: i32 = 0;
for (commandei < commandbaseenv.len) {
if (!strings.hasprefix(commandbaseenv[commandei], "WW_W6C=")
&& !strings.hasprefix(commandbaseenv[commandei], "WW_W6A=")
&& !strings.hasprefix(commandbaseenv[commandei], "WW_W6L=")
&& !strings.hasprefix(commandbaseenv[commandei],
"WW_PATTERN_COMPILER_TRACE=")
&& !strings.hasprefix(commandbaseenv[commandei],
"WW_PATTERN_ASSEMBLER_TRACE=")
&& !strings.hasprefix(commandbaseenv[commandei],
"WW_PATTERN_LINKER_TRACE=")
&& !strings.hasprefix(commandbaseenv[commandei],
"WW_PATTERN_REAL_COMPILER=")
&& !strings.hasprefix(commandbaseenv[commandei],
"WW_PATTERN_REAL_ASSEMBLER=")
&& !strings.hasprefix(commandbaseenv[commandei],
"WW_PATTERN_REAL_LINKER=")) {
append(commandenv, commandbaseenv[commandei]);
};
commandei += 1;
};
append(commandenv, strings.concat("WW_W6C=", commandcompilerwrapper));
append(commandenv, strings.concat("WW_W6A=", commandassemblerwrapper));
append(commandenv, strings.concat("WW_W6L=", commandlinkerwrapper));
append(commandenv, strings.concat("WW_PATTERN_COMPILER_TRACE=",
commandcompilertraces[commandstage]));
append(commandenv, strings.concat("WW_PATTERN_ASSEMBLER_TRACE=",
commandassemblertraces[commandstage]));
append(commandenv, strings.concat("WW_PATTERN_LINKER_TRACE=",
commandlinkertraces[commandstage]));
append(commandenv, strings.concat("WW_PATTERN_REAL_COMPILER=",
driver(commandcompilers[commandstage])));
append(commandenv, strings.concat("WW_PATTERN_REAL_ASSEMBLER=",
driver(commandassemblers[commandstage])));
append(commandenv, strings.concat("WW_PATTERN_REAL_LINKER=",
driver(commandlinkers[commandstage])));
let commandforward: []str = [driver(commandstages[commandstage]), "build",
"-w", commandworks[commandstage], "-I", commands,
"-L", strings.concat(repo(), "/out/lib"), "-lwcc", "-o",
commandbins[commandstage], commandspec, commandaliasspec,
commandspec, commandalpha];
let commandreverse: []str = [driver(commandstages[commandstage]), "build",
"-w", commandreverseworks[commandstage], "-I", commands,
"-L", strings.concat(repo(), "/out/lib"), "-lwcc", "-o",
commandreverseoutputs[commandstage], commandalpha, commandspec,
commandaliasspec, commandspec];
if (commandstage == 0) {
runcommandenv(root, "tree-command-output-c", commandforward, commandenv,
(60i64 * (time.second: i64)): time.duration, &outc);
expectexit(&outc, 0);
} else {
runcommandenv(root, "tree-command-output-ww", commandforward, commandenv,
(60i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outw, 0);
};
let commandstdout: str;
let commandstderr: str;
if (commandstage == 0) {
commandstdout = strings.dup(outc.stdout);
commandstderr = strings.dup(outc.stderr);
} else {
commandstdout = strings.dup(outw.stdout);
commandstderr = strings.dup(outw.stderr);
};
let commandalphabin: str = strings.dup(readfile(strings.concat(
commandbins[commandstage], "/cmd-alpha")));
let commandzetabin: str = strings.dup(readfile(strings.concat(
commandbins[commandstage], "/cmd-zeta")));
let commandwork: str = strings.concat(commandworks[commandstage], "/");
commandworkpaths[commandstage] = strings.dup(commandwork);
let commandctrace: str = readfile(commandcompilertraces[commandstage]);
let commandatrace: str = readfile(commandassemblertraces[commandstage]);
let commandltrace: str = readfile(commandlinkertraces[commandstage]);
assert(occurrences(commandctrace, "\n") == 3);
assert(occurrences(commandatrace, "\n") == 5);
assert(occurrences(commandltrace, "\n") == 2);
let commandalphacompile: str = linecontaining(commandctrace,
strings.concat(commandalphaid, ".unit.new"));
assert(occurrences(commandalphacompile, strings.concat(
"<--import><library><", commandwork, "library.wwi.new>")) == 1);
assert(!has(commandalphacompile, "cmd-zeta.wwi"));
let alphaassembly: str = strings.concat("BEGIN<-o><", commandwork,
commandalphaid, ".init.o.new><", commandwork, commandalphaid,
".init.s.new>");
let zetaassembly: str = strings.concat("BEGIN<-o><", commandwork,
commandzetaid, ".init.o.new><", commandwork, commandzetaid,
".init.s.new>");
assert(same(linecontaining(commandatrace, strings.concat(commandalphaid,
".init.o.new")), alphaassembly));
assert(same(linecontaining(commandatrace, strings.concat(commandzetaid,
".init.o.new")), zetaassembly));
let commandalphalink: str = linecontaining(commandltrace,
strings.concat("<-o><", commandbins[commandstage], "/cmd-alpha.new>"));
let commandzetalink: str = linecontaining(commandltrace,
strings.concat("<-o><", commandbins[commandstage], "/cmd-zeta.new>"));
assert(occurrences(commandalphalink, strings.concat("<", commandwork,
commandalphaid, ".a.new>")) == 1);
assert(occurrences(commandalphalink, strings.concat("<", commandwork,
"library.a.new>")) == 1);
assert(!has(commandalphalink, strings.concat(commandzetaid, ".a")));
assert(!has(commandalphalink, ".wwi>"));
assert(has(commandalphalink, strings.concat("<-L><", repo(),
"/out/lib><-l><wcc>")));
assert(has(commandzetalink, strings.concat("<", commandwork,
commandzetaid, ".a.new>")));
assert(!has(commandzetalink, "library.a"));
assert(!has(commandzetalink, ".wwi>"));
let normalizedcommandcompiler: str = normalizedtrace(commandctrace,
commandwork, commandbins[commandstage]);
let normalizedcommandassembler: str = normalizedtrace(commandatrace,
commandwork, commandbins[commandstage]);
let normalizedcommandlinker: str = normalizedtrace(commandltrace,
commandwork, commandbins[commandstage]);
if (commandstage == 0) {
referencecommandcompiler = strings.dup(normalizedcommandcompiler);
referencecommandassembler = strings.dup(normalizedcommandassembler);
referencecommandlinker = strings.dup(normalizedcommandlinker);
} else {
assert(same(referencecommandcompiler, normalizedcommandcompiler));
assert(same(referencecommandassembler, normalizedcommandassembler));
assert(same(referencecommandlinker, normalizedcommandlinker));
};
// Reverse the identical request multiset into an independent cold
// work/output root inside this stage. Canonical product ordering leaves
// diagnostics, normalized tool argv, artifacts, and binaries fixed.
rewritefile(commandcompilertraces[commandstage], "");
rewritefile(commandassemblertraces[commandstage], "");
rewritefile(commandlinkertraces[commandstage], "");
if (commandstage == 0) {
runcommandenv(root, "tree-command-reverse-c", commandreverse, commandenv,
(60i64 * (time.second: i64)): time.duration, &outc);
expectexit(&outc, 0);
assert(same(commandstdout, outc.stdout));
assert(same(commandstderr, outc.stderr));
} else {
runcommandenv(root, "tree-command-reverse-ww", commandreverse, commandenv,
(60i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outw, 0);
assert(same(commandstdout, outw.stdout));
assert(same(commandstderr, outw.stderr));
};
let reversework: str = strings.concat(
commandreverseworks[commandstage], "/");
let reversectrace: str = readfile(commandcompilertraces[commandstage]);
let reverseatrace: str = readfile(commandassemblertraces[commandstage]);
let reverseltrace: str = readfile(commandlinkertraces[commandstage]);
assert(same(normalizedcommandcompiler, normalizedtrace(reversectrace,
reversework, commandreversebins[commandstage])));
assert(same(normalizedcommandassembler, normalizedtrace(reverseatrace,
reversework, commandreversebins[commandstage])));
assert(same(normalizedcommandlinker, normalizedtrace(reverseltrace,
reversework, commandreversebins[commandstage])));
let reverseactions: []str = [commandalphaid, commandzetaid, "library"];
let reversesuffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"];
let rai: i32 = 0;
for (rai < reverseactions.len) {
let rsi: i32 = 0;
for (rsi < reversesuffixes.len) {
assert(same(readfile(strings.concat(commandwork,
reverseactions[rai], reversesuffixes[rsi])),
readfile(strings.concat(reversework, reverseactions[rai],
reversesuffixes[rsi]))));
rsi += 1;
};
rai += 1;
};
assert(same(commandalphabin, readfile(strings.concat(
commandreversebins[commandstage], "/cmd-alpha"))));
assert(same(commandzetabin, readfile(strings.concat(
commandreversebins[commandstage], "/cmd-zeta"))));
// Return to the forward store: a warm equivalent request invokes no
// compiler or assembler before the direct-form reuse check below.
rewritefile(commandcompilertraces[commandstage], "");
rewritefile(commandassemblertraces[commandstage], "");
rewritefile(commandlinkertraces[commandstage], "");
if (commandstage == 0) {
runcommandenv(root, "tree-command-warm-c", commandforward, commandenv,
(60i64 * (time.second: i64)): time.duration, &outc);
expectexit(&outc, 0);
} else {
runcommandenv(root, "tree-command-warm-ww", commandforward, commandenv,
(60i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outw, 0);
};
assert(readfile(commandcompilertraces[commandstage]).len == 0);
assert(readfile(commandassemblertraces[commandstage]).len == 0);
let directbin: str = strings.concat(root, "/direct-",
commandstages[commandstage]);
let directav: []str = [driver(commandstages[commandstage]), "build",
"-w", commandworks[commandstage], "-I", commands,
"-L", strings.concat(repo(), "/out/lib"), "-lwcc",
"-o", directbin, commandalpha];
if (commandstage == 0) {
runcommandenv(root, "tree-command-direct-c", directav, commandenv,
(60i64 * (time.second: i64)): time.duration, &outc);
expectexit(&outc, 0);
} else {
runcommandenv(root, "tree-command-direct-ww", directav, commandenv,
(60i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outw, 0);
};
assert(readfile(commandcompilertraces[commandstage]).len == 0);
assert(readfile(commandassemblertraces[commandstage]).len == 0);
assert(same(commandalphabin, readfile(directbin)));
rewritefile(commandcompilertraces[commandstage], "");
rewritefile(commandassemblertraces[commandstage], "");
rewritefile(commandlinkertraces[commandstage], "");
let commandasm: []str = [driver(commandstages[commandstage]), "build",
"-S", "-w", commandasmworks[commandstage], "-I", commands,
commandspec, commandaliasspec, commandalpha];
if (commandstage == 0) {
runcommandenv(root, "tree-command-asm-c", commandasm, commandenv,
(60i64 * (time.second: i64)): time.duration, &outc);
expectexit(&outc, 0);
} else {
runcommandenv(root, "tree-command-asm-ww", commandasm, commandenv,
(60i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outw, 0);
};
let commandasmwork: str = strings.concat(commandasmworks[commandstage],
"/");
let commandasmtrace: str = readfile(commandcompilertraces[commandstage]);
assert(occurrences(commandasmtrace, "\n") == 3);
assert(readfile(commandassemblertraces[commandstage]).len == 0);
assert(readfile(commandlinkertraces[commandstage]).len == 0);
assert(os.exists(strings.concat(commandasmwork, commandalphaid, ".s")));
assert(os.exists(strings.concat(commandasmwork, commandzetaid, ".s")));
assert(os.exists(strings.concat(commandasmwork, "library.s")));
let normalizedasmcompiler: str = normalizedtrace(commandasmtrace,
commandasmwork, commandbins[commandstage]);
if (commandstage == 0) {
referenceasmcompiler = strings.dup(normalizedasmcompiler);
} else { assert(same(referenceasmcompiler, normalizedasmcompiler)); };
if (commandstage == 0) {
runcommandenv(root, "tree-command-asm-warm-c", commandasm, commandenv,
(60i64 * (time.second: i64)): time.duration, &outc);
expectexit(&outc, 0);
} else {
runcommandenv(root, "tree-command-asm-warm-ww", commandasm, commandenv,
(60i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outw, 0);
};
assert(same(commandasmtrace,
readfile(commandcompilertraces[commandstage])));
rewritefile(commandcompilertraces[commandstage], "");
rewritefile(commandassemblertraces[commandstage], "");
rewritefile(commandlinkertraces[commandstage], "");
let commandasmnowork: []str = [driver(commandstages[commandstage]),
"build", "-S", "-I", commands, commandspec];
if (commandstage == 0) {
runcommandenv(root, "tree-command-asm-no-work-c", commandasmnowork,
commandenv, time.second, &outc);
expectexit(&outc, 2);
referenceasmrejectdiag = strings.dup(outc.stderr);
} else {
runcommandenv(root, "tree-command-asm-no-work-ww", commandasmnowork,
commandenv, time.second, &outw);
expectexit(&outw, 2);
assert(same(referenceasmrejectdiag, outw.stderr));
};
assert(has(referenceasmrejectdiag,
"wwtest package: recursive -S needs -w\n"));
assert(readfile(commandcompilertraces[commandstage]).len == 0);
assert(readfile(commandassemblertraces[commandstage]).len == 0);
assert(readfile(commandlinkertraces[commandstage]).len == 0);
rewritefile(commandcompilertraces[commandstage], "");
rewritefile(commandassemblertraces[commandstage], "");
rewritefile(commandlinkertraces[commandstage], "");
let collisionav: []str = [driver(commandstages[commandstage]), "build",
"-w", collisionworks[commandstage], "-o", collisionout,
collisionspec];
if (commandstage == 0) {
runcommandenv(root, "tree-collision-c", collisionav, commandenv,
time.second, &outc);
expectexit(&outc, 1);
referencecollisiondiag = strings.dup(outc.stderr);
} else {
runcommandenv(root, "tree-collision-ww", collisionav, commandenv,
time.second, &outw);
expectexit(&outw, 1);
assert(same(referencecollisiondiag, outw.stderr));
};
assert(readfile(commandcompilertraces[commandstage]).len == 0);
assert(readfile(commandassemblertraces[commandstage]).len == 0);
assert(readfile(commandlinkertraces[commandstage]).len == 0);
assert(!os.exists(collisionworks[commandstage]));
rewritefile(commandcompilertraces[commandstage], "");
rewritefile(commandassemblertraces[commandstage], "");
rewritefile(commandlinkertraces[commandstage], "");
let fanoutpathav: []str = [driver(commandstages[commandstage]),
"build", "-o", longoutputdir, "-I", commands, commandspec];
if (commandstage == 0) {
runcommandenv(root, "tree-fanout-path-c", fanoutpathav, commandenv,
time.second, &outc);
expectexit(&outc, 1);
referencefanoutpathdiag = strings.dup(outc.stderr);
} else {
runcommandenv(root, "tree-fanout-path-ww", fanoutpathav, commandenv,
time.second, &outw);
expectexit(&outw, 1);
assert(same(referencefanoutpathdiag, outw.stderr));
};
assert(has(referencefanoutpathdiag,
"ww: command output path is too long\n"));
assert(readfile(commandcompilertraces[commandstage]).len == 0);
assert(readfile(commandassemblertraces[commandstage]).len == 0);
assert(readfile(commandlinkertraces[commandstage]).len == 0);
let scratchpathav: []str = [driver(commandstages[commandstage]),
"build", "-o", longscratchout, "-I", commands, commandalpha];
if (commandstage == 0) {
runcommandenv(root, "tree-scratch-path-c", scratchpathav, commandenv,
time.second, &outc);
expectexit(&outc, 1);
referencescratchpathdiag = strings.dup(outc.stderr);
} else {
runcommandenv(root, "tree-scratch-path-ww", scratchpathav, commandenv,
time.second, &outw);
expectexit(&outw, 1);
assert(same(referencescratchpathdiag, outw.stderr));
};
assert(has(referencescratchpathdiag,
"ww: scratch path is too long\n"));
assert(readfile(commandcompilertraces[commandstage]).len == 0);
assert(readfile(commandassemblertraces[commandstage]).len == 0);
assert(readfile(commandlinkertraces[commandstage]).len == 0);
let workpathav: []str = [driver(commandstages[commandstage]),
"build", "-w", longworkdir, "-I", commands, commandalpha];
if (commandstage == 0) {
runcommandenv(root, "tree-work-path-c", workpathav, commandenv,
time.second, &outc);
expectexit(&outc, 1);
referenceworkpathdiag = strings.dup(outc.stderr);
} else {
runcommandenv(root, "tree-work-path-ww", workpathav, commandenv,
time.second, &outw);
expectexit(&outw, 1);
assert(same(referenceworkpathdiag, outw.stderr));
};
assert(has(referenceworkpathdiag,
"ww: workdir path is too long\n"));
assert(readfile(commandcompilertraces[commandstage]).len == 0);
assert(readfile(commandassemblertraces[commandstage]).len == 0);
assert(readfile(commandlinkertraces[commandstage]).len == 0);
commandstage += 1;
};
assert(has(referencecollisiondiag,
"ww: multiple commands produce output basename \"same\""));
assert(!os.exists(strings.concat(collisionout, "/same")));
let commandactions: []str = [commandalphaid, commandzetaid, "library"];
let commandsuffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"];
let commandaction: i32 = 0;
for (commandaction < commandactions.len) {
let commandsuffix: i32 = 0;
for (commandsuffix < commandsuffixes.len) {
assert(same(readfile(strings.concat(commandworkpaths[0],
commandactions[commandaction], commandsuffixes[commandsuffix])),
readfile(strings.concat(commandworkpaths[1],
commandactions[commandaction], commandsuffixes[commandsuffix]))));
commandsuffix += 1;
};
commandaction += 1;
};
assert(os.exists(strings.concat(binc, "/cmd-alpha")));
assert(os.exists(strings.concat(binc, "/cmd-zeta")));
assert(os.exists(strings.concat(binw, "/cmd-alpha")));
assert(os.exists(strings.concat(binw, "/cmd-zeta")));
assert(!os.exists(strings.concat(binc, "/library")));
assert(!os.exists(strings.concat(binw, "/library")));
assert(same(readfile(strings.concat(binc, "/cmd-alpha")),
readfile(strings.concat(binw, "/cmd-alpha"))));
assert(same(readfile(strings.concat(binc, "/cmd-zeta")),
readfile(strings.concat(binw, "/cmd-zeta"))));
// `--` ends build option parsing and every following argument remains a
// package selector. The coordinator receives and builds that direct root.
let dashworks: []str = [strings.concat(root, "/dash-work-c"),
strings.concat(root, "/dash-work-ww")];
let dashbins: []str = [strings.concat(root, "/dash-bin-c"),
strings.concat(root, "/dash-bin-ww")];
let dashtrailworks: []str = [strings.concat(root, "/dash-trail-work-c"),
strings.concat(root, "/dash-trail-work-ww")];
let dashtrailbins: []str = [strings.concat(root, "/dash-trail-bin-c"),
strings.concat(root, "/dash-trail-bin-ww")];
let referencedashstdout: str = "";
let referencedashstderr: str = "";
let dashstage: i32 = 0;
for (dashstage < commandstages.len) {
let dashav: []str = [driver(commandstages[dashstage]), "build",
"-w", dashworks[dashstage], "-I", commands, "-o",
dashbins[dashstage], "--", dashselector];
if (dashstage == 0) {
runcommanddir(root, "tree-dash-c", root, dashav,
(30i64 * (time.second: i64)): time.duration, &outc);
expectexit(&outc, 0);
referencedashstdout = strings.dup(outc.stdout);
referencedashstderr = strings.dup(outc.stderr);
} else {
runcommanddir(root, "tree-dash-ww", root, dashav,
(30i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outw, 0);
assert(same(referencedashstdout, outw.stdout));
assert(same(referencedashstderr, outw.stderr));
};
assert(os.exists(strings.concat(dashworks[dashstage], "/",
commandalphaid, ".unit.ww")));
// Once the first positional has stopped flag parsing, a later `--` is
// another package argument, not a second terminator.
let dashtrailav: []str = [driver(commandstages[dashstage]), "build",
"-w", dashtrailworks[dashstage], "-I", commands, "-o",
dashtrailbins[dashstage], commandalpha, "--"];
if (dashstage == 0) {
runcommand(root, "tree-dash-trailing-c", dashtrailav,
time.second, &outc);
expectexit(&outc, 1);
assert(has(outc.stderr,
"--: cannot canonicalize package directory\n"));
} else {
runcommand(root, "tree-dash-trailing-ww", dashtrailav,
time.second, &outw);
expectexit(&outw, 1);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
assert(has(outw.stderr,
"--: cannot canonicalize package directory\n"));
};
assert(!os.exists(dashtrailworks[dashstage]));
assert(!os.exists(dashtrailbins[dashstage]));
dashstage += 1;
};
assert(same(readfile(dashbins[0]), readfile(dashbins[1])));
let commandrun: []str = [strings.concat(binc, "/cmd-alpha")];
runcommand(root, "tree-command-run", commandrun, time.second, &outc);
expectexit(&outc, 0);
let nomainpattern: str = strings.concat(commandlib, "/...");
let nomainc: []str = [driver("ww"), "build", "-o", binc, nomainpattern];
let nomainw: []str = [driver("ww_ww"), "build", "-o", binw, nomainpattern];
runcommand(root, "tree-no-main-c", nomainc, time.second, &outc);
runcommand(root, "tree-no-main-ww", nomainw, time.second, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "ww: no main packages to build\n"));
assert(has(seq, strings.concat("ok ", tree,
" [rootpkg]\n")));
assert(has(seq, strings.concat("ok ", tree,
"/alpha [alpha]\n")));
assert(has(seq, strings.concat("ok ", tree,
"/app [app]\n")));
assert(has(seq, strings.concat("ok ", tree,
"/beta/inner [inner]\n")));
assert(has(seq, strings.concat("ok ", tree,
"/domain/app [app]\n")));
assert(has(seq, strings.concat("? ", tree,
"/gamma [no tests]\n")));
assert(has(seq, strings.concat("? ", tree,
"/vendor [no tests]\n")));
assert(has(seq, strings.concat("? ", tree,
"/vendorx [no tests]\n")));
let rootreport: i32 = pos(seq, strings.concat("ok ", tree,
" [rootpkg]\n"));
let alphareport: i32 = pos(seq, strings.concat("ok ", tree,
"/alpha [alpha]\n"));
let appreport: i32 = pos(seq, strings.concat("ok ", tree,
"/app [app]\n"));
let innerreport: i32 = pos(seq, strings.concat("ok ", tree,
"/beta/inner [inner]\n"));
let domainreport: i32 = pos(seq, strings.concat("ok ", tree,
"/domain/app [app]\n"));
let gammareport: i32 = pos(seq, strings.concat("? ", tree,
"/gamma [no tests]\n"));
let vendorreport: i32 = pos(seq, strings.concat("? ", tree,
"/vendor [no tests]\n"));
let vendorxreport: i32 = pos(seq, strings.concat("? ", tree,
"/vendorx [no tests]\n"));
assert(rootreport >= 0 && rootreport < alphareport
&& alphareport < appreport && appreport < innerreport
&& innerreport < domainreport && domainreport < gammareport
&& gammareport < vendorreport && vendorreport < vendorxreport);
assert(occurrences(seq, strings.concat(tree, " [")) == 1);
assert(occurrences(seq, strings.concat("ok ", tree,
"/alpha [alpha]\n")) == 1);
assert(occurrences(seq, strings.concat("ok ", tree,
"/app [app]\n")) == 1);
assert(occurrences(seq, strings.concat("ok ", tree,
"/beta/inner [inner]\n")) == 1);
assert(occurrences(seq, strings.concat("ok ", tree,
"/domain/app [app]\n")) == 1);
assert(occurrences(seq, strings.concat("? ", tree,
"/gamma [no tests]\n")) == 1);
assert(occurrences(seq, strings.concat("? ", tree,
"/vendor [no tests]\n")) == 1);
assert(occurrences(seq, strings.concat("? ", tree,
"/vendorx [no tests]\n")) == 1);
assert(!has(seq, ".hidden"));
assert(!has(seq, "_skip"));
assert(!has(seq, "/testdata"));
assert(!has(seq, "/vendor/bad"));
assert(!has(seq, "/app/vendor/lib/math"));
assert(!has(seq, outside));
let buildworkc: str = strings.concat(root, "/build-work-c");
let buildworkw: str = strings.concat(root, "/build-work-ww");
let buildc: []str = [driver("ww"), "build", "-w", buildworkc,
"-I", tree, spec];
let buildw: []str = [driver("ww_ww"), "build", "-w", buildworkw,
"-I", tree, spec];
runcommand(root, "tree-build-c", buildc,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "tree-build-ww", buildw,
(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 buildactions: []str = [localidentity(tree, "rootpkg"), "alpha",
"app", "domain.app", "gamma", "vendor", "vendorx"];
let bai: i32 = 0;
for (bai < buildactions.len) {
let cunit: str = readfile(strings.concat(buildworkc, "/",
buildactions[bai], ".unit.ww"));
assert(same(cunit, readfile(strings.concat(buildworkw, "/",
buildactions[bai], ".unit.ww"))));
bai += 1;
};
assert(!os.exists(strings.concat(buildworkc,
"/beta.inner.unit.ww")));
assert(!os.exists(strings.concat(buildworkw,
"/beta.inner.unit.ww")));
assert(!os.exists(strings.concat(buildworkc,
"/alpha-internal-test.unit.ww")));
assert(!os.exists(strings.concat(buildworkw,
"/alpha-internal-test.unit.ww")));
// Concurrent scheduling must not reorder the emitted byte stream.
let j4: []str = [driver("ww"), "test", "-j", "4", "-I", tree, 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 overlapc: []str = [driver("ww"), "test", "-I", tree,
strings.concat(tree, "/alpha"), spec, spec,
strings.concat(alias, "/...")];
let overlapcreverse: []str = [driver("ww"), "test", "-I", tree,
strings.concat(alias, "/..."), spec, spec,
strings.concat(tree, "/alpha")];
let overlapw: []str = [driver("ww_ww"), "test", "-I", tree,
strings.concat(alias, "/..."), spec, spec,
strings.concat(tree, "/alpha")];
let overlapwreverse: []str = [driver("ww_ww"), "test", "-I", tree,
strings.concat(tree, "/alpha"), spec, spec,
strings.concat(alias, "/...")];
runcommand(root, "tree-overlap-c", overlapc,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "tree-overlap-ww", overlapw,
(30i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 0);
expectexit(&outw, 0);
assert(same(outc.stdout, seq));
assert(same(outw.stdout, seq));
assert(same(outc.stderr, outw.stderr));
let overlapstderr: str = strings.dup(outc.stderr);
runcommand(root, "tree-overlap-reverse-c", overlapcreverse,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "tree-overlap-reverse-ww", overlapwreverse,
(30i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 0);
expectexit(&outw, 0);
assert(same(outc.stdout, seq));
assert(same(outw.stdout, seq));
assert(same(outc.stderr, overlapstderr));
assert(same(outw.stderr, overlapstderr));
// The first ellipsis need not be a path element. With cwd as the implicit
// traversal root, matching uses cleaned relative candidates rather than an
// accidental "./" prefix.
let middlec: []str = [driver("ww"), "test", "-I", tree, "tr.../alpha"];
let middlew: []str = [driver("ww_ww"), "test", "-I", tree,
"tr.../alpha"];
runcommanddir(root, "tree-middle-pattern-c", root, middlec,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommanddir(root, "tree-middle-pattern-ww", root, middlew,
(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,
"/alpha [alpha]\n")));
assert(!has(outc.stdout, strings.concat("ok ", tree,
" [rootpkg]\n")));
// The recursive exclusions are traversal rules, not bans on direct roots.
let directc: []str = [driver("ww"), "test", "-I", tree,
strings.concat(tree, "/.hidden"), strings.concat(tree, "/_skip"),
strings.concat(tree, "/testdata/bad")];
let directw: []str = [driver("ww_ww"), "test", "-I", tree,
strings.concat(tree, "/testdata/bad"), strings.concat(tree, "/_skip"),
strings.concat(tree, "/.hidden")];
runcommand(root, "tree-direct-exclusions-c", directc,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "tree-direct-exclusions-ww", directw,
(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,
"/.hidden [hid]\n")));
assert(has(outc.stdout, strings.concat("ok ", tree,
"/_skip [_skip]\n")));
assert(has(outc.stdout, strings.concat("ok ", tree,
"/testdata/bad [bad]\n")));
// A generic wildcard selects a code-bearing terminal vendor directory but
// cannot consume it. Rooting the pattern at vendor selects its descendants;
// a second non-terminal vendor remains a barrier.
let vendorspec: str = strings.concat(tree, "/vendor/...");
let vendorc: []str = [driver("ww"), "test", "-I", tree, vendorspec];
let vendorw: []str = [driver("ww_ww"), "test", "-I", tree, vendorspec];
runcommand(root, "tree-explicit-vendor-c", vendorc,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "tree-explicit-vendor-ww", vendorw,
(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("? ", tree,
"/vendor [no tests]\n")));
assert(has(outc.stdout, strings.concat("ok ", tree,
"/vendor/bad [bad]\n")));
assert(!has(outc.stdout, "/vendor/bad/vendor/deep"));
let vendordirectc: []str = [driver("ww"), "test", "-I", tree,
strings.concat(tree, "/app/vendor/lib/math")];
let vendordirectw: []str = [driver("ww_ww"), "test", "-I", tree,
strings.concat(tree, "/app/vendor/lib/math")];
runcommand(root, "tree-direct-below-vendor-c", vendordirectc,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "tree-direct-below-vendor-ww", vendordirectw,
(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("? ", tree,
"/app/vendor/lib/math [no tests]\n")));
let vendorroots: []str = [driver("ww"), "test", "-I", tree,
strings.concat(tree, "/app/vendor/...")];
runcommand(root, "tree-pattern-below-vendor", vendorroots,
(30i64 * (time.second: i64)): time.duration, &outc);
expectexit(&outc, 0);
assert(has(outc.stdout, strings.concat("? ", tree,
"/app/vendor/lib/math [no tests]\n")));
// A child symlink is never traversed. The same symlink is followed when it
// is itself the explicit traversal root, then canonical output names it once.
let escapec: []str = [driver("ww"), "test", "-I", root,
strings.concat(tree, "/escape/...")];
let escapew: []str = [driver("ww_ww"), "test", "-I", root,
strings.concat(tree, "/escape/...")];
runcommand(root, "tree-explicit-symlink-root-c", escapec,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "tree-explicit-symlink-root-ww", escapew,
(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 ", outside,
" [outside]\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,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "tree-o-ww", ow,
(30i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(outc.stdout.len == 0 && outw.stdout.len == 0);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr,
"with multiple packages, -o must refer to a directory or /dev/null"));
assert(!os.exists(strings.concat(root, "/stem")));
// -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,
"-I", tree, spec];
let wdw: []str = [driver("ww_ww"), "test", "-w", wdroot,
"-I", tree, spec];
runcommand(root, "tree-w-c", wdc,
(30i64 * (time.second: i64)): time.duration, &outc);
let wdkey: str = wdroot;
let expandedmath: str = "app.vendor.lib.math";
let expandedancestor: str = "domain.vendor.dep";
assert(os.exists(strings.concat(wdkey, "/", expandedmath, ".unit.ww")));
assert(os.exists(strings.concat(wdkey, "/", expandedancestor, ".unit.ww")));
assert(!os.exists(strings.concat(wdkey, "/math.unit.ww")));
let appunit: str = readfile(strings.concat(wdkey,
"/app-internal-test.unit.ww"));
assert(has(appunit, strings.concat("//ww:import-map lib.math ",
expandedmath, " ")));
assert(has(readfile(strings.concat(wdkey, "/", expandedmath,
".unit.ww")), strings.concat("//ww:module-reset ",
expandedmath, "\n")));
let ancestorunit: str = readfile(strings.concat(wdkey,
"/domain.app-internal-test.unit.ww"));
assert(has(ancestorunit, strings.concat("//ww:import-map dep ",
expandedancestor, " ")));
assert(has(readfile(strings.concat(wdkey, "/", expandedancestor,
".unit.ww")), strings.concat("//ww:module-reset ",
expandedancestor, "\n")));
let alphaunit: str = readfile(strings.concat(wdkey, "/alpha.unit.ww"));
assert(pos(alphaunit, "export fn value()")
< pos(alphaunit, "export fn linked()"));
assert(same(readfile(strings.concat(wdkey, "/.wwtool.stamp")),
"ww workdir fmt 19 mode test asm 0\n"));
let directorymains: []str = [strings.concat(localidentity(tree,
"rootpkg"), "-test-main"),
"alpha-test-main", "app-test-main", "beta.inner-test-main",
"domain.app-test-main"];
let dmi: i32 = 0;
for (dmi < directorymains.len) {
assert(os.exists(strings.concat(wdkey, "/", directorymains[dmi],
".unit.ww")));
dmi += 1;
};
let notestactions: []str = ["gamma", "vendor", "vendorx"];
let nti: i32 = 0;
for (nti < notestactions.len) {
assert(os.exists(strings.concat(wdkey, "/", notestactions[nti],
".unit.ww")));
assert(!os.exists(strings.concat(wdkey, "/", notestactions[nti],
"-test-main.unit.ww")));
nti += 1;
};
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));
// The retained executable is separate from the persistent action store, so
// -c can suppress execution while reusing the same complete graph.
let wcbin: str = strings.concat(root, "/tree-wc-c.test");
let wwbin: str = strings.concat(root, "/tree-wc-ww.test");
let wcc: []str = [driver("ww"), "test", "-c", "-w", wdroot,
"-o", wcbin, "-I", tree, strings.concat(tree, "/alpha")];
let wcw: []str = [driver("ww_ww"), "test", "-c", "-w", wdroot,
"-o", wwbin, "-I", tree, strings.concat(tree, "/alpha")];
runcommand(root, "tree-wc-c", wcc,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "tree-wc-ww", wcw,
(30i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 0);
expectexit(&outw, 0);
assert(outc.stdout.len == 0 && outc.stderr.len == 0);
assert(outw.stdout.len == 0 && outw.stderr.len == 0);
assert(os.exists(wcbin) && os.exists(wwbin));
assert(same(readfile(wcbin), readfile(wwbin)));
assert(same(outc.stderr, outw.stderr));
clean(wcbin); clean(wwbin);
let bare: str = strings.concat(root, "/bare");
let barez: str = strings.concat(root, "/zz-bare");
assert(os.mkdir(bare, 448i32) == 0);
assert(os.mkdir(strings.concat(bare, "/sub"), 448i32) == 0);
assert(os.mkdir(barez, 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, strings.concat("ww: warning: \"", bare,
"/...\" matched no packages\n")));
assert(has(outc.stderr, "ww test: no packages to test\n"));
let baredirectc: []str = [driver("ww"), "test", bare];
let baredirectw: []str = [driver("ww_ww"), "test", bare];
runcommand(root, "tree-bare-direct-c", baredirectc, time.second, &outc);
runcommand(root, "tree-bare-direct-ww", baredirectw, time.second, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "directory contains no WW package sources\n"));
let quotedpattern: str = strings.concat(root, "/no\"...");
let quotedc: []str = [driver("ww"), "test", quotedpattern];
let quotedw: []str = [driver("ww_ww"), "test", quotedpattern];
runcommand(root, "tree-quoted-unmatched-c", quotedc, time.second, &outc);
runcommand(root, "tree-quoted-unmatched-ww", quotedw, time.second, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, strings.concat("ww: warning: \"", root,
"/no\\\"...\" matched no packages\n")));
// strconv.Quote escapes valid but non-printing Unicode, not only malformed
// bytes and ASCII controls. U+2028 is a stable discriminator.
let nonprintingbytes: []u8 = alloc([], (root.len + 8): u64)!;
let qi: i32 = 0;
for (qi < root.len) { append(nonprintingbytes, root[qi]); qi += 1; };
append(nonprintingbytes, '/': u8); append(nonprintingbytes, 'n': u8);
append(nonprintingbytes, 0xe2u8); append(nonprintingbytes, 0x80u8);
append(nonprintingbytes, 0xa8u8); append(nonprintingbytes, '.': u8);
append(nonprintingbytes, '.': u8); append(nonprintingbytes, '.': u8);
let nonprintingpattern: str = strings.frombytes(nonprintingbytes);
let nonprintingc: []str = [driver("ww"), "test", nonprintingpattern];
let nonprintingw: []str = [driver("ww_ww"), "test", nonprintingpattern];
runcommand(root, "tree-nonprinting-unmatched-c", nonprintingc,
time.second, &outc);
runcommand(root, "tree-nonprinting-unmatched-ww", nonprintingw,
time.second, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "\\u2028...\" matched no packages\n"));
let mixedc: []str = [driver("ww"), "test", "-I", tree,
strings.concat(barez, "/..."), spec, strings.concat(bare, "/...")];
let mixedw: []str = [driver("ww_ww"), "test", "-I", tree,
strings.concat(bare, "/..."), spec, strings.concat(barez, "/...")];
runcommand(root, "tree-unmatched-order-c", mixedc,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "tree-unmatched-order-ww", mixedw,
(30i64 * (time.second: i64)): time.duration, &outw);
expectexit(&outc, 0);
expectexit(&outw, 0);
assert(same(outc.stdout, seq));
assert(same(outw.stdout, seq));
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, strings.concat("ww: warning: \"", bare,
"/...\" matched no packages\n")));
let barewarning: str = strings.concat("ww: warning: \"", bare,
"/...\" matched no packages\n");
let barezwarning: str = strings.concat("ww: warning: \"", barez,
"/...\" matched no packages\n");
assert(pos(outc.stderr, barewarning) < pos(outc.stderr, barezwarning));
// Pinned pkgpattern rejects invalid UTF-8 patterns before regexp
// construction, so they match nothing and receive the ordinary quoted
// warning. Candidate names still use regexp's DecodeRune behavior.
let invalidpatternbytes: []u8 = alloc([], (root.len + 6): u64)!;
let mpi: i32 = 0;
for (mpi < root.len) {
append(invalidpatternbytes, root[mpi]); mpi += 1;
};
append(invalidpatternbytes, '/': u8); append(invalidpatternbytes, '.': u8);
append(invalidpatternbytes, '.': u8); append(invalidpatternbytes, '.': u8);
append(invalidpatternbytes, 0xffu8);
let invalidpattern: str = strings.frombytes(invalidpatternbytes);
let invalidpatternc: []str = [driver("ww"), "test", invalidpattern];
let invalidpatternw: []str = [driver("ww_ww"), "test", invalidpattern];
runcommand(root, "tree-invalid-pattern-c", invalidpatternc,
time.second, &outc);
runcommand(root, "tree-invalid-pattern-ww", invalidpatternw,
time.second, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "...\\xff\" matched no packages\n"));
// U+FFFD in a valid pattern matches a malformed candidate filename byte as
// regexp does, while the wildcard below does not consume a newline.
let utfbase: str = strings.concat(root, "/utf-names");
assert(os.mkdir(utfbase, 448i32) == 0);
let invalidnamebytes: []u8 = alloc([], (utfbase.len + 2): u64)!;
mpi = 0;
for (mpi < utfbase.len) {
append(invalidnamebytes, utfbase[mpi]); mpi += 1;
};
append(invalidnamebytes, '/': u8); append(invalidnamebytes, 0xffu8);
let invalidname: str = strings.frombytes(invalidnamebytes);
assert(os.mkdir(invalidname, 448i32) == 0);
writefile(strings.concat(invalidname, "/case_test.ww"), strings.concat(
"package invalidname;\n@test fn replacement_match() void = {",
" assert(true); };\n"));
let replacementbytes: []u8 = alloc([], (utfbase.len + 8): u64)!;
mpi = 0;
for (mpi < utfbase.len) {
append(replacementbytes, utfbase[mpi]); mpi += 1;
};
append(replacementbytes, '/': u8); append(replacementbytes, 0xefu8);
append(replacementbytes, 0xbfu8); append(replacementbytes, 0xbdu8);
append(replacementbytes, '.': u8); append(replacementbytes, '.': u8);
append(replacementbytes, '.': u8);
let replacementpattern: str = strings.frombytes(replacementbytes);
let replacementc: []str = [driver("ww"), "test", replacementpattern];
let replacementw: []str = [driver("ww_ww"), "test", replacementpattern];
runcommand(root, "tree-replacement-pattern-c", replacementc,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "tree-replacement-pattern-ww", replacementw,
(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, "invalidname.replacement_match ... ok\n"));
let newlinebase: str = strings.concat(root, "/newline-names");
assert(os.mkdir(newlinebase, 448i32) == 0);
let newlinedir: str = strings.concat(newlinebase, "/line\nbreak");
assert(os.mkdir(newlinedir, 448i32) == 0);
writefile(strings.concat(newlinedir, "/case_test.ww"),
"package newline;\n@test fn must_not_match() void = { assert(false); };\n");
let newlinepattern: str = strings.concat(newlinebase, "/line...break");
let newlinec: []str = [driver("ww"), "test", newlinepattern];
let newlinew: []str = [driver("ww_ww"), "test", newlinepattern];
runcommand(root, "tree-newline-pattern-c", newlinec, time.second, &outc);
runcommand(root, "tree-newline-pattern-ww", newlinew, time.second, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "line...break\" matched no packages\n"));
let barebuildc: []str = [driver("ww"), "build",
strings.concat(bare, "/...")];
let barebuildw: []str = [driver("ww_ww"), "build",
strings.concat(bare, "/...")];
runcommand(root, "tree-empty-build-c", barebuildc, time.second, &outc);
runcommand(root, "tree-empty-build-ww", barebuildw, time.second, &outw);
expectexit(&outc, 0);
expectexit(&outw, 0);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "matched no packages\n"));
// A wildcard recognizes a test-only directory, so it is not unmatched;
// build then omits it while test keeps its isolated variant. Direct build
// remains an explicit unusable-package error.
let testonly: str = strings.concat(tree, "/beta/...");
let testonlyc: []str = [driver("ww"), "build", "-I", tree, testonly];
let testonlyw: []str = [driver("ww_ww"), "build", "-I", tree, testonly];
runcommand(root, "tree-test-only-build-c", testonlyc, time.second, &outc);
runcommand(root, "tree-test-only-build-ww", testonlyw, time.second, &outw);
expectexit(&outc, 0);
expectexit(&outw, 0);
assert(outc.stdout.len == 0 && outc.stderr.len == 0);
assert(same(outc.stdout, outw.stdout));
assert(same(outc.stderr, outw.stderr));
let testdirectc: []str = [driver("ww"), "build",
strings.concat(tree, "/beta/inner")];
let testdirectw: []str = [driver("ww_ww"), "build",
strings.concat(tree, "/beta/inner")];
runcommand(root, "tree-test-only-direct-c", testdirectc, time.second, &outc);
runcommand(root, "tree-test-only-direct-ww", testdirectw, time.second, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "directory contains no WW package sources\n"));
let malformed: str = strings.concat(root, "/malformed");
let malformedgood: str = strings.concat(malformed, "/good");
let malformedbad: str = strings.concat(malformed, "/bad");
assert(os.mkdir(malformed, 448i32) == 0);
assert(os.mkdir(malformedgood, 448i32) == 0);
assert(os.mkdir(malformedbad, 448i32) == 0);
writefile(strings.concat(malformedgood, "/good.ww"),
"package good;\nexport fn value() int = { return 1; };\n");
let loop: str = strings.concat(root, "/loop");
let loopav: []str = ["/bin/ln", "-s", loop, loop];
runcommand(root, "recursive-root-loop", loopav, time.second, &linkout);
expectexit(&linkout, 0);
let rejecttrace: str = strings.concat(root, "/pattern-reject.trace");
let rejectcompiler: str = strings.concat(root, "/pattern-reject-w6c.sh");
writefile(rejecttrace, "");
writeexecutable(rejectcompiler, strings.concat(
"#!/bin/sh\nprintf 'compiler\\n' >> \"$WW_PATTERN_REJECT_TRACE\"\n",
"exit 99\n"));
let baseenv: []str = os.getenvs();
let rejectenv: []str = alloc([], (baseenv.len + 2): u64)!;
let ei: i32 = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_PATTERN_REJECT_TRACE=")) {
append(rejectenv, baseenv[ei]);
};
ei += 1;
};
append(rejectenv, strings.concat("WW_W6C=", rejectcompiler));
append(rejectenv, strings.concat("WW_PATTERN_REJECT_TRACE=", rejecttrace));
let rejectspec: str = strings.concat(malformed, "/...");
let warmworkc: str = strings.concat(root, "/warm-reject-work-c");
let warmworkw: str = strings.concat(root, "/warm-reject-work-ww");
let warmc: []str = [driver("ww"), "build", "-w", warmworkc,
"-I", malformed, rejectspec];
let warmw: []str = [driver("ww_ww"), "build", "-w", warmworkw,
"-I", malformed, rejectspec];
// Seed genuine committed package, voucher, and tool state before making a
// second selected directory malformed.
runcommand(root, "tree-malformed-seed-c", warmc,
(30i64 * (time.second: i64)): time.duration, &outc);
runcommand(root, "tree-malformed-seed-ww", warmw,
(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 warmsuffixes: []str = ["/good.unit.ww", "/good.wwi", "/good.s",
"/good.o", "/good.a", "/.wwtool.stamp", "/.wwtool.ww",
"/.wwtool.w6c", "/.wwtool.w6a"];
let warmcstate: []str = alloc([], warmsuffixes.len: u64)!;
let warmwstate: []str = alloc([], warmsuffixes.len: u64)!;
let wi: i32 = 0;
for (wi < warmsuffixes.len) {
append(warmcstate, readfile(strings.concat(warmworkc,
warmsuffixes[wi])));
append(warmwstate, readfile(strings.concat(warmworkw,
warmsuffixes[wi])));
wi += 1;
};
writefile(strings.concat(warmworkc, "/marker"), "c-warm\n");
writefile(strings.concat(warmworkw, "/marker"), "ww-warm\n");
writefile(strings.concat(malformedbad, "/bad.ww"),
"this selected source has no package clause\n");
let rejectworkc: str = strings.concat(root, "/cold-reject-work-c");
let rejectworkw: str = strings.concat(root, "/cold-reject-work-ww");
let rejectc: []str = [driver("ww"), "build", "-w", rejectworkc,
"-I", malformed, rejectspec];
let rejectw: []str = [driver("ww_ww"), "build", "-w", rejectworkw,
"-I", malformed, rejectspec];
runcommandenv(root, "tree-malformed-c", rejectc, rejectenv,
time.second, &outc);
runcommandenv(root, "tree-malformed-ww", rejectw, rejectenv,
time.second, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "invalid or missing package clause\n"));
assert(readfile(rejecttrace).len == 0);
assert(!os.exists(rejectworkc) && !os.exists(rejectworkw));
// Warm rejection preserves all previously committed package, voucher,
// tool, and caller-owned marker bytes while still reaching no producer.
runcommandenv(root, "tree-malformed-warm-c", warmc, rejectenv,
time.second, &outc);
runcommandenv(root, "tree-malformed-warm-ww", warmw, rejectenv,
time.second, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "invalid or missing package clause\n"));
assert(readfile(rejecttrace).len == 0);
assert(same(readfile(strings.concat(warmworkc, "/marker")), "c-warm\n"));
assert(same(readfile(strings.concat(warmworkw, "/marker")), "ww-warm\n"));
wi = 0;
for (wi < warmsuffixes.len) {
assert(same(warmcstate[wi], readfile(strings.concat(warmworkc,
warmsuffixes[wi]))));
assert(same(warmwstate[wi], readfile(strings.concat(warmworkw,
warmsuffixes[wi]))));
wi += 1;
};
// A valid package clause that fails during source-import graph loading is
// also rejected before private work/output directories are materialized.
let graphbad: str = strings.concat(root, "/graph-bad");
let graphapp: str = strings.concat(graphbad, "/app");
assert(os.mkdir(graphbad, 448i32) == 0);
assert(os.mkdir(graphapp, 448i32) == 0);
writefile(strings.concat(graphapp, "/main.ww"),
"package main;\nimport nowhere;\nfn main() void = { };\n");
let graphspec: str = strings.concat(graphbad, "/...");
let graphworkc: str = strings.concat(root, "/graph-work-c");
let graphworkw: str = strings.concat(root, "/graph-work-ww");
let graphoutc: str = strings.concat(root, "/graph-out-c/");
let graphoutw: str = strings.concat(root, "/graph-out-ww/");
let graphc: []str = [driver("ww"), "build", "-w", graphworkc,
"-o", graphoutc, "-I", graphbad, graphspec];
let graphw: []str = [driver("ww_ww"), "build", "-w", graphworkw,
"-o", graphoutw, "-I", graphbad, graphspec];
runcommandenv(root, "tree-graph-reject-c", graphc, rejectenv,
time.second, &outc);
runcommandenv(root, "tree-graph-reject-ww", graphw, rejectenv,
time.second, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "cannot find package nowhere\n"));
assert(readfile(rejecttrace).len == 0);
assert(!os.exists(graphworkc) && !os.exists(graphworkw));
assert(!os.exists(graphoutc) && !os.exists(graphoutw));
// If output creation succeeds but a later workdir prefix is unusable, the
// driver reclaims only the output prefixes it just minted. Both stages make
// the same pre-producer failure and leave the caller tree unchanged.
let setupblock: str = strings.concat(root, "/setup-block");
let setupwork: str = strings.concat(setupblock, "/child");
let setupoutroot: str = strings.concat(root, "/setup-output");
let setuppreserved: str = strings.concat(root, "/setup-preserved");
assert(os.mkdir(setuppreserved, 448i32) == 0);
let setupout: str = strings.concat(setupoutroot,
"/../setup-preserved/nested/");
writefile(setupblock, "not a directory\n");
let setupc: []str = [driver("ww"), "build", "-w", setupwork,
"-o", setupout, "-I", commands, commandspec];
let setupw: []str = [driver("ww_ww"), "build", "-w", setupwork,
"-o", setupout, "-I", commands, commandspec];
runcommandenv(root, "tree-setup-rollback-c", setupc, rejectenv,
time.second, &outc);
expectexit(&outc, 1);
assert(has(outc.stderr, strings.concat("ww: workdir ", setupwork,
" is not a directory\n")));
assert(readfile(rejecttrace).len == 0);
assert(!os.exists(setupoutroot));
assert(os.exists(setuppreserved));
assert(!os.exists(strings.concat(setuppreserved, "/nested")));
assert(!os.exists(setupwork));
assert(same(readfile(setupblock), "not a directory\n"));
runcommandenv(root, "tree-setup-rollback-ww", setupw, rejectenv,
time.second, &outw);
expectexit(&outw, 1);
assert(same(outc.stderr, outw.stderr));
assert(readfile(rejecttrace).len == 0);
assert(!os.exists(setupoutroot));
assert(os.exists(setuppreserved));
assert(!os.exists(strings.concat(setuppreserved, "/nested")));
assert(!os.exists(setupwork));
assert(same(readfile(setupblock), "not a directory\n"));
let loopc: []str = [driver("ww"), "test",
strings.concat(loop, "/...")];
let loopw: []str = [driver("ww_ww"), "test",
strings.concat(loop, "/...")];
runcommandenv(root, "tree-loop-c", loopc, rejectenv, time.second, &outc);
runcommandenv(root, "tree-loop-ww", loopw, rejectenv, time.second, &outw);
expectexit(&outc, 1);
expectexit(&outw, 1);
assert(same(outc.stderr, outw.stderr));
assert(has(outc.stderr, "cannot canonicalize package directory\n"));
assert(readfile(rejecttrace).len == 0);
clean(root);
};
@test fn persistent_package_request_workdir_is_stable() void = {
let root: str = fresh();
let tree: str = deeppunctuationpath(root, "request tree");
assert(tree.len > 255);
let adir: str = strings.concat(tree, "/a");
let bdir: str = strings.concat(tree, "/b");
let a: str = strings.concat(adir, "/foo");
let b: str = strings.concat(bdir, "/foo");
let workc: str = strings.concat(root, "/work-c");
let workww: str = strings.concat(root, "/work-ww");
mkdirall(tree);
assert(os.mkdir(adir, 448i32) == 0);
assert(os.mkdir(bdir, 448i32) == 0);
assert(os.mkdir(a, 448i32) == 0);
assert(os.mkdir(b, 448i32) == 0);
assert(os.mkdir(workc, 448i32) == 0);
assert(os.mkdir(workww, 448i32) == 0);
writefile(strings.concat(a, "/foo.ww"),
"package foo;\nfn value() i32 = { return 1; };\n");
writefile(strings.concat(a, "/foo_test.ww"),
"package foo;\n@test fn first() void = { assert(value() == 1); };\n");
writefile(strings.concat(b, "/foo.ww"),
"package foo;\nfn value() i32 = { return 2; };\n");
writefile(strings.concat(b, "/foo_test.ww"),
"package foo;\n@test fn second() void = { assert(value() == 2); };\n");
let av: []str = [driver("ww"), "test", "-j", "2", "-w", workc,
"-I", tree,
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,
" [foo]\n")));
assert(has(cold, strings.concat("ok ", b,
" [foo]\n")));
let ckey: str = workc;
assert(os.exists(ckey));
let aaction: str = "a.foo-internal-test";
let baction: str = "b.foo-internal-test";
assert(os.exists(strings.concat(ckey, "/", aaction, ".unit.ww")));
assert(os.exists(strings.concat(ckey, "/", baction, ".unit.ww")));
let aunit: str = readfile(strings.concat(ckey, "/", aaction, ".unit.ww"));
let bunit: str = readfile(strings.concat(ckey, "/", baction, ".unit.ww"));
let awwi: str = readfile(strings.concat(ckey, "/", aaction, ".wwi"));
let bwwi: str = readfile(strings.concat(ckey, "/", baction, ".wwi"));
let aa: str = readfile(strings.concat(ckey, "/", aaction, ".a"));
let ba: str = readfile(strings.concat(ckey, "/", baction, ".a"));
assert(has(aunit, "return 1") && !has(aunit, "return 2"));
assert(has(bunit, "return 2") && !has(bunit, "return 1"));
runcommand(root, "workkey-warm", av,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(cold, out.stdout));
let wwav: []str = [driver("ww_ww"), "test", "-j", "1", "-w", workww,
"-I", tree,
strings.concat(tree, "/...")];
runcommand(root, "workkey-ww", wwav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(cold, out.stdout));
let wwkey: str = workww;
assert(same(aunit, readfile(strings.concat(wwkey, "/", aaction,
".unit.ww"))));
assert(same(bunit, readfile(strings.concat(wwkey, "/", baction,
".unit.ww"))));
assert(same(awwi, readfile(strings.concat(wwkey, "/", aaction, ".wwi"))));
assert(same(bwwi, readfile(strings.concat(wwkey, "/", baction, ".wwi"))));
assert(same(aa, readfile(strings.concat(wwkey, "/", aaction, ".a"))));
assert(same(ba, readfile(strings.concat(wwkey, "/", baction, ".a"))));
// The shared semantic-action store and warm action set are unchanged by an
// equivalent recursive-root spelling.
let equivalentav: []str = [driver("ww_ww"), "test", "-j", "2", "-w",
workww, "-I", tree, strings.concat(tree, "/./...")];
runcommand(root, "workkey-equivalent", equivalentav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, strings.concat("ok ", a,
" [foo]\n")));
assert(has(out.stdout, strings.concat("ok ", b,
" [foo]\n")));
assert(os.exists(wwkey));
assert(same(aunit, readfile(strings.concat(wwkey, "/", aaction,
".unit.ww"))));
assert(same(bunit, readfile(strings.concat(wwkey, "/", baction,
".unit.ww"))));
assert(same(awwi, readfile(strings.concat(wwkey, "/", aaction, ".wwi"))));
assert(same(bwwi, readfile(strings.concat(wwkey, "/", baction, ".wwi"))));
assert(same(aa, readfile(strings.concat(wwkey, "/", aaction, ".a"))));
assert(same(ba, readfile(strings.concat(wwkey, "/", baction, ".a"))));
// Outside every active import root, equal declaration leaves remain two
// deterministic command-local identities derived from canonical dirs.
let localleft: str = deeppunctuationpath(root, "local left");
let localright: str = deeppunctuationpath(root, "local right");
mkdirall(localleft);
mkdirall(localright);
writefile(strings.concat(localleft, "/foo.ww"),
"package foo;\nexport fn value() i32 = { return 11; };\n");
writefile(strings.concat(localright, "/foo.ww"),
"package foo;\nexport fn value() i32 = { return 22; };\n");
let localids: []str = [localidentity(localleft, "foo"),
localidentity(localright, "foo")];
assert(!same(localids[0], localids[1]));
assert(localids[0].len > 255 && localids[1].len > 255);
let localstorage: []str = [packagestoragekey(localids[0], localleft, 0, 0),
packagestoragekey(localids[1], localright, 0, 0)];
assert(!same(localstorage[0], localstorage[1]));
let stages: []str = ["ww", "ww_ww"];
let localrefs: []str = ["", "", "", "", "", ""];
let si: i32 = 0;
for (si < stages.len) {
let leftout: str = strings.concat(root, "/local-", stages[si],
"-left.test");
let rightout: str = strings.concat(root, "/local-", stages[si],
"-right.test");
let lav: []str = [driver(stages[si]), "test", "-c",
"--ww-package-build",
"--ww-package-test", "build", "foo", "foo", "-", "-",
localleft, leftout,
"-",
strings.concat(root, "/local-", stages[si], "-left.status"),
"--ww-package-test", "build", "foo", "foo", "-", "-",
localright, rightout,
"-",
strings.concat(root, "/local-", stages[si], "-right.status"),
localleft];
runcommand(root, strings.concat("local-command-union-", stages[si]),
lav, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let localwork: str = strings.concat(leftout, ".sepwork/");
let li: i32 = 0;
for (li < localids.len) {
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
let xi: i32 = 0;
for (xi < suffixes.len) {
let artifact: str = readfile(strings.concat(localwork,
localstorage[li], suffixes[xi]));
if (xi == 0) {
assert(has(artifact, strings.concat("//ww:module-reset ",
localids[li], "\n")));
} else { if (xi == 1) {
assert(strings.hasprefix(artifact, strings.concat(
"//ww:module ", localids[li], "\n")));
}; };
let refi: i32 = li * 3 + xi;
if (si == 0) { localrefs[refi] = strings.dup(artifact); }
else { assert(same(localrefs[refi], artifact)); };
xi += 1;
};
li += 1;
};
si += 1;
};
clean(root);
};
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", "-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 proves WWstage uses
// the same separate flag/value linker argv contract as Cstage.
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);
let wwdelta: str = strings.sub(wtraced, ctraced.len, wtraced.len);
assert(has(wwdelta, strings.concat(" -L ", root, " -l extra")));
assert(!has(wwdelta, strings.concat(" -L", root)));
assert(!has(wwdelta, " -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);
};
@test fn vendor_directory_import_resolution() void = {
let root: str = fresh();
let source: str = strings.concat(root, "/source");
let runtime: str = strings.concat(root, "/runtime");
let tools: str = strings.concat(root, "/tools");
let leaf: str = strings.concat(source, "/lib/leaf");
let nearest: str = strings.concat(source,
"/domain/app/vendor/lib/math");
let outer: str = strings.concat(source, "/domain/vendor/lib/math");
let rootvendor: str = strings.concat(source, "/vendor/lib/math");
let ordinary: str = strings.concat(source, "/lib/math");
let client: str = strings.concat(source, "/domain/app/client");
let one: str = strings.concat(source, "/domain/app/one");
let two: str = strings.concat(source, "/domain/app/two");
let outerclient: str = strings.concat(source, "/domain/other/client");
let rootclient: str = strings.concat(source, "/other/client");
let emptyclient: str = strings.concat(source, "/domain/empty/client");
let testonlyclient: str = strings.concat(source,
"/domain/testonly/client");
let bareclient: str = strings.concat(source, "/domain/bare/client");
let outsider: str = strings.concat(source, "/outsider");
let prefixclient: str = strings.concat(source, "/domainx/client");
let directclient: str = strings.concat(source, "/domain/app/direct");
let directhijack: str = strings.concat(directclient,
"/vendor/domain/app/vendor/lib/math");
let nested: str = strings.concat(source,
"/nested/owner/vendor/outer/vendor/lib/math");
let nestedclient: str = strings.concat(source,
"/nested/owner/vendor/outer/client");
let ordinaryclient: str = strings.concat(source, "/ordinaryclient");
let vendorx: str = strings.concat(source, "/vendorx/lib/math");
let terminalvendor: str = strings.concat(source, "/terminal/vendor");
let physicalclient: str = strings.concat(source,
"/domain/app/physicalclient");
let aliasclient: str = strings.concat(source, "/aliasclient");
let physicaldirect: str = strings.concat(source,
"/domain/app/physicaldirect");
let aliasdirect: str = strings.concat(source, "/aliasdirect");
let escapephysical: str = strings.concat(root, "/escape/client");
let escapeclient: str = strings.concat(source, "/domain/app/escape");
let shapeclient: str = strings.concat(source, "/shape/owner/client");
let shapevendor: str = strings.concat(source,
"/shape/owner/vendor/lib/math");
let shapevault: str = strings.concat(root, "/vault/deep/different");
let testclient: str = strings.concat(source, "/domain/app/testclient");
let testbad: str = strings.concat(source, "/testbad");
let supportcase: str = strings.concat(source, "/supportcase");
let toolsource: str = strings.concat(root, "/toolsource");
let toolsupport: str = strings.concat(toolsource, "/test");
let toolvendor: str = strings.concat(toolsource,
"/test/vendor/fnmatch");
let vendortest: str = strings.concat(source,
"/literal/owner/vendor/lib/math");
let nestedvendortest: str = strings.concat(vendortest,
"/vendor/lib/math");
let alpha: str = strings.concat(source, "/alpha/client");
let beta: str = strings.concat(source, "/beta/client");
let alphavendor: str = strings.concat(alpha, "/vendor/lib/math");
let betavendor: str = strings.concat(beta, "/vendor/lib/math");
let pairvault: str = strings.concat(root, "/pair-vault/math");
let boundary: str = strings.concat(root, "/boundary");
let active: str = strings.concat(boundary, "/active");
let boundaryclient: str = strings.concat(active, "/domain/app");
let boundaryordinary: str = strings.concat(active, "/lib/math");
let boundaryabove: str = strings.concat(boundary, "/vendor/lib/math");
let cleanroot: str = strings.concat(root, "/clean");
let cleanclient: str = strings.concat(cleanroot, "/domain/app");
let cleanordinary: str = strings.concat(cleanroot, "/lib/math");
let foldvendorupper: str = strings.concat(source,
"/domain/fold/vendor/lib/Foo");
let foldvendorlower: str = strings.concat(source,
"/domain/fold/vendor/lib/foo");
let foldvendorleft: str = strings.concat(source, "/domain/fold/left");
let foldvendorright: str = strings.concat(source, "/domain/fold/right");
let foldvendorclient: str = strings.concat(source, "/domain/fold/client");
let foldvendorreverseclient: str = strings.concat(source,
"/domain/fold/reverseclient");
let foldaliasvendorlib: str = strings.concat(source,
"/domain/foldalias/vendor/lib");
let foldaliasvendorupper: str = strings.concat(foldaliasvendorlib, "/Foo");
let foldaliasvendorlower: str = strings.concat(foldaliasvendorlib, "/foo");
let foldaliasvendorleft: str = strings.concat(source,
"/domain/foldalias/left");
let foldaliasvendorright: str = strings.concat(source,
"/domain/foldalias/right");
let foldaliasvendorclient: str = strings.concat(source,
"/domain/foldalias/client");
let foldaliasvendorvault: str = strings.concat(root, "/fold-vendor-vault");
let dirs: []str = [leaf, nearest, outer, rootvendor, ordinary, client,
one, two, outerclient, rootclient, emptyclient,
strings.concat(emptyclient, "/vendor/lib/math/fake.ww"),
testonlyclient, strings.concat(testonlyclient, "/vendor/lib/math"),
bareclient, strings.concat(bareclient, "/vendor/lib/math"), outsider,
prefixclient, directclient, directhijack, nested, nestedclient,
ordinaryclient,
vendorx, terminalvendor, physicalclient, physicaldirect, escapephysical,
shapeclient, strings.concat(source, "/shape/owner/vendor/lib"),
shapevault, testclient, testbad, supportcase, toolsupport,
toolvendor, vendortest, nestedvendortest,
alpha, beta, strings.concat(alpha, "/vendor/lib"),
strings.concat(beta, "/vendor/lib"), pairvault, boundaryclient,
boundaryordinary, boundaryabove, cleanclient, cleanordinary,
foldvendorupper, foldvendorlower, foldvendorleft, foldvendorright,
foldvendorclient, foldvendorreverseclient, foldaliasvendorlib, foldaliasvendorleft,
foldaliasvendorright, foldaliasvendorclient, foldaliasvendorvault,
runtime, tools];
let di: i32 = 0;
for (di < dirs.len) { mkdirall(dirs[di]); di += 1; };
writefile(strings.concat(runtime, "/libwwrt.a"),
readfile(strings.concat(repo(), "/out/lib/libwwrt.a")));
writefile(strings.concat(leaf, "/leaf.ww"), strings.concat(
"package leaf;\n",
"export fn value() i32 = { return 1; };\n"));
let neara: str = strings.concat(
"package math;\nimport lib.leaf;\n",
"export fn value() i32 = { return leaf.value() + 10; };\n");
let nearz: str = strings.concat(
"package math;\n",
"fn private_value() i32 = { return 99; };\n");
writefile(strings.concat(nearest, "/a.ww"), neara);
writefile(strings.concat(nearest, "/z.ww"), nearz);
writefile(strings.concat(outer, "/math.ww"),
"package math;\nexport fn value() i32 = { return 22; };\n");
writefile(strings.concat(rootvendor, "/math.ww"),
"package math;\nexport fn value() i32 = { return 33; };\n");
writefile(strings.concat(ordinary, "/math.ww"),
"package math;\nexport fn value() i32 = { return 44; };\n");
let mainbody: str = strings.concat(
"package main;\nimport lib.math;\n",
"fn main() i32 = { return math.value(); };\n");
writefile(strings.concat(client, "/main.ww"), mainbody);
writefile(strings.concat(one, "/main.ww"), mainbody);
writefile(strings.concat(two, "/main.ww"), mainbody);
writefile(strings.concat(outerclient, "/main.ww"), mainbody);
writefile(strings.concat(rootclient, "/main.ww"), mainbody);
writefile(strings.concat(emptyclient, "/main.ww"), mainbody);
writefile(strings.concat(testonlyclient, "/main.ww"), mainbody);
writefile(strings.concat(testonlyclient,
"/vendor/lib/math/only_test.ww"),
"package math;\n@test fn only() void = { assert(true); };\n");
writefile(strings.concat(bareclient, "/main.ww"), mainbody);
writefile(strings.concat(bareclient, "/vendor/lib/math/.ww"),
"package math;\n");
let expanded: str = "domain.app.vendor.lib.math";
let directbody: str = strings.concat(
"package main;\nimport ", expanded, ";\n",
"fn main() i32 = { return math.value(); };\n");
writefile(strings.concat(outsider, "/main.ww"), directbody);
writefile(strings.concat(prefixclient, "/main.ww"), directbody);
writefile(strings.concat(directclient, "/main.ww"), directbody);
writefile(strings.concat(directhijack, "/math.ww"),
"package math;\nexport fn value() i32 = { return 99; };\n");
writefile(strings.concat(nested, "/math.ww"),
"package math;\nexport fn value() i32 = { return 77; };\n");
writefile(strings.concat(nestedclient, "/main.ww"), mainbody);
writefile(strings.concat(vendorx, "/math.ww"),
"package math;\nexport fn value() i32 = { return 4; };\n");
writefile(strings.concat(terminalvendor, "/vendor.ww"),
"package vendor;\nexport fn value() i32 = { return 8; };\n");
writefile(strings.concat(ordinaryclient, "/main.ww"), strings.concat(
"package main;\nimport vendorx.lib.math;\nimport terminal.vendor;\n",
"fn main() i32 = { return math.value() + vendor.value(); };\n"));
writefile(strings.concat(physicalclient, "/main.ww"), mainbody);
assert(os.symlink(physicalclient, aliasclient) == 0);
writefile(strings.concat(physicaldirect, "/main.ww"), directbody);
assert(os.symlink(physicaldirect, aliasdirect) == 0);
writefile(strings.concat(escapephysical, "/main.ww"), mainbody);
assert(os.symlink(escapephysical, escapeclient) == 0);
writefile(strings.concat(shapevault, "/math.ww"),
"package math;\nexport fn value() i32 = { return 17; };\n");
assert(os.symlink(shapevault, shapevendor) == 0);
writefile(strings.concat(shapeclient, "/main.ww"), mainbody);
writefile(strings.concat(testclient, "/testclient.ww"), strings.concat(
"package testclient;\nimport lib.math;\n",
"export fn value() i32 = { return math.value(); };\n"));
writefile(strings.concat(testclient, "/same_test.ww"), strings.concat(
"package testclient;\nimport lib.math;\n",
"@test fn same_vendor() void = { assert(math.value() == 11); };\n"));
writefile(strings.concat(testclient, "/external_test.ww"), strings.concat(
"package testclient_test;\nimport lib.math;\n",
"import domain.app.testclient;\n",
"@test fn external_vendor() void = {\n",
" assert(math.value() + testclient.value() == 22);\n};\n"));
writefile(strings.concat(testbad, "/testbad.ww"),
"package testbad;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(testbad, "/same_test.ww"), strings.concat(
"package testbad;\nimport ", expanded, ";\n",
"@test fn forbidden_vendor() void = { assert(false); };\n"));
writefile(strings.concat(supportcase, "/supportcase.ww"),
"package supportcase;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(supportcase, "/supportcase_test.ww"),
"package supportcase;\n@test fn support_runs() void = { assert(value() == 1); };\n");
writefile(strings.concat(toolsupport, "/run.ww"),
readfile(strings.concat(repo(), "/lib/test/run.ww")));
writefile(strings.concat(toolvendor, "/fnmatch.ww"),
readfile(strings.concat(repo(), "/lib/fnmatch/fnmatch.ww")));
let tooldeps: []str = ["ascii", "bytes", "encoding", "os", "rt",
"strings", "time", "types"];
di = 0;
for (di < tooldeps.len) {
assert(os.symlink(strings.concat(repo(), "/lib/", tooldeps[di]),
strings.concat(toolsource, "/", tooldeps[di])) == 0);
di += 1;
};
writefile(strings.concat(vendortest, "/math.ww"),
"package math;\nexport fn value() i32 = { return 7; };\n");
writefile(strings.concat(vendortest, "/math_test.ww"), strings.concat(
"package math_test;\nimport lib.math;\n",
"@test fn nested_external_vendor() void = {\n",
" assert(math.value() == 9);\n};\n"));
writefile(strings.concat(nestedvendortest, "/math.ww"),
"package math;\nexport fn value() i32 = { return 9; };\n");
writefile(strings.concat(pairvault, "/math.ww"),
"package math;\nexport fn value() i32 = { return 61; };\n");
assert(os.symlink(pairvault, alphavendor) == 0);
assert(os.symlink(pairvault, betavendor) == 0);
writefile(strings.concat(alpha, "/main.ww"), mainbody);
writefile(strings.concat(beta, "/main.ww"), mainbody);
writefile(strings.concat(boundaryclient, "/main.ww"), mainbody);
writefile(strings.concat(boundaryordinary, "/math.ww"),
"package math;\nexport fn value() i32 = { return 55; };\n");
writefile(strings.concat(boundaryabove, "/math.ww"),
"package math;\nexport fn value() i32 = { return 66; };\n");
writefile(strings.concat(cleanclient, "/main.ww"), mainbody);
writefile(strings.concat(cleanordinary, "/math.ww"),
"package math;\nexport fn value() i32 = { return 44; };\n");
writefile(strings.concat(foldvendorupper, "/pkg.ww"),
"package upper;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(foldvendorlower, "/pkg.ww"),
"package lower;\nexport fn value() i32 = { return 2; };\n");
writefile(strings.concat(foldvendorleft, "/pkg.ww"), strings.concat(
"package left;\nimport _ lib.Foo;\n",
"export fn value() i32 = { return 1; };\n"));
writefile(strings.concat(foldvendorright, "/pkg.ww"), strings.concat(
"package right;\nimport _ lib.foo;\n",
"export fn value() i32 = { return 2; };\n"));
writefile(strings.concat(foldvendorclient, "/main.ww"), strings.concat(
"package main;\nimport _ domain.fold.left;\n",
"import _ domain.fold.right;\nfn main() i32 = { return 0; };\n"));
writefile(strings.concat(foldvendorreverseclient, "/main.ww"), strings.concat(
"package main;\nimport _ domain.fold.right;\n",
"import _ domain.fold.left;\nfn main() i32 = { return 0; };\n"));
writefile(strings.concat(foldaliasvendorvault, "/pkg.ww"),
"package shared;\nexport fn value() i32 = { return 1; };\n");
assert(os.symlink(foldaliasvendorvault, foldaliasvendorupper) == 0);
assert(os.symlink(foldaliasvendorvault, foldaliasvendorlower) == 0);
writefile(strings.concat(foldaliasvendorleft, "/pkg.ww"), strings.concat(
"package left;\nimport _ lib.Foo;\n",
"export fn value() i32 = { return 1; };\n"));
writefile(strings.concat(foldaliasvendorright, "/pkg.ww"), strings.concat(
"package right;\nimport _ lib.foo;\n",
"export fn value() i32 = { return 2; };\n"));
writefile(strings.concat(foldaliasvendorclient, "/main.ww"), strings.concat(
"package main;\nimport _ domain.foldalias.left;\n",
"import _ domain.foldalias.right;\nfn main() i32 = { return 0; };\n"));
let compilerwrapper: str = strings.concat(tools, "/w6c.sh");
let assemblerwrapper: str = strings.concat(tools, "/w6a.sh");
let linkerwrapper: str = strings.concat(tools, "/w6l.sh");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_VENDOR_COMPILER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_VENDOR_COMPILER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_VENDOR_COMPILER_TRACE\"\n",
"exec \"$WW_VENDOR_REAL_COMPILER\" \"$@\"\n"));
writeexecutable(assemblerwrapper, strings.concat(
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_VENDOR_ASSEMBLER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_VENDOR_ASSEMBLER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_VENDOR_ASSEMBLER_TRACE\"\n",
"exec \"$WW_VENDOR_REAL_ASSEMBLER\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_VENDOR_LINKER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_VENDOR_LINKER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_VENDOR_LINKER_TRACE\"\n",
"exec \"$WW_VENDOR_REAL_LINKER\" \"$@\"\n"));
let stages: []str = ["ww", "ww_ww"];
let compilers: []str = ["w6c", "w6c_ww"];
let assemblers: []str = ["w6a", "w6a_ww"];
let linkers: []str = ["w6l", "w6l_ww"];
let works: []str = [strings.concat(root, "/c-work"),
strings.concat(root, "/ww-work")];
let bins: []str = [strings.concat(root, "/c-bin"),
strings.concat(root, "/ww-bin")];
let compilertraces: []str = [strings.concat(root, "/c-compiler"),
strings.concat(root, "/ww-compiler")];
let assemblertraces: []str = [strings.concat(root, "/c-assembler"),
strings.concat(root, "/ww-assembler")];
let linkertraces: []str = [strings.concat(root, "/c-linker"),
strings.concat(root, "/ww-linker")];
let coreartifacts: []str = ["lib.leaf", expanded, "domain.app.client"];
let coresuffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"];
let references: []str = alloc([],
(coreartifacts.len * coresuffixes.len): u64)!;
let ri: i32 = 0;
for (ri < coreartifacts.len * coresuffixes.len) {
append(references, ""); ri += 1;
};
let referencebin: str = "";
let referencecompiler: str = "";
let referenceassembler: str = "";
let referencelinker: str = "";
let referencedirectdiag: str = "";
let referenceoutsidediag: str = "";
let combinedrefs: []str = ["", "", "", "", "", ""];
let referencetestout: str = "";
let referencetesterr: str = "";
let testrefs: []str = ["", "", "", "", "", ""];
let referencesupportout: str = "";
let supportrefs: []str = ["", "", ""];
let referenceorderdiag: str = "";
let referenceescapeddiag: str = "";
let referencealiasdirectdiag: str = "";
let referenceprefixdiag: str = "";
let candidate_diag_refs: []str = ["", ""];
let foldvendorrefs: []str = ["", "", ""];
let foldvendormultiref: str = "";
let supplementalrefs: []str = ["", "", "", "", "", "", "", "",
""];
let referencevendortestout: str = "";
let referencevendortesterr: str = "";
let referencetestbaddiag: str = "";
let baseenv: []str = os.getenvs();
let si: i32 = 0;
for (si < stages.len) {
assert(os.mkdir(works[si], 448i32) == 0);
writefile(compilertraces[si], "");
writefile(assemblertraces[si], "");
writefile(linkertraces[si], "");
let env: []str = alloc([], (baseenv.len + 11): 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_LIB=")
&& !strings.hasprefix(baseenv[ei], "WW_SRCLIB=")
&& !strings.hasprefix(baseenv[ei],
"WW_VENDOR_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_VENDOR_ASSEMBLER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_VENDOR_LINKER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_VENDOR_REAL_COMPILER=")
&& !strings.hasprefix(baseenv[ei],
"WW_VENDOR_REAL_ASSEMBLER=")
&& !strings.hasprefix(baseenv[ei],
"WW_VENDOR_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_LIB=", runtime));
append(env, strings.concat("WW_VENDOR_COMPILER_TRACE=",
compilertraces[si]));
append(env, strings.concat("WW_VENDOR_ASSEMBLER_TRACE=",
assemblertraces[si]));
append(env, strings.concat("WW_VENDOR_LINKER_TRACE=",
linkertraces[si]));
append(env, strings.concat("WW_VENDOR_REAL_COMPILER=",
driver(compilers[si])));
append(env, strings.concat("WW_VENDOR_REAL_ASSEMBLER=",
driver(assemblers[si])));
append(env, strings.concat("WW_VENDOR_REAL_LINKER=",
driver(linkers[si])));
let out: commandout;
let foldtargets: []str = [foldvendorclient, foldvendorreverseclient,
foldaliasvendorclient];
let foldlabels: []str = ["distinct", "reverse-imports", "one-dir"];
let foldwants: []str = [
"ww: case-insensitive import collision: \"domain.fold.vendor.lib.Foo\" and \"domain.fold.vendor.lib.foo\"\n",
"ww: case-insensitive import collision: \"domain.fold.vendor.lib.Foo\" and \"domain.fold.vendor.lib.foo\"\n",
"ww: case-insensitive import collision: \"domain.foldalias.vendor.lib.Foo\" and \"domain.foldalias.vendor.lib.foo\"\n",
];
let fi: i32 = 0;
for (fi < foldtargets.len) {
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let foldwork: str = strings.concat(root, "/vendor-fold-",
foldlabels[fi], "-", stages[si], "-work");
let foldout: str = strings.concat(root, "/vendor-fold-",
foldlabels[fi], "-", stages[si]);
assert(os.mkdir(foldwork, 448i32) == 0);
let foldav: []str = [driver(stages[si]), "build", "-w",
foldwork, "-I", source, "-o", foldout, foldtargets[fi]];
runcommandenv(root, strings.concat("vendor-fold-", foldlabels[fi],
"-", stages[si]), foldav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && same(out.stderr, foldwants[fi]));
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(readfile(linkertraces[si]).len == 0);
assert(!os.exists(foldout));
assert(!os.exists(strings.concat(foldout, ".new")));
assert(!os.exists(strings.concat(foldout, ".sepwork")));
assert(!os.exists(strings.concat(foldwork, "/.wwtool.stamp")));
assert(directoryisempty(foldwork));
if (si == 0) { foldvendorrefs[fi] = strings.dup(out.stderr); }
else { assert(same(foldvendorrefs[fi], out.stderr)); };
fi += 1;
};
assert(same(foldvendorrefs[0], foldvendorrefs[1]));
// A command-global multi-product request is one rejection transaction.
// Reversing its descriptors cannot publish the unrelated product or
// mutate either pre-existing status.
let foldmultiwork: str = strings.concat(root, "/vendor-fold-multi-",
stages[si], "-work");
assert(os.mkdir(foldmultiwork, 448i32) == 0);
let foldallowedout: str = strings.concat(root, "/vendor-fold-allowed-",
stages[si]);
let foldcollisionout: str = strings.concat(root,
"/vendor-fold-collision-", stages[si]);
let foldallowedstatus: str = strings.concat(foldallowedout, ".status");
let foldcollisionstatus: str = strings.concat(foldcollisionout, ".status");
writefile(foldallowedstatus, "sentinel-allowed\n");
writefile(foldcollisionstatus, "sentinel-collision\n");
let foldforward: []str = [driver(stages[si]), "test", "-c", "-w",
foldmultiwork, "-I", source, "--ww-package-build",
"--ww-package-test", "build", "main", "main", "-", "-", client,
foldallowedout, "-", foldallowedstatus,
"--ww-package-test", "build", "main", "main", "-", "-",
foldvendorclient, foldcollisionout, "-", foldcollisionstatus, client];
let foldreverse: []str = [driver(stages[si]), "test", "-c", "-w",
foldmultiwork, "-I", source, "--ww-package-build",
"--ww-package-test", "build", "main", "main", "-", "-",
foldvendorclient, foldcollisionout, "-", foldcollisionstatus,
"--ww-package-test", "build", "main", "main", "-", "-", client,
foldallowedout, "-", foldallowedstatus, client];
let foldrequests: [][]str = [foldforward, foldreverse];
let foldmultidiags: []str = ["", ""];
let foldorderlabels: []str = ["forward", "reverse"];
let foi: i32 = 0;
for (foi < foldrequests.len) {
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
runcommandenv(root, strings.concat("vendor-fold-multi-", stages[si],
"-", foldorderlabels[foi]), foldrequests[foi], env,
(180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && same(out.stderr, foldwants[0]));
foldmultidiags[foi] = strings.dup(out.stderr);
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(readfile(linkertraces[si]).len == 0);
assert(same(readfile(foldallowedstatus), "sentinel-allowed\n"));
assert(same(readfile(foldcollisionstatus), "sentinel-collision\n"));
assert(!os.exists(strings.concat(foldallowedstatus, ".new")));
assert(!os.exists(strings.concat(foldcollisionstatus, ".new")));
assert(!os.exists(foldallowedout));
assert(!os.exists(strings.concat(foldallowedout, ".new")));
assert(!os.exists(strings.concat(foldallowedout, ".sepwork")));
assert(!os.exists(strings.concat(foldallowedout, ".result")));
assert(!os.exists(strings.concat(foldallowedout, ".result.new")));
assert(!os.exists(foldcollisionout));
assert(!os.exists(strings.concat(foldcollisionout, ".new")));
assert(!os.exists(strings.concat(foldcollisionout, ".sepwork")));
assert(!os.exists(strings.concat(foldcollisionout, ".result")));
assert(!os.exists(strings.concat(foldcollisionout, ".result.new")));
assert(directoryisempty(foldmultiwork));
foi += 1;
};
assert(same(foldmultidiags[0], foldmultidiags[1]));
if (si == 0) { foldvendormultiref = strings.dup(foldmultidiags[0]); }
else { assert(same(foldvendormultiref, foldmultidiags[0])); };
let av: []str = [driver(stages[si]), "build", "-w", works[si],
"-I", source, "-o", bins[si], client];
runcommandenv(root, strings.concat("vendor-cold-", stages[si]), av,
env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let wantnear: str = strings.concat(
"//ww:module-reset ", expanded, "\n", neara, "\n",
"//ww:module-reset ", expanded, "\n", nearz, "\n",
"//ww:vendor-dir ", hexbytes(nearest), "\n");
let nearunit: str = readfile(strings.concat(works[si], "/", expanded,
".unit.ww"));
assert(strings.hasprefix(nearunit, wantnear));
assert(has(nearunit, "//ww:direct-export lib.leaf "));
let clientunit: str = readfile(strings.concat(works[si],
"/domain.app.client.unit.ww"));
assert(has(clientunit, strings.concat("//ww:import-map lib.math ",
expanded, " ", hexbytes(nearest), "\n")));
let ai: i32 = 0;
for (ai < coreartifacts.len) {
let xi: i32 = 0;
for (xi < coresuffixes.len) {
let bytes: str = readfile(strings.concat(works[si], "/",
coreartifacts[ai], coresuffixes[xi]));
let index: i32 = ai * coresuffixes.len + xi;
if (si == 0) { references[index] = strings.dup(bytes); }
else { assert(same(references[index], bytes)); };
xi += 1;
};
ai += 1;
};
let ctrace: str = readfile(compilertraces[si]);
let atrace: str = readfile(assemblertraces[si]);
let ltrace: str = readfile(linkertraces[si]);
assert(occurrences(ctrace, "\n") == 3);
assert(occurrences(atrace, "\n") == 4);
assert(occurrences(ltrace, "\n") == 1);
assert(has(ltrace, strings.concat("BEGIN<-o><", bins[si], ".new>")));
let dispatchline: str = strings.concat("BEGIN<-o><", works[si],
"/domain.app.client.init.o.new><", works[si],
"/domain.app.client.init.s.new>");
assert(same(linecontaining(atrace,
"/domain.app.client.init.o.new"), dispatchline));
let nearline: str = linecontaining(ctrace,
strings.concat(expanded, ".unit.new"));
assert(occurrences(nearline, "<--import><lib.leaf>") == 1);
assert(!has(nearline, "domain.app.client.wwi"));
let clientline: str = linecontaining(ctrace,
"domain.app.client.unit.new");
assert(occurrences(clientline, strings.concat("<--import><", expanded,
"><", works[si], "/", expanded, ".wwi.new>")) == 1);
assert(occurrences(clientline, strings.concat(
"<--import-map><lib.math><", expanded, ">")) == 1);
assert(!has(clientline, "lib.leaf.wwi"));
assert(occurrences(ltrace, strings.concat("<", works[si],
"/domain.app.client.a.new>")) == 1);
assert(occurrences(ltrace, strings.concat("<", works[si], "/",
expanded, ".a.new>")) == 1);
assert(occurrences(ltrace, strings.concat("<", works[si],
"/lib.leaf.a.new>")) == 1);
assert(!has(ltrace, ".wwi>"));
let nc: str = normalizedtrace(ctrace,
strings.concat(works[si], "/"), bins[si]);
let na: str = normalizedtrace(atrace,
strings.concat(works[si], "/"), bins[si]);
let nl: str = normalizedtrace(ltrace,
strings.concat(works[si], "/"), bins[si]);
if (si == 0) {
referencecompiler = strings.dup(nc);
referenceassembler = strings.dup(na);
referencelinker = strings.dup(nl);
referencebin = strings.dup(readfile(bins[si]));
} else {
assert(same(referencecompiler, nc));
assert(same(referenceassembler, na));
assert(same(referencelinker, nl));
assert(same(referencebin, readfile(bins[si])));
};
let runav: []str = [bins[si]];
runcommand(root, strings.concat("vendor-run-", stages[si]), runav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 11);
let voucher: str = readfile(strings.concat(works[si], "/",
expanded, ".unit.ww"));
let toolww: str = readfile(strings.concat(works[si], "/.wwtool.ww"));
let toolc: str = readfile(strings.concat(works[si], "/.wwtool.w6c"));
let toola: str = readfile(strings.concat(works[si], "/.wwtool.w6a"));
let stamp: str = readfile(strings.concat(works[si], "/.wwtool.stamp"));
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
runcommandenv(root, strings.concat("vendor-warm-", stages[si]), av,
env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(occurrences(readfile(linkertraces[si]), "\n") == 1);
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let badout: str = strings.concat(root, "/warm-bad-", stages[si]);
let badav: []str = [driver(stages[si]), "build", "-w", works[si],
"-I", source, "-o", badout, outsider];
runcommandenv(root, strings.concat("vendor-warm-bad-", stages[si]),
badav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let outsidediag: str = strings.concat(outsider,
"/main.ww:2:1: error: use of vendored package not allowed\n");
assert(same(out.stderr, outsidediag));
if (si == 0) { referenceoutsidediag = strings.dup(out.stderr); }
else { assert(same(referenceoutsidediag, out.stderr)); };
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(readfile(linkertraces[si]).len == 0);
assert(!os.exists(badout));
assert(same(voucher, readfile(strings.concat(works[si], "/",
expanded, ".unit.ww"))));
assert(same(toolww, readfile(strings.concat(works[si], "/.wwtool.ww"))));
assert(same(toolc, readfile(strings.concat(works[si], "/.wwtool.w6c"))));
assert(same(toola, readfile(strings.concat(works[si], "/.wwtool.w6a"))));
assert(same(stamp, readfile(strings.concat(works[si],
"/.wwtool.stamp"))));
ai = 0;
for (ai < coreartifacts.len) {
let xi: i32 = 0;
for (xi < coresuffixes.len) {
let index: i32 = ai * coresuffixes.len + xi;
assert(same(references[index], readfile(strings.concat(
works[si], "/", coreartifacts[ai], coresuffixes[xi]))));
xi += 1;
};
ai += 1;
};
let coldout: str = strings.concat(root, "/cold-bad-", stages[si]);
let coldav: []str = [driver(stages[si]), "build", "-I", source,
"-o", coldout, outsider];
runcommandenv(root, strings.concat("vendor-cold-bad-", stages[si]),
coldav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(same(out.stderr, outsidediag));
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(readfile(linkertraces[si]).len == 0);
assert(!os.exists(coldout));
assert(!os.exists(strings.concat(coldout, ".sepwork")));
let directout: str = strings.concat(root, "/direct-bad-", stages[si]);
let directav: []str = [driver(stages[si]), "build", "-I", source,
"-o", directout, directclient];
runcommandenv(root, strings.concat("vendor-direct-bad-", stages[si]),
directav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let directdiag: str = strings.concat(directclient,
"/main.ww:2:1: error: ", expanded,
" must be imported as lib.math\n");
assert(same(out.stderr, directdiag));
if (si == 0) { referencedirectdiag = strings.dup(out.stderr); }
else { assert(same(referencedirectdiag, out.stderr)); };
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(readfile(linkertraces[si]).len == 0);
assert(!os.exists(directout));
assert(!os.exists(strings.concat(directout, ".sepwork")));
// The lexical importer is outside domain/app, but the symlink target is
// physically inside it. Visibility therefore passes and the later
// effective-spelling diagnostic proves physical importer containment.
let aliasdirectout: str = strings.concat(root,
"/alias-direct-bad-", stages[si]);
let aliasdirectav: []str = [driver(stages[si]), "build", "-I", source,
"-o", aliasdirectout, aliasdirect];
runcommandenv(root, strings.concat("vendor-alias-direct-bad-",
stages[si]), aliasdirectav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let aliasdirectdiag: str = strings.concat(aliasdirect,
"/main.ww:2:1: error: ", expanded,
" must be imported as lib.math\n");
assert(same(out.stderr, aliasdirectdiag));
if (si == 0) { referencealiasdirectdiag = strings.dup(out.stderr); }
else { assert(same(referencealiasdirectdiag, out.stderr)); };
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(readfile(linkertraces[si]).len == 0);
assert(!os.exists(aliasdirectout));
assert(!os.exists(strings.concat(aliasdirectout, ".sepwork")));
// Remaining resolution rows reuse the stage workdir, but every output
// remains independently executable and compared across stages below.
let targets: []str = [outerclient, rootclient, emptyclient,
boundaryclient, cleanclient, nestedclient, ordinaryclient,
aliasclient, shapeclient];
let roots: []str = [source, source, source, active, cleanroot, source,
source, source, source];
let codes: []i32 = [22, 33, 22, 55, 44, 77, 12, 33, 17];
let labels: []str = ["outer", "root", "empty", "boundary", "ordinary",
"nested", "names", "alias", "shape"];
let ti: i32 = 0;
for (ti < targets.len) {
let output: str = strings.concat(root, "/", labels[ti], "-",
stages[si]);
let tav: []str = [driver(stages[si]), "build", "-w", works[si],
"-I", roots[ti], "-o", output, targets[ti]];
runcommandenv(root, strings.concat("vendor-", labels[ti], "-",
stages[si]), tav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let rr: []str = [output];
runcommand(root, strings.concat("vendor-run-", labels[ti], "-",
stages[si]), rr,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, codes[ti]);
if (si == 0) {
supplementalrefs[ti] = strings.dup(readfile(output));
} else {
assert(same(supplementalrefs[ti], readfile(output)));
};
ti += 1;
};
let escapedout: str = strings.concat(root, "/escape-bad-", stages[si]);
let escapedav: []str = [driver(stages[si]), "build", "-I", source,
"-o", escapedout, escapeclient];
runcommandenv(root, strings.concat("vendor-escape-bad-", stages[si]),
escapedav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "use of vendored package not allowed\n"));
if (si == 0) { referenceescapeddiag = strings.dup(out.stderr); }
else { assert(same(referenceescapeddiag, out.stderr)); };
let prefixout: str = strings.concat(root, "/prefix-bad-", stages[si]);
let prefixav: []str = [driver(stages[si]), "build", "-I", source,
"-o", prefixout, prefixclient];
runcommandenv(root, strings.concat("vendor-prefix-bad-", stages[si]),
prefixav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "use of vendored package not allowed\n"));
if (si == 0) { referenceprefixdiag = strings.dup(out.stderr); }
else { assert(same(referenceprefixdiag, out.stderr)); };
let candidateclients: []str = [testonlyclient, bareclient];
let candidatefiles: []str = ["only_test.ww", ".ww"];
let ci: i32 = 0;
for (ci < candidateclients.len) {
let candidateout: str = strings.concat(root, "/candidate-bad-",
stages[si], "-", candidatefiles[ci]);
let cav: []str = [driver(stages[si]), "build", "-I", source,
"-o", candidateout, candidateclients[ci]];
runcommandenv(root, strings.concat("vendor-candidate-bad-",
stages[si], "-", candidatefiles[ci]), cav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "/vendor/lib/math: directory contains no WW package sources\n"));
assert(!os.exists(strings.concat(candidateout, ".sepwork")));
if (si == 0) {
candidate_diag_refs[ci] = strings.dup(out.stderr);
} else {
assert(same(candidate_diag_refs[ci], out.stderr));
};
ci += 1;
};
let selected: str = strings.concat(root, "/selected-", stages[si], ".a");
let selectedav: []str = [driver(stages[si]), "build", "-I", source,
"-o", selected, nearest];
runcommandenv(root, strings.concat("vendor-selected-", stages[si]),
selectedav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(references[1 * coresuffixes.len + 4], readfile(selected)));
assert(same(references[1 * coresuffixes.len + 1],
readfile(strings.concat(selected, ".wwi"))));
// One command-global union shares one vendored action between three
// importers, keeps an outer physical copy distinct, and also keeps two
// expanded identities distinct when their lexical vendor routes converge
// through symlinks on one physical directory.
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let combinedwork: str = strings.concat(root, "/combined-work-",
stages[si]);
assert(os.mkdir(combinedwork, 448i32) == 0);
let combinedtargets: []str = [client, one, two, outerclient, alpha,
beta, pairvault];
let combinedpackages: []str = ["main", "main", "main", "main",
"main", "main", "math"];
let combinedcodes: []i32 = [11, 11, 11, 22, 61, 61];
let combinedoutputs: []str = [
strings.concat(root, "/combined-client-", stages[si]),
strings.concat(root, "/combined-one-", stages[si]),
strings.concat(root, "/combined-two-", stages[si]),
strings.concat(root, "/combined-outer-", stages[si]),
strings.concat(root, "/combined-alpha-", stages[si]),
strings.concat(root, "/combined-beta-", stages[si]),
strings.concat(root, "/combined-local-", stages[si])];
let combinedstatuses: []str = [
strings.concat(combinedoutputs[0], ".status"),
strings.concat(combinedoutputs[1], ".status"),
strings.concat(combinedoutputs[2], ".status"),
strings.concat(combinedoutputs[3], ".status"),
strings.concat(combinedoutputs[4], ".status"),
strings.concat(combinedoutputs[5], ".status"),
strings.concat(combinedoutputs[6], ".status")];
let combinedav: []str = alloc([],
(9 + combinedtargets.len * 10): u64)!;
append(combinedav, driver(stages[si]));
append(combinedav, "test"); append(combinedav, "-c");
append(combinedav, "-w"); append(combinedav, combinedwork);
append(combinedav, "-I"); append(combinedav, source);
append(combinedav, "--ww-package-build");
let ui: i32 = 0;
for (ui < combinedtargets.len) {
append(combinedav, "--ww-package-test");
append(combinedav, "build");
append(combinedav, combinedpackages[ui]);
append(combinedav, combinedpackages[ui]);
append(combinedav, "-");
append(combinedav, "-");
append(combinedav, combinedtargets[ui]);
append(combinedav, combinedoutputs[ui]);
append(combinedav, "-");
append(combinedav, combinedstatuses[ui]);
ui += 1;
};
append(combinedav, client);
runcommandenv(root, strings.concat("vendor-combined-", stages[si]),
combinedav, env, (180i64 * (time.second: i64)): time.duration,
&out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let combinedtrace: str = readfile(compilertraces[si]);
assert(occurrences(combinedtrace, strings.concat("/", expanded,
".unit.new")) == 1);
assert(occurrences(combinedtrace,
"/domain.vendor.lib.math.unit.new") == 1);
assert(occurrences(combinedtrace,
"/alpha.client.vendor.lib.math.unit.new") == 1);
assert(occurrences(combinedtrace,
"/beta.client.vendor.lib.math.unit.new") == 1);
assert(has(combinedtrace, localidentity(pairvault, "math")));
assert(occurrences(combinedtrace, "/lib.leaf.unit.new") == 1);
let combinedidentities: []str = [expanded,
"alpha.client.vendor.lib.math", "beta.client.vendor.lib.math"];
let combinedsuffixes: []str = [".wwi", ".a"];
ui = 0;
for (ui < combinedidentities.len) {
let xi: i32 = 0;
for (xi < combinedsuffixes.len) {
let bytes: str = readfile(strings.concat(combinedwork, "/",
combinedidentities[ui], combinedsuffixes[xi]));
let index: i32 = ui * combinedsuffixes.len + xi;
if (si == 0) {
combinedrefs[index] = strings.dup(bytes);
} else {
assert(same(combinedrefs[index], bytes));
};
xi += 1;
};
ui += 1;
};
assert(os.exists(strings.concat(combinedwork,
"/domain.vendor.lib.math.wwi")));
assert(os.exists(strings.concat(combinedwork,
"/domain.vendor.lib.math.a")));
ui = 0;
for (ui < combinedcodes.len) {
let cav: []str = [combinedoutputs[ui]];
runcommand(root, strings.concat("vendor-combined-run-", stages[si],
"-", labels[ui]), cav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, combinedcodes[ui]);
ui += 1;
};
assert(!os.exists(combinedoutputs[6]));
assert(same(readfile(combinedstatuses[6]), "ok\n"));
// A target interned by the allowed product is still checked at the
// forbidden source edge. Reversing product descriptors changes neither
// the diagnostic nor any status/tool state.
let orderwork: str = strings.concat(root, "/vendor-order-work-",
stages[si]);
assert(os.mkdir(orderwork, 448i32) == 0);
let orderallowed: str = strings.concat(root, "/vendor-order-allowed-",
stages[si]);
let orderforbidden: str = strings.concat(root,
"/vendor-order-forbidden-", stages[si]);
let orderallowedstatus: str = strings.concat(orderallowed, ".status");
let orderforbiddenstatus: str = strings.concat(orderforbidden,
".status");
writefile(orderallowedstatus, "sentinel-allowed\n");
writefile(orderforbiddenstatus, "sentinel-forbidden\n");
let orderforward: []str = [driver(stages[si]), "test", "-c", "-w",
orderwork, "-I", source, "--ww-package-build",
"--ww-package-test", "build", "main", "main", "-", "-", client,
orderallowed, "-", orderallowedstatus,
"--ww-package-test", "build", "main", "main", "-", "-", outsider,
orderforbidden, "-", orderforbiddenstatus, client];
let orderreverse: []str = [driver(stages[si]), "test", "-c", "-w",
orderwork, "-I", source, "--ww-package-build",
"--ww-package-test", "build", "main", "main", "-", "-", outsider,
orderforbidden, "-", orderforbiddenstatus,
"--ww-package-test", "build", "main", "main", "-", "-", client,
orderallowed, "-", orderallowedstatus, client];
let orderrequests: [][]str = [orderforward, orderreverse];
let orderdiags: []str = ["", ""];
let oi: i32 = 0;
for (oi < orderrequests.len) {
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
runcommandenv(root, strings.concat("vendor-order-", stages[si],
"-", labels[oi]), orderrequests[oi], env,
(180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(same(out.stderr, outsidediag));
orderdiags[oi] = strings.dup(out.stderr);
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(readfile(linkertraces[si]).len == 0);
assert(same(readfile(orderallowedstatus), "sentinel-allowed\n"));
assert(same(readfile(orderforbiddenstatus),
"sentinel-forbidden\n"));
assert(!os.exists(strings.concat(orderwork, "/.wwtool.stamp")));
assert(!os.exists(orderallowed) && !os.exists(orderforbidden));
oi += 1;
};
assert(same(orderdiags[0], orderdiags[1]));
if (si == 0) { referenceorderdiag = strings.dup(orderdiags[0]); }
else { assert(same(referenceorderdiag, orderdiags[0])); };
// Production, same-package test, and external test sources all retain
// their short spelling while consuming the one expanded direct export.
let testworkroot: str = strings.concat(root, "/vendor-test-work-",
stages[si]);
assert(os.mkdir(testworkroot, 448i32) == 0);
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let testav: []str = [driver(stages[si]), "test", "-w", testworkroot,
"-I", source, testclient];
runcommandenv(root, strings.concat("vendor-tests-", stages[si]), testav,
env, (180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "same_vendor ... ok\n"));
assert(has(out.stdout, "external_vendor ... ok\n"));
if (si == 0) {
referencetestout = strings.dup(out.stdout);
referencetesterr = strings.dup(out.stderr);
} else {
assert(same(referencetestout, out.stdout));
assert(same(referencetesterr, out.stderr));
};
let testwork: str = strings.concat(testworkroot, "/");
let testactions: []str = ["domain.app.testclient-internal-test",
"domain.app.testclient_test-external-test"];
let testsuffixes: []str = [".unit.ww", ".wwi", ".a"];
ui = 0;
for (ui < testactions.len) {
let xi: i32 = 0;
for (xi < testsuffixes.len) {
let bytes: str = readfile(strings.concat(testwork,
testactions[ui], testsuffixes[xi]));
let index: i32 = ui * testsuffixes.len + xi;
if (si == 0) { testrefs[index] = strings.dup(bytes); }
else { assert(same(testrefs[index], bytes)); };
xi += 1;
};
assert(has(readfile(strings.concat(testwork, testactions[ui],
".unit.ww")), strings.concat("//ww:import-map lib.math ",
expanded, " ", hexbytes(nearest), "\n")));
ui += 1;
};
let testtrace: str = readfile(compilertraces[si]);
assert(occurrences(testtrace, strings.concat("/", expanded,
".unit.new")) == 1);
let internalline: str = linecontaining(testtrace,
"domain.app.testclient-internal-test.unit.new");
let externalline: str = linecontaining(testtrace,
"domain.app.testclient_test-external-test.unit.new");
assert(occurrences(internalline, strings.concat("<--import><", expanded,
"><", testwork, expanded, ".wwi.new>")) == 1);
assert(occurrences(externalline, strings.concat("<--import><", expanded,
"><", testwork, expanded, ".wwi.new>")) == 1);
assert(occurrences(internalline, strings.concat(
"<--import-map><lib.math><", expanded, ">")) == 1);
assert(occurrences(externalline, strings.concat(
"<--import-map><lib.math><", expanded, ">")) == 1);
assert(occurrences(externalline, strings.concat(
"<--import><domain.app.testclient><", testwork,
"domain.app.testclient-internal-test.wwi.new>")) == 1);
assert(!has(internalline, "lib.leaf.wwi"));
assert(!has(externalline, "lib.leaf.wwi"));
let mainline: str = linecontaining(testtrace,
"domain.app.testclient-test-main.unit.new");
assert(!has(mainline, expanded));
assert(occurrences(mainline, "<--test-target-package>") == 2);
assert(pos(mainline,
"<--test-target-package><domain.app.testclient>")
< pos(mainline,
"<--test-target-package><domain.app.testclient_test>"));
assert(has(mainline, strings.concat(
"<--import><domain.app.testclient><", testwork,
"domain.app.testclient-internal-test.wwi.new>")));
assert(has(mainline, strings.concat(
"<--import><domain.app.testclient_test><", testwork,
"domain.app.testclient_test-external-test.wwi.new>")));
let testlinktrace: str = readfile(linkertraces[si]);
assert(occurrences(testlinktrace, "\n") == 1);
assert(has(testlinktrace,
"/domain.app.testclient-test-main.a.new>"));
assert(!has(testlinktrace, ".wwi>"));
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
runcommandenv(root, strings.concat("vendor-tests-warm-", stages[si]),
testav, env, (180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(referencetestout, out.stdout));
assert(same(referencetesterr, out.stderr));
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(occurrences(readfile(linkertraces[si]), "\n") == 1);
// A directly selected vendored test root is legal, and its external
// source still performs the ordinary nearest-vendor search first.
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let vendortestav: []str = [driver(stages[si]), "test", "-I", source,
vendortest];
runcommandenv(root, strings.concat("vendor-literal-test-", stages[si]),
vendortestav, env,
(180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "nested_external_vendor ... ok\n"));
if (si == 0) {
referencevendortestout = strings.dup(out.stdout);
referencevendortesterr = strings.dup(out.stderr);
} else {
assert(same(referencevendortestout, out.stdout));
assert(same(referencevendortesterr, out.stderr));
};
assert(has(readfile(compilertraces[si]),
"literal.owner.vendor.lib.math.vendor.lib.math.unit.ww"));
// A cold forbidden public test request is rejected before any
// persistent tool or package state is written.
let testbadworkroot: str = strings.concat(root, "/vendor-test-bad-work-",
stages[si]);
assert(os.mkdir(testbadworkroot, 448i32) == 0);
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let testbadav: []str = [driver(stages[si]), "test", "-w",
testbadworkroot, "-I", source, testbad];
runcommandenv(root, strings.concat("vendor-test-bad-", stages[si]),
testbadav, env, (180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let testbaddiag: str = strings.concat(testbad,
"/same_test.ww:2:1: error: use of vendored package not allowed\n");
assert(has(out.stderr, testbaddiag));
if (si == 0) { referencetestbaddiag = strings.dup(out.stderr); }
else { assert(same(referencetestbaddiag, out.stderr)); };
assert(!os.exists(strings.concat(testbadworkroot, "/.wwtool.stamp")));
assert(readfile(compilertraces[si]).len == 0);
assert(readfile(assemblertraces[si]).len == 0);
assert(readfile(linkertraces[si]).len == 0);
// The coordinator's synthetic support/main edges stay synthetic, while
// imports written in the real test-support source use this same resolver.
let supportenv: []str = alloc([], (env.len + 1): u64)!;
ei = 0;
for (ei < env.len) { append(supportenv, env[ei]); ei += 1; };
append(supportenv, strings.concat("WW_SRCLIB=", toolsource));
let supportworkroot: str = strings.concat(root, "/vendor-support-work-",
stages[si]);
assert(os.mkdir(supportworkroot, 448i32) == 0);
rewritefile(compilertraces[si], "");
rewritefile(assemblertraces[si], "");
rewritefile(linkertraces[si], "");
let supportav: []str = [driver(stages[si]), "test", "-w",
supportworkroot, "-I", source, supportcase];
runcommandenv(root, strings.concat("vendor-support-", stages[si]),
supportav, supportenv,
(240i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "support_runs ... ok\n"));
assert(out.stderr.len == 0);
if (si == 0) { referencesupportout = strings.dup(out.stdout); }
else { assert(same(referencesupportout, out.stdout)); };
let supportwork: str = strings.concat(supportworkroot, "/");
let supportunit: str = readfile(strings.concat(supportwork,
"test.unit.ww"));
assert(has(supportunit, strings.concat("//ww:import-map fnmatch ",
"test.vendor.fnmatch ", hexbytes(toolvendor), "\n")));
assert(has(readfile(strings.concat(supportwork,
"test.vendor.fnmatch.unit.ww")), strings.concat(
"//ww:vendor-dir ", hexbytes(toolvendor), "\n")));
let supporttrace: str = readfile(compilertraces[si]);
let supportline: str = linecontaining(supporttrace, "/test.unit.new");
assert(occurrences(supportline,
"<--import><test.vendor.fnmatch>") == 1);
assert(occurrences(supportline,
"<--import-map><fnmatch><test.vendor.fnmatch>") == 1);
assert(!has(supportline, "/ascii.wwi>"));
assert(occurrences(supporttrace,
"/test.vendor.fnmatch.unit.new") == 1);
let supportmainline: str = linecontaining(supporttrace,
"supportcase-test-main.unit.new");
assert(!has(supportmainline, "test.vendor.fnmatch"));
assert(!has(readfile(linkertraces[si]), ".wwi>"));
let supportsuffixes: []str = [".unit.ww", ".wwi", ".a"];
ui = 0;
for (ui < supportsuffixes.len) {
let bytes: str = readfile(strings.concat(supportwork,
"test.vendor.fnmatch", supportsuffixes[ui]));
if (si == 0) { supportrefs[ui] = strings.dup(bytes); }
else { assert(same(supportrefs[ui], bytes)); };
ui += 1;
};
si += 1;
};
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 declared_name_identity_and_file_import_scope() void = {
let root: str = fresh();
let source: str = strings.concat(root, "/source");
let tools: str = strings.concat(root, "/tools");
let codec: str = strings.concat(source, "/acme/codec");
let bridge: str = strings.concat(source, "/acme/bridge");
let direct: str = strings.concat(source, "/cmd/direct");
let app: str = strings.concat(source, "/cmd/app");
let scopeone: str = strings.concat(source, "/scope/one");
let scopetwo: str = strings.concat(source, "/scope/two");
let scoped: str = strings.concat(source, "/cmd/scoped");
let repeated: str = strings.concat(source, "/cmd/repeated");
let commitcodec: str = strings.concat(source, "/commit/codec");
let commitapp: str = strings.concat(source, "/cmd/commit");
let leafbad: str = strings.concat(source, "/cmd/leafbad");
let leak: str = strings.concat(source, "/cmd/leak");
let duplicate: str = strings.concat(source, "/cmd/duplicate");
let collision: str = strings.concat(source, "/cmd/collision");
let crosscollision: str = strings.concat(source, "/cmd/crosscollision");
let conflict: str = strings.concat(source, "/conflict/pkg");
let leafmain: str = strings.concat(source, "/domain/main");
let program: str = strings.concat(source, "/domain/program");
let leafmainuser: str = strings.concat(source, "/cmd/leafmain");
let programuser: str = strings.concat(source, "/cmd/programuser");
let testcodec: str = strings.concat(source, "/testpkg/codec");
let testhelper: str = strings.concat(source, "/testonly/helper");
let vendored: str = strings.concat(source,
"/vend/vendor/short/codec");
let vendorclient: str = strings.concat(source, "/vend/client");
let dirs: []str = [source, tools, codec, bridge, direct, app, scopeone,
scopetwo, scoped, repeated, commitcodec, commitapp, leafbad, leak,
duplicate, collision,
crosscollision, conflict, leafmain, program, leafmainuser, programuser, testcodec,
testhelper, vendored, vendorclient];
let di: i32 = 0;
for (di < dirs.len) { mkdirall(dirs[di]); di += 1; };
let wirebody: str = strings.concat(
"package wire;\n",
"export type Thing = i32;\n",
"export fn value() i32 = { return 42; };\n");
let cablebody: str = strings.concat(
"package cable;\n",
"export type Thing = i32;\n",
"export fn value() i32 = { return 42; };\n");
let codecfile: str = strings.concat(codec, "/codec.ww");
writefile(codecfile, wirebody);
let commitcodecfile: str = strings.concat(commitcodec, "/codec.ww");
let commitappfile: str = strings.concat(commitapp, "/main.ww");
writefile(commitcodecfile, wirebody);
writefile(commitappfile, strings.concat(
"package main;\nimport commit.codec;\n",
"fn main() i32 = { return wire.value(); };\n"));
let bridgefile: str = strings.concat(bridge, "/bridge.ww");
let stablebridgebody: str = strings.concat(
"package bridge;\nimport stable acme.codec;\n",
"export type BridgedThing = stable.Thing;\n",
"export fn bridged() i32 = { return stable.value(); };\n");
let steadybridgebody: str = strings.concat(
"package bridge;\nimport steady acme.codec;\n",
"export type BridgedThing = steady.Thing;\n",
"export fn bridged() i32 = { return steady.value(); };\n");
writefile(bridgefile, stablebridgebody);
writefile(strings.concat(direct, "/main.ww"), strings.concat(
"package main;\nimport acme.codec;\n",
"fn main() i32 = { return wire.value(); };\n"));
writefile(strings.concat(app, "/main.ww"), strings.concat(
"package main;\nimport acme.bridge;\n",
"fn main() i32 = { return bridge.bridged(); };\n"));
writefile(strings.concat(scopeone, "/one.ww"),
"package same;\nexport fn value() i32 = { return 20; };\n");
writefile(strings.concat(scopetwo, "/two.ww"),
"package same;\nexport fn value() i32 = { return 22; };\n");
writefile(strings.concat(scoped, "/a.ww"), strings.concat(
"package main;\nimport shared scope.one;\n",
"fn left() i32 = { return shared.value(); };\n"));
writefile(strings.concat(scoped, "/b.ww"), strings.concat(
"package main;\nimport shared scope.two;\n",
"fn right() i32 = { return shared.value(); };\n"));
writefile(strings.concat(scoped, "/main.ww"),
"package main;\nfn main() i32 = { return left() + right(); };\n");
writefile(strings.concat(repeated, "/a.ww"), strings.concat(
"package main;\nimport stable acme.codec;\n",
"fn first() i32 = { return stable.value(); };\n"));
writefile(strings.concat(repeated, "/b.ww"), strings.concat(
"package main;\nimport acme.codec;\n",
"fn second() i32 = { return wire.value(); };\n"));
writefile(strings.concat(repeated, "/main.ww"), strings.concat(
"package main;\n",
"fn main() i32 = { return first() - second(); };\n"));
writefile(strings.concat(leafbad, "/main.ww"), strings.concat(
"package main;\nimport acme.codec;\n",
"fn main() i32 = { return codec.value(); };\n"));
writefile(strings.concat(leak, "/a.ww"), strings.concat(
"package main;\nimport acme.codec;\n",
"fn anchor() i32 = { return 1; };\n"));
writefile(strings.concat(leak, "/b.ww"),
"package main;\nfn leaked() i32 = { return wire.value(); };\n");
writefile(strings.concat(leak, "/main.ww"),
"package main;\nfn main() i32 = { return leaked(); };\n");
writefile(strings.concat(duplicate, "/main.ww"), strings.concat(
"package main;\nimport scope.one;\nimport scope.two;\n",
"fn main() i32 = { return same.value(); };\n"));
writefile(strings.concat(collision, "/main.ww"), strings.concat(
"package main;\nimport scope.one;\n",
"fn same() i32 = { return 0; };\n",
"fn main() i32 = { return same(); };\n"));
writefile(strings.concat(crosscollision, "/a.ww"), strings.concat(
"package main;\nimport scope.one;\n",
"fn fromdep() i32 = { return same.value(); };\n"));
writefile(strings.concat(crosscollision, "/b.ww"), strings.concat(
"package main;\nfn same() i32 = { return 0; };\n",
"fn main() i32 = { return fromdep(); };\n"));
writefile(strings.concat(conflict, "/a.ww"),
"package first;\nexport fn a() i32 = { return 1; };\n");
writefile(strings.concat(conflict, "/b.ww"),
"package second;\nexport fn b() i32 = { return 2; };\n");
writefile(strings.concat(leafmain, "/utility.ww"),
"package utility;\nexport fn value() i32 = { return 7; };\n");
writefile(strings.concat(program, "/program.ww"),
"package main;\nexport fn value() i32 = { return 9; };\n");
writefile(strings.concat(leafmainuser, "/main.ww"), strings.concat(
"package main;\nimport domain.main;\n",
"fn main() i32 = { return utility.value(); };\n"));
writefile(strings.concat(programuser, "/main.ww"), strings.concat(
"package main;\nimport stable domain.program;\n",
"fn main() i32 = { return stable.value(); };\n"));
writefile(strings.concat(testhelper, "/helper.ww"),
"package helper;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(testcodec, "/codec.ww"), wirebody);
writefile(strings.concat(testcodec, "/internal_test.ww"), strings.concat(
"package wire;\nimport assist testonly.helper;\n",
"@test fn internal_name_uses_declaration() void = {\n",
" assert(value() + assist.value() == 43);\n};\n"));
writefile(strings.concat(testcodec, "/external_test.ww"), strings.concat(
"package wire_test;\nimport prod testpkg.codec;\n",
"@test fn external_name_uses_declaration() void = {\n",
" assert(prod.value() == 42);\n};\n"));
writefile(strings.concat(vendored, "/codec.ww"),
"package cable;\nexport fn value() i32 = { return 13; };\n");
writefile(strings.concat(vendorclient, "/a.ww"), strings.concat(
"package main;\nimport stable short.codec;\n",
"fn vendora() i32 = { return stable.value(); };\n"));
writefile(strings.concat(vendorclient, "/b.ww"), strings.concat(
"package main;\nimport short.codec;\n",
"fn vendorb() i32 = { return cable.value(); };\n"));
writefile(strings.concat(vendorclient, "/main.ww"),
"package main;\nfn main() i32 = { return vendora(); };\n");
let compilerwrapper: str = strings.concat(tools, "/w6c.sh");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\n",
"printf 'BEGIN' >> \"$WW_NAME_COMPILER_TRACE\"\n",
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_NAME_COMPILER_TRACE\"; done\n",
"printf '\\n' >> \"$WW_NAME_COMPILER_TRACE\"\n",
"exec \"$WW_NAME_REAL_COMPILER\" \"$@\"\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 works: []str = [strings.concat(root, "/c-work"),
strings.concat(root, "/ww-work")];
let traces: []str = [strings.concat(root, "/c-compiler"),
strings.concat(root, "/ww-compiler")];
let directbins: []str = [strings.concat(root, "/c-direct"),
strings.concat(root, "/ww-direct")];
let appbins: []str = [strings.concat(root, "/c-app"),
strings.concat(root, "/ww-app")];
let scopedbins: []str = [strings.concat(root, "/c-scoped"),
strings.concat(root, "/ww-scoped")];
let repeatedbins: []str = [strings.concat(root, "/c-repeated"),
strings.concat(root, "/ww-repeated")];
let commitworks: []str = [strings.concat(root, "/c-commit-work"),
strings.concat(root, "/ww-commit-work")];
let commitcoldbins: []str = [strings.concat(root, "/c-commit-cold"),
strings.concat(root, "/ww-commit-cold")];
let commitrejectbins: []str = [strings.concat(root, "/c-commit-reject"),
strings.concat(root, "/ww-commit-reject")];
let commitfixedbins: []str = [strings.concat(root, "/c-commit-fixed"),
strings.concat(root, "/ww-commit-fixed")];
let leafmainbins: []str = [strings.concat(root, "/c-leafmain"),
strings.concat(root, "/ww-leafmain")];
let vendorbins: []str = [strings.concat(root, "/c-vendor"),
strings.concat(root, "/ww-vendor")];
let actions: []str = ["acme.codec", "acme.bridge", "cmd.direct",
"cmd.app", "scope.one", "scope.two", "cmd.scoped",
"cmd.repeated", "domain.main", "cmd.leafmain",
"vend.vendor.short.codec", "vend.client"];
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
let artifactrefs: []str = alloc([], (actions.len * suffixes.len): u64)!;
let ari: i32 = 0;
for (ari < actions.len * suffixes.len) {
append(artifactrefs, "");
ari += 1;
};
let binaryrefs: []str = ["", "", "", "", "", ""];
let diagnosticrefs: []str = ["", "", "", "", "", ""];
let directtraceref: str = "";
let scopedtraceref: str = "";
let repeatedtraceref: str = "";
let changedtraceref: str = "";
let aliastraceref: str = "";
let commitbindingref: str = "";
let commitbinref: str = "";
let initialwwiref: str = "";
let testoutref: str = "";
let baseenv: []str = os.getenvs();
let si: i32 = 0;
for (si < stages.len) {
rewritefile(codecfile, wirebody);
rewritefile(bridgefile, stablebridgebody);
rewritefile(commitcodecfile, wirebody);
rewritefile(commitappfile, strings.concat(
"package main;\nimport commit.codec;\n",
"fn main() i32 = { return wire.value(); };\n"));
assert(os.mkdir(works[si], 448i32) == 0);
assert(os.mkdir(commitworks[si], 448i32) == 0);
writefile(traces[si], "");
let env: []str = alloc([], (baseenv.len + 7): 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_SRCLIB=")
&& !strings.hasprefix(baseenv[ei],
"WW_NAME_COMPILER_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_NAME_REAL_COMPILER=")) {
append(env, baseenv[ei]);
};
ei += 1;
};
append(env, strings.concat("WW_W6C=", compilerwrapper));
append(env, strings.concat("WW_W6A=", driver(assemblers[si])));
append(env, strings.concat("WW_W6L=", driver(linkers[si])));
append(env, strings.concat("WW_SRCLIB=", repo(), "/lib"));
append(env, strings.concat("WW_NAME_COMPILER_TRACE=", traces[si]));
append(env, strings.concat("WW_NAME_REAL_COMPILER=",
driver(compilers[si])));
// A directly selected library keeps canonical action/artifact identity
// even though its declaration is unrelated to the path leaf.
let out: commandout;
let selectav: []str = [driver(stages[si]), "build", "-w", works[si],
"-I", source, codec];
runcommandenv(root, strings.concat("name-select-", stages[si]),
selectav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(os.exists(strings.concat(works[si], "/acme.codec.wwi")));
assert(!os.exists(strings.concat(works[si], "/wire.wwi")));
let initialwwi: str = readfile(strings.concat(works[si],
"/acme.codec.wwi"));
assert(has(initialwwi, "//ww:module acme.codec\npackage wire;\n"));
if (si == 0) { initialwwiref = strings.dup(initialwwi); }
else { assert(same(initialwwiref, initialwwi)); };
rewritefile(traces[si], "");
let directav: []str = [driver(stages[si]), "build", "-w", works[si],
"-I", source, "-o", directbins[si], direct];
runcommandenv(root, strings.concat("name-direct-", stages[si]),
directav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let directtrace: str = readfile(traces[si]);
let directline: str = linecontaining(directtrace,
"cmd.direct.unit.new");
assert(occurrences(directline, "<--import><acme.codec>") == 1);
assert(!has(directline, "wire.wwi"));
let ndirect: str = normalizedtrace(directtrace,
strings.concat(works[si], "/"), directbins[si]);
if (si == 0) { directtraceref = strings.dup(ndirect); }
else { assert(same(directtraceref, ndirect)); };
let runav: []str = [directbins[si]];
runcommand(root, strings.concat("name-direct-run-", stages[si]), runav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 42);
// The package and command form one publication transaction. A changed
// declared name is visible to the importer through the staged .wwi, but
// its resulting semantic rejection must preserve the complete prior
// generation and force the next request to reconsider both actions.
let commitcoldav: []str = [driver(stages[si]), "build", "-w",
commitworks[si], "-I", source, "-o", commitcoldbins[si], commitapp];
runcommandenv(root, strings.concat("name-commit-cold-", stages[si]),
commitcoldav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let commitrun: []str = [commitcoldbins[si]];
runcommand(root, strings.concat("name-commit-cold-run-", stages[si]),
commitrun, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 42);
let commitpaths: []str = ["/.wwtool.ww", "/.wwtool.w6c",
"/.wwtool.w6a", "/.wwtool.stamp", "/commit.codec.unit.ww",
"/commit.codec.wwi", "/commit.codec.s", "/commit.codec.o",
"/commit.codec.a", "/cmd.commit.unit.ww", "/cmd.commit.wwi",
"/cmd.commit.s", "/cmd.commit.o", "/cmd.commit.a",
"/cmd.commit.init.unit.ww", "/cmd.commit.init.s",
"/cmd.commit.init.o"];
let commitsnapshots: []str = alloc([], commitpaths.len: u64)!;
let cpi: i32 = 0;
for (cpi < commitpaths.len) {
append(commitsnapshots, readfile(strings.concat(commitworks[si],
commitpaths[cpi])));
cpi += 1;
};
let commitcoldbytes: str = readfile(commitcoldbins[si]);
rewritefile(commitcodecfile, cablebody);
let commitrejectav: []str = [driver(stages[si]), "build", "-w",
commitworks[si], "-I", source, "-o", commitrejectbins[si],
commitapp];
let partialsuffixes: []str = [".unit.new", ".wwi.new", ".s.new",
".o.new", ".a.new", ".init.unit.new", ".init.s.new",
".init.o.new"];
let rejectedactions: []str = ["commit.codec", "cmd.commit"];
let attemptlabels: []str = ["0", "1"];
let attempt: i32 = 0;
for (attempt < 2) {
rewritefile(traces[si], "");
runcommandenv(root, strings.concat("name-commit-reject-",
stages[si], "-", attemptlabels[attempt]),
commitrejectav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "imported as cable and not used"));
assert(has(out.stderr, "undefined: wire"));
assert(has(out.stderr, "ww: w6c failed for cmd.commit\n"));
let ncommitbinding: str = normalizedtrace(out.stderr,
strings.concat(commitworks[si], "/"), commitrejectbins[si]);
if (si == 0 && attempt == 0) {
commitbindingref = strings.dup(ncommitbinding);
} else { assert(same(commitbindingref, ncommitbinding)); };
let rejecttrace: str = readfile(traces[si]);
assert(occurrences(rejecttrace,
"/commit.codec.unit.new") == 1);
assert(occurrences(rejecttrace,
"/cmd.commit.unit.new") == 1);
cpi = 0;
for (cpi < commitpaths.len) {
assert(same(commitsnapshots[cpi], readfile(strings.concat(
commitworks[si], commitpaths[cpi]))));
cpi += 1;
};
assert(same(commitcoldbytes, readfile(commitcoldbins[si])));
let rai: i32 = 0;
for (rai < rejectedactions.len) {
let psi: i32 = 0;
for (psi < partialsuffixes.len) {
assert(!os.exists(strings.concat(commitworks[si], "/",
rejectedactions[rai], partialsuffixes[psi])));
psi += 1;
};
rai += 1;
};
assert(!os.exists(commitrejectbins[si]));
assert(!os.exists(strings.concat(commitrejectbins[si], ".new")));
attempt += 1;
};
rewritefile(commitappfile, strings.concat(
"package main;\nimport commit.codec;\n",
"fn main() i32 = { return cable.value(); };\n"));
let commitfixedav: []str = [driver(stages[si]), "build", "-w",
commitworks[si], "-I", source, "-o", commitfixedbins[si], commitapp];
runcommandenv(root, strings.concat("name-commit-fixed-", stages[si]),
commitfixedav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let commitfixedrun: []str = [commitfixedbins[si]];
runcommand(root, strings.concat("name-commit-fixed-run-", stages[si]),
commitfixedrun, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 42);
assert(has(readfile(strings.concat(commitworks[si],
"/commit.codec.wwi")),
"//ww:module commit.codec\npackage cable;\n"));
assert(same(commitcoldbytes, readfile(commitcoldbins[si])));
let commitbinbytes: str = readfile(commitfixedbins[si]);
if (si == 0) { commitbinref = strings.dup(commitbinbytes); }
else { assert(same(commitbinref, commitbinbytes)); };
// The same declared qualifier belongs to each importing source file,
// not to the package-wide namespace.
rewritefile(traces[si], "");
let scopedav: []str = [driver(stages[si]), "build", "-w", works[si],
"-I", source, "-o", scopedbins[si], scoped];
runcommandenv(root, strings.concat("name-scoped-", stages[si]),
scopedav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let scopedtrace: str = readfile(traces[si]);
let scopedline: str = linecontaining(scopedtrace,
"cmd.scoped.unit.new");
assert(occurrences(scopedline, "<--import><scope.one>") == 1);
assert(occurrences(scopedline, "<--import><scope.two>") == 1);
let nscoped: str = normalizedtrace(scopedtrace,
strings.concat(works[si], "/"), scopedbins[si]);
if (si == 0) { scopedtraceref = strings.dup(nscoped); }
else { assert(same(scopedtraceref, nscoped)); };
let scopedrun: []str = [scopedbins[si]];
runcommand(root, strings.concat("name-scoped-run-", stages[si]),
scopedrun, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 42);
// Two per-file binding records for one canonical package still form
// exactly one direct graph edge and one compiler input.
rewritefile(traces[si], "");
let repeatedav: []str = [driver(stages[si]), "build", "-w", works[si],
"-I", source, "-o", repeatedbins[si], repeated];
runcommandenv(root, strings.concat("name-repeated-", stages[si]),
repeatedav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let repeatedunit: str = readfile(strings.concat(works[si],
"/cmd.repeated.unit.ww"));
assert(occurrences(repeatedunit, "import stable acme.codec;") == 1);
assert(occurrences(repeatedunit, "import acme.codec;") == 1);
let repeatedtrace: str = readfile(traces[si]);
let repeatedline: str = linecontaining(repeatedtrace,
"cmd.repeated.unit.new");
assert(occurrences(repeatedline, "<--import><acme.codec>") == 1);
assert(occurrences(repeatedtrace, "acme.codec.unit.new") == 0);
let nrepeated: str = normalizedtrace(repeatedtrace,
strings.concat(works[si], "/"), repeatedbins[si]);
if (si == 0) { repeatedtraceref = strings.dup(nrepeated); }
else { assert(same(repeatedtraceref, nrepeated)); };
let repeatedrun: []str = [repeatedbins[si]];
runcommand(root, strings.concat("name-repeated-run-", stages[si]),
repeatedrun, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
// A path ending in main remains importable when its declaration is not
// main. A different path declaring main is rejected by loaded name.
let leafmainav: []str = [driver(stages[si]), "build", "-w", works[si],
"-I", source, "-o", leafmainbins[si], leafmainuser];
runcommandenv(root, strings.concat("name-leafmain-", stages[si]),
leafmainav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let leafmainrun: []str = [leafmainbins[si]];
runcommand(root, strings.concat("name-leafmain-run-", stages[si]),
leafmainrun, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 7);
// Compiler-owned binding failures are deterministic across stages and
// never commit an action voucher/artifact or publish a binary.
let rejectwork: str = strings.concat(root, "/reject-work-", stages[si]);
assert(os.mkdir(rejectwork, 448i32) == 0);
let rejecttargets: []str = [leafbad, leak, duplicate, collision,
crosscollision, programuser];
let rejectactions: []str = ["cmd.leafbad", "cmd.leak",
"cmd.duplicate", "cmd.collision", "cmd.crosscollision",
"cmd.programuser"];
let rejectneedles: []str = ["undefined: codec",
"package 'wire' is not directly imported",
"same redeclared in this block",
"same already declared through import of package same",
"same already declared through import of package same",
"package domain.program is a program, not an importable package"];
let rj: i32 = 0;
for (rj < rejecttargets.len) {
let badbin: str = strings.concat(root, "/reject-bin-", stages[si],
"-", rejectactions[rj]);
let badav: []str = [driver(stages[si]), "build", "-w", rejectwork,
"-I", source, "-o", badbin, rejecttargets[rj]];
runcommandenv(root, strings.concat("name-reject-", stages[si],
"-", rejectactions[rj]), badav, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, rejectneedles[rj]));
let normalized: str = normalizedtrace(out.stderr,
strings.concat(rejectwork, "/"), badbin);
if (rj == 2) {
assert(same(normalized, strings.concat(
"$WORK/cmd.duplicate.unit.new:4:1: error: same redeclared in this block\n",
"\t$WORK/cmd.duplicate.unit.new:3:1: other declaration of same\n",
"$WORK/cmd.duplicate.unit.new:4:1: error: \"scope.two\" imported as same and not used\n",
"ww: w6c failed for cmd.duplicate\n")));
};
if (rj == 3) {
assert(same(normalized, strings.concat(
"$WORK/cmd.collision.unit.new:3:1: error: \"scope.one\" imported as same and not used\n",
"$WORK/cmd.collision.unit.new:4:1: error: same already declared through import of package same (\"scope.one\")\n",
"\t$WORK/cmd.collision.unit.new:3:1: other declaration of same\n",
"ww: w6c failed for cmd.collision\n")));
};
if (si == 0) { diagnosticrefs[rj] = strings.dup(normalized); }
else { assert(same(diagnosticrefs[rj], normalized)); };
assert(!os.exists(badbin));
let committed: []str = [".unit.ww", ".wwi", ".s", ".o", ".a",
".unit.new", ".wwi.new", ".s.new", ".o.new", ".a.new"];
let ci: i32 = 0;
for (ci < committed.len) {
assert(!os.exists(strings.concat(rejectwork, "/",
rejectactions[rj], committed[ci])));
ci += 1;
};
rj += 1;
};
let conflictav: []str = [driver(stages[si]), "build", "-w",
rejectwork, "-I", source, conflict];
runcommandenv(root, strings.concat("name-conflict-", stages[si]),
conflictav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "conflicting package names"));
assert(!os.exists(strings.concat(rejectwork,
"/conflict.pkg.unit.ww")));
// Production/internal/external naming uses the declaration, while every
// action and generated-main artifact retains canonical variant identity.
let testwork: str = strings.concat(root, "/test-work-", stages[si]);
assert(os.mkdir(testwork, 448i32) == 0);
rewritefile(traces[si], "");
let testav: []str = [driver(stages[si]), "test", "-w", testwork,
"-I", source, testcodec];
runcommandenv(root, strings.concat("name-test-", stages[si]), testav,
env, (240i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "internal_name_uses_declaration ... ok\n"));
assert(has(out.stdout, "external_name_uses_declaration ... ok\n"));
assert(out.stderr.len == 0);
if (si == 0) { testoutref = strings.dup(out.stdout); }
else { assert(same(testoutref, out.stdout)); };
assert(has(out.stdout, strings.concat("ok ", testcodec,
" [wire]\n")));
assert(!os.exists(strings.concat(testwork,
"/testpkg.codec.unit.ww")));
let internalunit: str = readfile(strings.concat(testwork,
"/testpkg.codec-internal-test.unit.ww"));
let externalunit: str = readfile(strings.concat(testwork,
"/testpkg.codec_test-external-test.unit.ww"));
assert(has(internalunit, "export type Thing = i32;"));
assert(has(internalunit, "export fn value()"));
assert(has(internalunit, "import assist testonly.helper;"));
assert(!has(externalunit, "testonly.helper"));
assert(has(externalunit, "package wire_test;"));
assert(has(externalunit,
"//ww:direct-export testpkg.codec "));
assert(os.exists(strings.concat(testwork,
"/testpkg.codec-test-main.a")));
assert(!os.exists(strings.concat(testwork,
"/testpkg.codec-internal-test-main.a")));
assert(!os.exists(strings.concat(testwork,
"/testpkg.codec_test-external-test-main.a")));
assert(os.exists(strings.concat(testwork, "/test.a")));
let testtrace: str = readfile(traces[si]);
let externalline: str = linecontaining(testtrace,
"/testpkg.codec_test-external-test.unit.new");
assert(has(externalline, strings.concat(
"<--import><testpkg.codec><", testwork,
"/testpkg.codec-internal-test.wwi.new>")));
let mainline: str = linecontaining(testtrace,
"/testpkg.codec-test-main.unit.new");
assert(occurrences(mainline, "<--test-target-package>") == 2);
assert(pos(mainline, "<--test-target-package><testpkg.codec>")
< pos(mainline,
"<--test-target-package><testpkg.codec_test>"));
let mainunit: str = readfile(strings.concat(testwork,
"/testpkg.codec-test-main.unit.ww"));
assert(has(mainunit, "import testpkg.codec;"));
assert(has(mainunit, "import testpkg.codec_test;"));
assert(has(mainunit, "import test;"));
assert(!has(mainunit, "testonly.helper"));
let recursivebuildwork: str = strings.concat(root,
"/recursive-build-", stages[si]);
assert(os.mkdir(recursivebuildwork, 448i32) == 0);
let recursivebuildav: []str = [driver(stages[si]), "build", "-w",
recursivebuildwork, "-I", source,
strings.concat(source, "/testpkg/...")];
runcommandenv(root, strings.concat("name-recursive-build-", stages[si]),
recursivebuildav, env,
(180i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(os.exists(strings.concat(recursivebuildwork,
"/testpkg.codec.wwi")));
let recursivetestwork: str = strings.concat(root,
"/recursive-test-", stages[si]);
assert(os.mkdir(recursivetestwork, 448i32) == 0);
let recursivetestav: []str = [driver(stages[si]), "test", "-w",
recursivetestwork, "-I", source,
strings.concat(source, "/testpkg/...")];
runcommandenv(root, strings.concat("name-recursive-test-", stages[si]),
recursivetestav, env,
(240i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "external_name_uses_declaration ... ok\n"));
// Vendor expansion owns the action/map identity; the loaded declaration
// independently supplies cable as the source-visible qualifier.
rewritefile(traces[si], "");
let vendorav: []str = [driver(stages[si]), "build", "-w", works[si],
"-I", source, "-o", vendorbins[si], vendorclient];
runcommandenv(root, strings.concat("name-vendor-", stages[si]),
vendorav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let vendorunit: str = readfile(strings.concat(works[si],
"/vend.client.unit.ww"));
assert(occurrences(vendorunit, "import stable short.codec;") == 1);
assert(occurrences(vendorunit, "import short.codec;") == 1);
assert(has(vendorunit, strings.concat(
"//ww:import-map short.codec vend.vendor.short.codec ",
hexbytes(vendored), "\n")));
assert(occurrences(vendorunit,
"//ww:import-map short.codec vend.vendor.short.codec ") == 1);
let vendortrace: str = readfile(traces[si]);
let vendorline: str = linecontaining(vendortrace,
"vend.client.unit.new");
assert(occurrences(vendorline,
"<--import><vend.vendor.short.codec>") == 1);
assert(occurrences(vendorline, strings.concat(
"<--import-map><short.codec><vend.vendor.short.codec>")) == 1);
let vendorwwi: str = readfile(strings.concat(works[si],
"/vend.vendor.short.codec.wwi"));
assert(has(vendorwwi, strings.concat(
"//ww:module vend.vendor.short.codec\npackage cable;\n")));
assert(!os.exists(strings.concat(works[si], "/short.codec.a")));
let vendorrun: []str = [vendorbins[si]];
runcommand(root, strings.concat("name-vendor-run-", stages[si]),
vendorrun, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 13);
// A stable explicit alias survives a dependency declared-name change.
// Canonicalized exported type references keep the bridge interface
// unchanged, so reconsideration stops after the direct importer.
rewritefile(traces[si], "");
let appav: []str = [driver(stages[si]), "build", "-w", works[si],
"-I", source, "-o", appbins[si], app];
runcommandenv(root, strings.concat("name-app-cold-", stages[si]), appav,
env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let apprun: []str = [appbins[si]];
runcommand(root, strings.concat("name-app-run-", stages[si]), apprun,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 42);
let stablebridgewwi: str = readfile(strings.concat(works[si],
"/acme.bridge.wwi"));
assert(has(stablebridgewwi,
"import __wwi_61636d652e636f646563 acme.codec;\n"));
assert(has(stablebridgewwi,
"export type BridgedThing = __wwi_61636d652e636f646563.Thing;\n"));
assert(!has(stablebridgewwi, "stable.Thing"));
rewritefile(traces[si], "");
runcommandenv(root, strings.concat("name-app-warm-", stages[si]), appav,
env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(readfile(traces[si]).len == 0);
rewritefile(codecfile, cablebody);
rewritefile(traces[si], "");
runcommandenv(root, strings.concat("name-app-renamed-", stages[si]),
appav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let changedtrace: str = readfile(traces[si]);
assert(occurrences(changedtrace, "\n") == 2);
assert(occurrences(changedtrace, "/acme.codec.unit.new") == 1);
assert(occurrences(changedtrace, "/acme.bridge.unit.new") == 1);
assert(!has(changedtrace, "/cmd.app.unit.new"));
let nchanged: str = normalizedtrace(changedtrace,
strings.concat(works[si], "/"), appbins[si]);
if (si == 0) { changedtraceref = strings.dup(nchanged); }
else { assert(same(changedtraceref, nchanged)); };
let renamedwwi: str = readfile(strings.concat(works[si],
"/acme.codec.wwi"));
assert(has(renamedwwi, "//ww:module acme.codec\npackage cable;\n"));
assert(!has(renamedwwi, "package wire;"));
assert(same(stablebridgewwi, readfile(strings.concat(works[si],
"/acme.bridge.wwi"))));
runcommand(root, strings.concat("name-app-renamed-run-", stages[si]),
apprun, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 42);
// Editing only the local alias rebuilds its owning source action. It
// cannot rename canonical exports or force the downstream command.
rewritefile(bridgefile, steadybridgebody);
rewritefile(traces[si], "");
runcommandenv(root, strings.concat("name-app-alias-edit-", stages[si]),
appav, env, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let aliastrace: str = readfile(traces[si]);
assert(occurrences(aliastrace, "\n") == 1);
assert(occurrences(aliastrace, "/acme.bridge.unit.new") == 1);
assert(!has(aliastrace, "/acme.codec.unit.new"));
assert(!has(aliastrace, "/cmd.app.unit.new"));
assert(same(stablebridgewwi, readfile(strings.concat(works[si],
"/acme.bridge.wwi"))));
let nalias: str = normalizedtrace(aliastrace,
strings.concat(works[si], "/"), appbins[si]);
if (si == 0) { aliastraceref = strings.dup(nalias); }
else { assert(same(aliastraceref, nalias)); };
runcommand(root, strings.concat("name-app-alias-edit-run-", stages[si]),
apprun, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 42);
// New semantic artifacts and binaries are byte-identical across the
// independently cold Cstage and WWstage work roots.
ari = 0;
for (ari < actions.len) {
let xi: i32 = 0;
for (xi < suffixes.len) {
let index: i32 = ari * suffixes.len + xi;
let bytes: str = readfile(strings.concat(works[si], "/",
actions[ari], suffixes[xi]));
if (si == 0) { artifactrefs[index] = strings.dup(bytes); }
else { assert(same(artifactrefs[index], bytes)); };
xi += 1;
};
ari += 1;
};
let stagebins: []str = [directbins[si], appbins[si], scopedbins[si],
repeatedbins[si], leafmainbins[si], vendorbins[si]];
let bini: i32 = 0;
for (bini < stagebins.len) {
let bytes: str = readfile(stagebins[bini]);
if (si == 0) { binaryrefs[bini] = strings.dup(bytes); }
else { assert(same(binaryrefs[bini], bytes)); };
bini += 1;
};
si += 1;
};
clean(root);
};
@test fn explicit_import_alias_binding_modes() void = {
let root: str = fresh();
let source: str = strings.concat(root, "/source");
let one: str = strings.concat(source, "/pkg/one");
let two: str = strings.concat(source, "/pkg/two");
let positives: []str = ["default", "alias", "reuse", "repeatok",
"repeatedfiles", "blankalias", "blankrepeat", "blankdefault",
"blankexplicit", "blankfiles"];
let negatives: []str = ["barefn", "baretype", "baredef", "bareconst",
"barevar", "aliasbad", "aliasleak", "repeatdup", "aliasdup",
"defaultalias", "declcollision", "unusedalias", "blankqual",
"blankbare", "blankordinaryunused"];
let dirs: []str = [one, two];
let i: i32 = 0;
for (i < positives.len) {
append(dirs, strings.concat(source, "/cmd/", positives[i]));
i += 1;
};
i = 0;
for (i < negatives.len) {
append(dirs, strings.concat(source, "/cmd/", negatives[i]));
i += 1;
};
i = 0;
for (i < dirs.len) { mkdirall(dirs[i]); i += 1; };
writefile(strings.concat(one, "/one.ww"), strings.concat(
"package wire;\n",
"export fn value() i32 = { return 11; };\n",
"export type Thing = i32;\n",
"export def DEFINED: i32 = 13;\n",
"export const CONSTANT: i32 = 17;\n",
"export let VARIABLE: i32 = 19;\n"));
writefile(strings.concat(two, "/two.ww"),
"package cable;\nexport fn value() i32 = { return 29; };\n");
let defaultbody: str = strings.concat(
"package main;\nimport pkg.one;\n",
"fn typed(v: wire.Thing) i32 = { return v: i32; };\n",
"fn main() i32 = { return wire.value() + wire.DEFINED + ",
"wire.CONSTANT + wire.VARIABLE + typed(23); };\n");
writefile(strings.concat(source, "/cmd/default/main.ww"), defaultbody);
writefile(strings.concat(source, "/cmd/alias/main.ww"), strings.concat(
"package main;\nimport stable pkg.one;\n",
"fn typed(v: stable.Thing) i32 = { return v: i32; };\n",
"fn main() i32 = { return stable.value() + stable.DEFINED + ",
"stable.CONSTANT + stable.VARIABLE + typed(23); };\n"));
writefile(strings.concat(source, "/cmd/reuse/a.ww"), strings.concat(
"package main;\nimport shared pkg.one;\n",
"fn left() i32 = { return shared.value(); };\n"));
writefile(strings.concat(source, "/cmd/reuse/b.ww"), strings.concat(
"package main;\nimport shared pkg.two;\n",
"fn right() i32 = { return shared.value(); };\n"));
writefile(strings.concat(source, "/cmd/reuse/main.ww"),
"package main;\nfn main() i32 = { return left() + right(); };\n");
writefile(strings.concat(source, "/cmd/repeatok/main.ww"), strings.concat(
"package main;\nimport pkg.one;\nimport first pkg.one;\n",
"import second pkg.one;\n",
"fn main() i32 = { return wire.value() + first.value() + ",
"second.value(); };\n"));
writefile(strings.concat(source, "/cmd/repeatedfiles/a.ww"), strings.concat(
"package main;\nimport left pkg.one;\n",
"fn first() i32 = { return left.value(); };\n"));
writefile(strings.concat(source, "/cmd/repeatedfiles/b.ww"), strings.concat(
"package main;\nimport right pkg.one;\n",
"fn second() i32 = { return right.value(); };\n"));
writefile(strings.concat(source, "/cmd/repeatedfiles/main.ww"),
"package main;\nfn main() i32 = { return first() + second(); };\n");
writefile(strings.concat(source, "/cmd/blankalias/main.ww"),
"package main;\nimport _ pkg.one;\nfn main() i32 = { return 0; };\n");
writefile(strings.concat(source, "/cmd/blankrepeat/main.ww"),
strings.concat("package main;\nimport _ pkg.one;\n",
"import _ pkg.one;\nfn main() i32 = { return 0; };\n"));
writefile(strings.concat(source, "/cmd/blankdefault/main.ww"),
strings.concat("package main;\nimport _ pkg.one;\nimport pkg.one;\n",
"fn main() i32 = { return wire.value(); };\n"));
writefile(strings.concat(source, "/cmd/blankexplicit/main.ww"),
strings.concat("package main;\nimport _ pkg.one;\n",
"import stable pkg.one;\n",
"fn main() i32 = { return stable.value(); };\n"));
writefile(strings.concat(source, "/cmd/blankfiles/a.ww"),
"package main;\nimport _ pkg.one;\n");
writefile(strings.concat(source, "/cmd/blankfiles/b.ww"),
"package main;\nimport _ pkg.one;\n");
writefile(strings.concat(source, "/cmd/blankfiles/main.ww"),
"package main;\nfn main() i32 = { return 0; };\n");
let bareexprs: []str = ["value()", "take(7)", "DEFINED", "CONSTANT",
"VARIABLE"];
let barenames: []str = ["barefn", "baretype", "baredef", "bareconst",
"barevar"];
i = 0;
for (i < barenames.len) {
let pre: str = "";
if (i == 1) { pre = "fn take(v: Thing) i32 = { return v: i32; };\n"; };
writefile(strings.concat(source, "/cmd/", barenames[i], "/main.ww"),
strings.concat("package main;\nimport pkg.one;\n", pre,
"fn main() i32 = { return ", bareexprs[i], "; };\n"));
i += 1;
};
writefile(strings.concat(source, "/cmd/aliasbad/main.ww"), strings.concat(
"package main;\nimport stable pkg.one;\n",
"fn bad(v: wire.Thing) i32 = { return v: i32; };\n",
"fn declared() i32 = { return wire.value(); };\n",
"fn leaf() i32 = { return one.value(); };\n",
"fn bare() i32 = { return value(); };\n",
"fn main() i32 = { return stable.value(); };\n"));
writefile(strings.concat(source, "/cmd/aliasleak/a.ww"), strings.concat(
"package main;\nimport stable pkg.one;\n",
"fn anchor() i32 = { return stable.value(); };\n"));
writefile(strings.concat(source, "/cmd/aliasleak/b.ww"),
"package main;\nfn leaked() i32 = { return stable.value(); };\n");
writefile(strings.concat(source, "/cmd/aliasleak/main.ww"),
"package main;\nfn main() i32 = { return leaked(); };\n");
writefile(strings.concat(source, "/cmd/repeatdup/main.ww"), strings.concat(
"package main;\nimport pkg.one;\nimport pkg.one;\n",
"fn main() i32 = { return wire.value(); };\n"));
writefile(strings.concat(source, "/cmd/aliasdup/main.ww"), strings.concat(
"package main;\nimport stable pkg.one;\nimport stable pkg.two;\n",
"fn main() i32 = { return stable.value(); };\n"));
writefile(strings.concat(source, "/cmd/defaultalias/main.ww"), strings.concat(
"package main;\nimport pkg.one;\nimport wire pkg.two;\n",
"fn main() i32 = { return wire.value(); };\n"));
writefile(strings.concat(source, "/cmd/declcollision/main.ww"), strings.concat(
"package main;\nimport stable pkg.one;\n",
"fn stable() i32 = { return 0; };\n",
"fn main() i32 = { return stable(); };\n"));
writefile(strings.concat(source, "/cmd/unusedalias/main.ww"),
"package main;\nimport stable pkg.one;\nfn main() i32 = { return 0; };\n");
writefile(strings.concat(source, "/cmd/blankqual/main.ww"),
strings.concat("package main;\nimport _ pkg.one;\n",
"fn main() i32 = { return wire.value(); };\n"));
writefile(strings.concat(source, "/cmd/blankbare/main.ww"),
strings.concat("package main;\nimport _ pkg.one;\n",
"fn main() i32 = { return value(); };\n"));
writefile(strings.concat(source, "/cmd/blankordinaryunused/main.ww"),
strings.concat("package main;\nimport _ pkg.one;\nimport pkg.one;\n",
"fn main() i32 = { return 0; };\n"));
let stages: []str = ["ww", "ww_ww"];
let expected: []i32 = [83, 83, 40, 33, 22, 0, 0, 11, 11, 0];
let binaryrefs: []str = ["", "", "", "", "", "", "", "", "", ""];
let diagrefs: []str = ["", "", "", "", "", "", "", "", "",
"", "", "", "", "", ""];
let needles: []str = ["undefined: value", "unknown type 'Thing'",
"undefined: DEFINED", "undefined: CONSTANT", "undefined: VARIABLE",
"unknown type 'wire.Thing'", "package 'stable' is not directly imported",
"wire redeclared in this block", "stable redeclared in this block",
"wire redeclared in this block",
"stable already declared through import of package stable",
"\"pkg.one\" imported as stable and not used", "undefined: wire",
"undefined: value", "\"pkg.one\" imported as wire and not used"];
let exactdiags: []str = [
strings.concat(
"$WORK/cmd.barefn.unit.new:3:1: error: \"pkg.one\" imported as wire and not used\n",
"$WORK/cmd.barefn.unit.new:4:26: error: undefined: value\n",
"ww: w6c failed for cmd.barefn\n"),
strings.concat(
"$WORK/cmd.baretype.unit.new:3:1: error: \"pkg.one\" imported as wire and not used\n",
"$WORK/cmd.baretype.unit.new:4:12: error: unknown type 'Thing'\n",
"ww: w6c failed for cmd.baretype\n"),
strings.concat(
"$WORK/cmd.baredef.unit.new:3:1: error: \"pkg.one\" imported as wire and not used\n",
"$WORK/cmd.baredef.unit.new:4:26: error: undefined: DEFINED\n",
"ww: w6c failed for cmd.baredef\n"),
strings.concat(
"$WORK/cmd.bareconst.unit.new:3:1: error: \"pkg.one\" imported as wire and not used\n",
"$WORK/cmd.bareconst.unit.new:4:26: error: undefined: CONSTANT\n",
"ww: w6c failed for cmd.bareconst\n"),
strings.concat(
"$WORK/cmd.barevar.unit.new:3:1: error: \"pkg.one\" imported as wire and not used\n",
"$WORK/cmd.barevar.unit.new:4:26: error: undefined: VARIABLE\n",
"ww: w6c failed for cmd.barevar\n"),
"", "",
strings.concat(
"$WORK/cmd.repeatdup.unit.new:4:1: error: wire redeclared in this block\n",
"\t$WORK/cmd.repeatdup.unit.new:3:1: other declaration of wire\n",
"$WORK/cmd.repeatdup.unit.new:4:1: error: \"pkg.one\" imported as wire and not used\n",
"ww: w6c failed for cmd.repeatdup\n"),
strings.concat(
"$WORK/cmd.aliasdup.unit.new:4:1: error: stable redeclared in this block\n",
"\t$WORK/cmd.aliasdup.unit.new:3:1: other declaration of stable\n",
"$WORK/cmd.aliasdup.unit.new:4:1: error: \"pkg.two\" imported as stable and not used\n",
"ww: w6c failed for cmd.aliasdup\n"),
strings.concat(
"$WORK/cmd.defaultalias.unit.new:4:1: error: wire redeclared in this block\n",
"\t$WORK/cmd.defaultalias.unit.new:3:1: other declaration of wire\n",
"$WORK/cmd.defaultalias.unit.new:4:1: error: \"pkg.two\" imported as wire and not used\n",
"ww: w6c failed for cmd.defaultalias\n"),
strings.concat(
"$WORK/cmd.declcollision.unit.new:3:1: error: \"pkg.one\" imported as stable and not used\n",
"$WORK/cmd.declcollision.unit.new:4:1: error: stable already declared through import of package stable (\"pkg.one\")\n",
"\t$WORK/cmd.declcollision.unit.new:3:1: other declaration of stable\n",
"ww: w6c failed for cmd.declcollision\n"),
strings.concat(
"$WORK/cmd.unusedalias.unit.new:3:1: error: \"pkg.one\" imported as stable and not used\n",
"ww: w6c failed for cmd.unusedalias\n"),
"", "", "",
];
let si: i32 = 0;
for (si < stages.len) {
let work: str = strings.concat(root, "/work-", stages[si]);
let rejectwork: str = strings.concat(root, "/reject-", stages[si]);
mkdirall(work); mkdirall(rejectwork);
i = 0;
for (i < positives.len) {
let target: str = strings.concat(source, "/cmd/", positives[i]);
let binary: str = strings.concat(root, "/", stages[si], "-",
positives[i]);
let av: []str = [driver(stages[si]), "build", "-w", work, "-I",
source, "-o", binary, target];
let out: commandout;
runcommand(root, strings.concat("alias-positive-", stages[si], "-",
positives[i]), av,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let runav: []str = [binary];
runcommand(root, strings.concat("alias-positive-run-", stages[si],
"-", positives[i]), runav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, expected[i]);
let bytes: str = readfile(binary);
if (si == 0) { binaryrefs[i] = strings.dup(bytes); }
else { assert(same(binaryrefs[i], bytes)); };
i += 1;
};
let aliasunit: str = readfile(strings.concat(work, "/cmd.alias.unit.ww"));
assert(has(aliasunit, "import stable pkg.one;"));
let aliaswwi: str = readfile(strings.concat(work, "/cmd.alias.wwi"));
assert(has(aliaswwi, "import __wwi_706b672e6f6e65 pkg.one;"));
assert(!has(aliaswwi, "import stable"));
assert(os.exists(strings.concat(work, "/pkg.one.a")));
assert(!os.exists(strings.concat(work, "/stable.a")));
let repeatunit: str = readfile(strings.concat(work,
"/cmd.repeatok.unit.ww"));
assert(occurrences(repeatunit, "pkg.one;") == 3);
let repeatedunit: str = readfile(strings.concat(work,
"/cmd.repeatedfiles.unit.ww"));
assert(occurrences(repeatedunit, "pkg.one;") == 2);
let blankunit: str = readfile(strings.concat(work,
"/cmd.blankalias.unit.ww"));
assert(has(blankunit, "import _ pkg.one;"));
let blankwwi: str = readfile(strings.concat(work,
"/cmd.blankalias.wwi"));
assert(!has(blankwwi, "import _") && !has(blankwwi, "__ww.."));
let blankrepeat: str = readfile(strings.concat(work,
"/cmd.blankrepeat.unit.ww"));
assert(occurrences(blankrepeat, "import _ pkg.one;") == 2);
assert(occurrences(blankrepeat,
"//ww:direct-export pkg.one ") == 1);
let blankfiles: str = readfile(strings.concat(work,
"/cmd.blankfiles.unit.ww"));
assert(occurrences(blankfiles, "import _ pkg.one;") == 2);
assert(occurrences(blankfiles,
"//ww:direct-export pkg.one ") == 1);
let blankdispatch: str = readfile(strings.concat(work,
"/cmd.blankdefault.init.unit.ww"));
assert(occurrences(blankdispatch,
"//ww:init-call __ww..pkg.p.pkg.one.v0.r0.init") == 1);
i = 0;
for (i < negatives.len) {
let target: str = strings.concat(source, "/cmd/", negatives[i]);
let binary: str = strings.concat(root, "/reject-bin-", stages[si],
"-", negatives[i]);
let av: []str = [driver(stages[si]), "build", "-w", rejectwork,
"-I", source, "-o", binary, target];
let out: commandout;
runcommand(root, strings.concat("alias-negative-", stages[si], "-",
negatives[i]), av,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, needles[i]));
if (i == 5) {
assert(has(out.stderr, "undefined: wire"));
assert(has(out.stderr, "undefined: one"));
assert(has(out.stderr, "undefined: value"));
};
if (i < 5) {
let unusedpos: i32 = pos(out.stderr,
"\"pkg.one\" imported as wire and not used");
let namepos: i32 = pos(out.stderr, needles[i]);
assert(unusedpos >= 0 && namepos > unusedpos);
};
if (i == 7 || i == 8 || i == 9) {
let redeclared: i32 = pos(out.stderr, "redeclared in this block");
let unused: i32 = pos(out.stderr, "imported as");
assert(redeclared >= 0 && unused > redeclared);
};
let normalized: str = normalizedtrace(out.stderr,
strings.concat(rejectwork, "/"), binary);
if (exactdiags[i].len > 0) {
assert(same(normalized, exactdiags[i]));
};
if (si == 0) { diagrefs[i] = strings.dup(normalized); }
else { assert(same(diagrefs[i], normalized)); };
assert(!os.exists(binary));
let action: str = strings.concat("cmd.", negatives[i]);
let suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a",
".unit.new", ".wwi.new", ".s.new", ".o.new", ".a.new"];
let j: i32 = 0;
for (j < suffixes.len) {
assert(!os.exists(strings.concat(rejectwork, "/", action,
suffixes[j])));
j += 1;
};
i += 1;
};
si += 1;
};
clean(root);
};
@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 family;\nexport fn v() i32 = { return 7; };\n");
writefile(strings.concat(pdir, "/same_test.ww"), strings.concat(
"package family;\nimport os;\n",
"@test fn seven() void = { let av: []str = os.args();",
" if (av.len != 0) { os.write(os.STDOUT_FILENO, av[0].ptr,",
" av[0].len: u64); os.write(os.STDOUT_FILENO, \"\\n\".ptr, 1u64); };",
" assert(v() == 7); };\n"));
let adir: str = strings.concat(root, "/a");
assert(os.mkdir(adir, 493i32) == 0);
writefile(strings.concat(adir, "/a.ww"),
"package other;\nexport fn v() i32 = { return 1; };\n");
writefile(strings.concat(adir, "/a_test.ww"),
"package other;\n@test fn one() void = { assert(v() == 1); };\n");
let none: str = strings.concat(root, "/znone");
assert(os.mkdir(none, 493i32) == 0);
writefile(strings.concat(none, "/none.ww"),
"package renamed;\nexport fn v() i32 = { return 9; };\n");
// '_' roots are excluded from recursive package discovery.
let outdir: str = strings.concat(root, "/_out");
assert(os.mkdir(outdir, 493i32) == 0);
let out: commandout;
let drvs: []str = ["ww", "ww_ww"];
let namedbytes: str = "";
let defaultbytes: str = "";
let fanabytes: str = "";
let fanpkgbytes: str = "";
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", "-I", root,
"-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");
};
assert(((fi.mode: u32) & 73u32) != 0u32);
assert(!has(out.stdout, "seven ... "));
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;
};
if (i == 0) { namedbytes = readfile(named); }
else { assert(same(namedbytes, readfile(named))); };
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 ... "));
let runnamed: str = strings.concat(outdir, "/run_", drvs[i], ".bin");
let nocav: []str = [driver(drvs[i]), "test", "-I", root,
"-o", runnamed, pdir];
runcommand(root, strings.concat("noc_", drvs[i]), nocav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stderr.len == 0 && os.exists(runnamed));
assert(has(out.stdout, "seven ... "));
assert(has(out.stdout, "/package.test\n"));
assert(!has(out.stdout, runnamed));
let defaultbin: str = strings.concat(root, "/pkg.test");
let defaultav: []str = [driver(drvs[i]), "test", "-c", "-I", root,
pdir];
runcommanddir(root, strings.concat("default_", drvs[i]), root,
defaultav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(os.exists(defaultbin));
assert(!os.exists(strings.concat(root, "/family.test")));
assert(!os.exists(strings.concat(pdir, "/family.test")));
if (i == 0) { defaultbytes = readfile(defaultbin); }
else { assert(same(defaultbytes, readfile(defaultbin))); };
clean(defaultbin);
let fanroot: str = strings.concat(root, "/_fan_", drvs[i]);
let fanarg: str = strings.concat(fanroot, "/nested/");
let fanav: []str = [driver(drvs[i]), "test", "-c", "-j", "2",
"-I", root, "-o", fanarg, strings.concat(root, "/...")];
runcommand(root, strings.concat("fan_", drvs[i]), fanav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
let fanabin: str = strings.concat(fanarg, "a.test");
let fanpkg: str = strings.concat(fanarg, "pkg.test");
assert(os.exists(fanabin) && os.exists(fanpkg));
assert(!os.exists(strings.concat(fanarg, "znone.test")));
assert(has(out.stdout, strings.concat("? ", none, " [no tests]\n")));
if (i == 0) {
fanabytes = readfile(fanabin);
fanpkgbytes = readfile(fanpkg);
} else {
assert(same(fanabytes, readfile(fanabin)));
assert(same(fanpkgbytes, readfile(fanpkg)));
};
let badout: str = strings.concat(outdir, "/multi-file-", drvs[i]);
let mulav: []str = [driver(drvs[i]), "test", "-c", "-o",
badout, strings.concat(root, "/...")];
runcommand(root, strings.concat("multi_", drvs[i]), mulav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr,
"with multiple packages, -o must refer to a directory or /dev/null"));
assert(!os.exists(badout));
let nullcompile: []str = [driver(drvs[i]), "test", "-c", "-I",
root, "-o", "/dev/null", pdir];
runcommand(root, strings.concat("null-compile_", drvs[i]), nullcompile,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(!has(out.stdout, "seven ... "));
assert(!os.exists("/dev/null.new"));
let nullrun: []str = [driver(drvs[i]), "test", "-I", root,
"-o", "/dev/null", pdir];
runcommand(root, strings.concat("null-run_", drvs[i]), nullrun,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "seven ... "));
i += 1;
};
clean(root);
};
@test fn test_binary_publication_transaction() void = {
let root: str = fresh();
let suite: str = strings.concat(root, "/suite");
let leftsame: str = strings.concat(suite, "/left/same");
let rightsame: str = strings.concat(suite, "/right/same");
let alpha: str = strings.concat(suite, "/alpha");
let beta: str = strings.concat(suite, "/beta");
let failed: str = strings.concat(suite, "/failed");
let none: str = strings.concat(suite, "/none");
let persist: str = strings.concat(suite, "/persist");
mkdirall(leftsame); mkdirall(rightsame); mkdirall(alpha);
mkdirall(beta); mkdirall(failed); mkdirall(none); mkdirall(persist);
writefile(strings.concat(leftsame, "/same.ww"),
"package declared_left;\nfn value() i32 = { return 1; };\n");
writefile(strings.concat(leftsame, "/same_test.ww"), strings.concat(
"package declared_left;\n",
"@test fn left() void = { assert(value() == 1); };\n"));
writefile(strings.concat(rightsame, "/same.ww"),
"package declared_right;\nfn value() i32 = { return 2; };\n");
writefile(strings.concat(rightsame, "/same_test.ww"), strings.concat(
"package declared_right;\n",
"@test fn right() void = { assert(value() == 2); };\n"));
writefile(strings.concat(alpha, "/alpha.ww"),
"package alpha_decl;\nfn value() i32 = { return 3; };\n");
writefile(strings.concat(alpha, "/alpha_test.ww"), strings.concat(
"package alpha_decl;\n",
"@test fn alpha_ok() void = { assert(value() == 3); };\n"));
writefile(strings.concat(beta, "/beta.ww"),
"package beta_decl;\nfn value() i32 = { return 4; };\n");
writefile(strings.concat(beta, "/beta_test.ww"), strings.concat(
"package beta_decl;\n",
"@test fn beta_ok() void = { assert(value() == 4); };\n"));
writefile(strings.concat(failed, "/failed.ww"),
"package failed_decl;\nfn value() i32 = { return 5; };\n");
writefile(strings.concat(failed, "/failed_test.ww"), strings.concat(
"package failed_decl;\n",
"@test fn runtime_failure() void = { assert(false); };\n"));
writefile(strings.concat(none, "/none.ww"),
"package none_decl;\nfn value() i32 = { return 6; };\n");
let persisttest: str = strings.concat(persist, "/persist_test.ww");
let persistbase: str = strings.concat(
"package persist_decl;\n",
"@test fn persistent_base() void = { assert(true); };\n");
let persistchanged: str = strings.concat(
"package persist_decl;\n",
"@test fn persistent_changed() void = { assert(1 + 1 == 2); };\n");
writefile(strings.concat(persist, "/persist.ww"),
"package persist_decl;\nfn value() i32 = { return 7; };\n");
writefile(persisttest, persistbase);
let compilerwrapper: str = strings.concat(root, "/publish-w6c.sh");
let linkerwrapper: str = strings.concat(root, "/publish-w6l.sh");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_PUBLISH_CTRACE\"\n",
"exec \"$WW_PUBLISH_REAL_C\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_PUBLISH_LTRACE\"\n",
"if test -n \"$WW_PUBLISH_FAIL\"; then\n",
" for arg do case \"$arg\" in *\"$WW_PUBLISH_FAIL\"*)\n",
" printf 'injected publication linker failure\\n' >&2\n",
" exit 97;; esac; done\nfi\n",
"exec \"$WW_PUBLISH_REAL_L\" \"$@\"\n"));
let stages: []str = ["ww", "ww_ww"];
let compilers: []str = ["w6c", "w6c_ww"];
let linkers: []str = ["w6l", "w6l_ww"];
let tags: []str = ["c", "ww"];
let duplicatediag: str = "";
let rollbackdiag: str = "";
let missingdiag: str = "";
let occupieddiag: str = "";
let failurebytes: str = "";
let persistbasebytes: str = "";
let persistchangedbytes: str = "";
let baseenv: []str = os.getenvs();
let out: commandout;
let si: i32 = 0;
for (si < stages.len) {
let ctrace: str = strings.concat(root, "/publish-", tags[si],
"-w6c.trace");
let ltrace: str = strings.concat(root, "/publish-", tags[si],
"-w6l.trace");
writefile(ctrace, ""); writefile(ltrace, "");
let env: []str = alloc([], (baseenv.len + 7): 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_PUBLISH_CTRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_PUBLISH_LTRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_PUBLISH_REAL_C=")
&& !strings.hasprefix(baseenv[ei], "WW_PUBLISH_REAL_L=")
&& !strings.hasprefix(baseenv[ei], "WW_PUBLISH_FAIL=")) {
append(env, baseenv[ei]);
};
ei += 1;
};
append(env, strings.concat("WW_W6C=", compilerwrapper));
append(env, strings.concat("WW_W6L=", linkerwrapper));
append(env, strings.concat("WW_PUBLISH_CTRACE=", ctrace));
append(env, strings.concat("WW_PUBLISH_LTRACE=", ltrace));
append(env, strings.concat("WW_PUBLISH_REAL_C=",
driver(compilers[si])));
append(env, strings.concat("WW_PUBLISH_REAL_L=",
driver(linkers[si])));
append(env, "WW_PUBLISH_FAIL=");
// Equal import leaves are rejected before tools or output creation,
// independent of their unequal declared package names.
let duplicateout: str = strings.concat(root, "/duplicate-output/");
let duplicateav: []str = [driver(stages[si]), "test", "-c",
"-j", "2", "-I", suite, "-o", duplicateout,
leftsame, rightsame];
runcommandenvdir(root, strings.concat("publish-duplicate-", tags[si]),
duplicateav, env, root,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0);
assert(has(out.stderr,
"ww test: cannot write test binary same.test for multiple packages:\n"));
assert(has(out.stderr, strings.concat(leftsame, "\n")));
assert(has(out.stderr, strings.concat(rightsame, "\n")));
assert(readfile(ctrace).len == 0 && readfile(ltrace).len == 0);
assert(!os.exists(duplicateout));
if (si == 0) { duplicatediag = strings.dup(out.stderr); }
else { assert(same(duplicatediag, out.stderr)); };
// /dev/null is Go's exact multi-package discard exception: both
// products build, neither publishes, and duplicate names are harmless.
let nullav: []str = [driver(stages[si]), "test", "-c", "-j", "2",
"-I", suite, "-o", "/dev/null", leftsame, rightsame];
runcommandenvdir(root, strings.concat("publish-null-", tags[si]),
nullav, env, root,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(readfile(ctrace).len != 0);
assert(occurrences(readfile(ltrace), "\n") == 2);
assert(!os.exists("/dev/null.new"));
// An occupied retained-binary stage is a pre-tool rejection. The
// caller's old destination and occupied stage both remain untouched.
let occupied: str = strings.concat(root, "/occupied");
if (si == 0) {
assert(os.mkdir(occupied, 448i32) == 0);
writefile(strings.concat(occupied, "/alpha.test"), "old-alpha\n");
writefile(strings.concat(occupied, "/alpha.test.new"),
"occupied-stage\n");
};
rewritefile(ctrace, ""); rewritefile(ltrace, "");
let occupiedav: []str = [driver(stages[si]), "test", "-c", "-I",
suite, "-o", strings.concat(occupied, "/"), alpha];
runcommandenvdir(root, strings.concat("publish-occupied-", tags[si]),
occupiedav, env, root,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, strings.concat(
"ww: product staging path already exists: ", occupied,
"/alpha.test.new\n")));
assert(same(readfile(strings.concat(occupied, "/alpha.test")),
"old-alpha\n"));
assert(same(readfile(strings.concat(occupied, "/alpha.test.new")),
"occupied-stage\n"));
assert(readfile(ctrace).len == 0 && readfile(ltrace).len == 0);
if (si == 0) { occupieddiag = strings.dup(out.stderr); }
else { assert(same(occupieddiag, out.stderr)); };
// Link failure after an earlier sibling has staged a retained copy
// rejects the whole request and preserves every old destination.
let rollback: str = strings.concat(root, "/rollback-", tags[si]);
assert(os.mkdir(rollback, 448i32) == 0);
writefile(strings.concat(rollback, "/alpha.test"), "alpha-sentinel\n");
writefile(strings.concat(rollback, "/beta.test"), "beta-sentinel\n");
rewritefile(ctrace, ""); rewritefile(ltrace, "");
env[env.len - 1] = "WW_PUBLISH_FAIL=beta-test-main";
let rollbackav: []str = [driver(stages[si]), "test", "-c", "-j",
"1", "-I", suite, "-o", strings.concat(rollback, "/"),
alpha, beta];
runcommandenvdir(root, strings.concat("publish-rollback-", tags[si]),
rollbackav, env, root,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "injected publication linker failure\n"));
assert(has(out.stderr, "ww: w6l failed\n"));
assert(same(readfile(strings.concat(rollback, "/alpha.test")),
"alpha-sentinel\n"));
assert(same(readfile(strings.concat(rollback, "/beta.test")),
"beta-sentinel\n"));
assert(!directoryhasnew(rollback));
assert(occurrences(readfile(ltrace), "\n") == 2);
if (si == 0) { rollbackdiag = strings.dup(out.stderr); }
else { assert(same(rollbackdiag, out.stderr)); };
// Output directories minted for a rejected request are rolled back.
let missingroot: str = strings.concat(root, "/missing-", tags[si]);
let missingout: str = strings.concat(missingroot, "/nested/");
rewritefile(ctrace, ""); rewritefile(ltrace, "");
env[env.len - 1] = "WW_PUBLISH_FAIL=alpha-test-main";
let missingav: []str = [driver(stages[si]), "test", "-c", "-j",
"1", "-I", suite, "-o", missingout, alpha];
runcommandenvdir(root, strings.concat("publish-missing-", tags[si]),
missingav, env, root,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(!os.exists(missingroot));
assert(occurrences(readfile(ltrace), "\n") == 1);
if (si == 0) { missingdiag = strings.dup(out.stderr); }
else { assert(same(missingdiag, out.stderr)); };
// A package with no tests never claims a binary or creates a requested
// output hierarchy, although its production package is still checked.
let noneroot: str = strings.concat(root, "/none-output-", tags[si]);
let noneav: []str = [driver(stages[si]), "test", "-c", "-I", suite,
"-o", strings.concat(noneroot, "/nested/"), none];
env[env.len - 1] = "WW_PUBLISH_FAIL=";
runcommandenvdir(root, strings.concat("publish-none-", tags[si]),
noneav, env, root,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, strings.concat("? ", none,
" [no tests]\n")));
assert(out.stderr.len == 0 && !os.exists(noneroot));
// Publication commits before execution. A failing test therefore leaves
// a runnable retained binary while its product failure stays on stdout.
let failurebin: str = strings.concat(root, "/failure-", tags[si],
".test");
let failureav: []str = [driver(stages[si]), "test", "-I", suite,
"-o", failurebin, failed];
runcommandenvdir(root, strings.concat("publish-runtime-", tags[si]),
failureav, env, root,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(os.exists(failurebin) && !os.exists(strings.concat(failurebin,
".new")));
assert(has(out.stdout,
"failed_decl.runtime_failure ... FAIL (exit 1)\n"));
assert(out.stderr.len == 0);
let fi: os.filestat;
match (os.stat(&fi, failurebin)) {
case void => void;
case let e: os.oserror => abort("retained failure binary missing");
};
assert(((fi.mode: u32) & 73u32) != 0u32);
if (si == 0) { failurebytes = readfile(failurebin); }
else { assert(same(failurebytes, readfile(failurebin))); };
// -w keeps semantic actions persistent while -c and -o remain execution
// and presentation policy. Compile-only can cold-build and invalidate;
// an unchanged running request reuses those actions and the same bytes.
rewritefile(persisttest, persistbase);
let persistwork: str = strings.concat(root, "/persist-work-", tags[si]);
let persistcompilebin: str = strings.concat(root, "/persist-compile-",
tags[si], ".test");
let persistbin: str = strings.concat(root, "/persist-run-", tags[si],
".test");
rewritefile(ctrace, ""); rewritefile(ltrace, "");
let persistcompileav: []str = [driver(stages[si]), "test", "-c",
"-w", persistwork, "-I", suite, "-o", persistcompilebin,
persist];
let persistav: []str = [driver(stages[si]), "test", "-w",
persistwork, "-I", suite, "-o", persistbin, persist];
runcommandenvdir(root, strings.concat("publish-persist-cold-c-", tags[si]),
persistcompileav, env, root,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(readfile(ctrace).len != 0);
let basebytes: str = readfile(persistcompilebin);
if (si == 0) { persistbasebytes = strings.dup(basebytes); }
else { assert(same(persistbasebytes, basebytes)); };
rewritefile(ctrace, ""); rewritefile(ltrace, "");
runcommandenvdir(root, strings.concat("publish-persist-warm-run-", tags[si]),
persistav, env, root,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "persistent_base ... ok\n"));
assert(readfile(ctrace).len == 0);
assert(same(basebytes, readfile(persistbin)));
rewritefile(persisttest, persistchanged);
rewritefile(ctrace, ""); rewritefile(ltrace, "");
runcommandenvdir(root, strings.concat("publish-persist-change-c-", tags[si]),
persistcompileav, env, root,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(readfile(ctrace).len != 0);
let changedbytes: str = readfile(persistcompilebin);
assert(!same(basebytes, changedbytes));
if (si == 0) { persistchangedbytes = strings.dup(changedbytes); }
else { assert(same(persistchangedbytes, changedbytes)); };
rewritefile(ctrace, ""); rewritefile(ltrace, "");
runcommandenvdir(root, strings.concat("publish-persist-change-run-",
tags[si]), persistav, env, root,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "persistent_changed ... ok\n"));
assert(readfile(ctrace).len == 0);
assert(same(changedbytes, readfile(persistbin)));
assert(!os.exists(strings.concat(persistcompilebin, ".new")));
assert(!os.exists(strings.concat(persistbin, ".new")));
assert(!directoryhasnew(persistwork));
si += 1;
};
assert(os.remove(strings.concat(root,
"/occupied/alpha.test.new")) == 0);
clean(root);
};