test/xmod/m1_test.ww replaces 989_m1mangle_run.c and 989_m1usehint_run.c with every assertion preserved (5 tree rows + 2 usehint rows, both stages, plus the leaf_collision byte-id leg; concat order strengthened from shell glob to byte-sorted listdir).
255 lines
8.4 KiB
Plaintext
255 lines
8.4 KiB
Plaintext
package m1_test;
|
|
|
|
// M1 path-mangle RUN-level observers over runtime-written dir-package
|
|
// trees, both driver stages. Ports of the retired native carriers
|
|
// test/wcc/989_m1mangle_run.c and 989_m1usehint_run.c; every assertion
|
|
// preserved. The symbol-level cousin claims live in
|
|
// test/byteid/mangle_test.ww; these rows own the build/link/run legs.
|
|
//
|
|
// m1mangle (#22 + #32) rows, each a tree beside a root main.ww built
|
|
// with `build -o main main.ww` (cwd = tree, Hare CWD==module-dir
|
|
// mirror) and run:
|
|
// nested_call | dir import path-mangles; qualified-ref hint
|
|
// | resolves the PATH aa.bb.val -> exit 42
|
|
// imported_main | imported pkg's private `fn main` mangles aa.bb.main
|
|
// | instead of colliding with the root entry -> 7
|
|
// priv_global | module-PRIVATE value global mangles aa.bb.pv -> 9
|
|
// single_level | control: single-level cc.v unchanged -> 5
|
|
// deep_nest | 2-level nest aa.bb.cc.val path-mangle -> 3
|
|
//
|
|
// m1usehint (#40) — the cgen mangle-hint must be MODULE-scoped, not
|
|
// unit-global: two dir-packages both `package math` export the same
|
|
// leaf `pick`, and each referencing module's `math.pick()` must bind
|
|
// its OWN import (a.math=111 / b.math=222; mis-route exits 1/2):
|
|
// leaf_collision | same-leaf exported fns, distinct bodies -> exit 0
|
|
// collision_diff | same, mismatched signatures (checker curmod-
|
|
// | preference agrees with the hint) -> exit 0
|
|
// plus the rule-10 byte-id leg: cstage vs wwstage sepwork *.s concat
|
|
// on the leaf_collision unit, byte-identical (concat order
|
|
// strengthened from the carrier's shell glob to explicit
|
|
// byte-lexicographic listdir).
|
|
//
|
|
// Dropped C machinery, not assertions: the ww_ww-absent skip gate
|
|
// (the Make target declares both drivers) and the per-path owned-flag
|
|
// cleanup ledger (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("m1 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;
|
|
};
|
|
|
|
// 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")) {
|
|
out = strings.concat(out,
|
|
testenv.readfile(strings.concat(sepdir, "/", names[i])));
|
|
};
|
|
i += 1;
|
|
};
|
|
return out;
|
|
};
|
|
|
|
fn mkdirs(td: str, dirs: []str) void = {
|
|
let d: i32 = 0;
|
|
for (d < dirs.len) {
|
|
assert(os.mkdir(strings.concat(td, "/", dirs[d]), 493) == 0);
|
|
d += 1;
|
|
};
|
|
};
|
|
|
|
// ---- m1mangle (#22 + #32) ----------------------------------------------
|
|
|
|
// dirs are '/'-joined mkdir steps, parents before children.
|
|
fn m1row(label: str, dirs: []str, rel: str, content: str, root: str,
|
|
want: i32) void = {
|
|
let drvs: []str = ["ww", "ww_ww"];
|
|
let s: i32 = 0;
|
|
for (s < 2) {
|
|
let td: str = testenv.fresh();
|
|
mkdirs(td, dirs);
|
|
testenv.writefile(strings.concat(td, "/", rel), content);
|
|
testenv.writefile(strings.concat(td, "/main.ww"), root);
|
|
let av: []str = [testenv.driver(drvs[s]), "build", "-o", "main",
|
|
"main.ww"];
|
|
if (runcode(td, strings.concat("build_", drvs[s]), av) != 0) {
|
|
fail(label, strings.concat(drvs[s], " build failed (broken ",
|
|
"mangle hint or skip rule -> link failure)"));
|
|
};
|
|
let rav: []str = [strings.concat(td, "/main")];
|
|
if (runcode(td, strings.concat("run_", drvs[s]), rav) != want) {
|
|
fail(label, strings.concat(drvs[s],
|
|
" run-exit differs from the row's want"));
|
|
};
|
|
testenv.clean(td);
|
|
s += 1;
|
|
};
|
|
};
|
|
|
|
@test fn nested_call() void = {
|
|
let dirs: []str = ["aa", "aa/bb"];
|
|
m1row("nested_call", dirs, "aa/bb/bb.ww", strings.concat(
|
|
"package bb;\n",
|
|
"export fn val() int = { return 42; };\n"), strings.concat(
|
|
"package main;\n",
|
|
"import aa.bb;\n",
|
|
"export fn main() int = { return bb.val(); };\n"), 42);
|
|
};
|
|
|
|
@test fn imported_main() void = {
|
|
let dirs: []str = ["aa", "aa/bb"];
|
|
m1row("imported_main", dirs, "aa/bb/bb.ww", strings.concat(
|
|
"package bb;\n",
|
|
"fn main() int = { return 7; };\n",
|
|
"export fn run() int = { return main(); };\n"), strings.concat(
|
|
"package main;\n",
|
|
"import aa.bb;\n",
|
|
"export fn main() int = { return bb.run(); };\n"), 7);
|
|
};
|
|
|
|
@test fn priv_global() void = {
|
|
let dirs: []str = ["aa", "aa/bb"];
|
|
m1row("priv_global", dirs, "aa/bb/bb.ww", strings.concat(
|
|
"package bb;\n",
|
|
"let pv: int = 9;\n",
|
|
"export fn getpv() int = { return pv; };\n"), strings.concat(
|
|
"package main;\n",
|
|
"import aa.bb;\n",
|
|
"export fn main() int = { return bb.getpv(); };\n"), 9);
|
|
};
|
|
|
|
@test fn single_level() void = {
|
|
let dirs: []str = ["cc"];
|
|
m1row("single_level", dirs, "cc/cc.ww", strings.concat(
|
|
"package cc;\n",
|
|
"export fn v() int = { return 5; };\n"), strings.concat(
|
|
"package main;\n",
|
|
"import cc;\n",
|
|
"export fn main() int = { return cc.v(); };\n"), 5);
|
|
};
|
|
|
|
@test fn deep_nest() void = {
|
|
let dirs: []str = ["aa", "aa/bb", "aa/bb/cc"];
|
|
m1row("deep_nest", dirs, "aa/bb/cc/cc.ww",
|
|
strings.concat(
|
|
"package cc;\n",
|
|
"export fn val() int = { return 3; };\n"), strings.concat(
|
|
"package main;\n",
|
|
"import aa.bb.cc;\n",
|
|
"export fn main() int = { return cc.val(); };\n"), 3);
|
|
};
|
|
|
|
// ---- m1usehint (#40) ---------------------------------------------------
|
|
|
|
fn uselayout(td: str, apick: str, onecall: str) void = {
|
|
let dirs: []str = ["a", "a/math", "b", "b/math", "one", "two"];
|
|
mkdirs(td, dirs);
|
|
testenv.writefile(strings.concat(td, "/a/math/math.ww"),
|
|
strings.concat("package math;\n", apick));
|
|
testenv.writefile(strings.concat(td, "/b/math/math.ww"),
|
|
strings.concat(
|
|
"package math;\n",
|
|
"export fn pick() int = { return 222; };\n"));
|
|
testenv.writefile(strings.concat(td, "/one/one.ww"), strings.concat(
|
|
"package one;\n",
|
|
"import a.math;\n",
|
|
"export fn getone() int = { return ", onecall, "; };\n"));
|
|
testenv.writefile(strings.concat(td, "/two/two.ww"), strings.concat(
|
|
"package two;\n",
|
|
"import b.math;\n",
|
|
"export fn gettwo() int = { return math.pick(); };\n"));
|
|
testenv.writefile(strings.concat(td, "/main.ww"), strings.concat(
|
|
"package main;\n",
|
|
"import one;\n",
|
|
"import two;\n",
|
|
"export fn main() int = {\n",
|
|
" if (one.getone() != 111) { return 1; };\n",
|
|
" if (two.gettwo() != 222) { return 2; };\n",
|
|
" return 0;\n",
|
|
"};\n"));
|
|
};
|
|
|
|
fn userow(label: str, apick: str, onecall: str) void = {
|
|
let drvs: []str = ["ww", "ww_ww"];
|
|
let s: i32 = 0;
|
|
for (s < 2) {
|
|
let td: str = testenv.fresh();
|
|
uselayout(td, apick, onecall);
|
|
let av: []str = [testenv.driver(drvs[s]), "build", "-o", "main",
|
|
"main.ww"];
|
|
if (runcode(td, strings.concat("build_", drvs[s]), av) != 0) {
|
|
fail(label, strings.concat(drvs[s], " build failed"));
|
|
};
|
|
let rav: []str = [strings.concat(td, "/main")];
|
|
if (runcode(td, strings.concat("run_", drvs[s]), rav) != 0) {
|
|
fail(label, strings.concat(drvs[s], " run-exit != 0 (a ",
|
|
"file-global first-match hint routes one math.pick() to ",
|
|
"the wrong package -- #40)"));
|
|
};
|
|
testenv.clean(td);
|
|
s += 1;
|
|
};
|
|
};
|
|
|
|
@test fn leaf_collision() void = {
|
|
userow("leaf_collision",
|
|
"export fn pick() int = { return 111; };\n", "math.pick()");
|
|
};
|
|
|
|
@test fn collision_diff() void = {
|
|
userow("collision_diff",
|
|
"export fn pick(x: int) int = { return x + 100; };\n",
|
|
"math.pick(11)");
|
|
};
|
|
|
|
@test fn usehint_byteid() void = {
|
|
let td: str = testenv.fresh();
|
|
uselayout(td, "export fn pick() int = { return 111; };\n",
|
|
"math.pick()");
|
|
let drvs: []str = ["ww", "ww_ww"];
|
|
let tags: []str = ["cstage", "wwstage"];
|
|
let asms: []str = ["", ""];
|
|
let s: i32 = 0;
|
|
for (s < 2) {
|
|
let av: []str = [testenv.driver(drvs[s]), "build", "-o", tags[s],
|
|
"main.ww"];
|
|
if (runcode(td, strings.concat("bid_", tags[s]), av) != 0) {
|
|
fail("usehint_byteid", strings.concat(tags[s],
|
|
" build failed"));
|
|
};
|
|
asms[s] = catasm(strings.concat(td, "/", tags[s], ".sepwork"));
|
|
s += 1;
|
|
};
|
|
if (asms[0].len == 0 || asms[1].len == 0) {
|
|
fail("usehint_byteid", "empty .s concat");
|
|
};
|
|
if (!testenv.same(asms[0], asms[1])) {
|
|
fail("usehint_byteid", "cstage.s != wwstage.s (byte-id break)");
|
|
};
|
|
testenv.clean(td);
|
|
};
|