strings: preserve UTF-8 and boundary invariants

This commit is contained in:
2026-08-09 17:46:22 +09:00
parent 2d947c469e
commit 8e2e6ae162
7 changed files with 124 additions and 61 deletions

View File

@@ -7,6 +7,7 @@ package strings_test;
import strings;
import os;
import test;
// ref/hare/strings/tokenize.ha:110 @test fn tokenize. Row drivers
// mirror lib/bytes/bytestest expect_token / expect_done but compare
@@ -171,6 +172,7 @@ fn expect_str(toks: []str, i: i32, want: str) void = {
assert(!(i >= toks.len));
let p: *str = &toks.ptr[i];
assert(!(p.len != want.len));
assert(!(p.cap != p.len));
let j: i32 = 0;
for (j < want.len) {
assert(!(p.ptr[j] != want[j]));
@@ -218,6 +220,14 @@ fn expect_str(toks: []str, i: i32, want: str) void = {
expect_str(t5, 2, "foo");
expect_str(t5, 3, "bar");
os.free(t5.ptr: *void, (t5.cap: u64) * size(str): u64);
let t6: []str = strings.splitn("a b", " ", 0);
assert(!(t6.len != 0 || t6.cap != 0));
};
@test fn splitn_negative_aborts() void = {
test.expectabort();
strings.splitn("a b", " ", -1);
};
@test fn rsplitn_cases() void = {
@@ -231,15 +241,12 @@ fn expect_str(toks: []str, i: i32, want: str) void = {
expect_str(t1, 3, "Drew");
os.free(t1.ptr: *void, (t1.cap: u64) * size(str): u64);
// n > token count — done short-circuit returns toks UN-reversed
// (last-token-first order). Mirrors bytes.rsplitn (Hare's
// ref/hare/strings/tokenize.ha:219-224 reverse step is gated
// behind the n-1 loop completion).
// n > token count still returns input order.
let t2: []str = strings.rsplitn("a b c", " ", 10);
assert(!(t2.len != 3));
expect_str(t2, 0, "c");
expect_str(t2, 0, "a");
expect_str(t2, 1, "b");
expect_str(t2, 2, "a");
expect_str(t2, 2, "c");
os.free(t2.ptr: *void, (t2.cap: u64) * size(str): u64);
// n == 1 — single slot holding the whole input as remainder.
@@ -255,6 +262,14 @@ fn expect_str(toks: []str, i: i32, want: str) void = {
assert(!(t4.len != 1));
expect_str(t4, 0, "abc");
os.free(t4.ptr: *void, (t4.cap: u64) * size(str): u64);
let t5: []str = strings.rsplitn("a b", " ", 0);
assert(!(t5.len != 0 || t5.cap != 0));
};
@test fn rsplitn_negative_aborts() void = {
test.expectabort();
strings.rsplitn("a b", " ", -1);
};
@test fn split_cases() void = {