test: prove canonical directory test products

This commit is contained in:
2026-08-15 02:50:00 +09:00
parent 8dad2755b3
commit 7d73d31b38
6 changed files with 2935 additions and 1806 deletions

View File

@@ -736,7 +736,11 @@ fn rejectrow(td: str, label: str, src: str, expected: str) void = {
let td: str = testenv.fresh();
let tree: str = strings.concat(td, "/tree");
assert(os.mkdir(tree, 493) == 0);
let body: str = "package main;\n";
let target: str = strings.concat(tree, "/target");
let bridge: str = strings.concat(tree, "/bridge");
assert(os.mkdir(target, 493) == 0);
assert(os.mkdir(bridge, 493) == 0);
let body: str = "package target;\n";
let i: i32 = 0;
for (i < 600) {
let name: str = allocpkgname(i);
@@ -747,63 +751,98 @@ fn rejectrow(td: str, label: str, src: str, expected: str) void = {
body = strings.concat(body, "import _ ", name, ";\n");
i += 1;
};
body = strings.concat(body, "fn main() i32 = { return 0; };\n");
let src: str = strings.concat(td, "/main.ww");
testenv.writefile(src, body);
let wrapper: str = strings.concat(td, "/w6c-trace.sh");
body = strings.concat(body,
"export fn value() i32 = { return 41; };\n");
testenv.writefile(strings.concat(target, "/target.ww"), body);
testenv.writefile(strings.concat(target, "/same_test.ww"), strings.concat(
"package target;\n",
"export fn internal_helper() i32 = { return value(); };\n",
"@test fn internal_runs() void = { assert(value() == 41); };\n"));
testenv.writefile(strings.concat(bridge, "/bridge.ww"), strings.concat(
"package bridge;\nimport target;\n",
"export fn helper() i32 = { return target.internal_helper(); };\n"));
testenv.writefile(strings.concat(target, "/external_test.ww"),
strings.concat("package target_test;\nimport bridge;\nimport target;\n",
"@test fn external_runs() void = {\n",
" assert(target.internal_helper() == 41);\n",
" assert(bridge.helper() == 41);\n};\n"));
let wrapper: str = strings.concat(td, "/tool-trace.sh");
testenv.writeexecutable(wrapper, strings.concat("#!/bin/sh\n",
"printf x >> \"$WW_SEPINIT_W6C_TRACE\"\nexit 99\n"));
"printf x >> \"$WW_SEPINIT_TOOL_TRACE\"\nexit 99\n"));
let stages: []str = ["ww", "ww_ww"];
let compilers: []str = ["w6c", "w6c_ww"];
let launcher: str = testenv.driver("sep-limitexec");
let found: bool = false;
let last: str = "";
let limit: i64 = 2621440i64;
let li: i32 = 0;
// Both implementations must reject under the same address-space ceiling.
// Search a bounded same-limit ladder because loader mappings differ across
// supported hosts; the 600-action graph makes the driver-allocation window
// broad, while the compiler trace pins failure before the first tool.
for (limit <= 16777216i64 && !found) {
let limitstr: str = strconv.i64tos(limit, strconv.base.DEC);
let good: [2]bool;
let diags: [2]str;
i = 0;
for (i < stages.len) {
let accepted: [2]str;
let stagei: i32 = 0;
// Address-space layouts differ, so each implementation searches its own
// bounded ceiling. The accepted point must fail while constructing the
// combined p/ptest/pxtest/pmain and transitive-clone graph, before any tool.
for (stagei < stages.len) {
let found: bool = false;
let last: str = "";
let limit: i64 = 2621440i64;
let li: i32 = 0;
for (limit <= 33554432i64 && !found) {
let tag: str = allocpkgname(li);
let trace: str = strings.concat(td, "/alloc-", stages[i], "-",
let trace: str = strings.concat(td, "/alloc-", stages[stagei], "-",
tag, ".trace");
let work: str = strings.concat(td, "/alloc-work-", stages[stagei],
"-", tag);
let output: str = strings.concat(td, "/alloc-output-",
stages[stagei], "-", tag);
let status: str = strings.concat(td, "/alloc-status-",
stages[stagei], "-", tag);
testenv.writefile(trace, "");
let env: []str = compilertraceenv(wrapper,
testenv.driver(compilers[i]), trace);
let output: str = strings.concat(td, "/alloc-", stages[i], "-",
tag);
let av: []str = [launcher, limitstr, testenv.driver(stages[i]),
"build", "-I", tree, "-o", output, src];
assert(os.mkdir(work, 493) == 0);
let base: []str = os.getenvs();
let env: []str = alloc([], (base.len + 4): u64)!;
i = 0;
for (i < base.len) {
if (!strings.hasprefix(base[i], "WW_W6C=")
&& !strings.hasprefix(base[i], "WW_W6A=")
&& !strings.hasprefix(base[i], "WW_W6L=")
&& !strings.hasprefix(base[i],
"WW_SEPINIT_TOOL_TRACE=")) {
append(env, base[i]);
};
i += 1;
};
append(env, strings.concat("WW_W6C=", wrapper));
append(env, strings.concat("WW_W6A=", wrapper));
append(env, strings.concat("WW_W6L=", wrapper));
append(env, strings.concat("WW_SEPINIT_TOOL_TRACE=", trace));
let limitstr: str = strconv.i64tos(limit, strconv.base.DEC);
let av: []str = [launcher, limitstr, testenv.driver(stages[stagei]),
"test", "-c", "-w", work, "-I", tree,
"--ww-package-test", "test", "target", "target", "target",
"target_test", target, output, status, target];
let out: testenv.commandout;
runenv(td, strings.concat("allocation-", stages[i], "-", tag),
runenv(td, strings.concat("allocation-", stages[stagei], "-", tag),
av, env, &out);
last = strings.dup(out.stderr);
good[i] = exitcode(&out) == 1 && testenv.same(out.stderr,
"ww: out of memory\n")
&& testenv.readfile(trace).len == 0;
diags[i] = strings.dup(out.stderr);
if (testenv.exists(output) || testenv.exists(strings.concat(output,
".sepwork"))) {
if (testenv.listdir(work).len != 0
|| nofollowexists(output)
|| nofollowexists(strings.concat(output, ".new"))
|| nofollowexists(strings.concat(output, ".sepwork"))
|| nofollowexists(status)
|| nofollowexists(strings.concat(status, ".new"))) {
fail("allocation", "failed pressure leg published state");
};
i += 1;
};
if (good[0] && good[1]) {
if (!testenv.same(diags[0], diags[1])) {
fail("allocation", "C/WW allocation diagnostic mismatch");
if (exitcode(&out) == 1 && out.stdout.len == 0
&& testenv.same(out.stderr, "ww: out of memory\n")
&& testenv.readfile(trace).len == 0) {
accepted[stagei] = strings.dup(out.stderr);
found = true;
};
found = true;
testenv.clean(work);
limit += 131072i64;
li += 1;
};
limit += 131072i64;
li += 1;
if (!found) { fail("allocation", last); };
stagei += 1;
};
if (!testenv.same(accepted[0], accepted[1])) {
fail("allocation", "C/WW allocation diagnostic mismatch");
};
if (!found) { fail("allocation", last); };
testenv.clean(td);
};
@@ -932,16 +971,12 @@ fn rejectrow(td: str, label: str, src: str, expected: str) void = {
let tags: []str = ["c", "ww"];
let reference: str = "";
let variantnames: []str = [
"widget-internal-test-main.init.unit.ww",
"widget-internal-test-main.init.s",
"widget-internal-test-main.init.o",
"widget-internal-test-main.a",
"widget_test-external-test-main.init.unit.ww",
"widget_test-external-test-main.init.s",
"widget_test-external-test-main.init.o",
"widget_test-external-test-main.a",
"widget-test-main.init.unit.ww",
"widget-test-main.init.s",
"widget-test-main.init.o",
"widget-test-main.a",
];
let variantrefs: []str = ["", "", "", "", "", "", "", ""];
let variantrefs: []str = ["", "", "", ""];
let i: i32 = 0;
for (i < 2) {
let work: str = strings.concat(td, "/test-work-", tags[i]);
@@ -967,61 +1002,45 @@ fn rejectrow(td: str, label: str, src: str, expected: str) void = {
let rr: i32 = testenv.pos(out.stdout, "<R>");
let ii: i32 = testenv.pos(out.stdout, "<I>");
let tt: i32 = testenv.pos(out.stdout, "<T>");
let tail: str = "";
if (tt >= 0) { tail = strings.sub(out.stdout, tt + 3, out.stdout.len); };
let de: i32 = testenv.pos(tail, "<D>");
let pe: i32 = testenv.pos(tail, "<P>");
let w: i32 = testenv.pos(tail, "<W>");
let e: i32 = testenv.pos(tail, "<E>");
let x: i32 = testenv.pos(tail, "<X>");
if (!(d >= 0 && d < q && q < rr && rr < p && p < ii && ii < tt
&& de >= 0 && de < pe && pe < w && w < e && e < x)) {
let w: i32 = testenv.pos(out.stdout, "<W>");
let e: i32 = testenv.pos(out.stdout, "<E>");
let x: i32 = testenv.pos(out.stdout, "<X>");
if (!(d >= 0 && d < q && q < rr && rr < p && p < ii && ii < w
&& w < e && e < tt && tt < x)) {
fail("variants", strings.concat("test init order: ", out.stdout));
};
if (testenv.occurrences(out.stdout, "<Q>") != 1
|| testenv.occurrences(out.stdout, "<D>") != 2
|| testenv.occurrences(out.stdout, "<D>") != 1
|| testenv.occurrences(out.stdout, "<R>") != 1
|| testenv.occurrences(out.stdout, "<W>") != 1
|| testenv.occurrences(out.stdout, "<I>") != 1
|| testenv.occurrences(out.stdout, "<E>") != 1
|| testenv.occurrences(out.stdout, "<P>") != 2) {
|| testenv.occurrences(out.stdout, "<P>") != 1) {
fail("variants", "variant initialization count");
};
let internal: str = testenv.readfile(strings.concat(work,
"/widget-internal-test-main.init.unit.ww"));
if (testenv.occurrences(internal,
let dispatcher: str = testenv.readfile(strings.concat(work,
"/widget-test-main.init.unit.ww"));
if (testenv.occurrences(dispatcher,
"__ww..pkg.p.testside.v0.r0.init") != 1
|| testenv.occurrences(internal,
|| testenv.occurrences(dispatcher,
"__ww..pkg.p.prodside.v0.r0.init") != 1
|| testenv.occurrences(internal,
|| testenv.occurrences(dispatcher,
"__ww..pkg.p.widget.v1.r0.init") != 1
|| testenv.occurrences(internal,
"__ww..pkg.p.test.v0.r0.init") != 1
|| testenv.occurrences(internal,
"//ww:init-call __ww..pkg.p.__wwtestmain.widget.internal.main.v3.r2.init") != 1
|| testenv.pos(internal, "__ww..pkg.p.test.v0.r0.init")
>= testenv.pos(internal,
"//ww:init-call __ww..pkg.p.__wwtestmain.widget.internal.main.v3.r2.init")
|| testenv.has(internal, "__ww..pkg.p.widget.v0.r0.init")) {
fail("variants", "internal variant dispatcher ownership");
};
let external: str = testenv.readfile(strings.concat(work,
"/widget_test-external-test-main.init.unit.ww"));
if (testenv.occurrences(external,
"__ww..pkg.p.widget.v0.r0.init") != 1
|| testenv.occurrences(external,
"__ww..pkg.p.prodside.v0.r0.init") != 1
|| testenv.occurrences(external,
|| testenv.occurrences(dispatcher,
"__ww..pkg.p.widget_test.v2.r0.init") != 1
|| testenv.occurrences(external,
|| testenv.occurrences(dispatcher,
"__ww..pkg.p.test.v0.r0.init") != 1
|| testenv.occurrences(external,
"//ww:init-call __ww..pkg.p.__wwtestmain.widget_test.external.main.v3.r2.init") != 1
|| testenv.pos(external, "__ww..pkg.p.test.v0.r0.init")
>= testenv.pos(external,
"//ww:init-call __ww..pkg.p.__wwtestmain.widget_test.external.main.v3.r2.init")
|| testenv.has(external, "testside")) {
fail("variants", "external variant dispatcher ownership");
|| testenv.occurrences(dispatcher,
"//ww:init-call __ww..pkg.p.__wwtestmain.widget.main.v3.r2.init") != 1
|| testenv.pos(dispatcher, "__ww..pkg.p.widget.v1.r0.init")
>= testenv.pos(dispatcher,
"__ww..pkg.p.widget_test.v2.r0.init")
|| testenv.pos(dispatcher,
"__ww..pkg.p.widget_test.v2.r0.init")
>= testenv.pos(dispatcher,
"//ww:init-call __ww..pkg.p.__wwtestmain.widget.main.v3.r2.init")
|| testenv.has(dispatcher, "__ww..pkg.p.widget.v0.r0.init")) {
fail("variants", "directory test dispatcher ownership");
};
let directstdout: str = strings.dup(out.stdout);
let recursivework: str = strings.concat(td, "/test-recursive-work-",
@@ -1100,7 +1119,7 @@ fn rejectrow(td: str, label: str, src: str, expected: str) void = {
av, env, tmo(), &out);
if (exitcode(&out) == 0
|| !testenv.has(out.stderr,
"ww: dependency cycle in initialization closure")
"ww: dependency cycle: p -> q -> r -> p")
|| testenv.readfile(trace).len != 0
|| testenv.listdir(work).len != 0) {
fail("test-cycle", out.stderr);