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).
111 lines
3.1 KiB
Plaintext
111 lines
3.1 KiB
Plaintext
// Vectors mirror ref/hare/strings/replace.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/replace.ha:46 (#4). Hare rows 1-5 (target found
|
|
// once / multiple times / shorter / longer / multibyte) plus ww rows
|
|
// (no-match returns fresh copy, empty-replacement, result-shrinks-to-
|
|
// empty).
|
|
|
|
@test fn replace_cases() void = {
|
|
// Hare row 1: target found once.
|
|
match (strings.replace("Hello world!", "world", "there")) {
|
|
case let s: str => {
|
|
assert(!(!streq(s, "Hello there!")));
|
|
os.free(s.ptr: *void, s.len: u64);
|
|
};
|
|
case nomem => { abort(); };
|
|
};
|
|
|
|
// Hare row 2: needle found four times (replacement same length).
|
|
match (strings.replace("I like dogs, dogs, birds, dogs", "dogs", "cats")) {
|
|
case let s: str => {
|
|
assert(!(!streq(s, "I like cats, cats, birds, cats")));
|
|
os.free(s.ptr: *void, s.len: u64);
|
|
};
|
|
case nomem => { abort(); };
|
|
};
|
|
|
|
// Hare row 3: replacement shorter than needle, non-overlapping
|
|
// matches (Hare advances by needle.len, not 1).
|
|
match (strings.replace("aaaaaa", "aa", "a")) {
|
|
case let s: str => {
|
|
assert(!(!streq(s, "aaa")));
|
|
os.free(s.ptr: *void, s.len: u64);
|
|
};
|
|
case nomem => { abort(); };
|
|
};
|
|
|
|
// Hare row 4: replacement longer than needle.
|
|
match (strings.replace("aaa", "a", "aa")) {
|
|
case let s: str => {
|
|
assert(!(!streq(s, "aaaaaa")));
|
|
os.free(s.ptr: *void, s.len: u64);
|
|
};
|
|
case nomem => { abort(); };
|
|
};
|
|
|
|
// Hare row 5: multibyte UTF-8 (3-byte runes).
|
|
match (strings.replace("こんにちは", "にち", "ばん")) {
|
|
case let s: str => {
|
|
assert(!(!streq(s, "こんばんは")));
|
|
os.free(s.ptr: *void, s.len: u64);
|
|
};
|
|
case nomem => { abort(); };
|
|
};
|
|
|
|
// ww row 1: needle not found — fresh copy (distinct from
|
|
// borrowed input ptr).
|
|
let src: str = "hello world";
|
|
match (strings.replace(src, "xyz", "abc")) {
|
|
case let s: str => {
|
|
assert(!(!streq(s, "hello world")));
|
|
assert(!(s.ptr == src.ptr));
|
|
os.free(s.ptr: *void, s.len: u64);
|
|
};
|
|
case nomem => { abort(); };
|
|
};
|
|
|
|
// ww row 2: empty replacement — needle is removed.
|
|
match (strings.replace("foo-bar-baz", "-", "")) {
|
|
case let s: str => {
|
|
assert(!(!streq(s, "foobarbaz")));
|
|
os.free(s.ptr: *void, s.len: u64);
|
|
};
|
|
case nomem => { abort(); };
|
|
};
|
|
|
|
// ww row 3: result shrinks to empty — total==0 nil-alloc path.
|
|
match (strings.replace("aaaa", "aa", "")) {
|
|
case let s: str => {
|
|
assert(!(!streq(s, "")));
|
|
assert(!(s.len != 0));
|
|
};
|
|
case nomem => { abort(); };
|
|
};
|
|
|
|
// ww row 4: multibyte single-rune replace — every "に" → "X".
|
|
match (strings.replace("こんにちは", "に", "X")) {
|
|
case let s: str => {
|
|
assert(!(!streq(s, "こんXちは")));
|
|
os.free(s.ptr: *void, s.len: u64);
|
|
};
|
|
case nomem => { abort(); };
|
|
};
|
|
|
|
// ww row 5: empty input — returns empty.
|
|
match (strings.replace("", "x", "y")) {
|
|
case let s: str => {
|
|
assert(!(s.len != 0));
|
|
};
|
|
case nomem => { abort(); };
|
|
};
|
|
};
|
|
|