Files
ww/test/misc/packedwwi_test.ww
Hojun-Cho 5dc8bea318 test: port the packed .wwi + identity legs to ww; retire 671_struct_packed
wwiroundtrip pins the @packed re-emit through a real -I tree on both
driver stages (importer-side layout exit 91), strengthened with the
`struct @packed {` needle in the retained sepwork pk2.wwi (a
single-file two-package form emits no .wwi, so the tree is
irreducible). identityreject pins the stage asymmetry as a DIVERGE
row: cstage rejects with "not assignable" (packed is type identity,
harec types.c:621), wwstage builds+runs through the documented
#224/#10 nominal-lossy leniency; a wwstage tighten fails the row and
demands graduation to a //ww:error fixture. The 15 layout/runtime
value rows are fixture-shaped and move to the declarative corpus per
the residual audit port split.
2026-08-08 15:05:52 +09:00

135 lines
4.8 KiB
Plaintext

package packedwwi_test;
// `struct @packed` legs no fixture can host, ported from the retired
// native carrier test/wcc/671_struct_packed.c (#51). The 15
// layout/runtime value rows are fixture-shaped and move to the
// declarative corpus per the residual audit port split; harec
// references live in that carrier's header (type_store.c:206-213,
// :886, :193; types.c:517,621).
//
// wwiroundtrip: a library package exports ONLY the packed type; the
// importer computes size+offset ITSELF, so the value depends on the
// .wwi producer re-emitting `struct @packed {` and the importer
// re-parsing it (unparse re-emit per ref/hare/hare/unparse/
// type.ha:122-126). Both driver stages must build the -I tree and run
// exit 91 (9*10+1; a dropped @packed gives 168). Strengthened over
// the carrier: the re-emitted `struct @packed {` is also asserted in
// the retained sepwork pk2.wwi. A single-file two-package form
// produces NO .wwi (one __root unit), so the real -I tree is
// irreducible here.
//
// identityreject: assigning packed A to a structurally-identical
// unpacked B — packed is type identity (harec types.c:621). STAGE-
// ASYMMETRIC divergence pin: cstage must reject WITH "not assignable"
// while wwstage must build AND run exit 0 through its pre-existing
// broadly-lenient nominal-lossy struct assignability (#224/#10 — a
// documented deferred arc, NOT desired behavior and NOT a #51
// regression). A wwstage tighten fails the row and demands graduation
// to a //ww:error two-frag fixture.
import os;
import os.exec;
import strings;
import testenv;
import time;
fn fail(label: str, why: str) void = {
let m: str = strings.concat("packedwwi 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;
};
fn rundir(dir: str, name: str, argv: []str, out: *testenv.commandout) i32 = {
testenv.runcommand(dir, dir, name, argv, tmo(), out);
if (out.termination != exec.termination.EXIT) { return -1; };
return out.code;
};
@test fn wwiroundtrip() void = {
let drvs: []str = ["ww", "ww_ww"];
let s: i32 = 0;
for (s < 2) {
let td: str = testenv.fresh();
assert(os.mkdir(strings.concat(td, "/lib"), 493) == 0);
assert(os.mkdir(strings.concat(td, "/lib/pk2"), 493) == 0);
assert(os.mkdir(strings.concat(td, "/app"), 493) == 0);
testenv.writefile(strings.concat(td, "/lib/pk2/pk2.ww"),
strings.concat(
"package pk2;\n",
"export type Ev = struct @packed { tag: u8, data: u64 };\n"));
testenv.writefile(strings.concat(td, "/app/main.ww"),
strings.concat(
"package main;\n",
"import pk2;\n",
"export fn main() i32 = {\n",
"\tlet e: pk2.Ev = pk2.Ev { tag = 1u8, data = 2u64 };\n",
"\treturn size(pk2.Ev): i32 * 10 + offset(e.data): i32;\n",
"};\n"));
let app: str = strings.concat(td, "/app");
let co: testenv.commandout;
let av: []str = [testenv.driver(drvs[s]), "build", "-I",
strings.concat(td, "/lib"), "-o", "m", "main.ww"];
if (rundir(app, strings.concat("build_", drvs[s]), av, &co)
!= 0) {
fail(drvs[s], "-I tree build failed");
};
let rav: []str = [strings.concat(app, "/m")];
if (rundir(app, strings.concat("run_", drvs[s]), rav, &co)
!= 91) {
fail(drvs[s], strings.concat("importer-side run-exit ",
"!= 91 (@packed dropped in the .wwi re-emit ",
"gives 168)"));
};
let wwi: str = testenv.readfile(
strings.concat(app, "/m.sepwork/pk2.wwi"));
if (!testenv.has(wwi, "struct @packed {")) {
fail(drvs[s],
"pk2.wwi lost the `struct @packed {` re-emit");
};
testenv.clean(td);
s += 1;
};
};
@test fn identityreject() void = {
let src: str = strings.concat(
"package main;\n",
"type A = struct @packed { x: u8, y: u64 };\n",
"type B = struct { x: u8, y: u64 };\n",
"export fn main() i32 = {\n",
"\tlet a: A = A { x = 1u8, y = 2u64 };\n",
"\tlet b: B = a;\n",
"\treturn 0;\n",
"};\n");
let td: str = testenv.fresh();
testenv.writefile(strings.concat(td, "/id.ww"), src);
let co: testenv.commandout;
let cav: []str = [testenv.driver("ww"), "build", "-o", "idc",
"id.ww"];
if (rundir(td, "build_cstage", cav, &co) == 0) {
fail("identity_reject",
"cstage accepted packed->unpacked assignment");
};
if (!testenv.has(co.stderr, "not assignable")) {
fail("identity_reject", strings.concat("cstage reject lost ",
"its `not assignable` diagnostic (crash is vacuous)"));
};
let wav: []str = [testenv.driver("ww_ww"), "build", "-o", "idw",
"id.ww"];
if (rundir(td, "build_wwstage", wav, &co) != 0) {
fail("identity_reject", strings.concat("wwstage rejected -- ",
"#224/#10 leniency closed; graduate this row to a ",
"//ww:error fixture"));
};
let rav: []str = [strings.concat(td, "/idw")];
if (rundir(td, "run_wwstage", rav, &co) != 0) {
fail("identity_reject", "wwstage run-exit != 0");
};
testenv.clean(td);
};