// pathtest — exercises lib/path (c2-stack subset). Run with // `out/bin/ww run lib/path/pathtest.ww`. Same signalled-then-fail() // -with-+10 pattern as bytes / getopt tests: a non-zero exit code // pinpoints the failing scenario. // // Vectors mirror Hare's @test fns in ref/hare/path/stack.ha:77-119 // and buffer.ha. The absolute rows (Hare's `local("/")`-seeded) DEFER // to c3 (abs/local unimplemented); only the relative rows run here. // // Parallel `[N]str` row arrays (rather than `[N]struct{...}`) sidestep // the cstage cgen chained `arr[i].field` store gap (getopttest.ww:6). // push is stateful, so each row is applied in sequence to one buffer; // the table holds {segment, expected-string} pairs (stack.ha:36-42 is // the normalization spec these rows encode). package path; import path; import os; let signalled: i32 = 0; fn fail() void = { os.exit(signalled + 10); }; // ---- push() + appendnorm normalization -------------------------------- // ref/hare/path/stack.ha:77-119 (relative rows only; absolute local() // rows defer to c3). The dot/dotdot handling exercised here IS the // appendnorm normalization spec (stack.ha:36-42), so no separate // appendnorm @test is needed. @test fn push_cases() void = { let buf = buffer { ... }; if (string(&buf) != ".") { fail(); }; // current-dir + parent-dir invariants (stack.ha:82-88). Single // segment per row → table-driven sequential apply. let segs: [5]str; let wants: [5]str; segs[0]=""; wants[0]="."; segs[1]="."; wants[1]="."; segs[2]=".."; wants[2]=".."; segs[3]=""; wants[3]=".."; segs[4]="."; wants[4]=".."; let i: i32 = 0; for (i < 5) { if (push(&buf, segs[i])! != wants[i]) { fail(); }; i += 1; }; // set(&buf) resets to "." (stack.ha:91). set forwards an EMPTY // variadic into push (KEN-oracle flag 1: zero-arg gather+forward). if (set(&buf)! != ".") { fail(); }; // regular path + parent (stack.ha:101-104, minus the local() row). let segs2: [3]str; let wants2: [3]str; segs2[0]="foo"; wants2[0]="foo"; segs2[1]="."; wants2[1]="foo"; segs2[2]=".."; wants2[2]="."; let k: i32 = 0; for (k < 3) { if (push(&buf, segs2[k])! != wants2[k]) { fail(); }; k += 1; }; // multi-segment (stack.ha:107-111). Variadic arity varies (1 or 2) // → inline. if (push(&buf, "a", "b")! != "a/b") { fail(); }; if (push(&buf, "..", "c")! != "a/c") { fail(); }; if (push(&buf, "..")! != "a") { fail(); }; // stack.ha:110; local()→literal, SEP='/' on Linux, proper local() rides c3 if (push(&buf, "/d")! != "a/d") { fail(); }; if (push(&buf, "..", "..")! != ".") { fail(); }; // stack.ha:111 // leading-SEP segment into an EMPTY buffer exercises push's // `j==0 && buf.end==0` root-seed arm (stack.ha:18-20), unreached // by the relative rows above. Hare covers it via local("/")-seeded // rows that defer to c3; literal "/foo" stands in (SEP='/' on Linux). if (set(&buf)! != ".") { fail(); }; if (push(&buf, "/foo")! != "/foo") { fail(); }; }; // ---- isroot() --------------------------------------------------------- // ref/hare/path/buffer.ha:44-51 (*buffer arm). Heterogeneous seeds // (manual root seed vs push) → inline rather than a uniform table. @test fn isroot_cases() void = { let buf = buffer { ... }; // empty buffer (end 0) if (isroot(&buf)) { fail(); }; // "/" — root. local() is c3, so seed the SEP byte directly. buf.buf[0] = SEP; buf.end = 1; if (!isroot(&buf)) { fail(); }; if (string(&buf) != "/") { fail(); }; // "foo" — relative, not root. buf.end = 0; if (push(&buf, "foo")! != "foo") { fail(); }; if (isroot(&buf)) { fail(); }; // "/foo" — absolute but not root. buf.buf[0] = SEP; buf.end = 1; if (push(&buf, "foo")! != "/foo") { fail(); }; if (isroot(&buf)) { fail(); }; }; // ---- string() --------------------------------------------------------- // ref/hare/path/buffer.ha:28-31. Empty buffer views as "."; a filled // buffer views the byte prefix. @test fn string_cases() void = { let buf = buffer { ... }; if (string(&buf) != ".") { fail(); }; if (push(&buf, "foo")! != "foo") { fail(); }; if (string(&buf) != "foo") { fail(); }; }; export fn main() i32 = { signalled = 1; push_cases(); signalled = 2; isroot_cases(); signalled = 3; string_cases(); return 0; };