lib/strings+test: port lpad/rpad from Hare
This commit is contained in:
@@ -1204,6 +1204,116 @@ fn expect_str(toks: []str, i: i32, want: str) void = {
|
||||
os.free(t3.ptr: *void, (t3.cap: u64) * 16u64);
|
||||
};
|
||||
|
||||
// ---- lpad / rpad -----------------------------------------------------
|
||||
// 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.
|
||||
|
||||
@test fn lpad_cases() void = {
|
||||
// Hare row 1: shorter s, ASCII pad.
|
||||
signalled = 1770;
|
||||
let r1: str = strings.lpad("2", '0', 5);
|
||||
if (!streq(r1, "00002")) { fail(); };
|
||||
if (r1.len != 5) { fail(); };
|
||||
os.free(r1.ptr: *void, r1.len: u64);
|
||||
|
||||
// Hare row 2: s.len == maxlen — early dup path.
|
||||
signalled = 1771;
|
||||
let r2: str = strings.lpad("12345", '0', 5);
|
||||
if (!streq(r2, "12345")) { fail(); };
|
||||
if (r2.len != 5) { fail(); };
|
||||
os.free(r2.ptr: *void, r2.len: u64);
|
||||
|
||||
// Hare row 3: empty s, full-width pad.
|
||||
signalled = 1772;
|
||||
let r3: str = strings.lpad("", '0', 5);
|
||||
if (!streq(r3, "00000")) { fail(); };
|
||||
if (r3.len != 5) { fail(); };
|
||||
os.free(r3.ptr: *void, r3.len: u64);
|
||||
|
||||
// ww row 1: s.len > maxlen — early dup path returns input copy.
|
||||
signalled = 1773;
|
||||
let r4: str = strings.lpad("abcdef", '_', 3);
|
||||
if (!streq(r4, "abcdef")) { fail(); };
|
||||
if (r4.len != 6) { fail(); };
|
||||
os.free(r4.ptr: *void, r4.len: u64);
|
||||
|
||||
// ww row 2: multibyte s — byte-length contract (Hare `len(s)`).
|
||||
// "café" is 5 bytes; maxlen 7 → 2 pad bytes prepended.
|
||||
signalled = 1774;
|
||||
let r5: str = strings.lpad("café", '_', 7);
|
||||
if (!streq(r5, "__café")) { fail(); };
|
||||
if (r5.len != 7) { fail(); };
|
||||
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.
|
||||
signalled = 1775;
|
||||
let r6: str = strings.lpad("x", 0x03B1u32: rune, 5);
|
||||
if (r6.len != 5) { fail(); };
|
||||
if (r6.ptr[0] != 0xCEu8) { fail(); }; // α byte 0
|
||||
if (r6.ptr[1] != 0xB1u8) { fail(); }; // α byte 1
|
||||
if (r6.ptr[2] != 0xCEu8) { fail(); }; // α byte 0
|
||||
if (r6.ptr[3] != 0xB1u8) { fail(); }; // α byte 1
|
||||
if (r6.ptr[4] != 0xCEu8) { fail(); }; // truncated α byte 0
|
||||
os.free(r6.ptr: *void, r6.len: u64);
|
||||
};
|
||||
|
||||
@test fn rpad_cases() void = {
|
||||
// Hare row 1: shorter s, ASCII pad.
|
||||
signalled = 1780;
|
||||
let r1: str = strings.rpad("2", '0', 5);
|
||||
if (!streq(r1, "20000")) { fail(); };
|
||||
if (r1.len != 5) { fail(); };
|
||||
os.free(r1.ptr: *void, r1.len: u64);
|
||||
|
||||
// Hare row 2: s.len == maxlen — early dup path.
|
||||
signalled = 1781;
|
||||
let r2: str = strings.rpad("12345", '0', 5);
|
||||
if (!streq(r2, "12345")) { fail(); };
|
||||
if (r2.len != 5) { fail(); };
|
||||
os.free(r2.ptr: *void, r2.len: u64);
|
||||
|
||||
// Hare row 3: empty s.
|
||||
signalled = 1782;
|
||||
let r3: str = strings.rpad("", '0', 5);
|
||||
if (!streq(r3, "00000")) { fail(); };
|
||||
if (r3.len != 5) { fail(); };
|
||||
os.free(r3.ptr: *void, r3.len: u64);
|
||||
|
||||
// ww row 1: s.len > maxlen — early dup path.
|
||||
signalled = 1783;
|
||||
let r4: str = strings.rpad("abcdef", '_', 3);
|
||||
if (!streq(r4, "abcdef")) { fail(); };
|
||||
if (r4.len != 6) { fail(); };
|
||||
os.free(r4.ptr: *void, r4.len: u64);
|
||||
|
||||
// ww row 2: multibyte s — byte-length contract.
|
||||
signalled = 1784;
|
||||
let r5: str = strings.rpad("café", '_', 7);
|
||||
if (!streq(r5, "café__")) { fail(); };
|
||||
if (r5.len != 7) { fail(); };
|
||||
os.free(r5.ptr: *void, r5.len: u64);
|
||||
|
||||
// ww row 3: multibyte pad rune (2-byte 'α'). s="x" (1 byte),
|
||||
// maxlen=5 → "xαα" appended is 1 + 4 = 5 bytes (no truncation).
|
||||
signalled = 1785;
|
||||
let r6: str = strings.rpad("x", 0x03B1u32: rune, 5);
|
||||
if (r6.len != 5) { fail(); };
|
||||
if (r6.ptr[0] != 'x') { fail(); };
|
||||
if (r6.ptr[1] != 0xCEu8) { fail(); }; // α byte 0
|
||||
if (r6.ptr[2] != 0xB1u8) { fail(); }; // α byte 1
|
||||
if (r6.ptr[3] != 0xCEu8) { fail(); }; // α byte 0
|
||||
if (r6.ptr[4] != 0xB1u8) { fail(); }; // α byte 1
|
||||
os.free(r6.ptr: *void, r6.len: u64);
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
signalled = 1; dup_cases();
|
||||
signalled = 2; concat_cases();
|
||||
@@ -1242,5 +1352,7 @@ export fn main() i32 = {
|
||||
signalled = 35; splitn_cases();
|
||||
signalled = 36; rsplitn_cases();
|
||||
signalled = 37; split_cases();
|
||||
signalled = 38; lpad_cases();
|
||||
signalled = 39; rpad_cases();
|
||||
return 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user