lib: migrate every test file to the canonical *_test.ww name
25 renames (git mv, content untouched). _test.ww is what the package coordinator's test detection and the sep loader's canonical exclusion key on; the old *test.ww spellings survived only through the line-leading-@test compatibility scan. Consumers updated in place: LIBRARY_TESTS, the libbyteid roster, the 901/974/975/976 carriers that copy or invoke these files, and the check.c/check.ww + path/ftos comments that cite them. Closes the open-driver-work migration bullet.
This commit is contained in:
180
lib/shlex/shlex_test.ww
Normal file
180
lib/shlex/shlex_test.ww
Normal file
@@ -0,0 +1,180 @@
|
||||
// shlextest — exercises lib/shlex. Run with
|
||||
// `out/bin/ww run lib/shlex/shlextest.ww`.
|
||||
//
|
||||
// Two cohorts, grouped Hare-style — one @test fn per cohort, table-
|
||||
// driven inside via per-arity helpers:
|
||||
//
|
||||
// • split rows go through [[check1]] / [[check2]] / [[check3]] /
|
||||
// [[checkerr]]. Inputs are lifted from ref/hare/shlex/+test.ha
|
||||
// @test fn split() (the de-facto spec for this port). Per-row
|
||||
// arity is fixed (1, 2, or 3 expected tokens across the Hare
|
||||
// cases), so we ship per-arity helpers rather than a full
|
||||
// variadic check that would obscure the row data.
|
||||
//
|
||||
// • quote rows go through [[checkquote]] — uniform (input, expected)
|
||||
// shape against a memio.dynamic sink, mirroring Hare's escape.ha
|
||||
// testquote table.
|
||||
//
|
||||
// Failure path: a miscompare aborts via the assert/abort builtin
|
||||
// (task #5 @test conversion).
|
||||
|
||||
package shlex_test;
|
||||
|
||||
import shlex;
|
||||
import io;
|
||||
import memio;
|
||||
|
||||
fn streq(a: str, b: str) bool = {
|
||||
if (a.len != b.len) { return false; };
|
||||
let i: i32 = 0;
|
||||
for (i < a.len) {
|
||||
if (a[i] != b[i]) { return false; };
|
||||
i += 1;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
// checkN — split `in` and assert the result is a slice of length N
|
||||
// matching the named expected tokens. Leaks the result (test process
|
||||
// is short-lived; same precedent as fnmatchtest).
|
||||
|
||||
fn check1(in: str, e0: str) void = {
|
||||
let r = shlex.split(in);
|
||||
match (r) {
|
||||
case shlex.syntaxerr => { abort(); };
|
||||
case let s: []str => {
|
||||
assert(!(s.len != 1));
|
||||
assert(!(!streq(s[0], e0)));
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fn check2(in: str, e0: str, e1: str) void = {
|
||||
let r = shlex.split(in);
|
||||
match (r) {
|
||||
case shlex.syntaxerr => { abort(); };
|
||||
case let s: []str => {
|
||||
assert(!(s.len != 2));
|
||||
assert(!(!streq(s[0], e0)));
|
||||
assert(!(!streq(s[1], e1)));
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fn check3(in: str, e0: str, e1: str, e2: str) void = {
|
||||
let r = shlex.split(in);
|
||||
match (r) {
|
||||
case shlex.syntaxerr => { abort(); };
|
||||
case let s: []str => {
|
||||
assert(!(s.len != 3));
|
||||
assert(!(!streq(s[0], e0)));
|
||||
assert(!(!streq(s[1], e1)));
|
||||
assert(!(!streq(s[2], e2)));
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fn checkerr(in: str) void = {
|
||||
let r = shlex.split(in);
|
||||
match (r) {
|
||||
case shlex.syntaxerr => {};
|
||||
case let s: []str => { abort(); };
|
||||
};
|
||||
};
|
||||
|
||||
fn checkempty(in: str) void = {
|
||||
let r = shlex.split(in);
|
||||
match (r) {
|
||||
case shlex.syntaxerr => { abort(); };
|
||||
case let s: []str => {
|
||||
assert(!(s.len != 0));
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fn checkquote(in: str, expected: str) void = {
|
||||
let st: memio.stream = memio.dynamic();
|
||||
let snk: io.stream = &st.vt;
|
||||
|
||||
let r = shlex.quote(snk, in);
|
||||
let n: size = 0;
|
||||
match (r) {
|
||||
case let v: size => { n = v; };
|
||||
case let _e: io.error => { abort(); };
|
||||
};
|
||||
assert(!(n != expected.len: size));
|
||||
|
||||
let view: str = memio.string(&st);
|
||||
assert(!(!streq(view, expected)));
|
||||
|
||||
let _c: (void | io.error) = io.close(snk);
|
||||
};
|
||||
|
||||
// ---- split: Hare's @test fn split() table --------------------------
|
||||
//
|
||||
// 9 success rows + 3 syntaxerr rows ported VERBATIM from
|
||||
// ref/hare/shlex/+test.ha; plus one ww-specific edge (empty input →
|
||||
// empty []str) confirmed by drew.
|
||||
//
|
||||
// Local @test fns are `test_*`-prefixed because `use shlex;` flat-
|
||||
// concats shlex's exported names (split / quote / quotestr / strerror)
|
||||
// into the fixture's namespace, and bare `fn split() ...` would
|
||||
// duplicate-define them. Retires when task #17 (cgen mod-mangles fn
|
||||
// labels) lands.
|
||||
|
||||
@test fn test_split() void = {
|
||||
check1("hello\\ world", "hello world");
|
||||
check1("'hello\\ world'", "hello\\ world");
|
||||
check1("\"hello\\\\world\"", "hello\\world");
|
||||
// "hello "'"'"world"'"' → hello "world"
|
||||
check1("\"hello \"'\"'\"world\"'\"'", "hello \"world\"");
|
||||
check3("hello '' world", "hello", "", "world");
|
||||
check2("Empty ''", "Empty", "");
|
||||
check2(" Leading spaces", "Leading", "spaces");
|
||||
check3("with\\ backslashes 'single quoted' \"double quoted\"",
|
||||
"with backslashes", "single quoted", "double quoted");
|
||||
check2("'multiple spaces' 42", "multiple spaces", "42");
|
||||
// pin the '\t'/'\n' arms of split's whitespace test.
|
||||
check3("a\tb\nc", "a", "b", "c");
|
||||
|
||||
// Invalid
|
||||
checkerr("\"dangling double quote");
|
||||
checkerr("'dangling single quote");
|
||||
checkerr("unterminated\\ backslash \\");
|
||||
|
||||
// Empty input → empty []str (ww edge confirmed by drew).
|
||||
checkempty("");
|
||||
};
|
||||
|
||||
// ---- quote: Hare's testquote rows + the empty-input edge ----------
|
||||
//
|
||||
// 4 rows from ref/hare/shlex/+test.ha @test fn quote(). The empty-
|
||||
// input row (→ `''`) is implementation-specific (Hare's testquote
|
||||
// doesn't cover it) but is documented behaviour per shlex.ww's
|
||||
// quote() header — exercised here so the contract is load-bearing.
|
||||
|
||||
@test fn test_quote() void = {
|
||||
checkquote("hello", "hello");
|
||||
checkquote("hello world", "'hello world'");
|
||||
checkquote("'hello' \"world\"", "''\"'\"'hello'\"'\"' \"world\"'");
|
||||
checkquote("hello\\world", "'hello\\world'");
|
||||
checkquote("", "''");
|
||||
// pin issafe's special-char set: all safe → emitted raw, unquoted.
|
||||
checkquote("@%+=:,./-", "@%+=:,./-");
|
||||
};
|
||||
|
||||
// ---- quotestr ------------------------------------------------------
|
||||
|
||||
@test fn test_quotestr() void = {
|
||||
let r: str = shlex.quotestr("hello world");
|
||||
assert(!(!streq(r, "'hello world'")));
|
||||
// leak r — short-lived test process, same precedent as fnmatchtest.
|
||||
};
|
||||
|
||||
// ---- strerror ------------------------------------------------------
|
||||
|
||||
@test fn test_strerror() void = {
|
||||
let e: shlex.syntaxerr;
|
||||
let s: str = shlex.strerror(e);
|
||||
assert(!(!streq(s, "Invalid shell syntax")));
|
||||
};
|
||||
Reference in New Issue
Block a user