test: prove declared package import semantics

This commit is contained in:
2026-08-14 03:08:16 +09:00
parent 6efe9b70d4
commit a841278333
11 changed files with 1001 additions and 131 deletions

View File

@@ -21,15 +21,16 @@ package wwi_test;
// qualification of the compiler-private name on both stages.
//
// wwileaf — BUG-C (#11) regression pin: a decl-less / export-less
// primary module's `.wwi` `package` line must carry the module's real
// leaf, NOT the literal default "main". Table-driven over the three
// primary module's `.wwi` must preserve its independently parsed declaration,
// rather than substituting the literal default "main". Table-driven over the three
// 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
// 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
// and both importers diagnose the same file-local unused binding after
// obtaining that declared name from export data. The owner units and
// separate exports are fed straight to w6c / w6c_ww (not `ww build`):
// the producer-unit shape `//ww:module-reset <path>` + body is exactly
// what the driver's sep_emit_body emits.
@@ -331,8 +332,8 @@ fn leafrow(tag: str, path: str, leaf: str, body: str, want: str) void = {
"package ", leaf, ";\n",
body));
// Leg a — both stages emit the dep `.wwi`; the `package` leaf is
// the module's real leaf, not the default "main".
// Leg a — both stages emit the dep `.wwi`; the `package` declaration is
// the source declaration supplied independently of its canonical owner.
let cav: []str = [testenv.driver("w6c"), "-c", "-I", cswwi,
"-o", css, prod];
if (!runok(td, "csprod", cav)) { fail(tag, "w6c producer errored"); };
@@ -342,7 +343,7 @@ fn leafrow(tag: str, path: str, leaf: str, body: str, want: str) void = {
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)");
fail(tag, ".wwi owner or declared package name is incomplete (BUG-C)");
};
// Leg b — the dep `.wwi` is byte-identical across stages (rule 10).
@@ -350,9 +351,11 @@ fn leafrow(tag: str, path: str, leaf: str, body: str, want: str) void = {
fail(tag, "w6c vs w6c_ww .wwi differ (rule 10)");
};
// Leg c — a root importing the dep RESOLVES from a separate export on
// both stages (pre-fix: "package main does not match import path"
// REJECT).
// Leg c — a root importing the empty dep obtains its default qualifier from
// the separate export on both stages. With no exported declaration to use,
// Go-style file scope requires the import itself to be rejected as unused;
// the diagnostic proves that the reader recovered the declared name rather
// than substituting the historical default `main` declaration.
testenv.writefile(root, strings.concat(
"//ww:module-reset\n",
"package main;\n",
@@ -360,22 +363,59 @@ fn leafrow(tag: str, path: str, leaf: str, body: str, want: str) void = {
"export fn main() i32 = { return 42; };\n"));
let rcav: []str = [testenv.driver("w6c"), "-c", "--import", path,
cswwi, "-o", rcss, root];
if (!runok(td, "csroot", rcav)) {
fail(tag, "w6c rejected the import (BUG-C)");
};
let rwav: []str = [testenv.driver("w6c_ww"), "-c", "--import", path,
wwwwi, "-o", rwws, root];
if (!runok(td, "wsroot", rwav)) {
fail(tag, "w6c_ww rejected the import (BUG-C)");
let rco: testenv.commandout;
let rwo: testenv.commandout;
testenv.runcommand(td, td, "csroot", rcav, lifetime(), &rco);
testenv.runcommand(td, td, "wsroot", rwav, lifetime(), &rwo);
let (prefix, suffix) = strings.rcut(path, ".");
let leaf: str = suffix;
if (leaf.len == 0) { leaf = path; };
let unused: str;
if (testenv.same(want, leaf)) {
unused = strings.concat(strings.concat("\"", path),
"\" imported and not used");
} else {
unused = strings.concat(strings.concat(strings.concat(
"\"", path), "\" imported as "), strings.concat(want,
" and not used"));
};
if (!testenv.same(testenv.readfile(rcss), testenv.readfile(rwws))) {
fail(tag, "importer .s differ cs vs ww (rule 10)");
if (rco.termination != exec.termination.EXIT || rco.code == 0
|| rwo.termination != exec.termination.EXIT || rwo.code == 0
|| !testenv.same(rco.stderr, rwo.stderr)
|| !testenv.has(rco.stderr, unused)) {
fail(tag, "imported-name or unused-import behavior differs by stage");
};
testenv.clean(td);
};
fn resetfallbackrow() void = {
let td: str = testenv.fresh();
let src: str = strings.concat(td, "/reset.ww");
testenv.writefile(src, strings.concat(
"//ww:module-reset raw.owner\n",
"export fn value() i32 = { return 7; };\n"));
let cs: str = strings.concat(td, "/c.wwi");
let ws: str = strings.concat(td, "/w.wwi");
let cav: []str = [testenv.driver("w6c"), "-c", "-I", cs,
"-o", strings.concat(td, "/c.s"), src];
let wav: []str = [testenv.driver("w6c_ww"), "-c", "-I", ws,
"-o", strings.concat(td, "/w.s"), src];
if (!runok(td, "reset-c", cav) || !runok(td, "reset-w", wav)) {
fail("nested", "a package-less reset owner failed to export");
};
let body: str = testenv.readfile(cs);
if (!testenv.same(body, testenv.readfile(ws))
|| !testenv.has(body, "//ww:module raw.owner\npackage main;\n")
|| !testenv.has(body, "export fn value() i32;")) {
fail("nested", "reset-owner fallback lost its source section");
};
testenv.clean(td);
};
// Each shape lacks any module-tagged decl, so wwi_emit's decl-scan
// misses and the leaf must come from the parse-stamped N_FILE identity.
// misses and the declaration must come from the parse-stamped N_FILE fact.
@test fn wwileaf_empty() void = {
leafrow("empty", "emptymod", "emptymod", "", "emptymod");
};
@@ -386,4 +426,5 @@ fn leafrow(tag: str, path: str, leaf: str, body: str, want: str) void = {
@test fn wwileaf_nested() void = {
leafrow("nested", "a.b.c", "c", "", "c");
resetfallbackrow();
};

View File

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

View File

@@ -368,7 +368,7 @@ fn writediamond(td: str, reverse: bool) str = {
testenv.writefile(strings.concat(shared, "/a.ww"), asrc);
};
testenv.writefile(strings.concat(left, "/left.ww"), strings.concat(
"package left;\nimport shared;\nimport shared;\n",
"package left;\nimport shared;\n",
"export fn make() shared.token = { return shared.token{value=shared.base() + 1}; };\n"));
testenv.writefile(strings.concat(right, "/right.ww"), strings.concat(
"package right;\nimport shared;\n",
@@ -424,7 +424,7 @@ fn writediamond(td: str, reverse: bool) str = {
let rightiface: str = testenv.readfile(strings.concat(scratch,
"right.wwi"));
if (testenv.occurrences(leftiface, "import shared;") != 1) {
fail("diamond", "duplicate import escaped into export data");
fail("diamond", "direct import is missing or duplicated in export data");
};
if (testenv.occurrences(leftiface, "export type token") != 1
|| testenv.occurrences(rightiface, "export type token") != 1
@@ -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 13 mode build asm 0\n")) {
"ww workdir fmt 14 mode build asm 0\n")) {
fail("driver-identity", "persistent artifacts or identities are incomplete");
};
let coldwwi: str = testenv.readfile(strings.concat(work, "/dep.wwi"));
@@ -1293,7 +1293,7 @@ fn writediamond(td: str, reverse: bool) str = {
"// ROOT_A\n",
"export fn value() i32 = { return dep.value() + 2; };\n"));
testenv.writefile(strings.concat(bar, "/z.ww"), strings.concat(
"package bar;\nimport foo.dep;\n",
"package bar;\n",
"// ROOT_Z\n",
"export fn other() i32 = { return 9; };\n"));
testenv.writefile(strings.concat(commanddir, "/main.ww"), strings.concat(
@@ -1819,16 +1819,21 @@ fn writediamond(td: str, reverse: bool) str = {
@test fn generated_test_hook_is_not_a_user_exemption() void = {
let td: str = testenv.fresh();
let src: str = strings.concat(td, "/case.ww");
let iface: str = strings.concat(td, "/test.wwi");
testenv.writefile(src, strings.concat(
"package probe;\nimport test;\n",
"fn bad() void = { test.run(); };\n",
"@test fn one() void = {};\n"));
testenv.writefile(iface, strings.concat(
"//ww:module test\n",
"package test;\n",
"export fn placeholder() void;\n"));
let compilers: []str = ["w6c", "w6c_ww"];
let i: i32 = 0;
for (i < compilers.len) {
let asm: str = strings.concat(td, "/case-", compilers[i], ".s");
let av: []str = [testenv.driver(compilers[i]), "-T", "-c", "-o",
asm, src];
let av: []str = [testenv.driver(compilers[i]), "-T", "-c",
"--import", "test", iface, "-o", asm, src];
let co: testenv.commandout;
command(td, strings.concat("test_hook_", compilers[i]), av, &co);
if (co.termination != exec.termination.EXIT || co.code == 0

View File

@@ -220,8 +220,8 @@ export fn occurrences(haystack: str, needle: str) i32 = {
// Expected semantic identity for a canonical absolute directory that is not
// representable below an active source root. Keep this independent observer
// byte-for-byte aligned with the documented driver protocol.
export fn localpackageidentity(dir: str, leaf: str) str = {
let out: []u8 = alloc([], (dir.len * 4 + leaf.len + 16): u64)!;
export fn localpackageidentity(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; };
@@ -244,9 +244,6 @@ export fn localpackageidentity(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);
};

View File

@@ -1,4 +1,4 @@
//ww:error "does not match import path"
//ww:compile
//ww:module foo
package bar;
export fn x() i32 = { return 0; };

View File

@@ -22,11 +22,12 @@ package direnum_test;
// source order); the two stages' units are byte-identical.
//
// rejects — the authoritative loader-reject table over private trees:
// root-conflict ("conflicting package names"), import-leaf ("does
// not match import path"), root-missing and root-invalid ("invalid
// or missing package clause"), attest-noncanon ("@test declaration
// outside *_test.ww" — Go's test-file contract); per row both stages
// fail, carry the needle, and their captured stderr is byte-identical.
// root-conflict ("conflicting package names"), root-missing and
// root-invalid ("invalid or missing package clause"), attest-noncanon
// ("@test declaration outside *_test.ww" — Go's test-file contract);
// per row both stages fail, carry the needle, and their captured stderr is
// byte-identical. The former import-leaf rejection is now an accepted
// path/name-decoupling case and uses the imported declaration as qualifier.
//
// Dropped C machinery, not assertions: the ww_ww-absent skip gate
// (the Make target declares both drivers) and the unlink/rmdir
@@ -179,7 +180,7 @@ fn rejectpair(label: str, td: str, target: str, needle: str) void = {
"package other;\nfn spare() i32 = { return 0; };\n");
testenv.writefile(strings.concat(importbad, "/entry.ww"),
strings.concat("package main;\nimport wanted;\n",
"fn main() i32 = { return wanted.value(); };\n"));
"fn main() i32 = { return other.value(); };\n"));
testenv.writefile(strings.concat(wanted, "/a.ww"),
"package other;\nexport fn value() i32 = { return 0; };\n");
testenv.writefile(strings.concat(missing, "/a.ww"),
@@ -192,12 +193,28 @@ fn rejectpair(label: str, td: str, target: str, needle: str) void = {
"package attbad;\n",
"@test fn hidden() void = { assert(false); };\n"));
let tags: []str = ["root-conflict", "import-leaf", "root-missing",
let drvs: []str = ["ww", "ww_ww"];
let s: i32 = 0;
for (s < drvs.len) {
let out: str = strings.concat(td, "/import-name-", drvs[s]);
let av: []str = [testenv.driver(drvs[s]), "build", "-o", out,
strings.concat(importbad, "/entry.ww")];
if (runcode(td, strings.concat("import-name-build-", drvs[s]), av)
!= 0) {
fail("import-name", strings.concat(drvs[s], " build failed"));
};
let rav: []str = [out];
if (runcode(td, strings.concat("import-name-run-", drvs[s]), rav)
!= 0) {
fail("import-name", strings.concat(drvs[s], " run failed"));
};
s += 1;
};
let tags: []str = ["root-conflict", "root-missing",
"root-invalid", "attest-noncanon"];
let targets: []str = [rootbad, strings.concat(importbad,
"/entry.ww"), missing, invalid, attbad];
let targets: []str = [rootbad, missing, invalid, attbad];
let needles: []str = ["conflicting package names",
"does not match import path",
"invalid or missing package clause",
"invalid or missing package clause",
"@test declaration outside *_test.ww"];

View File

@@ -203,7 +203,7 @@ fn userow(label: str, apick: str, onecall: str) void = {
let rav: []str = [strings.concat(td, "/main")];
if (runcode(td, strings.concat("run_", drvs[s]), rav) != 0) {
fail(label, strings.concat(drvs[s], " run-exit != 0 (a ",
"file-global first-match hint routes one math.pick() to ",
"cross-file first-match hint routes one math.pick() to ",
"the wrong package -- #40)"));
};
testenv.clean(td);