Files
ww/lib/strings/pad_test.ww

118 lines
3.8 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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 (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).
@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);
};