Migrate the slice/str-header core of drew's Family 1 from bespoke build+run C twins to test/lang @test, retiring each now-redundant twin in the same commit. Runtime coverage MOVES from $(TESTS) to test-lang (T1 runs+asserts via `ww test`) + test-lang-byteid (T2 keeps cs==ww .s byte-id); coverage is preserved, the $(TESTS) headline drops 6 (440->434). All asserts are primitive int/u8/bool comparisons (no fmt/strconv in the assert path); the slice-store families poison the slot (cap!=len) and read it back so a dropped data word FAILS. 928_str_abi_run.c -> str_abi_test.ww (str 24B ABI: .len/.cap across literal/arg/return/field/tuple/deref/index/tagged) 941_slice_store_cap_run.c -> slice_store_cap_test.ww (slice value store through indexed/field/chained lhs writes full 24B header; cap==8) 942_subslice_cap_run.c -> subslice_cap_test.ww (sub-slice cap = base_cap-lo; array/slice/str/append-no-realloc/hi-default) 943_subslice_ptresz_run.c -> subslice_ptresz_test.ww (sub-slice ptr advances lo*esz bytes; esz 2/4/8, let + call-arg) 944_deref_slice_store_run.c-> deref_slice_store_test.ww(*p=sliceval whole-deref store writes 24B header; cap==8) 949_f6_header_run.c -> f6_header_test.ww (str/slice header partial load/store; .cap/.len after clobber) Bump LANGBYTEID_EXPECTED_MIN 16->22 to ratchet the new corpus floor.
70 lines
2.4 KiB
Plaintext
70 lines
2.4 KiB
Plaintext
// deref_slice_store_test — a []T (slice-typed) VALUE stored through a
|
|
// WHOLE-deref lhs `*p = sliceval` must move the full 24B {ptr,len,cap} header
|
|
// (ref/hare/rt/ensure.ha:4-8), not just {ptr}, migrated from
|
|
// test/wcc/944_deref_slice_store_run.c (project #79). The `*p = v` deref-store
|
|
// arm was kind-gated on str ONLY; a slice fell to the 1-word default and
|
|
// silently DROPPED len+cap. str IS []u8 since Phase 2 (#1), so the str 3-word
|
|
// stash+store machinery applies to slices verbatim; the fix widens the gate
|
|
// from `str` to `str || slice`. SYMMETRIC across both stages (cs==ww,
|
|
// byte-id-BLIND), so only a store->read ROUNDTRIP catches it.
|
|
//
|
|
// cap != len in every row so a dropped len OR cap is caught.
|
|
|
|
package deref_slice_store_test;
|
|
|
|
type box = struct { s: []u8 };
|
|
|
|
@test fn d_slice_direct() void = {
|
|
// A — `*pp = p`, read back via the DIRECT local `dst`. dst is POISONED
|
|
// first with a different slice q (len=4,cap=5) via a PROVEN 3-word store
|
|
// (`dst = q`, NOT the site under test); a 1-word `*pp=p` leaves q's cap=5,
|
|
// the fix lands 8.
|
|
let hb: [8]u8; hb[0] = 104u8;
|
|
let p: []u8; p.ptr = &hb[0]; p.len = 2; p.cap = 8;
|
|
let qb: [8]u8;
|
|
let q: []u8; q.ptr = &qb[0]; q.len = 4; q.cap = 5;
|
|
let dst: []u8 = q;
|
|
let pp: *[]u8 = &dst;
|
|
*pp = p;
|
|
assert(dst.cap: i32 == 8);
|
|
assert(dst.len: i32 == 2);
|
|
assert(dst[0] == 104u8);
|
|
};
|
|
|
|
@test fn d_slice_thru() void = {
|
|
// B — same store, read back THROUGH the pointer via the 3-word field-deref
|
|
// read `(*pp).cap`/`.len` (already 3-word), confirming the stored header
|
|
// survives a pointer-side read.
|
|
let hb: [8]u8; hb[0] = 104u8;
|
|
let p: []u8; p.ptr = &hb[0]; p.len = 2; p.cap = 8;
|
|
let qb: [8]u8;
|
|
let q: []u8; q.ptr = &qb[0]; q.len = 4; q.cap = 5;
|
|
let dst: []u8 = q;
|
|
let pp: *[]u8 = &dst;
|
|
*pp = p;
|
|
assert((*pp).cap: i32 == 8);
|
|
assert((*pp).len: i32 == 2);
|
|
};
|
|
|
|
@test fn d_str_control() void = {
|
|
// C — control str-deref: the str arm the fix widens around must still land
|
|
// len=5 (regression guard). Poison d="xy" then `*pp="hello"`.
|
|
let d: str = "xy";
|
|
let pp: *str = &d;
|
|
*pp = "hello";
|
|
assert(d.len: i32 == 5);
|
|
};
|
|
|
|
@test fn d_field_control() void = {
|
|
// D — control (*p).field: explicit-deref field store, a separate
|
|
// already-3-word branch. `(*pb).s = p` into a struct{s:[]u8}.
|
|
let hb: [8]u8; hb[0] = 104u8;
|
|
let p: []u8; p.ptr = &hb[0]; p.len = 2; p.cap = 8;
|
|
let b: box;
|
|
let pb: *box = &b;
|
|
(*pb).s = p;
|
|
assert(b.s.cap: i32 == 8);
|
|
assert(b.s.len: i32 == 2);
|
|
assert(b.s[0] == 104u8);
|
|
};
|