package sepbuild_test; // `ww build` sep-driver layout observers, both stages. Ports of the // retired native carriers test/wcc/989_sepbuild_run.c, // 989_seproot_export_run.c, 989_sepstructdef_run.c and // 989_wwispread_sep.c; assertions retained where their production boundary // remains live. // // sepbuild (#46 commit-3) — build_one_sep END-TO-END on the real lib // chain root -> os -> {rt,time} (transitive-closure discovery + topo): // build+run exit 7 both stages; {time,rt,os}.wwi + __root.s // materialize (#69: the root is compiled without -I, so no // __root.wwi); per-package .s/.wwi/.unit.ww and the final binary // byte-id cs vs ww; every .unit.ww is the package's own sorted source // set; `ww run` routes through the same sole sep path (exit 7 both // stages). // // seproot (#69 BUG-1) — a ROOT whose `export fn use(a: *t)` names an // unexported local `type t` builds (exit 37 both stages) because the // root is compiled WITHOUT the -I .wwi-producer flag: __root.wwi must // NOT exist; replaying the driver's own __root.unit.ww plus c.wwi // through w6c/w6c_ww with -I must REJECT (the isolated bug) while -c // -o alone must accept; __root.s carries the exported fn. // // sepstructdef (#70 BUG-2) — a dep exporting aggregate-init defs // (struct-lit + array-lit) sep-builds and links (exit 20 both // stages); d.wwi carries the value-LESS prototypes `export def info: // s;` + `export def arr: [3]i32;` and NOT the value-serialized // `export def info: s = ` form (the producer took the aggregate arm). // // wwispread (#95) — the `...` union-spread marker survives N_TTAGGED // .wwi serialization: consumer build+run exit 0 over the checked-in // 2-arm and 3-arm trees, the produced .wwi contains the literal // marker, and cs.wwi == ww.wwi. // // Dropped C machinery, not assertions: 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("sepbuild 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 samefile(label: str, what: str, a: str, b: str) void = { if (!testenv.same(testenv.readfile(a), testenv.readfile(b))) { fail(label, strings.concat("cs!=ww for ", what, " (rule 10)")); }; }; @test fn sepbuild() void = { let td: str = testenv.fresh(); let rootww: str = strings.concat(td, "/root.ww"); testenv.writefile(rootww, strings.concat( "package main;\n", "import os;\n", "fn main() i32 = { return os.getpid() - os.getpid() + 7; };\n")); let drvs: []str = ["ww", "ww_ww"]; let tags: []str = ["cs", "ww"]; let s: i32 = 0; for (s < 2) { let prog: str = strings.concat(td, "/prog.", tags[s]); let av: []str = [testenv.driver(drvs[s]), "build", "-o", prog, rootww]; if (runcode(td, strings.concat("build_", tags[s]), av) != 0) { fail("sepbuild", strings.concat(drvs[s], " build failed")); }; let rav: []str = [prog]; if (runcode(td, strings.concat("runbin_", tags[s]), rav) != 7) { fail("sepbuild", strings.concat(drvs[s], " prog exit != 7")); }; s += 1; }; // discovery/topo: the transitive package set materialized. #69: the // root emits no .wwi (compiled without -I); its .s stands in. let pkgs: []str = ["time", "rt", "os", "__root"]; let i: i32 = 0; for (i < pkgs.len) { let suffix: str = ".wwi"; if (testenv.same(pkgs[i], "__root")) { suffix = ".s"; }; if (!testenv.exists(strings.concat(td, "/prog.cs.sepwork/", pkgs[i], suffix))) { fail("sepbuild", strings.concat(pkgs[i], suffix, " missing (discovery/topo)")); }; i += 1; }; // cs==ww (rule 10): per-package artifacts + the final binary let sufs: []str = [".s", ".wwi", ".unit.ww"]; let p: i32 = 0; for (p < pkgs.len) { let k: i32 = 0; for (k < sufs.len) { if (testenv.same(pkgs[p], "__root") && testenv.same(sufs[k], ".wwi")) { k += 1; continue; }; samefile("sepbuild", strings.concat(pkgs[p], sufs[k]), strings.concat(td, "/prog.cs.sepwork/", pkgs[p], sufs[k]), strings.concat(td, "/prog.ww.sepwork/", pkgs[p], sufs[k])); k += 1; }; p += 1; }; samefile("sepbuild", "the final binary", strings.concat(td, "/prog.cs"), strings.concat(td, "/prog.ww")); // `ww run` routes through the sole sep path on both stages let cav: []str = [testenv.driver("ww"), "run", rootww]; let rccs: i32 = runcode(td, "run_cs", cav); let wav: []str = [testenv.driver("ww_ww"), "run", rootww]; let rcww: i32 = runcode(td, "run_ww", wav); if (rccs != rcww || rccs != 7) { fail("sepbuild", "`ww run` exits differ or != 7 across stages"); }; testenv.clean(td); }; @test fn seproot() void = { let td: str = testenv.fresh(); assert(os.mkdir(strings.concat(td, "/lib"), 493) == 0); assert(os.mkdir(strings.concat(td, "/lib/c"), 493) == 0); testenv.writefile(strings.concat(td, "/lib/c/mod.ww"), strings.concat( "package c;\n", "export fn cval() i32 = { return 5; };\n")); let rootww: str = strings.concat(td, "/root.ww"); testenv.writefile(rootww, strings.concat( "package main;\n", "import c;\n", "type t = struct { v: i32 };\n", "export fn use(a: *t) i32 = { return a.v; };\n", "fn main() i32 = {\n", "\tlet x: t = t { v = 42 };\n", "\treturn use(&x) - c.cval();\n", "};\n")); let drvs: []str = ["ww", "ww_ww"]; let tags: []str = ["cs", "ww"]; let s: i32 = 0; for (s < 2) { let prog: str = strings.concat(td, "/prog.", tags[s]); let av: []str = [testenv.driver(drvs[s]), "build", "-I", strings.concat(td, "/lib"), "-o", prog, rootww]; if (runcode(td, strings.concat("build_", tags[s]), av) != 0) { fail("seproot", strings.concat(drvs[s], " build failed ", "(pre-fix: -I on the root rejects ", "export-fn-over-unexported-type)")); }; let rav: []str = [prog]; if (runcode(td, strings.concat("runbin_", tags[s]), rav) != 37) { fail("seproot", strings.concat(drvs[s], " prog exit != 37")); }; s += 1; }; // cs==ww; the root's .wwi is intentionally absent (asserted below) let pkgs: []str = ["c", "__root"]; let sufs: []str = [".s", ".wwi", ".unit.ww"]; let p: i32 = 0; for (p < pkgs.len) { let k: i32 = 0; for (k < sufs.len) { if (testenv.same(pkgs[p], "__root") && testenv.same(sufs[k], ".wwi")) { k += 1; continue; }; samefile("seproot", strings.concat(pkgs[p], sufs[k]), strings.concat(td, "/prog.cs.sepwork/", pkgs[p], sufs[k]), strings.concat(td, "/prog.ww.sepwork/", pkgs[p], sufs[k])); k += 1; }; p += 1; }; samefile("seproot", "the final binary", strings.concat(td, "/prog.cs"), strings.concat(td, "/prog.ww")); // the fix: the root is compiled WITHOUT -I, so no __root.wwi let s2: i32 = 0; for (s2 < 2) { if (testenv.exists(strings.concat(td, "/prog.", tags[s2], ".sepwork/__root.wwi"))) { fail("seproot", strings.concat(drvs[s2], " produced __root.wwi (-I still passed for the root)")); }; s2 += 1; }; // replay the pre-fix invocation on the driver's own __root.unit.ww: // with -I the export-check FIRES (the isolated bug); without it the // post-fix invocation accepts. Both compilers. let unit: str = strings.concat(td, "/prog.cs.sepwork/__root.unit.ww"); let ciface: str = strings.concat(td, "/prog.cs.sepwork/c.wwi"); let comps: []str = ["w6c", "w6c_ww"]; let c: i32 = 0; for (c < 2) { let wwi: str = strings.concat(td, "/nv.", comps[c], ".wwi"); let asmf: str = strings.concat(td, "/nv.", comps[c], ".s"); let rav: []str = [testenv.driver(comps[c]), "-c", "--import", "c", ciface, "-I", wwi, "-o", asmf, unit]; if (runcode(td, strings.concat("nvI_", comps[c]), rav) == 0) { fail("seproot", strings.concat(comps[c], " -c -I accepted the ", "root export-over-unexported-type (vacuous gate)")); }; let aav: []str = [testenv.driver(comps[c]), "-c", "--import", "c", ciface, "-o", asmf, unit]; if (runcode(td, strings.concat("nvO_", comps[c]), aav) != 0) { fail("seproot", strings.concat(comps[c], " -c -o (no -I) ", "rejected the root unit (post-fix invocation)")); }; c += 1; }; if (!testenv.has(testenv.readfile(strings.concat(td, "/prog.cs.sepwork/__root.s")), "use")) { fail("seproot", "__root.s lacks the exported `use` symbol"); }; testenv.clean(td); }; @test fn sepstructdef() void = { let td: str = testenv.fresh(); assert(os.mkdir(strings.concat(td, "/lib"), 493) == 0); assert(os.mkdir(strings.concat(td, "/lib/d"), 493) == 0); // the struct type must be EXPORTED: an exported def over an // unexported type is a separate loud reject (check_exported_type) testenv.writefile(strings.concat(td, "/lib/d/mod.ww"), strings.concat( "package d;\n", "export type s = struct { a: i32, b: i32 };\n", "export def info: s = s { a = 7, b = 11 };\n", "export def arr: [3]i32 = [1, 2, 3];\n", "export fn geta() i32 = { return info.a; };\n", "export fn getb() i32 = { return info.b; };\n", "export fn getelem(i: i32) i32 = { return arr[i]; };\n")); let rootww: str = strings.concat(td, "/root.ww"); testenv.writefile(rootww, strings.concat( "package main;\n", "import d;\n", "fn main() i32 = {\n", "\treturn d.geta() + d.getelem(1) + d.getb();\n", "};\n")); let drvs: []str = ["ww", "ww_ww"]; let tags: []str = ["cs", "ww"]; let s: i32 = 0; for (s < 2) { let prog: str = strings.concat(td, "/prog.", tags[s]); let av: []str = [testenv.driver(drvs[s]), "build", "-I", strings.concat(td, "/lib"), "-o", prog, rootww]; if (runcode(td, strings.concat("build_", tags[s]), av) != 0) { fail("sepstructdef", strings.concat(drvs[s], " build failed ", "(pre-fix: the aggregate-init def aborts the producer ", "with \"node kind 15\")")); }; let rav: []str = [prog]; if (runcode(td, strings.concat("runbin_", tags[s]), rav) != 20) { fail("sepstructdef", strings.concat(drvs[s], " prog exit != 20 ", "(external aggregate-DATA ref did not resolve)")); }; s += 1; }; let pkgs: []str = ["d", "__root"]; let sufs: []str = [".s", ".wwi", ".unit.ww"]; let p: i32 = 0; for (p < pkgs.len) { let k: i32 = 0; for (k < sufs.len) { if (testenv.same(pkgs[p], "__root") && testenv.same(sufs[k], ".wwi")) { k += 1; continue; }; samefile("sepstructdef", strings.concat(pkgs[p], sufs[k]), strings.concat(td, "/prog.cs.sepwork/", pkgs[p], sufs[k]), strings.concat(td, "/prog.ww.sepwork/", pkgs[p], sufs[k])); k += 1; }; p += 1; }; samefile("sepstructdef", "the final binary", strings.concat(td, "/prog.cs"), strings.concat(td, "/prog.ww")); // value-LESS prototypes present, value-serialized form absent (the // producer took the new aggregate arm, not the scalar arm) let wwi: str = testenv.readfile(strings.concat(td, "/prog.cs.sepwork/d.wwi")); if (!testenv.has(wwi, "export def info: s;\n")) { fail("sepstructdef", "d.wwi lacks value-less `export def info: s;`"); }; if (!testenv.has(wwi, "export def arr: [3]i32;\n")) { fail("sepstructdef", "d.wwi lacks value-less `export def arr: [3]i32;`"); }; if (testenv.has(wwi, "export def info: s = ")) { fail("sepstructdef", "d.wwi serialized the aggregate value (vacuous gate)"); }; testenv.clean(td); }; fn spreadshape(name: str, entry: str, wwi: str, marker: 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 s: i32 = 0; for (s < 2) { let prog: str = strings.concat(td, "/", name, ".", tags[s]); let av: []str = [testenv.driver(drvs[s]), "build", "-o", prog, src]; if (runcode(td, strings.concat("build_", tags[s]), av) != 0) { fail(name, strings.concat(drvs[s], " build failed (spread ", "member not assignable -> marker dropped?)")); }; let rav: []str = [prog]; if (runcode(td, strings.concat("runbin_", tags[s]), rav) != 0) { fail(name, strings.concat(drvs[s], " run exit != 0")); }; if (!testenv.has(testenv.readfile(strings.concat(prog, ".sepwork/", wwi)), marker)) { fail(name, strings.concat(wwi, " missing `", marker, "` (spread marker dropped in the serializer)")); }; s += 1; }; samefile(name, wwi, strings.concat(td, "/", name, ".cs.sepwork/", wwi), strings.concat(td, "/", name, ".ww.sepwork/", wwi)); testenv.clean(td); }; @test fn wwispread_twoarm() void = { spreadshape("twoarm", "test/wcc/data/wwispread/main.ww", "liba.wwi", "...inner"); }; @test fn wwispread_threearm() void = { spreadshape("threearm", "test/wcc/data/wwispread3/main.ww", "libb.wwi", "...three"); };