// Vectors mirror ref/hare/strings/pad.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; import encoding.utf8; import test; // ref/hare/strings/pad.ha:23 (@test fn lpad), :54 (@test fn rpad). Hare's // row triple (smaxlen (early return path), multibyte s with byte-length // counting, and multibyte pad rune (encoded width >1 byte). @test fn lpad_cases() void = { // Hare row 1: shorter s, ASCII pad. let r1: str = strings.lpad("2", '0', 5); assert(!(!streq(r1, "00002"))); assert(!(r1.len != 5)); os.free(r1.ptr: *void, r1.len: u64); // Hare row 2: s.len == maxlen — early dup path. let r2: str = strings.lpad("12345", '0', 5); assert(!(!streq(r2, "12345"))); assert(!(r2.len != 5)); os.free(r2.ptr: *void, r2.len: u64); // Hare row 3: empty s, full-width pad. let r3: str = strings.lpad("", '0', 5); assert(!(!streq(r3, "00000"))); assert(!(r3.len != 5)); os.free(r3.ptr: *void, r3.len: u64); // ww row 1: s.len > maxlen — early dup path returns input copy. let r4: str = strings.lpad("abcdef", '_', 3); assert(!(!streq(r4, "abcdef"))); assert(!(r4.len != 6)); 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. let r5: str = strings.lpad("café", '_', 7); assert(!(!streq(r5, "__café"))); assert(!(r5.len != 7)); 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 leaves exactly two complete pad runes. let r6: str = strings.lpad("x", 0x03B1u32: rune, 5); 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); assert(!(!streq(r1, "20000"))); assert(!(r1.len != 5)); os.free(r1.ptr: *void, r1.len: u64); // Hare row 2: s.len == maxlen — early dup path. let r2: str = strings.rpad("12345", '0', 5); assert(!(!streq(r2, "12345"))); assert(!(r2.len != 5)); os.free(r2.ptr: *void, r2.len: u64); // Hare row 3: empty s. let r3: str = strings.rpad("", '0', 5); assert(!(!streq(r3, "00000"))); assert(!(r3.len != 5)); os.free(r3.ptr: *void, r3.len: u64); // ww row 1: s.len > maxlen — early dup path. let r4: str = strings.rpad("abcdef", '_', 3); assert(!(!streq(r4, "abcdef"))); assert(!(r4.len != 6)); os.free(r4.ptr: *void, r4.len: u64); // ww row 2: multibyte s — byte-length contract. let r5: str = strings.rpad("café", '_', 7); assert(!(!streq(r5, "café__"))); assert(!(r5.len != 7)); 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). let r6: str = strings.rpad("x", 0x03B1u32: rune, 5); assert(!(r6.len != 5)); assert(!(r6.ptr[0] != 'x')); assert(!(r6.ptr[1] != 0xCEu8)); // α byte 0 assert(!(r6.ptr[2] != 0xB1u8)); // α byte 1 assert(!(r6.ptr[3] != 0xCEu8)); // α byte 0 assert(!(r6.ptr[4] != 0xB1u8)); // α byte 1 os.free(r6.ptr: *void, r6.len: u64); }; @test fn rpad_split_rune_aborts() void = { test.expectabort(); strings.rpad("x", 0x03B1u32: rune, 4); };