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).
97 lines
4.0 KiB
Plaintext
97 lines
4.0 KiB
Plaintext
// Vectors mirror ref/hare/strings/sub.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 encoding.utf8;
|
|
|
|
// ref/hare/strings/sub.ha:44 (@test fn sub), :79 (@test fn bytesub). Hare's
|
|
// 2-arg `sub(s, start)` rows are omitted: ww has no default-parameter
|
|
// syntax (filed as #37). bytesub now validates rune boundaries (#7).
|
|
|
|
@test fn sub_cases() void = {
|
|
assert(!(!streq(strings.sub("a string", 0, 8), "a string")));
|
|
assert(!(!streq(strings.sub("a string", 0, 1), "a")));
|
|
assert(!(!streq(strings.sub("a string", 0, 3), "a s")));
|
|
assert(!(!streq(strings.sub("a string", 2, 8), "string")));
|
|
// start == end yields an empty borrowed view.
|
|
assert(!(!streq(strings.sub("a string", 4, 4), "")));
|
|
assert(!(strings.sub("a string", 4, 4).len != 0));
|
|
// Hare vector — rune indices 1..3 over "こんにちは" select bytes
|
|
// 3..9 ("んに"), not bytes 1..3.
|
|
assert(!(!streq(strings.sub("こんにちは", 1, 3), "んに")));
|
|
// 2-byte rune at rune index 1 in "héllo" — byte offsets 1..3.
|
|
assert(!(!streq(strings.sub("héllo", 1, 2), "é")));
|
|
// start == 0, end == rune-len of full string.
|
|
assert(!(!streq(strings.sub("héllo", 0, 5), "héllo")));
|
|
};
|
|
|
|
// Match-shape mirrors Hare's `bytesub(...)!` at ref/hare/strings/sub.ha:
|
|
// 80-86. Inlined at each call site (rather than a helper that takes
|
|
// `(str | utf8.invalid)` by value) because the union-by-value path
|
|
// crashes — same lift-on-pass-by-value family as #48.
|
|
@test fn bytesub_cases() void = {
|
|
match (strings.bytesub("a string", 0, 8)) {
|
|
case let s: str => { assert(!(!streq(s, "a string"))); };
|
|
case let e: utf8.invalid => { abort(); };
|
|
};
|
|
match (strings.bytesub("a string", 0, 1)) {
|
|
case let s: str => { assert(!(!streq(s, "a"))); };
|
|
case let e: utf8.invalid => { abort(); };
|
|
};
|
|
match (strings.bytesub("a string", 0, 3)) {
|
|
case let s: str => { assert(!(!streq(s, "a s"))); };
|
|
case let e: utf8.invalid => { abort(); };
|
|
};
|
|
match (strings.bytesub("a string", 2, 8)) {
|
|
case let s: str => { assert(!(!streq(s, "string"))); };
|
|
case let e: utf8.invalid => { abort(); };
|
|
};
|
|
match (strings.bytesub("a string", 4, 4)) {
|
|
case let s: str => { assert(!(!streq(s, ""))); };
|
|
case let e: utf8.invalid => { abort(); };
|
|
};
|
|
// Hare vector — byte indices 3..9 over "こんにちは" select "んに".
|
|
match (strings.bytesub("こんにちは", 3, 9)) {
|
|
case let s: str => { assert(!(!streq(s, "んに"))); };
|
|
case let e: utf8.invalid => { abort(); };
|
|
};
|
|
// Rune/byte axis disagree on identical args (#3): sub(s,0,3) walks 3
|
|
// runes and yields 9 bytes; bytesub(s,0,3) yields the first 3 bytes
|
|
// — one 3-byte codepoint.
|
|
assert(!(!streq(strings.sub("こんにちは", 0, 3), "こんに")));
|
|
match (strings.bytesub("こんにちは", 0, 3)) {
|
|
case let s: str => { assert(!(!streq(s, "こ"))); };
|
|
case let e: utf8.invalid => { abort(); };
|
|
};
|
|
// Borrowed view: ptr aliases input.
|
|
let s: str = "hello";
|
|
match (strings.bytesub(s, 1, 4)) {
|
|
case let r: str => {
|
|
assert(!(r.ptr != s.ptr + 1u64));
|
|
assert(!(r.len != 3));
|
|
};
|
|
case let e: utf8.invalid => { abort(); };
|
|
};
|
|
// Hare's invalid row (ref/hare/strings/sub.ha:87) — start lands on
|
|
// a continuation byte (2nd byte of "こ"), bytesub must reject (#7).
|
|
match (strings.bytesub("こんにちは", 1, 3)) {
|
|
case let r: str => { abort(); };
|
|
case let e: utf8.invalid => void;
|
|
};
|
|
// Symmetric: end lands on a continuation byte (2nd byte of "ん").
|
|
match (strings.bytesub("こんにちは", 0, 4)) {
|
|
case let r: str => { abort(); };
|
|
case let e: utf8.invalid => void;
|
|
};
|
|
// end == s.len bypasses the continuation check (s[end] is OOB).
|
|
match (strings.bytesub("こんにちは", 0, 15)) {
|
|
case let s: str => { assert(!(!streq(s, "こんにちは"))); };
|
|
case let e: utf8.invalid => { abort(); };
|
|
};
|
|
};
|
|
|