package sepimport_test; // Import/namespace-resolution observers on the sep drivers, both // stages. Ports of the retired native carriers // test/wcc/989_coloimport_sep.c, 989_depmain_sep.c, 989_declns_sep.c // and 989_slttypepref_run.c; every assertion preserved. // // coloimport (#98) — a co-located `_test` entry must not shadow the // dir-package it imports under `ww test`: the two-pass locate_import // walk resolves `import widget` to the DIR-package on a later -I // entry, not the same-named sibling FILE on the srcd entry. Exit 0 // both stages (pre-fix w6c rejects `package widget does not match // import path gadget`), widget.{unit.ww,wwi} registered in .sepwork, // and every .s/.wwi byte-id cs vs ww (rule 10). // // depmain (#99) — an IMPORTED dir-package's non-exported `fn main` // mangles on its import path (aa.bb.main / cc.main) instead of // emitting a bare `TEXT main` that collides with the root entry; // EXACTLY one column-0 `TEXT main,` across the whole sep build. // // declns (#23/#30 modfn leg) — a value-namespace `fn aa` coexists // with an imported MODULE aa (exit 6 = aa() + aa.helper()); the _vbu // layout flips decl order and must stay byte-identical on // {aa.s,aa.wwi,__root.s} (silent order-dependence in the SK_USE/value // promote is the regression); __root.s carries BOTH // `CALL aa.helper(SB)` and `CALL main.aa(SB)`. // // slttypepref (#58/#50 c1) — scopelookuptype must prefer the current // module's SK_TYPE when a param shadows a type leaf two modules both // export: xb's `size(invalid)` resolves xb's !i64 (exit 8), never // xa's !i8, on both stages, shadow and noshadow rows. The // two-DIRECTORY tree is load-bearing (a single-file twin risks a // different scope-install order — E3-C1 retarget note in the // carrier); each (row,driver) rebuilds a fresh tree. // // Dropped C machinery, not assertions: the ww_ww-absent skip gate // (the Make target declares both drivers) and the per-path // 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("sepimport 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 cmpsepwork(label: str, csdir: str, wwdir: str) void = { if (!testenv.isdir(csdir)) { fail(label, "no cs sepwork"); }; let names: []str = testenv.listdir(csdir); let seen: i32 = 0; let i: i32 = 0; for (i < names.len) { if (strings.hassuffix(names[i], ".s") || strings.hassuffix(names[i], ".wwi") || strings.hassuffix(names[i], ".a")) { seen += 1; if (!testenv.same( testenv.readfile(strings.concat(csdir, "/", names[i])), testenv.readfile(strings.concat(wwdir, "/", names[i])))) { fail(label, strings.concat("cs!=ww for ", names[i], " (rule 10)")); }; }; i += 1; }; // an existing-but-empty sepwork would pass the loop vacuously if (seen == 0) { fail(label, "no package artifacts in cs sepwork"); }; }; @test fn coloimport() void = { let td: str = testenv.fresh(); let inc: str = strings.concat(testenv.repo(), "/test/wcc/data/colo98"); let entry: str = strings.concat(inc, "/widget/widget_test.ww"); let drvs: []str = ["ww", "ww_ww"]; let tags: []str = ["cs", "ww"]; let i: i32 = 0; for (i < 2) { let prog: str = strings.concat(td, "/widget.", tags[i], ".bin"); let av: []str = [testenv.driver(drvs[i]), "test", "-I", inc, "-o", prog, entry]; if (runcode(td, strings.concat("colo_", tags[i]), av) != 0) { fail("coloimport", strings.concat("`ww test` exit != 0 on ", drvs[i], " (import folded to the sibling file?)")); }; i += 1; }; let csdir: str = strings.concat(td, "/widget.cs.bin.sepwork"); let wwdir: str = strings.concat(td, "/widget.ww.bin.sepwork"); if (!testenv.exists(strings.concat(csdir, "/widget.unit.ww"))) { fail("coloimport", strings.concat("widget.unit.ww missing (import ", "folded to the sibling file, not the dir-package)")); }; if (!testenv.exists(strings.concat(csdir, "/widget.wwi"))) { fail("coloimport", "widget.wwi missing"); }; cmpsepwork("coloimport", csdir, wwdir); testenv.clean(td); }; // column-0 anchored `TEXT main,` labels across every .s under `dir`; // the leading '\n' prepend also counts a file-leading label. fn countbaremain(dir: str) i32 = { let names: []str = testenv.listdir(dir); let n: i32 = 0; let i: i32 = 0; for (i < names.len) { if (strings.hassuffix(names[i], ".s")) { let body: str = strings.concat("\n", testenv.readfile(strings.concat(dir, "/", names[i]))); n += testenv.occurrences(body, "\nTEXT main,"); }; i += 1; }; return n; }; fn depmainrow(label: str, entry: str, want: i32, deps: str, mangled: str) void = { let td: str = testenv.fresh(); let src: str = strings.concat(testenv.repo(), "/", entry); let drvs: []str = ["ww", "ww_ww"]; let tags: []str = ["cs", "ww"]; let i: i32 = 0; for (i < 2) { let prog: str = strings.concat(td, "/", label, ".", tags[i], ".bin"); let av: []str = [testenv.driver(drvs[i]), "build", "-o", prog, src]; if (runcode(td, strings.concat("build_", tags[i]), av) != 0) { fail(label, strings.concat(drvs[i], " build failed (bare-main ", "collision -> w6l duplicate symbol?)")); }; let rav: []str = [prog]; if (runcode(td, strings.concat("run_", tags[i]), rav) != want) { fail(label, strings.concat(drvs[i], " run-exit != the dep main's return")); }; i += 1; }; let csdir: str = strings.concat(td, "/", label, ".cs.bin.sepwork"); let wwdir: str = strings.concat(td, "/", label, ".ww.bin.sepwork"); if (!testenv.has(testenv.readfile(strings.concat(csdir, "/", deps)), mangled)) { fail(label, strings.concat(deps, " lacks `", mangled, "` (dep main not mangled)")); }; if (countbaremain(csdir) != 1) { fail(label, strings.concat("bare `TEXT main,` count != 1 ", "(only the root entry stays bare)")); }; cmpsepwork(label, csdir, wwdir); testenv.clean(td); }; @test fn depmain_aabb() void = { depmainrow("aabb", "test/wcc/data/depmain99/main.ww", 7, "aa.bb.s", "TEXT aa.bb.main,"); }; @test fn depmain_cc() void = { depmainrow("cc", "test/wcc/data/depmain99/main_cc.ww", 9, "cc.s", "TEXT cc.main,"); }; @test fn declns() void = { let td: str = testenv.fresh(); let lays: []str = ["modfn_coexist", "modfn_coexist_vbu"]; let labs: []str = ["coexist", "coexist_vbu"]; let drvs: []str = ["ww", "ww_ww"]; let tags: []str = ["cs", "ww"]; let l: i32 = 0; for (l < 2) { let s: i32 = 0; for (s < 2) { let prog: str = strings.concat(td, "/", labs[l], ".", tags[s]); let src: str = strings.concat(testenv.repo(), "/test/wcc/data/", lays[l], "/main.ww"); let av: []str = [testenv.driver(drvs[s]), "build", "-o", prog, src]; if (runcode(td, strings.concat("b_", labs[l], "_", tags[s]), av) != 0) { fail(labs[l], strings.concat(drvs[s], " build failed")); }; let rav: []str = [prog]; if (runcode(td, strings.concat("r_", labs[l], "_", tags[s]), rav) != 6) { fail(labs[l], strings.concat(drvs[s], " exit != 6 (coexistence mis-resolved)")); }; s += 1; }; l += 1; }; // Both the dependency and raw explicit root emit complete package artifacts. let parts: []str = ["aa.s", "aa.wwi", "aa.a", "aa.unit.ww", "__root.s", "__root.wwi", "__root.a", "__root.unit.ww"]; // cs==ww (rule 10) per layout over the complete package-artifact table let l2: i32 = 0; for (l2 < 2) { let p: i32 = 0; for (p < parts.len) { if (!testenv.same( testenv.readfile(strings.concat(td, "/", labs[l2], ".cs.sepwork/", parts[p])), testenv.readfile(strings.concat(td, "/", labs[l2], ".ww.sepwork/", parts[p])))) { fail(labs[l2], strings.concat("cs!=ww for ", parts[p], " (rule 10)")); }; p += 1; }; l2 += 1; }; // cross-LAYOUT byte-id, same stage: decl-order independence of the // SK_USE/value promote. `.unit.ww` embeds the differently ORDERED // source, so the codegen claim is tested on .s/.wwi only. let oparts: []str = ["aa.s", "aa.wwi", "__root.s"]; let t: i32 = 0; for (t < 2) { let p: i32 = 0; for (p < oparts.len) { if (!testenv.same( testenv.readfile(strings.concat(td, "/coexist.", tags[t], ".sepwork/", oparts[p])), testenv.readfile(strings.concat(td, "/coexist_vbu.", tags[t], ".sepwork/", oparts[p])))) { fail("declns", strings.concat("vbu!=non-vbu for ", oparts[p], " (", tags[t], ") -- silent decl-order dependence")); }; p += 1; }; t += 1; }; // non-vacuity: the two namespaces resolve to DISTINCT symbols let t2: i32 = 0; for (t2 < 2) { let rs: str = testenv.readfile(strings.concat(td, "/coexist.", tags[t2], ".sepwork/__root.s")); if (!testenv.has(rs, "CALL\taa.helper(SB)")) { fail("declns", strings.concat("__root.s (", tags[t2], ") lacks module-qualified `CALL aa.helper(SB)`")); }; if (!testenv.has(rs, "CALL\tmain.aa(SB)")) { fail("declns", strings.concat("__root.s (", tags[t2], ") lacks local-fn `CALL main.aa(SB)`")); }; t2 += 1; }; testenv.clean(td); }; // fresh two-directory tree per (row,driver); relative build with the // tree as cwd (canonical dir-package build, binary lands in cwd). fn sltbuild(drv: str, param: str) i32 = { let dir: str = testenv.fresh(); assert(os.mkdir(strings.concat(dir, "/xa"), 493) == 0); assert(os.mkdir(strings.concat(dir, "/xb"), 493) == 0); testenv.writefile(strings.concat(dir, "/xa/xa.ww"), strings.concat( "package xa;\n", "export type invalid = !i8;\n")); testenv.writefile(strings.concat(dir, "/xb/xb.ww"), strings.concat( "package xb;\n", "import xa;\n", "export type invalid = !i64;\n", "export fn f(", param, ": i32) i64 = { return size(invalid): i64; };\n")); testenv.writefile(strings.concat(dir, "/root.ww"), strings.concat( "package main;\n", "import xb;\n", "import xa;\n", "fn main() int = { return xb.f(0): int; };\n")); let bav: []str = [testenv.driver(drv), "build", "root.ww"]; let brc: i32 = runcode(dir, "build", bav); if (brc != 0) { testenv.clean(dir); return -1; }; let rav: []str = [strings.concat(dir, "/root")]; let got: i32 = runcode(dir, "run", rav); testenv.clean(dir); return got; }; fn sltrow(label: str, param: str, want: i32) void = { let gc: i32 = sltbuild("ww", param); if (gc != want) { fail(label, "cstage exit != want (size of the wrong module's type)"); }; let gw: i32 = sltbuild("ww_ww", param); if (gw != gc) { fail(label, strings.concat("cs != ww exit (scopelookuptype ", "mod-preference divergence -- #58/#50 c1)")); }; if (gw != want) { fail(label, "wwstage exit != want"); }; }; @test fn slt_shadow() void = { sltrow("shadow", "invalid", 8); }; @test fn slt_noshadow() void = { sltrow("noshadow", "x", 8); };