Files
ww/lib/ascii/asciitest.ww
Hojun-Cho 99e3393048 lib/test: Go external-test packages (<mod>_test); retire decimaltest (#16 PREP-a)
30 lib test files: package <mod> -> <mod>_test, the sanctioned Go-over-Hare
departure (CLAUDE.md rule-9 carve-out; white-box testing deferred, not
forbidden). decimaltest retired per .ai/rob-16-decimaltest-ruling.md: Hare
ships no decimal_test.ha (engine covered transitively); coverage migrated
losslessly into stoftest rows (all-9s carry, nd>19 pure-decimal) + ftostest
f64_roundtrip mirroring ref/hare strconv ftos_test.ha tcsf64; k=0 micro-gap
documented at site. regex_test keeps its white-box internal probes under a
documented rule-7 divergence (rehome = task #9). 922_decimal_run + its 989
byte-id row removed with the fixture.
2026-06-10 12:11:11 +09:00

80 lines
2.7 KiB
Plaintext

// asciitest — exercises lib/ascii case folding. Run with
// `ww run lib/ascii/asciitest.ww`. Same signalled-then-fail()-with-+10
// pattern as bytestest: a non-zero exit pinpoints the failing scenario.
//
// Vectors mirror Hare's @test fn strcasecmp in ref/hare/ascii/string.ha.
package ascii_test;
import ascii;
import os;
let signalled: i32 = 0;
fn fail() void = { os.exit(signalled + 10); };
// checkfold — one table row: strlower(in) == lo and strupper(in) == up.
fn checkfold(in: str, lo: str, up: str) void = {
match (ascii.strlower(in)) {
case let got: str => { if (got != lo) { fail(); }; };
case nomem => { fail(); };
};
match (ascii.strupper(in)) {
case let got: str => { if (got != up) { fail(); }; };
case nomem => { fail(); };
};
};
// ref/hare/ascii/string.ha:70 case-fold vectors. The こ row pins that a
// UTF-8 multibyte sequence (all bytes >=0x80) passes through unchanged.
@test fn strfold_cases() void = {
signalled = 100; checkfold("ABC", "abc", "ABC");
signalled = 101; checkfold("abc", "abc", "ABC");
signalled = 102; checkfold("[[[", "[[[", "[[[");
signalled = 103; checkfold("こ", "こ", "こ");
signalled = 104; checkfold("", "", "");
signalled = 105; checkfold("aB1z", "ab1z", "AB1Z");
};
// checkbuf — strlower_buf/strupper_buf into an exactly-sized buf.
fn checkbuf(in: str, lo: str, up: str) void = {
let lstore: [16]u8; let lbuf: []u8 = lstore[0:16]; lbuf.len = 0;
match (ascii.strlower_buf(in, lbuf)) {
case let got: str => { if (got != lo) { fail(); }; };
case nomem => { fail(); };
};
let ustore: [16]u8; let ubuf: []u8 = ustore[0:16]; ubuf.len = 0;
match (ascii.strupper_buf(in, ubuf)) {
case let got: str => { if (got != up) { fail(); }; };
case nomem => { fail(); };
};
};
@test fn strfold_buf_cases() void = {
signalled = 110; checkbuf("ABC", "abc", "ABC");
signalled = 111; checkbuf("aB1z", "ab1z", "AB1Z");
signalled = 112; checkbuf("", "", "");
// non-ASCII pins UTF-8 multibyte passthrough through the _buf path
// directly (all bytes >=0x80, untouched by the byte-wise fold).
signalled = 113; checkbuf("こ", "こ", "こ");
// cap exactly == s.len must succeed — pins the `<` boundary in the
// buf.cap check (a `<=` off-by-one would wrongly return nomem here).
signalled = 114;
let exact: [3]u8; let ebuf: []u8 = exact[0:3]; ebuf.len = 0;
match (ascii.strlower_buf("ABC", ebuf)) {
case let got: str => { if (got != "abc") { fail(); }; };
case nomem => { fail(); };
};
signalled = 115;
let small: [2]u8; let sbuf: []u8 = small[0:2]; sbuf.len = 0;
match (ascii.strlower_buf("ABC", sbuf)) {
case let got: str => { fail(); };
case nomem => void;
};
};
export fn main() i32 = {
signalled = 1; strfold_cases();
signalled = 2; strfold_buf_cases();
return 0;
};