test: prove declared package import semantics
This commit is contained in:
@@ -319,8 +319,8 @@ fn workescape(s: str) str = {
|
||||
return strings.frombytes(out);
|
||||
};
|
||||
|
||||
fn localidentity(dir: str, leaf: str) str = {
|
||||
let out: []u8 = alloc([], (dir.len * 4 + leaf.len + 16): u64)!;
|
||||
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; };
|
||||
@@ -343,9 +343,6 @@ fn localidentity(dir: str, leaf: str) str = {
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
append(out, '.');
|
||||
i = 0;
|
||||
for (i < leaf.len) { append(out, leaf[i]); i += 1; };
|
||||
return strings.frombytes(out);
|
||||
};
|
||||
|
||||
@@ -1241,14 +1238,16 @@ fn hexbytes(value: str) str = {
|
||||
let externalmaincompile: str = linecontaining(ctrace,
|
||||
"pkg_test-external-test-main.unit.ww");
|
||||
assert(same(samemaincompile, strings.concat(
|
||||
"-T --entry --test-support-module test -c --import pkg ",
|
||||
"-T --entry --test-support-module test ",
|
||||
"--test-target-package pkg -c --import pkg ",
|
||||
sharedwork, "pkg-internal-test.wwi --import test ",
|
||||
sharedwork, "test.wwi -I ", sharedwork,
|
||||
"pkg-internal-test-main.wwi -o ", sharedwork,
|
||||
"pkg-internal-test-main.s ", sharedwork,
|
||||
"pkg-internal-test-main.unit.ww")));
|
||||
assert(same(externalmaincompile, strings.concat(
|
||||
"-T --entry --test-support-module test -c --import pkg_test ",
|
||||
"-T --entry --test-support-module test ",
|
||||
"--test-target-package pkg_test -c --import pkg_test ",
|
||||
sharedwork, "pkg_test-external-test.wwi --import test ",
|
||||
sharedwork, "test.wwi -I ", sharedwork,
|
||||
"pkg_test-external-test-main.wwi -o ", sharedwork,
|
||||
@@ -1495,9 +1494,9 @@ fn hexbytes(value: str) str = {
|
||||
aliasunit];
|
||||
runcommand(root, strings.concat("alias-unowned-", aliasstages[i]),
|
||||
rawav, (30i64 * (time.second: i64)): time.duration, &out);
|
||||
assert(out.termination == exec.termination.EXIT && out.code != 0);
|
||||
assert(has(out.stderr, "package")
|
||||
&& has(out.stderr, "does not match import path"));
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
||||
assert(os.exists(asmout));
|
||||
let badav: []str = [driver(aliasstages[i]), "-c",
|
||||
"--test-support-module", "arbitrary", "-o", asmout, aliasunit];
|
||||
runcommand(root, strings.concat("alias-arbitrary-", aliasstages[i]),
|
||||
@@ -4226,9 +4225,13 @@ fn hexbytes(value: str) str = {
|
||||
let leftbody: str = strings.concat(
|
||||
"package parityleft;\n",
|
||||
"import ", baseidentity, ";\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",
|
||||
@@ -4242,7 +4245,8 @@ fn hexbytes(value: str) str = {
|
||||
"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);
|
||||
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);
|
||||
|
||||
@@ -4316,7 +4320,8 @@ fn hexbytes(value: str) str = {
|
||||
"//ww:module-reset ", baseidentity, "\n", basea,
|
||||
"\n//ww:module-reset ", baseidentity, "\n", basez, "\n"),
|
||||
strings.concat("//ww:module-reset ", leftidentity, "\n",
|
||||
leftbody, "\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,
|
||||
@@ -4425,9 +4430,8 @@ fn hexbytes(value: str) str = {
|
||||
assert(has(assembly, strings.concat(identities[ai], ".value")));
|
||||
};
|
||||
if (ai == 3) {
|
||||
assert(has(exportf, strings.concat("\npackage paritycommand",
|
||||
";\n")));
|
||||
assert(!has(exportf, "\npackage main;\n"));
|
||||
assert(has(exportf, "\npackage main;\n"));
|
||||
assert(!has(exportf, "\npackage paritycommand;\n"));
|
||||
};
|
||||
if (si == 0) {
|
||||
referenceexports[ai] = strings.dup(exportf);
|
||||
@@ -4476,18 +4480,23 @@ fn hexbytes(value: str) str = {
|
||||
assert(same(linecontaining(ctrace, strings.concat(artifacts[3],
|
||||
".unit.ww")), rootline));
|
||||
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.
|
||||
// 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", "-I", rejectwwi,
|
||||
"-o", rejectasm, strings.concat(work, artifacts[3], ".unit.ww")];
|
||||
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, 1);
|
||||
assert(has(out.stderr, "does not match import path"));
|
||||
assert(has(out.stderr, rootidentity));
|
||||
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-",
|
||||
@@ -4726,11 +4735,11 @@ fn hexbytes(value: str) str = {
|
||||
"package main_test;\n",
|
||||
"import ", commandid, ";\n",
|
||||
"@test fn command_external() void = { ",
|
||||
"assert(cmdtool.value() == 41); };\n"));
|
||||
"assert(main.value() == 41); };\n"));
|
||||
writefile(strings.concat(importer, "/importer.ww"), strings.concat(
|
||||
"package importer;\n",
|
||||
"import ", commandid, ";\n",
|
||||
"export fn value() i32 = { return cmdtool.value(); };\n"));
|
||||
"export fn value() i32 = { return main.value(); };\n"));
|
||||
writeexecutable(wrapper, strings.concat(
|
||||
"#!/bin/sh\n",
|
||||
"printf 'BEGIN' >> \"$WW_COMMAND_COMPILER_TRACE\"\n",
|
||||
@@ -4830,8 +4839,12 @@ fn hexbytes(value: str) str = {
|
||||
strings.concat(artifacts[4], ".unit.new"));
|
||||
assert(has(internalmainline, strings.concat("<--import><", internalid,
|
||||
"><", work, artifacts[1], ".wwi>")));
|
||||
assert(has(internalmainline, strings.concat(
|
||||
"<--test-target-package><", internalid, ">")));
|
||||
assert(has(externalmainline, strings.concat("<--import><", externalid,
|
||||
"><", work, artifacts[2], ".wwi>")));
|
||||
assert(has(externalmainline, strings.concat(
|
||||
"<--test-target-package><", externalid, ">")));
|
||||
assert(occurrences(ctrace, strings.concat("<", work, artifacts[0],
|
||||
".unit.new>")) == 1);
|
||||
assert(has(readfile(strings.concat(work, artifacts[0], ".s")),
|
||||
@@ -4870,7 +4883,7 @@ fn hexbytes(value: str) str = {
|
||||
};
|
||||
|
||||
// The same command action is not generally source-importable. It is
|
||||
// classified before leaf validation so this Go-like diagnostic is stable,
|
||||
// classified from its declaration so this Go-like diagnostic is stable,
|
||||
// and graph failure occurs before any compiler invocation.
|
||||
clean(trace);
|
||||
writefile(trace, "");
|
||||
@@ -7844,6 +7857,547 @@ fn runtimepath(relative: str) str = {
|
||||
// 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 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, 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 fn value() i32 = { return 42; };\n");
|
||||
let cablebody: str = strings.concat(
|
||||
"package cable;\n",
|
||||
"export fn value() i32 = { return 42; };\n");
|
||||
let codecfile: str = strings.concat(codec, "/codec.ww");
|
||||
writefile(codecfile, wirebody);
|
||||
writefile(strings.concat(bridge, "/bridge.ww"), strings.concat(
|
||||
"package bridge;\nimport acme.codec;\n",
|
||||
// WW retains its direct-import bare-declaration convenience. It is
|
||||
// useful here because changing only the dependency declaration leaves
|
||||
// this source unchanged while still forcing its action to reconsider.
|
||||
"export fn bridged() i32 = { return value(); };\n"));
|
||||
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 scope.one;\n",
|
||||
"fn left() i32 = { return same.value(); };\n"));
|
||||
writefile(strings.concat(scoped, "/b.ww"), strings.concat(
|
||||
"package main;\nimport scope.two;\n",
|
||||
"fn right() i32 = { return same.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 acme.codec;\n",
|
||||
"fn first() i32 = { return wire.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 domain.program;\n",
|
||||
"fn main() i32 = { return main.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 testonly.helper;\n",
|
||||
"@test fn internal_name_uses_declaration() void = {\n",
|
||||
" assert(value() + helper.value() == 43);\n};\n"));
|
||||
writefile(strings.concat(testcodec, "/external_test.ww"), strings.concat(
|
||||
"package wire_test;\nimport testpkg.codec;\n",
|
||||
"@test fn external_name_uses_declaration() void = {\n",
|
||||
" assert(wire.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 short.codec;\n",
|
||||
"fn vendora() i32 = { return cable.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 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 initialwwiref: str = "";
|
||||
let testoutref: str = "";
|
||||
let baseenv: []str = os.getenvs();
|
||||
let si: i32 = 0;
|
||||
for (si < stages.len) {
|
||||
rewritefile(codecfile, wirebody);
|
||||
assert(os.mkdir(works[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 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 acme.codec;") == 2);
|
||||
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)); };
|
||||
let productionunit: str = readfile(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(productionunit, "testonly.helper"));
|
||||
assert(has(internalunit, "import testonly.helper;"));
|
||||
assert(!has(externalunit, "testonly.helper"));
|
||||
assert(has(externalunit, "package wire_test;"));
|
||||
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")));
|
||||
assert(!has(readfile(strings.concat(testwork,
|
||||
"/testpkg.codec-internal-test-main.unit.ww")), "testonly.helper"));
|
||||
assert(!has(readfile(strings.concat(testwork,
|
||||
"/testpkg.codec_test-external-test-main.unit.ww")),
|
||||
"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 short.codec;") == 2);
|
||||
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);
|
||||
|
||||
// Build the bare-import bridge and its command, establish a no-op warm
|
||||
// rebuild, then change only the dependency's declared name. The direct
|
||||
// importer is reconsidered; its unchanged export stops propagation.
|
||||
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);
|
||||
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;"));
|
||||
runcommand(root, strings.concat("name-app-renamed-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 compile_artifact_naming() void = {
|
||||
let root: str = fresh();
|
||||
let pdir: str = strings.concat(root, "/pkg");
|
||||
|
||||
Reference in New Issue
Block a user