test: prove long package identity semantics

This commit is contained in:
2026-08-13 05:38:05 +09:00
parent c3df0afeb0
commit 5705c0e3fa
4 changed files with 692 additions and 130 deletions

View File

@@ -26,7 +26,8 @@ package wwi_test;
// decl-less shapes routing the wwi_emit fallback (empty, comment-only,
// nested dotted path a.b.c -> leaf c). Each row drives the REAL
// producer->importer flow on BOTH stages: (a) the dep `.wwi` package
// line equals the real leaf, (b) the dep `.wwi` is byte-identical
// owner marker is the complete path and its package line equals the real leaf,
// (b) the dep `.wwi` is byte-identical
// across stages, (c) a root importing the dep RESOLVES on both stages
// and the two importer `.s` are byte-identical. The owner units and
// separate exports are fed straight to w6c / w6c_ww (not `ww build`):
@@ -55,13 +56,6 @@ fn runok(dir: str, name: str, argv: []str) bool = {
return co.termination == exec.termination.EXIT && co.code == 0;
};
fn firstline(path: str) str = {
let body: str = testenv.readfile(path);
let nl: i32 = testenv.pos(body, "\n");
if (nl < 0) { return body; };
return strings.sub(body, 0, nl);
};
// one positive package: build the target as primary, produce the `.wwi`
// on both stages, require byte-id + re-parse.
fn m2positive(pkg: str) void = {
@@ -345,9 +339,10 @@ fn leafrow(tag: str, path: str, leaf: str, body: str, want: str) void = {
let wav: []str = [testenv.driver("w6c_ww"), "-c", "-I", wwwwi,
"-o", wws, prod];
if (!runok(td, "wsprod", wav)) { fail(tag, "w6c_ww producer errored"); };
let wantline: str = strings.concat("package ", want, ";");
if (!testenv.same(firstline(cswwi), wantline)) {
fail(tag, ".wwi package line is not the real leaf (BUG-C)");
let wanthead: str = strings.concat(strings.concat(strings.concat(
"//ww:module ", path), "\npackage "), strings.concat(want, ";\n"));
if (!strings.hasprefix(testenv.readfile(cswwi), wanthead)) {
fail(tag, ".wwi owner or package leaf is incomplete (BUG-C)");
};
// Leg b — the dep `.wwi` is byte-identical across stages (rule 10).

View File

@@ -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)); };

View File

@@ -907,7 +907,7 @@ fn writediamond(td: str, reverse: bool) str = {
"/.wwtool.w6a")), testenv.readfile(assembler))
|| !testenv.same(testenv.readfile(strings.concat(work,
"/.wwtool.stamp")),
"ww workdir fmt 8 mode build asm 0\n")) {
"ww workdir fmt 10 mode build asm 0\n")) {
fail("driver-identity", "persistent artifacts or identities are incomplete");
};
let coldwwi: str = testenv.readfile(strings.concat(work, "/dep.wwi"));