package mangle_test; // M1 (#22) symbol-name proof. Port of the retired native carrier // test/wcc/989_m1mangle_sym.c; every assertion preserved. Builds a // fixture importing the real nested DIRECTORY package encoding.utf8 // to .s through BOTH driver stages and asserts the symbol table: // // needle | want | proves // --------------------------+------+--------------------------------- // "encoding.utf8.runesz" | yes | nested pkg path-mangles (the M1 // | | DELTA: leaf utf8 -> path // | | encoding.utf8) // "TEXT main," | yes | root entry stays BARE (#32) // "TEXT utf8.runesz," | no | pre-M1 leaf-only mangle is gone // // plus cstage.s == wwstage.s byte-for-byte (rule 10) over the // re-baselined names. // // #93 sep layout: `build -S -o ` splits the asm across // .sepwork/.s (root in __root.s, the import in // encoding.utf8.s), so each stage's per-package .s are concatenated // before the needle scans and the byte-id compare. Concat order is // strengthened from the carrier's shell glob to explicit // byte-lexicographic (the libbyteid_test move); an empty concat fails // loudly exactly as the carrier's `cat .sepwork/*.s` did. // // Dropped C machinery, not assertions: the ww_ww-absent skip gate // (the Make target declares both drivers), getpid /tmp keying + // rm accounting (testenv.fresh/clean), and the shell `timeout 180` // wrapper (runcommand's 180s deadline carries it). import os; import os.exec; import strings; import testenv; import time; fn fail(label: str, why: str) void = { let m: str = strings.concat("mangle FAIL: ", label, " -- ", why, "\n"); os.write(2, m.ptr, m.len: u64); assert(false); }; fn tmo() time.duration = { return (180i64 * (time.second: i64)): time.duration; }; fn buildstage(td: str, stage: str, drv: str, stem: str) void = { let av: []str = []; append(av, drv); append(av, "build"); append(av, "-S"); append(av, "-o"); append(av, stem); append(av, "m1sym.ww"); let co: testenv.commandout; testenv.runcommand(td, td, stage, av, tmo(), &co); let ok: bool = co.termination == exec.termination.EXIT && co.code == 0; if (!ok) { fail(stage, "build failed"); }; }; // Every per-package .s under `sepdir`, concatenated in byte-sorted // order; "" when the directory is missing or holds no .s. fn catasm(sepdir: str) str = { if (!testenv.isdir(sepdir)) { return ""; }; let names: []str = testenv.listdir(sepdir); let out: str = ""; let i: i32 = 0; for (i < names.len) { if (strings.hassuffix(names[i], ".s")) { let body: str = testenv.readfile( strings.concat(sepdir, "/", names[i])); out = strings.concat(out, body); }; i += 1; }; return out; }; fn checksyms(stage: str, s: str) void = { if (!testenv.has(s, "encoding.utf8.runesz")) { fail(stage, "'encoding.utf8.runesz' missing -- nested pkg path-mangle absent"); }; if (!testenv.has(s, "TEXT main,")) { fail(stage, "'TEXT main,' missing -- root entry no longer bare"); }; if (testenv.has(s, "TEXT utf8.runesz,")) { fail(stage, "'TEXT utf8.runesz,' present -- pre-M1 leaf-only mangle returned"); }; }; @test fn m1mangle() void = { let td: str = testenv.fresh(); testenv.writefile(strings.concat(td, "/m1sym.ww"), strings.concat( "package main;\n", "import encoding.utf8;\n", "export fn main() int = { return utf8.runesz('A'): int; };\n")); let cstem: str = strings.concat(td, "/c_m1sym"); let wstem: str = strings.concat(td, "/w_m1sym"); buildstage(td, "cstage", testenv.driver("ww"), cstem); buildstage(td, "wwstage", testenv.driver("ww_ww"), wstem); let cs: str = catasm(strings.concat(cstem, ".sepwork")); let ws: str = catasm(strings.concat(wstem, ".sepwork")); if (cs.len == 0 || ws.len == 0) { fail("m1mangle", "empty .s concat"); }; checksyms("cstage", cs); checksyms("wwstage", ws); if (!testenv.same(cs, ws)) { fail("m1mangle", "cstage.s != wwstage.s (byte-id break)"); }; testenv.clean(td); };