lib: split path_test into buffer/stack/posix tests per ref/hare/path
Mirror ref/hare/path's impl layout in the test siblings: abs/isroot/string/local rows -> buffer_test.ww (ref/hare/path/ buffer.ha:28-77); push/parent/pop-split rows -> stack_test.ww (ref/hare/path/stack.ha:9-180); dirname/basename rows -> posix_test.ww (ref/hare/path/posix.ha:17-71). Pure move: every @test block is byte-identical; only the section banner lines are deleted (file names now carry them) and each section's ref-cite WHY comment rides with its @test. The suite header's Hare-vector/parallel-array WHY paragraphs ride with stack_test.ww (push is their subject); the stale `ww run lib/path/path_test.ww` sentence is dropped, not relocated. Consumers: Makefile LIBRARY_TESTS entry replaced in place. The byteid roster is untouched: lib/path is enrolled there as an import-probe, not a fixture.
This commit is contained in:
3
Makefile
3
Makefile
@@ -497,7 +497,8 @@ LIBRARY_TESTS = lib/errors/errno_test.ww lib/ascii/ascii_test.ww \
|
|||||||
lib/encoding/base64/base64_test.ww \
|
lib/encoding/base64/base64_test.ww \
|
||||||
lib/hash/adler32/adler32_test.ww lib/hash/crc16/crc16_test.ww \
|
lib/hash/adler32/adler32_test.ww lib/hash/crc16/crc16_test.ww \
|
||||||
lib/hash/crc32/crc32_test.ww lib/hash/crc64/crc64_test.ww \
|
lib/hash/crc32/crc32_test.ww lib/hash/crc64/crc64_test.ww \
|
||||||
lib/path/path_test.ww lib/crypto/sha256/sha256_test.ww \
|
lib/path/buffer_test.ww lib/path/posix_test.ww \
|
||||||
|
lib/path/stack_test.ww lib/crypto/sha256/sha256_test.ww \
|
||||||
lib/hash/siphash/siphash_test.ww \
|
lib/hash/siphash/siphash_test.ww \
|
||||||
lib/os/os_test.ww lib/os/stat_test.ww lib/dirs/dirs_test.ww
|
lib/os/os_test.ww lib/os/stat_test.ww lib/dirs/dirs_test.ww
|
||||||
|
|
||||||
|
|||||||
101
lib/path/buffer_test.ww
Normal file
101
lib/path/buffer_test.ww
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package path_test;
|
||||||
|
|
||||||
|
import path;
|
||||||
|
|
||||||
|
|
||||||
|
// ref/hare/path/buffer.ha:34-41. str literals widen into the (*buffer|str)
|
||||||
|
// union arg (str-arm = hasprefix vs sepstr); buffer-arm = byte. Parallel
|
||||||
|
// [N]str inputs + [N]i32 wantbool (no [N]bool in the stack; cgen-field gap).
|
||||||
|
|
||||||
|
@test fn abs_cases() void = {
|
||||||
|
let ins: [4]str;
|
||||||
|
let want: [4]i32;
|
||||||
|
ins[0]="/"; want[0]=1;
|
||||||
|
ins[1]="/foo"; want[1]=1;
|
||||||
|
ins[2]="foo"; want[2]=0;
|
||||||
|
ins[3]=""; want[3]=0;
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < 4) {
|
||||||
|
let got: i32 = 0;
|
||||||
|
if (abs(ins[i])) { got = 1; };
|
||||||
|
assert(!(got != want[i]));
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// buffer-arm: &buf ptr-ident-widens into the union.
|
||||||
|
let buf = buffer { ... };
|
||||||
|
assert(!(abs(&buf))); // empty → false
|
||||||
|
assert(!(push(&buf, "/foo")! != "/foo"));
|
||||||
|
assert(!(!abs(&buf))); // "/foo" → true
|
||||||
|
buf.end = 0;
|
||||||
|
assert(!(push(&buf, "foo")! != "foo"));
|
||||||
|
assert(!(abs(&buf))); // "foo" → false
|
||||||
|
};
|
||||||
|
|
||||||
|
// ref/hare/path/buffer.ha:44-51. Both arms: str (== sepstr) and *buffer
|
||||||
|
// (byte+int). Heterogeneous buffer seeds (manual root seed vs push) →
|
||||||
|
// inline; str-arm rows table-driven.
|
||||||
|
|
||||||
|
@test fn isroot_cases() void = {
|
||||||
|
let buf = buffer { ... };
|
||||||
|
// empty buffer (end 0)
|
||||||
|
assert(!(isroot(&buf)));
|
||||||
|
|
||||||
|
// "/" — root. local() is c3, so seed the SEP byte directly.
|
||||||
|
buf.buf[0] = SEP; buf.end = 1;
|
||||||
|
assert(!(!isroot(&buf)));
|
||||||
|
assert(!(string(&buf) != "/"));
|
||||||
|
|
||||||
|
// "foo" — relative, not root.
|
||||||
|
buf.end = 0;
|
||||||
|
assert(!(push(&buf, "foo")! != "foo"));
|
||||||
|
assert(!(isroot(&buf)));
|
||||||
|
|
||||||
|
// "/foo" — absolute but not root.
|
||||||
|
buf.buf[0] = SEP; buf.end = 1;
|
||||||
|
assert(!(push(&buf, "foo")! != "/foo"));
|
||||||
|
assert(!(isroot(&buf)));
|
||||||
|
|
||||||
|
// str-arm (buffer.ha:47): only the bare separator is root.
|
||||||
|
let ins: [4]str;
|
||||||
|
let want: [4]i32;
|
||||||
|
ins[0]="/"; want[0]=1;
|
||||||
|
ins[1]="/foo"; want[1]=0;
|
||||||
|
ins[2]="foo"; want[2]=0;
|
||||||
|
ins[3]=""; want[3]=0;
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < 4) {
|
||||||
|
let got: i32 = 0;
|
||||||
|
if (isroot(ins[i])) { got = 1; };
|
||||||
|
assert(!(got != want[i]));
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 { ... };
|
||||||
|
assert(!(string(&buf) != "."));
|
||||||
|
assert(!(push(&buf, "foo")! != "foo"));
|
||||||
|
assert(!(string(&buf) != "foo"));
|
||||||
|
};
|
||||||
|
|
||||||
|
// ref/hare/path/buffer.ha:55-77. Rewrites '/'→SEP into a static buffer;
|
||||||
|
// on Linux (SEP=='/') that is identity. The returned view borrows the
|
||||||
|
// module-private localbuf, so compare each row before the next call.
|
||||||
|
|
||||||
|
@test fn local_cases() void = {
|
||||||
|
let ins: [4]str;
|
||||||
|
let want: [4]str;
|
||||||
|
ins[0]="a/b"; want[0]="a/b";
|
||||||
|
ins[1]="/"; want[1]="/";
|
||||||
|
ins[2]="foo"; want[2]="foo";
|
||||||
|
ins[3]=""; want[3]="";
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < 4) {
|
||||||
|
assert(!(local(ins[i])! != want[i]));
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,269 +0,0 @@
|
|||||||
// pathtest — exercises lib/path (c2-stack subset). Run with
|
|
||||||
// `out/bin/ww run lib/path/path_test.ww`. A failing row aborts via the
|
|
||||||
// assert/abort builtin (task #5 @test conversion).
|
|
||||||
//
|
|
||||||
// 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 (getopt_test.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_test;
|
|
||||||
|
|
||||||
import path;
|
|
||||||
|
|
||||||
|
|
||||||
// ---- 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 { ... };
|
|
||||||
assert(!(string(&buf) != "."));
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
assert(!(push(&buf, segs[i])! != wants[i]));
|
|
||||||
i += 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
// set(&buf) resets to "." (stack.ha:91). set forwards an EMPTY
|
|
||||||
// variadic into push (KEN-oracle flag 1: zero-arg gather+forward).
|
|
||||||
assert(!(set(&buf)! != "."));
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
assert(!(push(&buf, segs2[k])! != wants2[k]));
|
|
||||||
k += 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
// multi-segment (stack.ha:107-111). Variadic arity varies (1 or 2)
|
|
||||||
// → inline.
|
|
||||||
assert(!(push(&buf, "a", "b")! != "a/b"));
|
|
||||||
assert(!(push(&buf, "..", "c")! != "a/c"));
|
|
||||||
assert(!(push(&buf, "..")! != "a"));
|
|
||||||
// stack.ha:110; local()→literal, SEP='/' on Linux, proper local() rides c3
|
|
||||||
assert(!(push(&buf, "/d")! != "a/d"));
|
|
||||||
assert(!(push(&buf, "..", "..")! != ".")); // 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).
|
|
||||||
assert(!(set(&buf)! != "."));
|
|
||||||
assert(!(push(&buf, "/foo")! != "/foo"));
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---- abs() ------------------------------------------------------------
|
|
||||||
// ref/hare/path/buffer.ha:34-41. str literals widen into the (*buffer|str)
|
|
||||||
// union arg (str-arm = hasprefix vs sepstr); buffer-arm = byte. Parallel
|
|
||||||
// [N]str inputs + [N]i32 wantbool (no [N]bool in the stack; cgen-field gap).
|
|
||||||
|
|
||||||
@test fn abs_cases() void = {
|
|
||||||
let ins: [4]str;
|
|
||||||
let want: [4]i32;
|
|
||||||
ins[0]="/"; want[0]=1;
|
|
||||||
ins[1]="/foo"; want[1]=1;
|
|
||||||
ins[2]="foo"; want[2]=0;
|
|
||||||
ins[3]=""; want[3]=0;
|
|
||||||
let i: i32 = 0;
|
|
||||||
for (i < 4) {
|
|
||||||
let got: i32 = 0;
|
|
||||||
if (abs(ins[i])) { got = 1; };
|
|
||||||
assert(!(got != want[i]));
|
|
||||||
i += 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
// buffer-arm: &buf ptr-ident-widens into the union.
|
|
||||||
let buf = buffer { ... };
|
|
||||||
assert(!(abs(&buf))); // empty → false
|
|
||||||
assert(!(push(&buf, "/foo")! != "/foo"));
|
|
||||||
assert(!(!abs(&buf))); // "/foo" → true
|
|
||||||
buf.end = 0;
|
|
||||||
assert(!(push(&buf, "foo")! != "foo"));
|
|
||||||
assert(!(abs(&buf))); // "foo" → false
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---- isroot() ---------------------------------------------------------
|
|
||||||
// ref/hare/path/buffer.ha:44-51. Both arms: str (== sepstr) and *buffer
|
|
||||||
// (byte+int). Heterogeneous buffer seeds (manual root seed vs push) →
|
|
||||||
// inline; str-arm rows table-driven.
|
|
||||||
|
|
||||||
@test fn isroot_cases() void = {
|
|
||||||
let buf = buffer { ... };
|
|
||||||
// empty buffer (end 0)
|
|
||||||
assert(!(isroot(&buf)));
|
|
||||||
|
|
||||||
// "/" — root. local() is c3, so seed the SEP byte directly.
|
|
||||||
buf.buf[0] = SEP; buf.end = 1;
|
|
||||||
assert(!(!isroot(&buf)));
|
|
||||||
assert(!(string(&buf) != "/"));
|
|
||||||
|
|
||||||
// "foo" — relative, not root.
|
|
||||||
buf.end = 0;
|
|
||||||
assert(!(push(&buf, "foo")! != "foo"));
|
|
||||||
assert(!(isroot(&buf)));
|
|
||||||
|
|
||||||
// "/foo" — absolute but not root.
|
|
||||||
buf.buf[0] = SEP; buf.end = 1;
|
|
||||||
assert(!(push(&buf, "foo")! != "/foo"));
|
|
||||||
assert(!(isroot(&buf)));
|
|
||||||
|
|
||||||
// str-arm (buffer.ha:47): only the bare separator is root.
|
|
||||||
let ins: [4]str;
|
|
||||||
let want: [4]i32;
|
|
||||||
ins[0]="/"; want[0]=1;
|
|
||||||
ins[1]="/foo"; want[1]=0;
|
|
||||||
ins[2]="foo"; want[2]=0;
|
|
||||||
ins[3]=""; want[3]=0;
|
|
||||||
let i: i32 = 0;
|
|
||||||
for (i < 4) {
|
|
||||||
let got: i32 = 0;
|
|
||||||
if (isroot(ins[i])) { got = 1; };
|
|
||||||
assert(!(got != want[i]));
|
|
||||||
i += 1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---- 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 { ... };
|
|
||||||
assert(!(string(&buf) != "."));
|
|
||||||
assert(!(push(&buf, "foo")! != "foo"));
|
|
||||||
assert(!(string(&buf) != "foo"));
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---- dirname() / basename() -------------------------------------------
|
|
||||||
// ref/hare/path/posix.ha:51-71. Hare seeds each row through _local/local()
|
|
||||||
// for cross-platform SEP; on ww (Linux, SEP='/') that is identity, so the
|
|
||||||
// raw str literals stand in directly (local/_local defer to c3). POSIX
|
|
||||||
// dirname/basename do NOT normalize the input (posix.ha:14-15,35), so no
|
|
||||||
// seeding is needed. Parallel `[N]str` rows (cgen chained-field gap, as
|
|
||||||
// above). Rows whose expected is a borrowed VIEW (not a "."/"/" literal)
|
|
||||||
// compare a computed str to a literal — cstage-correct; wwstage mis-
|
|
||||||
// compares via #146 (str== over a frombytes result), and this @test is
|
|
||||||
// cstage-gated, so those rows are #146-deferred on wwstage only.
|
|
||||||
|
|
||||||
@test fn dirname_basename_cases() void = {
|
|
||||||
let inputs: [10]str;
|
|
||||||
let wantdir: [10]str;
|
|
||||||
let wantbase: [10]str;
|
|
||||||
inputs[0]="usr"; wantdir[0]="."; wantbase[0]="usr";
|
|
||||||
inputs[1]="usr/"; wantdir[1]="."; wantbase[1]="usr";
|
|
||||||
inputs[2]=""; wantdir[2]="."; wantbase[2]=".";
|
|
||||||
inputs[3]="/"; wantdir[3]="/"; wantbase[3]="/";
|
|
||||||
inputs[4]="//"; wantdir[4]="/"; wantbase[4]="/"; // impl-defined
|
|
||||||
inputs[5]="///"; wantdir[5]="/"; wantbase[5]="/";
|
|
||||||
inputs[6]="/usr/"; wantdir[6]="/"; wantbase[6]="usr";
|
|
||||||
inputs[7]="/usr/lib"; wantdir[7]="/usr"; wantbase[7]="lib";
|
|
||||||
inputs[8]="//usr//lib//"; wantdir[8]="//usr"; wantbase[8]="lib";
|
|
||||||
inputs[9]="/home//dwc//test"; wantdir[9]="/home//dwc"; wantbase[9]="test";
|
|
||||||
let i: i32 = 0;
|
|
||||||
for (i < 10) {
|
|
||||||
assert(!(dirname(inputs[i]) != wantdir[i]));
|
|
||||||
assert(!(basename(inputs[i]) != wantbase[i]));
|
|
||||||
i += 1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---- local() ----------------------------------------------------------
|
|
||||||
// ref/hare/path/buffer.ha:55-77. Rewrites '/'→SEP into a static buffer;
|
|
||||||
// on Linux (SEP=='/') that is identity. The returned view borrows the
|
|
||||||
// module-private localbuf, so compare each row before the next call.
|
|
||||||
|
|
||||||
@test fn local_cases() void = {
|
|
||||||
let ins: [4]str;
|
|
||||||
let want: [4]str;
|
|
||||||
ins[0]="a/b"; want[0]="a/b";
|
|
||||||
ins[1]="/"; want[1]="/";
|
|
||||||
ins[2]="foo"; want[2]="foo";
|
|
||||||
ins[3]=""; want[3]="";
|
|
||||||
let i: i32 = 0;
|
|
||||||
for (i < 4) {
|
|
||||||
assert(!(local(ins[i])! != want[i]));
|
|
||||||
i += 1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---- parent() ---------------------------------------------------------
|
|
||||||
// ref/hare/path/stack.ha:172-180. Parent dir; root → root; empty → "..".
|
|
||||||
// Each row reseeds a reset buffer (parent goes through appendnorm). push's
|
|
||||||
// normalized echo is dropped so the empty-buffer row ("" pushes to ".",
|
|
||||||
// not "") can share the table.
|
|
||||||
|
|
||||||
@test fn parent_cases() void = {
|
|
||||||
let buf = buffer { ... };
|
|
||||||
let ins: [5]str;
|
|
||||||
let want: [5]str;
|
|
||||||
ins[0]="/usr/lib"; want[0]="/usr";
|
|
||||||
ins[1]="foo"; want[1]=".";
|
|
||||||
ins[2]="/"; want[2]="/";
|
|
||||||
ins[3]="a/b/c"; want[3]="a/b";
|
|
||||||
ins[4]=""; want[4]=".."; // empty buffer: appendnorm(dotdot) → ".."
|
|
||||||
let i: i32 = 0;
|
|
||||||
for (i < 5) {
|
|
||||||
buf.end = 0;
|
|
||||||
push(&buf, ins[i])!;
|
|
||||||
assert(!(parent(&buf)! != want[i]));
|
|
||||||
i += 1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---- split() / pop() / peek() -----------------------------------------
|
|
||||||
// ref/hare/path/stack.ha:147-170 (@test pop). split is the helper, covered
|
|
||||||
// through pop/peek. Sequential off ONE buffer, reset buf.end=0 per case.
|
|
||||||
// The peek-then-string-unchanged assert is load-bearing: it pins that the
|
|
||||||
// #48 respelling didn't smuggle in pop's buf.end mutation.
|
|
||||||
|
|
||||||
@test fn popsplit_cases() void = {
|
|
||||||
let buf = buffer { ... };
|
|
||||||
|
|
||||||
// empty
|
|
||||||
assert(!(!(pop(&buf) is void)));
|
|
||||||
assert(!(string(&buf) != "."));
|
|
||||||
|
|
||||||
// root dir
|
|
||||||
buf.end = 0;
|
|
||||||
assert(!(push(&buf, "/")! != "/"));
|
|
||||||
assert(!(!(pop(&buf) is void)));
|
|
||||||
assert(!(string(&buf) != "/"));
|
|
||||||
|
|
||||||
// relative file — peek is NON-mutating
|
|
||||||
buf.end = 0;
|
|
||||||
assert(!(push(&buf, "foo")! != "foo"));
|
|
||||||
assert(!(peek(&buf) as str != "foo"));
|
|
||||||
assert(!(string(&buf) != "foo"));
|
|
||||||
assert(!(pop(&buf) as str != "foo"));
|
|
||||||
assert(!(string(&buf) != "."));
|
|
||||||
|
|
||||||
// absolute file
|
|
||||||
buf.end = 0;
|
|
||||||
assert(!(push(&buf, "/foo")! != "/foo"));
|
|
||||||
assert(!(peek(&buf) as str != "foo"));
|
|
||||||
assert(!(pop(&buf) as str != "foo"));
|
|
||||||
assert(!(string(&buf) != "/"));
|
|
||||||
};
|
|
||||||
36
lib/path/posix_test.ww
Normal file
36
lib/path/posix_test.ww
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package path_test;
|
||||||
|
|
||||||
|
import path;
|
||||||
|
|
||||||
|
|
||||||
|
// ref/hare/path/posix.ha:51-71. Hare seeds each row through _local/local()
|
||||||
|
// for cross-platform SEP; on ww (Linux, SEP='/') that is identity, so the
|
||||||
|
// raw str literals stand in directly (local/_local defer to c3). POSIX
|
||||||
|
// dirname/basename do NOT normalize the input (posix.ha:14-15,35), so no
|
||||||
|
// seeding is needed. Parallel `[N]str` rows (cgen chained-field gap, as
|
||||||
|
// above). Rows whose expected is a borrowed VIEW (not a "."/"/" literal)
|
||||||
|
// compare a computed str to a literal — cstage-correct; wwstage mis-
|
||||||
|
// compares via #146 (str== over a frombytes result), and this @test is
|
||||||
|
// cstage-gated, so those rows are #146-deferred on wwstage only.
|
||||||
|
|
||||||
|
@test fn dirname_basename_cases() void = {
|
||||||
|
let inputs: [10]str;
|
||||||
|
let wantdir: [10]str;
|
||||||
|
let wantbase: [10]str;
|
||||||
|
inputs[0]="usr"; wantdir[0]="."; wantbase[0]="usr";
|
||||||
|
inputs[1]="usr/"; wantdir[1]="."; wantbase[1]="usr";
|
||||||
|
inputs[2]=""; wantdir[2]="."; wantbase[2]=".";
|
||||||
|
inputs[3]="/"; wantdir[3]="/"; wantbase[3]="/";
|
||||||
|
inputs[4]="//"; wantdir[4]="/"; wantbase[4]="/"; // impl-defined
|
||||||
|
inputs[5]="///"; wantdir[5]="/"; wantbase[5]="/";
|
||||||
|
inputs[6]="/usr/"; wantdir[6]="/"; wantbase[6]="usr";
|
||||||
|
inputs[7]="/usr/lib"; wantdir[7]="/usr"; wantbase[7]="lib";
|
||||||
|
inputs[8]="//usr//lib//"; wantdir[8]="//usr"; wantbase[8]="lib";
|
||||||
|
inputs[9]="/home//dwc//test"; wantdir[9]="/home//dwc"; wantbase[9]="test";
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < 10) {
|
||||||
|
assert(!(dirname(inputs[i]) != wantdir[i]));
|
||||||
|
assert(!(basename(inputs[i]) != wantbase[i]));
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
128
lib/path/stack_test.ww
Normal file
128
lib/path/stack_test.ww
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
// 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 (getopt_test.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_test;
|
||||||
|
|
||||||
|
import path;
|
||||||
|
|
||||||
|
|
||||||
|
// 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 { ... };
|
||||||
|
assert(!(string(&buf) != "."));
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
assert(!(push(&buf, segs[i])! != wants[i]));
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// set(&buf) resets to "." (stack.ha:91). set forwards an EMPTY
|
||||||
|
// variadic into push (KEN-oracle flag 1: zero-arg gather+forward).
|
||||||
|
assert(!(set(&buf)! != "."));
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
assert(!(push(&buf, segs2[k])! != wants2[k]));
|
||||||
|
k += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// multi-segment (stack.ha:107-111). Variadic arity varies (1 or 2)
|
||||||
|
// → inline.
|
||||||
|
assert(!(push(&buf, "a", "b")! != "a/b"));
|
||||||
|
assert(!(push(&buf, "..", "c")! != "a/c"));
|
||||||
|
assert(!(push(&buf, "..")! != "a"));
|
||||||
|
// stack.ha:110; local()→literal, SEP='/' on Linux, proper local() rides c3
|
||||||
|
assert(!(push(&buf, "/d")! != "a/d"));
|
||||||
|
assert(!(push(&buf, "..", "..")! != ".")); // 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).
|
||||||
|
assert(!(set(&buf)! != "."));
|
||||||
|
assert(!(push(&buf, "/foo")! != "/foo"));
|
||||||
|
};
|
||||||
|
|
||||||
|
// ref/hare/path/stack.ha:172-180. Parent dir; root → root; empty → "..".
|
||||||
|
// Each row reseeds a reset buffer (parent goes through appendnorm). push's
|
||||||
|
// normalized echo is dropped so the empty-buffer row ("" pushes to ".",
|
||||||
|
// not "") can share the table.
|
||||||
|
|
||||||
|
@test fn parent_cases() void = {
|
||||||
|
let buf = buffer { ... };
|
||||||
|
let ins: [5]str;
|
||||||
|
let want: [5]str;
|
||||||
|
ins[0]="/usr/lib"; want[0]="/usr";
|
||||||
|
ins[1]="foo"; want[1]=".";
|
||||||
|
ins[2]="/"; want[2]="/";
|
||||||
|
ins[3]="a/b/c"; want[3]="a/b";
|
||||||
|
ins[4]=""; want[4]=".."; // empty buffer: appendnorm(dotdot) → ".."
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < 5) {
|
||||||
|
buf.end = 0;
|
||||||
|
push(&buf, ins[i])!;
|
||||||
|
assert(!(parent(&buf)! != want[i]));
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// ref/hare/path/stack.ha:147-170 (@test pop). split is the helper, covered
|
||||||
|
// through pop/peek. Sequential off ONE buffer, reset buf.end=0 per case.
|
||||||
|
// The peek-then-string-unchanged assert is load-bearing: it pins that the
|
||||||
|
// #48 respelling didn't smuggle in pop's buf.end mutation.
|
||||||
|
|
||||||
|
@test fn popsplit_cases() void = {
|
||||||
|
let buf = buffer { ... };
|
||||||
|
|
||||||
|
// empty
|
||||||
|
assert(!(!(pop(&buf) is void)));
|
||||||
|
assert(!(string(&buf) != "."));
|
||||||
|
|
||||||
|
// root dir
|
||||||
|
buf.end = 0;
|
||||||
|
assert(!(push(&buf, "/")! != "/"));
|
||||||
|
assert(!(!(pop(&buf) is void)));
|
||||||
|
assert(!(string(&buf) != "/"));
|
||||||
|
|
||||||
|
// relative file — peek is NON-mutating
|
||||||
|
buf.end = 0;
|
||||||
|
assert(!(push(&buf, "foo")! != "foo"));
|
||||||
|
assert(!(peek(&buf) as str != "foo"));
|
||||||
|
assert(!(string(&buf) != "foo"));
|
||||||
|
assert(!(pop(&buf) as str != "foo"));
|
||||||
|
assert(!(string(&buf) != "."));
|
||||||
|
|
||||||
|
// absolute file
|
||||||
|
buf.end = 0;
|
||||||
|
assert(!(push(&buf, "/foo")! != "/foo"));
|
||||||
|
assert(!(peek(&buf) as str != "foo"));
|
||||||
|
assert(!(pop(&buf) as str != "foo"));
|
||||||
|
assert(!(string(&buf) != "/"));
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user