Unblocked by the package-mode ruling: same-package test files now
compose everywhere (coordinator dir-mode owns test-library and the
libbyteid dir entry owns byte identity), so the per-file standalone
constraint is gone and Go's stdlib layout applies directly. The
15-banner strings_test.ww monolith dissolves into per-ref-file
family files — dup, concat, trim, sub, utf8, iter, tokenize
(tokenize+splitn+cut, all of ref tokenize.ha), pad, replace — plus
helpers_test.ww holding exactly the one cross-family helper (streq),
Go's shared test-helper idiom. Pure moves; family-local helpers
(expect_str_token et al.) stay in their family file. Leading banners
that merely restated the filename dropped; 6 interior sub-family
boundaries remain. lib/ census 141 -> 132.
libbyteid gains the dx() dir-mode entry form decided in B2: compose
every *_test.ww under moddir exactly as pkgcombined does
(module-reset separators, byte-lex order) and byte-id the composed
root through both driver stages. The five per-file strings fx
entries retire into one dx("lib/strings") — every source line they
covered is inside the composed unit, and the completeness scan still
keys the module. NENTEXPECT 60 -> 56.
Recorded, not split: fmt_test's 13 banners are scenario groups over
the one fprint surface and ref/hare/fmt itself keeps a single
+test.ha — a print/wrappers split would fight the ref; memio stays
per the standing ruling (everything ww ports lives in ref
stream.ha).
113 lines
2.9 KiB
Plaintext
113 lines
2.9 KiB
Plaintext
// Vectors mirror ref/hare/strings/dup.ha where ww can express them.
|
|
// External strings_test package per the Go foo_test idiom (rule-5/9
|
|
// carve-out, task #16); the shared streq helper lives in
|
|
// helpers_test.ww — same-package test files compose in dir-mode
|
|
// (the package, not the file, is the unit of testing).
|
|
package strings_test;
|
|
|
|
import strings;
|
|
import os;
|
|
|
|
// ref/hare/strings/dup.ha:45.
|
|
|
|
@test fn dup_cases() void = {
|
|
let e: str = strings.dup("");
|
|
assert(!(!streq(e, "")));
|
|
assert(!(e.len != 0));
|
|
|
|
let h: str = strings.dup("hello");
|
|
assert(!(!streq(h, "hello")));
|
|
defer os.free(h.ptr: *void, h.len: u64);
|
|
|
|
// multi-byte UTF-8: dup must copy raw bytes, not aliased view.
|
|
let m: str = strings.dup("こんにちは");
|
|
assert(!(m.len != 15));
|
|
assert(!(!streq(m, "こんにちは")));
|
|
assert(!(m.ptr == "こんにちは".ptr)); // fresh alloc
|
|
defer os.free(m.ptr: *void, m.len: u64);
|
|
};
|
|
|
|
// ---- dupall -----------------------------------------------------------
|
|
// ref/hare/strings/dup.ha:55 (#6). Element reads go through
|
|
// `&toks.ptr[i]: *str`
|
|
// per the splitn cases (16B element copy gap, cgen.c:6515).
|
|
|
|
@test fn dupall_cases() void = {
|
|
// Empty input — empty result, mirrors Hare's `payload = []`.
|
|
let empty: []str;
|
|
empty.ptr = nil: *str;
|
|
empty.len = 0;
|
|
empty.cap = 0;
|
|
match (strings.dupall(empty)) {
|
|
case let r: []str => {
|
|
assert(!(r.len != 0));
|
|
strings.freeall(r);
|
|
};
|
|
case nomem => { abort(); };
|
|
};
|
|
|
|
// Two-element ASCII — each output element is a fresh allocation
|
|
// independent of the input (ptr differs from the borrowed source).
|
|
let in2: [2]str;
|
|
in2[0] = "hello";
|
|
in2[1] = "world";
|
|
let src2: []str;
|
|
src2.ptr = &in2[0];
|
|
src2.len = 2;
|
|
src2.cap = 2;
|
|
match (strings.dupall(src2)) {
|
|
case let r: []str => {
|
|
assert(!(r.len != 2));
|
|
expect_str(r, 0, "hello");
|
|
expect_str(r, 1, "world");
|
|
let p0: *str = &r.ptr[0];
|
|
assert(!(p0.ptr == in2[0].ptr));
|
|
let p1: *str = &r.ptr[1];
|
|
assert(!(p1.ptr == in2[1].ptr));
|
|
strings.freeall(r);
|
|
};
|
|
case nomem => { abort(); };
|
|
};
|
|
|
|
// Singleton — `only` rune-equivalent of Hare's `["only"]`.
|
|
let in1: [1]str;
|
|
in1[0] = "only";
|
|
let src1: []str;
|
|
src1.ptr = &in1[0];
|
|
src1.len = 1;
|
|
src1.cap = 1;
|
|
match (strings.dupall(src1)) {
|
|
case let r: []str => {
|
|
assert(!(r.len != 1));
|
|
expect_str(r, 0, "only");
|
|
strings.freeall(r);
|
|
};
|
|
case nomem => { abort(); };
|
|
};
|
|
|
|
// Multibyte — UTF-8 bytes (5-byte and 15-byte) round-trip.
|
|
let inm: [2]str;
|
|
inm[0] = "héllo";
|
|
inm[1] = "こんにちは";
|
|
let srcm: []str;
|
|
srcm.ptr = &inm[0];
|
|
srcm.len = 2;
|
|
srcm.cap = 2;
|
|
match (strings.dupall(srcm)) {
|
|
case let r: []str => {
|
|
assert(!(r.len != 2));
|
|
expect_str(r, 0, "héllo");
|
|
expect_str(r, 1, "こんにちは");
|
|
let p0: *str = &r.ptr[0];
|
|
assert(!(p0.len != 6)); // é is 2 bytes
|
|
assert(!(p0.ptr == inm[0].ptr));
|
|
let p1: *str = &r.ptr[1];
|
|
assert(!(p1.len != 15)); // each kana is 3 bytes
|
|
assert(!(p1.ptr == inm[1].ptr));
|
|
strings.freeall(r);
|
|
};
|
|
case nomem => { abort(); };
|
|
};
|
|
};
|
|
|