|
|
|
|
@@ -3,6 +3,8 @@ 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;
|
|
|
|
|
@@ -287,6 +289,98 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
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 packagestoragekey(path: str, canon: str, variant: i32, role: i32) str = {
|
|
|
|
|
let state: sha256.state = sha256.sha256();
|
|
|
|
|
let h: *hash.hash = (&state): *hash.hash;
|
|
|
|
|
hash.write(h, strings.toutf8("ww-package-storage-v2:"));
|
|
|
|
|
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));
|
|
|
|
|
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 requestworkkey(dir: str) str = {
|
|
|
|
|
let state: sha256.state = sha256.sha256();
|
|
|
|
|
let h: *hash.hash = (&state): *hash.hash;
|
|
|
|
|
hash.write(h, strings.toutf8("ww-request-workdir-v1:"));
|
|
|
|
|
hash.write(h, strings.toutf8(dir));
|
|
|
|
|
return strings.concat("d_", digesthex(h));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@test fn deterministic_routing_and_filters() void = {
|
|
|
|
|
let root: str = fresh();
|
|
|
|
|
let target: str = packagepath("routing");
|
|
|
|
|
@@ -515,22 +609,97 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
clean(root);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@test fn symlink_package_is_rejected() void = {
|
|
|
|
|
@test fn symlink_package_root_reuses_canonical_directory() void = {
|
|
|
|
|
let root: str = fresh();
|
|
|
|
|
let real: str = strings.concat(root, "/real");
|
|
|
|
|
let real: str = deeppunctuationpath(root, "symlink target");
|
|
|
|
|
let link: str = strings.concat(root, "/link");
|
|
|
|
|
assert(os.mkdir(real, 448i32) == 0);
|
|
|
|
|
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);
|
|
|
|
|
let av: []str = [driver("ww"), "test", link];
|
|
|
|
|
runcommand(root, "reject", av,
|
|
|
|
|
(30i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 1);
|
|
|
|
|
assert(has(out.stderr, "symlink traversal is not allowed"));
|
|
|
|
|
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 = strings.concat(work, "/", requestworkkey(real));
|
|
|
|
|
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;
|
|
|
|
|
};
|
|
|
|
|
si += 1;
|
|
|
|
|
};
|
|
|
|
|
clean(root);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@@ -2606,44 +2775,48 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
let root: str = fresh();
|
|
|
|
|
let source: str = strings.concat(root, "/source tree");
|
|
|
|
|
let runtime: str = strings.concat(root, "/runtime library");
|
|
|
|
|
let base: str = strings.concat(source, "/ww_root_parity_base_7f3");
|
|
|
|
|
let left: str = strings.concat(source, "/ww_root_parity_left_7f3");
|
|
|
|
|
let right: str = strings.concat(source, "/ww_root_parity_right_7f3");
|
|
|
|
|
let rootidentity: str = "ww_root_parity_target_7f3";
|
|
|
|
|
let target: str = strings.concat(source, "/", rootidentity);
|
|
|
|
|
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")));
|
|
|
|
|
assert(os.mkdir(base, 448i32) == 0);
|
|
|
|
|
assert(os.mkdir(left, 448i32) == 0);
|
|
|
|
|
assert(os.mkdir(right, 448i32) == 0);
|
|
|
|
|
assert(os.mkdir(target, 448i32) == 0);
|
|
|
|
|
mkdirall(base);
|
|
|
|
|
mkdirall(left);
|
|
|
|
|
mkdirall(right);
|
|
|
|
|
mkdirall(target);
|
|
|
|
|
assert(os.mkdir(tools, 448i32) == 0);
|
|
|
|
|
let basea: str = strings.concat(
|
|
|
|
|
"package ww_root_parity_base_7f3;\n",
|
|
|
|
|
"package paritybase;\n",
|
|
|
|
|
"export fn value() i32 = { return 20; };\n");
|
|
|
|
|
let basez: str = strings.concat(
|
|
|
|
|
"package ww_root_parity_base_7f3;\n",
|
|
|
|
|
"package paritybase;\n",
|
|
|
|
|
"fn private_value() i32 = { return 99; };\n");
|
|
|
|
|
let leftbody: str = strings.concat(
|
|
|
|
|
"package ww_root_parity_left_7f3;\n",
|
|
|
|
|
"import ww_root_parity_base_7f3;\n",
|
|
|
|
|
"import ww_root_parity_base_7f3;\n",
|
|
|
|
|
"package parityleft;\n",
|
|
|
|
|
"import ", baseidentity, ";\n",
|
|
|
|
|
"import ", baseidentity, ";\n",
|
|
|
|
|
"export fn value() i32 = { return ",
|
|
|
|
|
"ww_root_parity_base_7f3.value(); };\n");
|
|
|
|
|
"paritybase.value(); };\n");
|
|
|
|
|
let rightbody: str = strings.concat(
|
|
|
|
|
"package ww_root_parity_right_7f3;\n",
|
|
|
|
|
"import ww_root_parity_base_7f3;\n",
|
|
|
|
|
"package parityright;\n",
|
|
|
|
|
"import ", baseidentity, ";\n",
|
|
|
|
|
"export fn value() i32 = { return ",
|
|
|
|
|
"ww_root_parity_base_7f3.value() + 1; };\n");
|
|
|
|
|
"paritybase.value() + 1; };\n");
|
|
|
|
|
let rootbody: str = strings.concat(
|
|
|
|
|
"package main;\n",
|
|
|
|
|
"import ww_root_parity_right_7f3;\n",
|
|
|
|
|
"import ww_root_parity_left_7f3;\n",
|
|
|
|
|
"fn main() i32 = { return ww_root_parity_left_7f3.value() + ",
|
|
|
|
|
"ww_root_parity_right_7f3.value() + 1; };\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, "/left.ww"), leftbody);
|
|
|
|
|
@@ -2703,18 +2876,25 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
let bin: str = strings.concat(root, "/published binary");
|
|
|
|
|
let workroot: str = strings.concat(bin, ".sepwork");
|
|
|
|
|
let work: str = strings.concat(workroot, "/");
|
|
|
|
|
let artifacts: []str = ["ww_root_parity_base_7f3",
|
|
|
|
|
"ww_root_parity_left_7f3", "ww_root_parity_right_7f3",
|
|
|
|
|
rootidentity];
|
|
|
|
|
let unitartifacts: []str = ["ww_root_parity_base_7f3",
|
|
|
|
|
"ww_root_parity_left_7f3", "ww_root_parity_right_7f3",
|
|
|
|
|
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 ww_root_parity_base_7f3\n", basea,
|
|
|
|
|
"\n//ww:module-reset ww_root_parity_base_7f3\n", basez, "\n"),
|
|
|
|
|
strings.concat("//ww:module-reset ww_root_parity_left_7f3\n",
|
|
|
|
|
"//ww:module-reset ", baseidentity, "\n", basea,
|
|
|
|
|
"\n//ww:module-reset ", baseidentity, "\n", basez, "\n"),
|
|
|
|
|
strings.concat("//ww:module-reset ", leftidentity, "\n",
|
|
|
|
|
leftbody, "\n"),
|
|
|
|
|
strings.concat("//ww:module-reset ww_root_parity_right_7f3\n",
|
|
|
|
|
strings.concat("//ww:module-reset ", rightidentity, "\n",
|
|
|
|
|
rightbody, "\n"),
|
|
|
|
|
strings.concat("//ww:module-reset ", rootidentity, "\n", rootbody,
|
|
|
|
|
"\n")];
|
|
|
|
|
@@ -2728,6 +2908,7 @@ fn localidentity(dir: str, leaf: str) 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) {
|
|
|
|
|
@@ -2788,8 +2969,10 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
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,
|
|
|
|
|
target];
|
|
|
|
|
request];
|
|
|
|
|
let out: commandout;
|
|
|
|
|
runcommandenv(root, strings.concat("exact-argv-", tags[si]), av, env,
|
|
|
|
|
(120i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
@@ -2809,12 +2992,19 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
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(strings.hasprefix(exportf, strings.concat("package ",
|
|
|
|
|
rootidentity, ";\n")));
|
|
|
|
|
assert(!strings.hasprefix(exportf, "package main;\n"));
|
|
|
|
|
assert(has(exportf, strings.concat("\npackage paritycommand",
|
|
|
|
|
";\n")));
|
|
|
|
|
assert(!has(exportf, "\npackage main;\n"));
|
|
|
|
|
};
|
|
|
|
|
if (si == 0) {
|
|
|
|
|
referenceexports[ai] = strings.dup(exportf);
|
|
|
|
|
@@ -2832,48 +3022,62 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
let ltrace: str = readfile(linkertrace);
|
|
|
|
|
assert(occurrences(ctrace, "\n") == 4);
|
|
|
|
|
let baseline: str = strings.concat("BEGIN<-c><-I><", work,
|
|
|
|
|
"ww_root_parity_base_7f3.wwi><-o><", work,
|
|
|
|
|
"ww_root_parity_base_7f3.s><", work,
|
|
|
|
|
"ww_root_parity_base_7f3.unit.ww>");
|
|
|
|
|
artifacts[0], ".wwi><-o><", work,
|
|
|
|
|
artifacts[0], ".s><", work,
|
|
|
|
|
artifacts[0], ".unit.ww>");
|
|
|
|
|
let leftline: str = strings.concat("BEGIN<-c><--import>",
|
|
|
|
|
"<ww_root_parity_base_7f3><", work,
|
|
|
|
|
"ww_root_parity_base_7f3.wwi><-I><", work,
|
|
|
|
|
"ww_root_parity_left_7f3.wwi><-o><", work,
|
|
|
|
|
"ww_root_parity_left_7f3.s><", work,
|
|
|
|
|
"ww_root_parity_left_7f3.unit.ww>");
|
|
|
|
|
"<", 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<-c><--import>",
|
|
|
|
|
"<ww_root_parity_base_7f3><", work,
|
|
|
|
|
"ww_root_parity_base_7f3.wwi><-I><", work,
|
|
|
|
|
"ww_root_parity_right_7f3.wwi><-o><", work,
|
|
|
|
|
"ww_root_parity_right_7f3.s><", work,
|
|
|
|
|
"ww_root_parity_right_7f3.unit.ww>");
|
|
|
|
|
"<", 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><-c><--import>",
|
|
|
|
|
"<ww_root_parity_left_7f3><", work,
|
|
|
|
|
"ww_root_parity_left_7f3.wwi><--import>",
|
|
|
|
|
"<ww_root_parity_right_7f3><", work,
|
|
|
|
|
"ww_root_parity_right_7f3.wwi><-I><", work,
|
|
|
|
|
rootidentity, ".wwi><-o><", work,
|
|
|
|
|
rootidentity, ".s><", work, rootidentity, ".unit.ww>");
|
|
|
|
|
"<", 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,
|
|
|
|
|
"ww_root_parity_base_7f3.unit.ww"), baseline));
|
|
|
|
|
strings.concat(artifacts[0], ".unit.ww")), baseline));
|
|
|
|
|
assert(same(linecontaining(ctrace,
|
|
|
|
|
"ww_root_parity_left_7f3.unit.ww"), leftline));
|
|
|
|
|
strings.concat(artifacts[1], ".unit.ww")), leftline));
|
|
|
|
|
assert(same(linecontaining(ctrace,
|
|
|
|
|
"ww_root_parity_right_7f3.unit.ww"), rightline));
|
|
|
|
|
assert(same(linecontaining(ctrace, strings.concat(rootidentity,
|
|
|
|
|
strings.concat(artifacts[2], ".unit.ww")), rightline));
|
|
|
|
|
assert(same(linecontaining(ctrace, strings.concat(artifacts[3],
|
|
|
|
|
".unit.ww")), rootline));
|
|
|
|
|
assert(!has(rootline, "ww_root_parity_base_7f3.wwi"));
|
|
|
|
|
assert(!has(rootline, strings.concat(artifacts[0], ".wwi")));
|
|
|
|
|
// The primary command declaration is accepted only when the compiler
|
|
|
|
|
// receives command classification from --entry. Imported interfaces and
|
|
|
|
|
// ordinary package compiles retain strict identity-leaf validation.
|
|
|
|
|
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", "-I", rejectwwi,
|
|
|
|
|
"-o", rejectasm, strings.concat(work, rootidentity, ".unit.ww")];
|
|
|
|
|
"-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, 1);
|
|
|
|
|
assert(has(out.stderr, "does not match import path"));
|
|
|
|
|
assert(has(out.stderr, rootidentity));
|
|
|
|
|
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") == 4);
|
|
|
|
|
ai = 0;
|
|
|
|
|
for (ai < artifacts.len) {
|
|
|
|
|
@@ -2885,7 +3089,7 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
};
|
|
|
|
|
assert(occurrences(ltrace, "\n") == 1);
|
|
|
|
|
assert(has(ltrace, strings.concat("BEGIN<-o><", bin, "><", work,
|
|
|
|
|
rootidentity, ".a>")));
|
|
|
|
|
artifacts[3], ".a>")));
|
|
|
|
|
ai = 0;
|
|
|
|
|
for (ai < artifacts.len) {
|
|
|
|
|
assert(occurrences(ltrace, strings.concat("<", work, artifacts[ai],
|
|
|
|
|
@@ -2917,6 +3121,127 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
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-test", "production", "paritybase", base,
|
|
|
|
|
combinedbase, combinedbasestatus,
|
|
|
|
|
"--ww-package-test", "production", "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", "-p", "-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);
|
|
|
|
|
|
|
|
|
|
@@ -2933,20 +3258,20 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
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,
|
|
|
|
|
"ww_root_parity_base_7f3.wwi"));
|
|
|
|
|
artifacts[0], ".wwi"));
|
|
|
|
|
append(failenv, strings.concat("WW_ARGV_MISSING_OWNER=", work,
|
|
|
|
|
"ww_root_parity_left_7f3.unit.ww"));
|
|
|
|
|
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 ww_root_parity_base_7f3: cannot read ", work,
|
|
|
|
|
"ww_root_parity_base_7f3.wwi\n",
|
|
|
|
|
"ww: w6c failed for ww_root_parity_left_7f3\n");
|
|
|
|
|
"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><ww_root_parity_base_7f3><", work,
|
|
|
|
|
"ww_root_parity_base_7f3.wwi>")));
|
|
|
|
|
"<--import><", baseidentity, "><", work,
|
|
|
|
|
artifacts[0], ".wwi>")));
|
|
|
|
|
if (si == 0) { referencefailure = strings.dup(out.stderr); }
|
|
|
|
|
else { assert(same(referencefailure, out.stderr)); };
|
|
|
|
|
clean(workroot);
|
|
|
|
|
@@ -2959,11 +3284,13 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
@test fn command_package_test_variants_keep_canonical_identity() void = {
|
|
|
|
|
let root: str = fresh();
|
|
|
|
|
let source: str = strings.concat(root, "/source");
|
|
|
|
|
let target: str = strings.concat(source, "/cmdtool");
|
|
|
|
|
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);
|
|
|
|
|
assert(os.mkdir(target, 448i32) == 0);
|
|
|
|
|
mkdirall(target);
|
|
|
|
|
assert(os.mkdir(importer, 448i32) == 0);
|
|
|
|
|
writefile(strings.concat(target, "/main.ww"), strings.concat(
|
|
|
|
|
"package main;\n",
|
|
|
|
|
@@ -2974,12 +3301,12 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
"@test fn command_internal() void = { assert(value() == 41); };\n"));
|
|
|
|
|
writefile(strings.concat(target, "/external_test.ww"), strings.concat(
|
|
|
|
|
"package main_test;\n",
|
|
|
|
|
"import cmdtool;\n",
|
|
|
|
|
"import ", commandid, ";\n",
|
|
|
|
|
"@test fn command_external() void = { ",
|
|
|
|
|
"assert(cmdtool.value() == 41); };\n"));
|
|
|
|
|
writefile(strings.concat(importer, "/importer.ww"), strings.concat(
|
|
|
|
|
"package importer;\n",
|
|
|
|
|
"import cmdtool;\n",
|
|
|
|
|
"import ", commandid, ";\n",
|
|
|
|
|
"export fn value() i32 = { return cmdtool.value(); };\n"));
|
|
|
|
|
writeexecutable(wrapper, strings.concat(
|
|
|
|
|
"#!/bin/sh\n",
|
|
|
|
|
@@ -2991,17 +3318,33 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
|
|
|
|
|
let stages: []str = ["ww", "ww_ww"];
|
|
|
|
|
let compilers: []str = ["w6c", "w6c_ww"];
|
|
|
|
|
let artifacts: []str = ["cmdtool", "cmdtool-internal-test",
|
|
|
|
|
"cmdtool_test-external-test"];
|
|
|
|
|
let internalid: str = commandid;
|
|
|
|
|
let externalid: str = strings.concat(commandid, "_test");
|
|
|
|
|
let internalmainid: str = strings.concat("__wwtestmain.", commandid,
|
|
|
|
|
".internal.main");
|
|
|
|
|
let externalmainid: str = strings.concat("__wwtestmain.", externalid,
|
|
|
|
|
".external.main");
|
|
|
|
|
let actionids: []str = [commandid, internalid, externalid,
|
|
|
|
|
internalmainid, externalmainid];
|
|
|
|
|
let artifacts: []str = [packagestoragekey(commandid, target, 0, 0),
|
|
|
|
|
packagestoragekey(internalid, target, 1, 0),
|
|
|
|
|
packagestoragekey(externalid, target, 2, 0),
|
|
|
|
|
packagestoragekey(internalmainid,
|
|
|
|
|
strings.concat(target, "#internal-test-main"), 3, 2),
|
|
|
|
|
packagestoragekey(externalmainid,
|
|
|
|
|
strings.concat(target, "#external-test-main"), 3, 2)];
|
|
|
|
|
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
|
|
|
|
|
let reference: []str = ["", "", "", "", "", "", "", "", ""];
|
|
|
|
|
let reference: []str = ["", "", "", "", "", "", "", "", "",
|
|
|
|
|
"", "", "", "", "", ""];
|
|
|
|
|
let samebin: str = strings.concat(target, "/main.test");
|
|
|
|
|
let externalbin: str = strings.concat(target, "/main_test.test");
|
|
|
|
|
let workroot: str = strings.concat(samebin, ".sepwork");
|
|
|
|
|
let work: str = strings.concat(workroot, "/");
|
|
|
|
|
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, "/", requestworkkey(target),
|
|
|
|
|
"/");
|
|
|
|
|
let trace: str = strings.concat(root, "/", stages[si], ".trace");
|
|
|
|
|
writefile(trace, "");
|
|
|
|
|
let env: []str = alloc([], (baseenv.len + 3): u64)!;
|
|
|
|
|
@@ -3020,24 +3363,34 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
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", "-c", "-I", source,
|
|
|
|
|
target];
|
|
|
|
|
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_test.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.ww"));
|
|
|
|
|
assert(has(line, "<--command-package>"));
|
|
|
|
|
strings.concat(artifacts[ai], ".unit.new"));
|
|
|
|
|
if (ai < 3) { 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)); };
|
|
|
|
|
@@ -3045,25 +3398,50 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
};
|
|
|
|
|
ai += 1;
|
|
|
|
|
};
|
|
|
|
|
assert(has(readfile(strings.concat(work, "cmdtool.unit.ww")),
|
|
|
|
|
"//ww:module-reset cmdtool\n"));
|
|
|
|
|
assert(has(readfile(strings.concat(work,
|
|
|
|
|
"cmdtool-internal-test.unit.ww")),
|
|
|
|
|
"//ww:module-reset cmdtool\n"));
|
|
|
|
|
assert(has(readfile(strings.concat(work,
|
|
|
|
|
"cmdtool_test-external-test.unit.ww")),
|
|
|
|
|
"//ww:module-reset cmdtool_test\n"));
|
|
|
|
|
|
|
|
|
|
let runav: []str = [samebin, "-package=main"];
|
|
|
|
|
runcommand(root, strings.concat("command-internal-run-", stages[si]),
|
|
|
|
|
runav, (60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
let externalline: str = linecontaining(ctrace,
|
|
|
|
|
strings.concat(artifacts[2], ".unit.new"));
|
|
|
|
|
assert(has(externalline, strings.concat("<--import><", commandid,
|
|
|
|
|
"><", work, artifacts[0], ".wwi>")));
|
|
|
|
|
let internalmainline: str = linecontaining(ctrace,
|
|
|
|
|
strings.concat(artifacts[3], ".unit.new"));
|
|
|
|
|
let externalmainline: str = linecontaining(ctrace,
|
|
|
|
|
strings.concat(artifacts[4], ".unit.new"));
|
|
|
|
|
assert(has(internalmainline, strings.concat("<--import><", internalid,
|
|
|
|
|
"><", work, artifacts[1], ".wwi>")));
|
|
|
|
|
assert(has(externalmainline, strings.concat("<--import><", externalid,
|
|
|
|
|
"><", work, artifacts[2], ".wwi>")));
|
|
|
|
|
assert(occurrences(ctrace, strings.concat("<", work, artifacts[0],
|
|
|
|
|
".unit.new>")) == 1);
|
|
|
|
|
assert(has(readfile(strings.concat(work, artifacts[0], ".s")),
|
|
|
|
|
strings.concat(commandid, ".value")));
|
|
|
|
|
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, "command_internal ... ok\n"));
|
|
|
|
|
let externalav: []str = [externalbin, "-package=main_test"];
|
|
|
|
|
runcommand(root, strings.concat("command-external-run-", stages[si]),
|
|
|
|
|
externalav, (60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(has(out.stdout, "command_external ... ok\n"));
|
|
|
|
|
assert(has(out.stdout, "main.command_internal ... ok\n"));
|
|
|
|
|
assert(has(out.stdout, "main_test.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 before leaf validation so this Go-like diagnostic is stable,
|
|
|
|
|
@@ -3076,8 +3454,8 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
runcommandenv(root, strings.concat("command-import-", stages[si]),
|
|
|
|
|
importav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 1);
|
|
|
|
|
assert(has(out.stderr,
|
|
|
|
|
"package cmdtool is a program, not an importable package\n"));
|
|
|
|
|
assert(has(out.stderr, strings.concat("package ", commandid,
|
|
|
|
|
" is a program, not an importable package\n")));
|
|
|
|
|
assert(readfile(trace).len == 0);
|
|
|
|
|
|
|
|
|
|
clean(workroot);
|
|
|
|
|
@@ -3426,14 +3804,15 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
|
|
|
|
|
@test fn persistent_package_request_workdir_is_stable() void = {
|
|
|
|
|
let root: str = fresh();
|
|
|
|
|
let tree: str = strings.concat(root, "/tree");
|
|
|
|
|
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");
|
|
|
|
|
assert(os.mkdir(tree, 448i32) == 0);
|
|
|
|
|
mkdirall(tree);
|
|
|
|
|
assert(os.mkdir(adir, 448i32) == 0);
|
|
|
|
|
assert(os.mkdir(bdir, 448i32) == 0);
|
|
|
|
|
assert(os.mkdir(a, 448i32) == 0);
|
|
|
|
|
@@ -3459,8 +3838,9 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
" [foo, same-package]\n")));
|
|
|
|
|
assert(has(cold, strings.concat("ok ", b,
|
|
|
|
|
" [foo, same-package]\n")));
|
|
|
|
|
let ckey: str = strings.concat(workc, "/d_", workescape(tree));
|
|
|
|
|
let ckey: str = strings.concat(workc, "/", requestworkkey(tree));
|
|
|
|
|
assert(os.exists(ckey));
|
|
|
|
|
assert(requestworkkey(tree).len == 66);
|
|
|
|
|
let aaction: str = "a.foo-internal-test";
|
|
|
|
|
let baction: str = "b.foo-internal-test";
|
|
|
|
|
assert(os.exists(strings.concat(ckey, "/", aaction, ".unit.ww")));
|
|
|
|
|
@@ -3483,7 +3863,7 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
(60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(same(cold, out.stdout));
|
|
|
|
|
let wwkey: str = strings.concat(workww, "/d_", workescape(tree));
|
|
|
|
|
let wwkey: str = strings.concat(workww, "/", requestworkkey(tree));
|
|
|
|
|
assert(same(aunit, readfile(strings.concat(wwkey, "/", aaction,
|
|
|
|
|
".unit.ww"))));
|
|
|
|
|
assert(same(bunit, readfile(strings.concat(wwkey, "/", baction,
|
|
|
|
|
@@ -3515,10 +3895,10 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
|
|
|
|
|
// Outside every active import root, equal declaration leaves remain two
|
|
|
|
|
// deterministic command-local identities derived from canonical dirs.
|
|
|
|
|
let localleft: str = strings.concat(root, "/local-left");
|
|
|
|
|
let localright: str = strings.concat(root, "/local-right");
|
|
|
|
|
assert(os.mkdir(localleft, 448i32) == 0);
|
|
|
|
|
assert(os.mkdir(localright, 448i32) == 0);
|
|
|
|
|
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"),
|
|
|
|
|
@@ -3526,6 +3906,10 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
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;
|
|
|
|
|
@@ -3550,7 +3934,14 @@ fn localidentity(dir: str, leaf: str) str = {
|
|
|
|
|
let xi: i32 = 0;
|
|
|
|
|
for (xi < suffixes.len) {
|
|
|
|
|
let artifact: str = readfile(strings.concat(localwork,
|
|
|
|
|
localids[li], suffixes[xi]));
|
|
|
|
|
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)); };
|
|
|
|
|
|