package direnum_test; // Directory-package loader observers on both driver stages. Port of // the retired native carrier test/wcc/737_direnum.c; every assertion // preserved, the bad/bad-deep rows strengthened with the stderr // parity leg the C carrier reserved for the reject table. // // okrun — the in-repo tree test/wcc/data/direnum/ (entry imports // multi-file dir ok/ with a.ww+b.ww both package ok, cross-pkg // bare-leaf calls): `ww run` exits 0 on BOTH stages. // // conflict — bad_entry.ww imports a dir with conflicting `package` // clauses; bad_deep_entry.ww the same with one clause behind a // >2048-byte comment header (the loader's whole-source header read). // Both stages must FAIL with "conflicting package names", and the // two stages' diagnostics must be byte-identical. // // rootorder — a private rootok/ command dir built DIRECTLY (z.ww ORDER-Z // value()=17 vs a.ww ORDER-A leading comment + main): build exit 0, // the binary exits 17, and the driver's local-identity owner unit // stores ORDER-A strictly before ORDER-Z (byte-sorted deterministic // source order); the two stages' units are byte-identical. // // rejects — the authoritative loader-reject table over private trees: // 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 // accounting (testenv.clean asserts the removal). import os; import os.exec; import strings; import testenv; import time; fn fail(label: str, why: str) void = { let m: str = strings.concat("direnum FAIL: ", label, " -- ", why, "\n"); os.write(2, m.ptr, m.len: u64); assert(false); }; fn tmo() time.duration = { return (240i64 * (time.second: i64)): time.duration; }; // -1 encodes an abnormal (non-EXIT) termination, never a valid code. fn runcode(dir: str, name: str, argv: []str) i32 = { let co: testenv.commandout; testenv.runcommand(dir, dir, name, argv, tmo(), &co); if (co.termination != exec.termination.EXIT) { return -1; }; return co.code; }; fn datasrc(name: str) str = { return strings.concat(testenv.repo(), "/test/wcc/data/direnum/", name); }; @test fn okrun() void = { let td: str = testenv.fresh(); let src: str = datasrc("entry.ww"); let drvs: []str = ["ww", "ww_ww"]; let s: i32 = 0; for (s < 2) { let av: []str = [testenv.driver(drvs[s]), "run", src]; if (runcode(td, strings.concat("run_", drvs[s]), av) != 0) { fail("okrun", strings.concat(drvs[s], " run failed on the ", "multi-file imported dir (cross-pkg bare-leaf calls)")); }; s += 1; }; testenv.clean(td); }; // A build expected to FAIL with `needle` on both stages, diagnostics // byte-identical across stages. fn rejectpair(label: str, td: str, target: str, needle: str) void = { let drvs: []str = ["ww", "ww_ww"]; let errs: []str = ["", ""]; let s: i32 = 0; for (s < 2) { let out: str = strings.concat(td, "/", label, "-", drvs[s]); let co: testenv.commandout; let av: []str = [testenv.driver(drvs[s]), "build", "-o", out, target]; testenv.runcommand(td, td, strings.concat(label, "_", drvs[s]), av, tmo(), &co); if (co.termination != exec.termination.EXIT || co.code == 0) { fail(label, strings.concat(drvs[s], " expected build failure, succeeded")); }; if (!testenv.has(co.stderr, needle)) { fail(label, strings.concat(drvs[s], " stderr missing '", needle, "'")); }; errs[s] = co.stderr; s += 1; }; if (!testenv.same(errs[0], errs[1])) { fail(label, "C/WW diagnostics differ"); }; }; @test fn conflict() void = { let td: str = testenv.fresh(); rejectpair("bad", td, datasrc("bad_entry.ww"), "conflicting package names"); rejectpair("bad-deep", td, datasrc("bad_deep_entry.ww"), "conflicting package names"); testenv.clean(td); }; @test fn rootorder() void = { let td: str = testenv.fresh(); let rootok: str = strings.concat(td, "/rootok"); assert(os.mkdir(rootok, 493) == 0); testenv.writefile(strings.concat(rootok, "/z.ww"), strings.concat( "package main;\n// ORDER-Z\n", "fn value() i32 = { return 17; };\n")); testenv.writefile(strings.concat(rootok, "/a.ww"), strings.concat( "// leading comment is part of the loader grammar\n", "package main;\n// ORDER-A\n", "fn main() i32 = { return value(); };\n")); let drvs: []str = ["ww", "ww_ww"]; let identity: str = testenv.localpackageidentity(rootok, "main"); let units: []str = ["", ""]; let s: i32 = 0; for (s < 2) { let out: str = strings.concat(td, "/root-", drvs[s]); let av: []str = [testenv.driver(drvs[s]), "build", "-o", out, rootok]; if (runcode(td, strings.concat("build_", drvs[s]), av) != 0) { fail("rootorder", strings.concat(drvs[s], " direct dir build failed")); }; let rav: []str = [out]; if (runcode(td, strings.concat("run_", drvs[s]), rav) != 17) { fail("rootorder", strings.concat(drvs[s], " exit != 17")); }; units[s] = testenv.readfile(strings.concat(out, ".sepwork/", identity, ".unit.ww")); let a: i32 = testenv.pos(units[s], "ORDER-A"); let z: i32 = testenv.pos(units[s], "ORDER-Z"); if (a < 0 || z < 0 || a >= z) { fail("rootorder", strings.concat(drvs[s], " stored sources are not byte-sorted")); }; s += 1; }; if (!testenv.same(units[0], units[1])) { fail("rootorder", "C/WW local root units differ"); }; testenv.clean(td); }; @test fn rejects() void = { let td: str = testenv.fresh(); let rootbad: str = strings.concat(td, "/rootbad"); let importbad: str = strings.concat(td, "/importbad"); let wanted: str = strings.concat(importbad, "/wanted"); let missing: str = strings.concat(td, "/missing"); let invalid: str = strings.concat(td, "/invalid"); let attbad: str = strings.concat(td, "/attbad"); assert(os.mkdir(rootbad, 493) == 0); assert(os.mkdir(importbad, 493) == 0); assert(os.mkdir(wanted, 493) == 0); assert(os.mkdir(missing, 493) == 0); assert(os.mkdir(invalid, 493) == 0); assert(os.mkdir(attbad, 493) == 0); testenv.writefile(strings.concat(rootbad, "/a.ww"), "package rootbad;\nfn main() i32 = { return 0; };\n"); testenv.writefile(strings.concat(rootbad, "/b.ww"), "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 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"), "fn main() i32 = { return 0; };\n"); testenv.writefile(strings.concat(invalid, "/a.ww"), "package 7bad;\nfn main() i32 = { return 0; };\n"); testenv.writefile(strings.concat(attbad, "/a.ww"), "package attbad;\nfn main() i32 = { return 0; };\n"); testenv.writefile(strings.concat(attbad, "/t.ww"), strings.concat( "package attbad;\n", "@test fn hidden() void = { assert(false); };\n")); 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, missing, invalid, attbad]; let needles: []str = ["conflicting package names", "invalid or missing package clause", "invalid or missing package clause", "@test declaration outside *_test.ww"]; let r: i32 = 0; for (r < tags.len) { rejectpair(tags[r], td, targets[r], needles[r]); r += 1; }; testenv.clean(td); };