lib/strings-core tests: hand-main plumbing -> assert (@test conversion B4)
bytes EXCLUDED: its green masked a real signalled corruption (filed; conversion rides the fix). stringstest documents the per-row signalled pinpoint loss.
This commit is contained in:
@@ -1,79 +1,73 @@
|
|||||||
// asciitest — exercises lib/ascii case folding. Run with
|
// asciitest — exercises lib/ascii case folding. Run with
|
||||||
// `ww run lib/ascii/asciitest.ww`. Same signalled-then-fail()-with-+10
|
// `ww run lib/ascii/asciitest.ww`. A failing row aborts via the
|
||||||
// pattern as bytestest: a non-zero exit pinpoints the failing scenario.
|
// assert/abort builtin (task #5 @test conversion).
|
||||||
//
|
//
|
||||||
// Vectors mirror Hare's @test fn strcasecmp in ref/hare/ascii/string.ha.
|
// Vectors mirror Hare's @test fn strcasecmp in ref/hare/ascii/string.ha.
|
||||||
|
|
||||||
package ascii_test;
|
package ascii_test;
|
||||||
|
|
||||||
import ascii;
|
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.
|
// checkfold — one table row: strlower(in) == lo and strupper(in) == up.
|
||||||
fn checkfold(in: str, lo: str, up: str) void = {
|
fn checkfold(in: str, lo: str, up: str) void = {
|
||||||
match (ascii.strlower(in)) {
|
match (ascii.strlower(in)) {
|
||||||
case let got: str => { if (got != lo) { fail(); }; };
|
case let got: str => { assert(!(got != lo)); };
|
||||||
case nomem => { fail(); };
|
case nomem => { abort(); };
|
||||||
};
|
};
|
||||||
match (ascii.strupper(in)) {
|
match (ascii.strupper(in)) {
|
||||||
case let got: str => { if (got != up) { fail(); }; };
|
case let got: str => { assert(!(got != up)); };
|
||||||
case nomem => { fail(); };
|
case nomem => { abort(); };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// ref/hare/ascii/string.ha:70 case-fold vectors. The こ row pins that a
|
// ref/hare/ascii/string.ha:70 case-fold vectors. The こ row pins that a
|
||||||
// UTF-8 multibyte sequence (all bytes >=0x80) passes through unchanged.
|
// UTF-8 multibyte sequence (all bytes >=0x80) passes through unchanged.
|
||||||
@test fn strfold_cases() void = {
|
@test fn strfold_cases() void = {
|
||||||
signalled = 100; checkfold("ABC", "abc", "ABC");
|
checkfold("ABC", "abc", "ABC");
|
||||||
signalled = 101; checkfold("abc", "abc", "ABC");
|
checkfold("abc", "abc", "ABC");
|
||||||
signalled = 102; checkfold("[[[", "[[[", "[[[");
|
checkfold("[[[", "[[[", "[[[");
|
||||||
signalled = 103; checkfold("こ", "こ", "こ");
|
checkfold("こ", "こ", "こ");
|
||||||
signalled = 104; checkfold("", "", "");
|
checkfold("", "", "");
|
||||||
signalled = 105; checkfold("aB1z", "ab1z", "AB1Z");
|
checkfold("aB1z", "ab1z", "AB1Z");
|
||||||
};
|
};
|
||||||
|
|
||||||
// checkbuf — strlower_buf/strupper_buf into an exactly-sized buf.
|
// checkbuf — strlower_buf/strupper_buf into an exactly-sized buf.
|
||||||
fn checkbuf(in: str, lo: str, up: str) void = {
|
fn checkbuf(in: str, lo: str, up: str) void = {
|
||||||
let lstore: [16]u8; let lbuf: []u8 = lstore[0:16]; lbuf.len = 0;
|
let lstore: [16]u8; let lbuf: []u8 = lstore[0:16]; lbuf.len = 0;
|
||||||
match (ascii.strlower_buf(in, lbuf)) {
|
match (ascii.strlower_buf(in, lbuf)) {
|
||||||
case let got: str => { if (got != lo) { fail(); }; };
|
case let got: str => { assert(!(got != lo)); };
|
||||||
case nomem => { fail(); };
|
case nomem => { abort(); };
|
||||||
};
|
};
|
||||||
let ustore: [16]u8; let ubuf: []u8 = ustore[0:16]; ubuf.len = 0;
|
let ustore: [16]u8; let ubuf: []u8 = ustore[0:16]; ubuf.len = 0;
|
||||||
match (ascii.strupper_buf(in, ubuf)) {
|
match (ascii.strupper_buf(in, ubuf)) {
|
||||||
case let got: str => { if (got != up) { fail(); }; };
|
case let got: str => { assert(!(got != up)); };
|
||||||
case nomem => { fail(); };
|
case nomem => { abort(); };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@test fn strfold_buf_cases() void = {
|
@test fn strfold_buf_cases() void = {
|
||||||
signalled = 110; checkbuf("ABC", "abc", "ABC");
|
checkbuf("ABC", "abc", "ABC");
|
||||||
signalled = 111; checkbuf("aB1z", "ab1z", "AB1Z");
|
checkbuf("aB1z", "ab1z", "AB1Z");
|
||||||
signalled = 112; checkbuf("", "", "");
|
checkbuf("", "", "");
|
||||||
// non-ASCII pins UTF-8 multibyte passthrough through the _buf path
|
// non-ASCII pins UTF-8 multibyte passthrough through the _buf path
|
||||||
// directly (all bytes >=0x80, untouched by the byte-wise fold).
|
// directly (all bytes >=0x80, untouched by the byte-wise fold).
|
||||||
signalled = 113; checkbuf("こ", "こ", "こ");
|
checkbuf("こ", "こ", "こ");
|
||||||
// cap exactly == s.len must succeed — pins the `<` boundary in the
|
// cap exactly == s.len must succeed — pins the `<` boundary in the
|
||||||
// buf.cap check (a `<=` off-by-one would wrongly return nomem here).
|
// 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;
|
let exact: [3]u8; let ebuf: []u8 = exact[0:3]; ebuf.len = 0;
|
||||||
match (ascii.strlower_buf("ABC", ebuf)) {
|
match (ascii.strlower_buf("ABC", ebuf)) {
|
||||||
case let got: str => { if (got != "abc") { fail(); }; };
|
case let got: str => { assert(!(got != "abc")); };
|
||||||
case nomem => { fail(); };
|
case nomem => { abort(); };
|
||||||
};
|
};
|
||||||
signalled = 115;
|
|
||||||
let small: [2]u8; let sbuf: []u8 = small[0:2]; sbuf.len = 0;
|
let small: [2]u8; let sbuf: []u8 = small[0:2]; sbuf.len = 0;
|
||||||
match (ascii.strlower_buf("ABC", sbuf)) {
|
match (ascii.strlower_buf("ABC", sbuf)) {
|
||||||
case let got: str => { fail(); };
|
case let got: str => { abort(); };
|
||||||
case nomem => void;
|
case nomem => void;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn main() i32 = {
|
export fn main() i32 = {
|
||||||
signalled = 1; strfold_cases();
|
strfold_cases();
|
||||||
signalled = 2; strfold_buf_cases();
|
strfold_buf_cases();
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,33 +8,19 @@
|
|||||||
// byte-wise and those would match byte-identically but obscure the
|
// byte-wise and those would match byte-identically but obscure the
|
||||||
// ASCII semantics the test is asserting.
|
// ASCII semantics the test is asserting.
|
||||||
//
|
//
|
||||||
// Failure path: each @test fn bumps `signalled` to its slot index,
|
// Failure path: a miscompare aborts via the assert/abort builtin
|
||||||
// `check` does `exit(signalled + 10)` on miscompare so the harness
|
// (task #5 @test conversion).
|
||||||
// reports `WEXITSTATUS = 11..N` pointing at the failing scenario.
|
|
||||||
// Same convention as lib/log/logtest.
|
|
||||||
|
|
||||||
package fnmatch_test;
|
package fnmatch_test;
|
||||||
|
|
||||||
import fnmatch;
|
import fnmatch;
|
||||||
|
|
||||||
// Direct rt_syscall binding rather than `use os;` — os exports
|
|
||||||
// read/write/close, which collide with io.read/write/close under the
|
|
||||||
// driver's flat-scope concat. Mirrors logtest / fmttest / bufiotest.
|
|
||||||
@symbol("rt_syscall") fn syscall1ww(num: i64, a: i64) i64;
|
|
||||||
fn doexit(code: i32) void = {
|
|
||||||
syscall1ww(60i64, code: i64);
|
|
||||||
};
|
|
||||||
|
|
||||||
let signalled: i32 = 0;
|
|
||||||
|
|
||||||
fn fail() void = { doexit(signalled + 10); };
|
|
||||||
|
|
||||||
// check — pin one row. `flags` is taken as i32 and cast to
|
// check — pin one row. `flags` is taken as i32 and cast to
|
||||||
// fnmatch.flag so the test rows can read as integer bitmasks
|
// fnmatch.flag so the test rows can read as integer bitmasks
|
||||||
// without dragging enum literals into every line.
|
// without dragging enum literals into every line.
|
||||||
fn check(pat: str, s: str, expected: bool, flags: i32) void = {
|
fn check(pat: str, s: str, expected: bool, flags: i32) void = {
|
||||||
let f: fnmatch.flag = flags as fnmatch.flag;
|
let f: fnmatch.flag = flags as fnmatch.flag;
|
||||||
if (fnmatch.fnmatch(pat, s, f) != expected) { fail(); };
|
assert(!(fnmatch.fnmatch(pat, s, f) != expected));
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---- basic literal / wildcard cases ---------------------------------
|
// ---- basic literal / wildcard cases ---------------------------------
|
||||||
@@ -263,13 +249,13 @@ fn check(pat: str, s: str, expected: bool, flags: i32) void = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export fn main() i32 = {
|
export fn main() i32 = {
|
||||||
signalled = 1; basic();
|
basic();
|
||||||
signalled = 2; brackets();
|
brackets();
|
||||||
signalled = 3; ctype();
|
ctype();
|
||||||
signalled = 4; period();
|
period();
|
||||||
signalled = 5; noescape();
|
noescape();
|
||||||
signalled = 6; musl_basic();
|
musl_basic();
|
||||||
signalled = 7; pathname();
|
pathname();
|
||||||
signalled = 8; combined();
|
combined();
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,10 +15,8 @@
|
|||||||
// shape against a memio.dynamic sink, mirroring Hare's escape.ha
|
// shape against a memio.dynamic sink, mirroring Hare's escape.ha
|
||||||
// testquote table.
|
// testquote table.
|
||||||
//
|
//
|
||||||
// Failure path: each @test fn bumps `signalled` to its slot index,
|
// Failure path: a miscompare aborts via the assert/abort builtin
|
||||||
// the helpers do `exit(signalled + 10)` on miscompare so the harness
|
// (task #5 @test conversion).
|
||||||
// reports `WEXITSTATUS = 11..N` pointing at the failing scenario.
|
|
||||||
// Same convention as fnmatchtest / logtest.
|
|
||||||
|
|
||||||
package shlex_test;
|
package shlex_test;
|
||||||
|
|
||||||
@@ -26,19 +24,6 @@ import shlex;
|
|||||||
import io;
|
import io;
|
||||||
import memio;
|
import memio;
|
||||||
|
|
||||||
// Direct rt_syscall binding rather than `use os;` — os exports
|
|
||||||
// read/write/close, which collide with io.read/write/close under the
|
|
||||||
// driver's flat-scope concat. Mirrors fnmatchtest / logtest / fmttest
|
|
||||||
// / bufiotest.
|
|
||||||
@symbol("rt_syscall") fn syscall1ww(num: i64, a: i64) i64;
|
|
||||||
fn doexit(code: i32) void = {
|
|
||||||
syscall1ww(60i64, code: i64);
|
|
||||||
};
|
|
||||||
|
|
||||||
let signalled: i32 = 0;
|
|
||||||
|
|
||||||
fn fail() void = { doexit(signalled + 10); };
|
|
||||||
|
|
||||||
fn streq(a: str, b: str) bool = {
|
fn streq(a: str, b: str) bool = {
|
||||||
if (a.len != b.len) { return false; };
|
if (a.len != b.len) { return false; };
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
@@ -56,10 +41,10 @@ fn streq(a: str, b: str) bool = {
|
|||||||
fn check1(in: str, e0: str) void = {
|
fn check1(in: str, e0: str) void = {
|
||||||
let r = shlex.split(in);
|
let r = shlex.split(in);
|
||||||
match (r) {
|
match (r) {
|
||||||
case shlex.syntaxerr => { fail(); };
|
case shlex.syntaxerr => { abort(); };
|
||||||
case let s: []str => {
|
case let s: []str => {
|
||||||
if (s.len != 1) { fail(); };
|
assert(!(s.len != 1));
|
||||||
if (!streq(s[0], e0)) { fail(); };
|
assert(!(!streq(s[0], e0)));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -67,11 +52,11 @@ fn check1(in: str, e0: str) void = {
|
|||||||
fn check2(in: str, e0: str, e1: str) void = {
|
fn check2(in: str, e0: str, e1: str) void = {
|
||||||
let r = shlex.split(in);
|
let r = shlex.split(in);
|
||||||
match (r) {
|
match (r) {
|
||||||
case shlex.syntaxerr => { fail(); };
|
case shlex.syntaxerr => { abort(); };
|
||||||
case let s: []str => {
|
case let s: []str => {
|
||||||
if (s.len != 2) { fail(); };
|
assert(!(s.len != 2));
|
||||||
if (!streq(s[0], e0)) { fail(); };
|
assert(!(!streq(s[0], e0)));
|
||||||
if (!streq(s[1], e1)) { fail(); };
|
assert(!(!streq(s[1], e1)));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -79,12 +64,12 @@ fn check2(in: str, e0: str, e1: str) void = {
|
|||||||
fn check3(in: str, e0: str, e1: str, e2: str) void = {
|
fn check3(in: str, e0: str, e1: str, e2: str) void = {
|
||||||
let r = shlex.split(in);
|
let r = shlex.split(in);
|
||||||
match (r) {
|
match (r) {
|
||||||
case shlex.syntaxerr => { fail(); };
|
case shlex.syntaxerr => { abort(); };
|
||||||
case let s: []str => {
|
case let s: []str => {
|
||||||
if (s.len != 3) { fail(); };
|
assert(!(s.len != 3));
|
||||||
if (!streq(s[0], e0)) { fail(); };
|
assert(!(!streq(s[0], e0)));
|
||||||
if (!streq(s[1], e1)) { fail(); };
|
assert(!(!streq(s[1], e1)));
|
||||||
if (!streq(s[2], e2)) { fail(); };
|
assert(!(!streq(s[2], e2)));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -93,16 +78,16 @@ fn checkerr(in: str) void = {
|
|||||||
let r = shlex.split(in);
|
let r = shlex.split(in);
|
||||||
match (r) {
|
match (r) {
|
||||||
case shlex.syntaxerr => {};
|
case shlex.syntaxerr => {};
|
||||||
case let s: []str => { fail(); };
|
case let s: []str => { abort(); };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fn checkempty(in: str) void = {
|
fn checkempty(in: str) void = {
|
||||||
let r = shlex.split(in);
|
let r = shlex.split(in);
|
||||||
match (r) {
|
match (r) {
|
||||||
case shlex.syntaxerr => { fail(); };
|
case shlex.syntaxerr => { abort(); };
|
||||||
case let s: []str => {
|
case let s: []str => {
|
||||||
if (s.len != 0) { fail(); };
|
assert(!(s.len != 0));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -115,12 +100,12 @@ fn checkquote(in: str, expected: str) void = {
|
|||||||
let n: size = 0;
|
let n: size = 0;
|
||||||
match (r) {
|
match (r) {
|
||||||
case let v: size => { n = v; };
|
case let v: size => { n = v; };
|
||||||
case let _e: io.error => { fail(); };
|
case let _e: io.error => { abort(); };
|
||||||
};
|
};
|
||||||
if (n != expected.len: size) { fail(); };
|
assert(!(n != expected.len: size));
|
||||||
|
|
||||||
let view: str = memio.string(&st);
|
let view: str = memio.string(&st);
|
||||||
if (!streq(view, expected)) { fail(); };
|
assert(!(!streq(view, expected)));
|
||||||
|
|
||||||
let _c: (void | io.error) = io.close(snk);
|
let _c: (void | io.error) = io.close(snk);
|
||||||
};
|
};
|
||||||
@@ -182,7 +167,7 @@ fn checkquote(in: str, expected: str) void = {
|
|||||||
|
|
||||||
@test fn test_quotestr() void = {
|
@test fn test_quotestr() void = {
|
||||||
let r: str = shlex.quotestr("hello world");
|
let r: str = shlex.quotestr("hello world");
|
||||||
if (!streq(r, "'hello world'")) { fail(); };
|
assert(!(!streq(r, "'hello world'")));
|
||||||
// leak r — short-lived test process, same precedent as fnmatchtest.
|
// leak r — short-lived test process, same precedent as fnmatchtest.
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -191,13 +176,13 @@ fn checkquote(in: str, expected: str) void = {
|
|||||||
@test fn test_strerror() void = {
|
@test fn test_strerror() void = {
|
||||||
let e: shlex.syntaxerr;
|
let e: shlex.syntaxerr;
|
||||||
let s: str = shlex.strerror(e);
|
let s: str = shlex.strerror(e);
|
||||||
if (!streq(s, "Invalid shell syntax")) { fail(); };
|
assert(!(!streq(s, "Invalid shell syntax")));
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn main() i32 = {
|
export fn main() i32 = {
|
||||||
signalled = 1; test_split();
|
test_split();
|
||||||
signalled = 2; test_quote();
|
test_quote();
|
||||||
signalled = 3; test_quotestr();
|
test_quotestr();
|
||||||
signalled = 4; test_strerror();
|
test_strerror();
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user