strings: preserve UTF-8 and boundary invariants
This commit is contained in:
@@ -7,14 +7,13 @@ package strings_test;
|
||||
|
||||
import strings;
|
||||
import os;
|
||||
import encoding.utf8;
|
||||
import test;
|
||||
|
||||
// ref/hare/strings/pad.ha:23 (@test fn lpad), :54 (@test fn rpad). Hare's
|
||||
// row triple (s<maxlen, s==maxlen, s=="" empty) is mirrored; ww extras
|
||||
// pin s>maxlen (early return path), multibyte s with byte-length
|
||||
// counting, and multibyte pad rune (encoded width >1 byte). The
|
||||
// multibyte-pad rows pin Hare's `[..maxlen]` slice contract — a
|
||||
// multibyte trailing pad may be truncated mid-codepoint, exactly as
|
||||
// Hare does.
|
||||
// counting, and multibyte pad rune (encoded width >1 byte).
|
||||
|
||||
@test fn lpad_cases() void = {
|
||||
// Hare row 1: shorter s, ASCII pad.
|
||||
@@ -49,19 +48,26 @@ import os;
|
||||
os.free(r5.ptr: *void, r5.len: u64);
|
||||
|
||||
// ww row 3: multibyte pad rune. 'α' U+03B1 is 2 bytes (0xCE 0xB1).
|
||||
// s="x" (1 byte), maxlen=5 → npads = 5 - 1 = 4, pad_bytes=2,
|
||||
// total writes = 4*2 + 1 = 9 bytes; result `[..5]` = "αα" (4 bytes)
|
||||
// + 0xCE (truncated leading byte of next α) — exactly Hare's slice.
|
||||
// s="x" (1 byte), maxlen=5 leaves exactly two complete pad runes.
|
||||
let r6: str = strings.lpad("x", 0x03B1u32: rune, 5);
|
||||
assert(!(r6.len != 5));
|
||||
assert(!(r6.ptr[0] != 0xCEu8)); // α byte 0
|
||||
assert(!(r6.ptr[1] != 0xB1u8)); // α byte 1
|
||||
assert(!(r6.ptr[2] != 0xCEu8)); // α byte 0
|
||||
assert(!(r6.ptr[3] != 0xB1u8)); // α byte 1
|
||||
assert(!(r6.ptr[4] != 0xCEu8)); // truncated α byte 0
|
||||
assert(!(!streq(r6, "ααx")));
|
||||
match (utf8.validate(strings.toutf8(r6))) {
|
||||
case void => void;
|
||||
case utf8.invalid => abort();
|
||||
};
|
||||
os.free(r6.ptr: *void, r6.len: u64);
|
||||
};
|
||||
|
||||
@test fn lpad_split_rune_aborts() void = {
|
||||
test.expectabort();
|
||||
strings.lpad("x", 0x03B1u32: rune, 4);
|
||||
};
|
||||
|
||||
@test fn lpad_negative_length_aborts() void = {
|
||||
test.expectabort();
|
||||
strings.lpad("x", ' ', -1);
|
||||
};
|
||||
|
||||
@test fn rpad_cases() void = {
|
||||
// Hare row 1: shorter s, ASCII pad.
|
||||
let r1: str = strings.rpad("2", '0', 5);
|
||||
@@ -105,3 +111,7 @@ import os;
|
||||
os.free(r6.ptr: *void, r6.len: u64);
|
||||
};
|
||||
|
||||
@test fn rpad_split_rune_aborts() void = {
|
||||
test.expectabort();
|
||||
strings.rpad("x", 0x03B1u32: rune, 4);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user