test: migrate str-elem-cap/size-in-type behavior to test/lang @test
Two more value-observable families ported additively (the .c sources
keep running in $(TESTS); de-dup deferred to fold 6).
932_str_elem_cap -> str_elem_cap_test: a str-element N_INDEX value
read must load the full 24B {ptr,len,cap}, not {ptr,len} (F2); each
shape poisons cap != len so a 2-word read fails the .cap assert.
Template for the 933-939 cap family.
957_size_type -> size_type_test: `size` binds in type position and
coexists with the size(T) operator (#85); a green row is the bind
proof.
This commit is contained in:
58
test/lang/str_elem_cap_test.ww
Normal file
58
test/lang/str_elem_cap_test.ww
Normal file
@@ -0,0 +1,58 @@
|
||||
// str_elem_cap_test — a str-element VALUE read via N_INDEX must load the full
|
||||
// 24B {ptr,len,cap} header, not just {ptr,len}, migrated from test/wcc/
|
||||
// 932_str_elem_cap_run.c (F2 fold). str is 24B since Phase 2 (#1); pre-F2 the
|
||||
// N_INDEX str-element arms dropped the cap word, so reading `.cap` off an
|
||||
// indexed str element returned garbage (the missing third word) — cs==ww held,
|
||||
// so the 990-997 byte-id gates were GREEN while the runtime was wrong.
|
||||
//
|
||||
// Each shape POISONS the element so cap != len (a `.cap =` pseudo-field write,
|
||||
// no malloc / no import), then observes cap through `let e: str = <index>` (a
|
||||
// 3-word copy into the slot) and `e.cap` (an N_IDENT pseudo-field read off the
|
||||
// slot). A 2-word read leaves cap = len (N_IDENT base) or a stale slice-cap
|
||||
// (fallback base), so the read-back .cap mismatches the poisoned value. .len is
|
||||
// the control. The shapes (index base form), not the data, are what vary, so
|
||||
// per-shape asserts — this file is the template for the 933-939 cap family.
|
||||
|
||||
package str_elem_cap_test;
|
||||
|
||||
type box = struct { items: []str };
|
||||
|
||||
@test fn sitea_ident_base() void = {
|
||||
// N_IDENT base: xs[0] on a local [N]str, constant index. Poison cap=8
|
||||
// (len=2); a broken 2-word read leaves cap = len = 2.
|
||||
let p: str = "hi";
|
||||
p.cap = 8i32;
|
||||
let xs: [2]str;
|
||||
xs[0] = p;
|
||||
let e: str = xs[0];
|
||||
assert(e.cap: i32 == 8);
|
||||
assert(e.len: i32 == 2);
|
||||
};
|
||||
|
||||
@test fn sitea_var_index() void = {
|
||||
// N_IDENT base indexed by a VARIABLE (not a constant) — the index
|
||||
// source must not change which words the element load reads.
|
||||
let p: str = "hey";
|
||||
p.cap = 12i32;
|
||||
let xs: [2]str;
|
||||
let i: i32 = 1;
|
||||
xs[i] = p;
|
||||
let e: str = xs[i];
|
||||
assert(e.cap: i32 == 12);
|
||||
assert(e.len: i32 == 3);
|
||||
};
|
||||
|
||||
@test fn siteb_fallback_base() void = {
|
||||
// Fallback base: the element sits behind an N_DOT slice field, so the
|
||||
// N_INDEX base isn't a plain ident. Poison cap=9 (len=5); a broken read
|
||||
// leaves cap = the slice header's own cap, not the element's.
|
||||
let q: str = "world";
|
||||
q.cap = 9i32;
|
||||
let arr: [2]str;
|
||||
arr[0] = q;
|
||||
let b: box;
|
||||
b.items = arr[0:2];
|
||||
let e: str = b.items[0];
|
||||
assert(e.cap: i32 == 9);
|
||||
assert(e.len: i32 == 5);
|
||||
};
|
||||
Reference in New Issue
Block a user