diff --git a/Makefile b/Makefile index fa5f2a96..3d15566b 100644 --- a/Makefile +++ b/Makefile @@ -488,7 +488,9 @@ LIBRARY_TESTS = lib/errors/errno_test.ww lib/ascii/ascii_test.ww \ lib/strconv/test/int_test.ww lib/strings/strings_test.ww \ lib/strings/suffix_test.ww lib/strings/contains_test.ww \ lib/strings/index_test.ww lib/strings/compare_test.ww \ - lib/bytes/bytes_test.ww lib/encoding/utf8/utf8_test.ww \ + lib/bytes/equal_test.ww lib/bytes/index_test.ww \ + lib/bytes/contains_test.ww lib/bytes/tokenize_test.ww \ + lib/bytes/trim_test.ww lib/encoding/utf8/utf8_test.ww \ lib/bufio/bufio_test.ww lib/math/random/random_test.ww \ lib/math/checked/checked_test.ww lib/fmt/fmt_test.ww \ lib/log/log_test.ww lib/log/silent_test.ww lib/fnmatch/fnmatch_test.ww \ diff --git a/lib/bytes/contains_test.ww b/lib/bytes/contains_test.ww new file mode 100644 index 00000000..66d40e2b --- /dev/null +++ b/lib/bytes/contains_test.ww @@ -0,0 +1,59 @@ +// containstest — exercises bytes.contains/hasprefix/hassuffix. A +// failing row aborts via the assert/abort builtin (task #5 @test +// conversion). Vectors mirror ref/hare/bytes/contains.ha. + +package bytes_test; + +import bytes; + +@test fn contains_cases() void = { + let a: [4]u8; a[0] = 1u8; a[1] = 3u8; a[2] = 3u8; a[3] = 7u8; + assert(!(!bytes.contains(a[0:4], 7u8))); + assert(!( bytes.contains(a[0:4], 42u8))); + let n: [2]u8; n[0] = 3u8; n[1] = 3u8; + assert(!(!bytes.contains(a[0:4], n[0:2]))); + let m: [2]u8; m[0] = 9u8; m[1] = 9u8; + assert(!( bytes.contains(a[0:4], m[0:2]))); + + // Variadic rows. ref/hare/bytes/contains.ha:6. + assert(!( bytes.contains(a[0:4]))); + assert(!(!bytes.contains(a[0:4], n[0:2]))); + assert(!(!bytes.contains(a[0:4], 7u8))); + assert(!(!bytes.contains(a[0:4], m[0:2], n[0:2], 42u8))); + assert(!( bytes.contains(a[0:4], m[0:2], 42u8, m[0:2]))); +}; + +// ref/hare/bytes/contains.ha:25. + +@test fn hasprefix_cases() void = { + let z: [1]u8; + assert(!(!bytes.hasprefix(z[0:0], z[0:0]))); + let one: [1]u8; one[0] = 0u8; + assert(!(!bytes.hasprefix(one[0:1], z[0:0]))); + assert(!( bytes.hasprefix(z[0:0], one[0:1]))); + let a: [3]u8; a[0] = 1u8; a[1] = 2u8; a[2] = 3u8; + let p12: [2]u8; p12[0] = 1u8; p12[1] = 2u8; + assert(!(!bytes.hasprefix(a[0:3], p12[0:2]))); + let p11: [2]u8; p11[0] = 1u8; p11[1] = 1u8; + assert(!( bytes.hasprefix(a[0:3], p11[0:2]))); + let pl: [4]u8; pl[0] = 1u8; pl[1] = 2u8; pl[2] = 3u8; pl[3] = 4u8; + assert(!( bytes.hasprefix(a[0:3], pl[0:4]))); +}; + +// ref/hare/bytes/contains.ha:40. + +@test fn hassuffix_cases() void = { + let z: [1]u8; + assert(!(!bytes.hassuffix(z[0:0], z[0:0]))); + let one: [1]u8; one[0] = 0u8; + assert(!(!bytes.hassuffix(one[0:1], z[0:0]))); + assert(!( bytes.hassuffix(z[0:0], one[0:1]))); + let a: [3]u8; a[0] = 1u8; a[1] = 2u8; a[2] = 3u8; + let s23: [2]u8; s23[0] = 2u8; s23[1] = 3u8; + assert(!(!bytes.hassuffix(a[0:3], s23[0:2]))); + let s22: [2]u8; s22[0] = 2u8; s22[1] = 2u8; + assert(!( bytes.hassuffix(a[0:3], s22[0:2]))); + let a4: [4]u8; a4[0] = 1u8; a4[1] = 2u8; a4[2] = 3u8; a4[3] = 4u8; + let s234: [3]u8; s234[0] = 2u8; s234[1] = 3u8; s234[2] = 4u8; + assert(!(!bytes.hassuffix(a4[0:4], s234[0:3]))); +}; diff --git a/lib/bytes/equal_test.ww b/lib/bytes/equal_test.ww new file mode 100644 index 00000000..13591a5e --- /dev/null +++ b/lib/bytes/equal_test.ww @@ -0,0 +1,23 @@ +// equaltest — exercises bytes.equal. A failing row aborts via the +// assert/abort builtin (task #5 @test conversion). +// Vectors mirror ref/hare/bytes/equal.ha. + +package bytes_test; + +import bytes; + +// ref/hare/bytes/equal.ha:21. + +@test fn equal_cases() void = { + let a: [3]u8; a[0] = 1u8; a[1] = 2u8; a[2] = 3u8; + let b: [3]u8; b[0] = 1u8; b[1] = 2u8; b[2] = 3u8; + let c: [3]u8; c[0] = 1u8; c[1] = 4u8; c[2] = 5u8; + let d: [4]u8; d[0] = 1u8; d[1] = 2u8; d[2] = 3u8; d[3] = 4u8; + let e: [2]u8; e[0] = 1u8; e[1] = 2u8; + let z: [1]u8; + assert(!(!bytes.equal(a[0:3], b[0:3]))); + assert(!( bytes.equal(a[0:3], c[0:3]))); + assert(!( bytes.equal(a[0:3], d[0:4]))); + assert(!( bytes.equal(a[0:3], e[0:2]))); + assert(!(!bytes.equal(z[0:0], z[0:0]))); // empty-empty +}; diff --git a/lib/bytes/index_test.ww b/lib/bytes/index_test.ww new file mode 100644 index 00000000..a8992863 --- /dev/null +++ b/lib/bytes/index_test.ww @@ -0,0 +1,157 @@ +// indextest — exercises bytes.index/rindex, u8 and []u8 arms. A +// failing row aborts via the assert/abort builtin (task #5 @test +// conversion). Vectors mirror ref/hare/bytes/index.ha. + +package bytes_test; + +import bytes; + +// ref/hare/bytes/index.ha:112. + +@test fn index_byte_cases() void = { + let a: [4]u8; a[0] = 1u8; a[1] = 3u8; a[2] = 3u8; a[3] = 7u8; + match (bytes.index(a[0:4], 1u8)) { + case let i: i32 => { assert(!(i != 0)); }; + case void => abort(); + }; + match (bytes.index(a[0:4], 3u8)) { + case let i: i32 => { assert(!(i != 1)); }; + case void => abort(); + }; + match (bytes.index(a[0:4], 7u8)) { + case let i: i32 => { assert(!(i != 3)); }; + case void => abort(); + }; + match (bytes.index(a[0:4], 42u8)) { + case let i: i32 => abort(); + case void => void; + }; + let z: [1]u8; + match (bytes.index(z[0:0], 42u8)) { + case let i: i32 => abort(); + case void => void; + }; +}; + +// ref/hare/bytes/index.ha:128-139. Vector strings copied verbatim where +// representable as ASCII byte sequences. + +@test fn index_slice_cases() void = { + let h1: [4]u8; h1[0] = 1u8; h1[1] = 42u8; h1[2] = 24u8; h1[3] = 0u8; + let n1: [2]u8; n1[0] = 42u8; n1[1] = 24u8; + match (bytes.index(h1[0:3], n1[0:2])) { + case let i: i32 => { assert(!(i != 1)); }; + case void => abort(); + }; + + let h2: [4]u8; h2[0] = 1u8; h2[1] = 3u8; h2[2] = 3u8; h2[3] = 7u8; + let n2: [2]u8; n2[0] = 3u8; n2[1] = 3u8; + match (bytes.index(h2[0:4], n2[0:2])) { + case let i: i32 => { assert(!(i != 1)); }; + case void => abort(); + }; + + // needle longer than haystack — void + let h3: [3]u8; h3[0] = 1u8; h3[1] = 2u8; h3[2] = 3u8; + let n3: [4]u8; n3[0] = 1u8; n3[1] = 2u8; n3[2] = 3u8; n3[3] = 4u8; + match (bytes.index(h3[0:3], n3[0:4])) { + case let i: i32 => abort(); + case void => void; + }; + + // len(haystack) == len(needle), match — offset 0 + let h4: [2]u8; h4[0] = 42u8; h4[1] = 20u8; + let n4: [2]u8; n4[0] = 42u8; n4[1] = 20u8; + match (bytes.index(h4[0:2], n4[0:2])) { + case let i: i32 => { assert(!(i != 0)); }; + case void => abort(); + }; + + // len(haystack) == len(needle), no match — void + let h5: [4]u8; h5[0] = 1u8; h5[1] = 1u8; h5[2] = 1u8; h5[3] = 2u8; + let n5: [4]u8; n5[0] = 1u8; n5[1] = 1u8; n5[2] = 1u8; n5[3] = 3u8; + match (bytes.index(h5[0:4], n5[0:4])) { + case let i: i32 => abort(); + case void => void; + }; + + // Partial-prefix recovery — needle [1,1,2] aligns at i=1 after the + // false-start at i=0 ([1,1,1] mismatches at byte 2). Pins the + // naive scanner's restart discipline. + let h6: [4]u8; h6[0] = 1u8; h6[1] = 1u8; h6[2] = 1u8; h6[3] = 2u8; + let n6s: [3]u8; n6s[0] = 1u8; n6s[1] = 1u8; n6s[2] = 2u8; + match (bytes.index(h6[0:4], n6s[0:3])) { + case let i: i32 => { assert(!(i != 1)); }; + case void => abort(); + }; + + // Same shape, longer haystack with no match anywhere. + let h7: [5]u8; h7[0] = 1u8; h7[1] = 1u8; h7[2] = 1u8; h7[3] = 3u8; h7[4] = 2u8; + let n7: [4]u8; n7[0] = 1u8; n7[1] = 1u8; n7[2] = 1u8; n7[3] = 2u8; + match (bytes.index(h7[0:5], n7[0:4])) { + case let i: i32 => abort(); + case void => void; + }; + + // empty needle — Hare returns 0 (ref/hare/bytes/index.ha:63). + let z: [1]u8; + let zn: [1]u8; + match (bytes.index(h2[0:4], zn[0:0])) { + case let i: i32 => { assert(!(i != 0)); }; + case void => abort(); + }; + // empty haystack, non-empty needle — void + match (bytes.index(z[0:0], n3[0:3])) { + case let i: i32 => abort(); + case void => void; + }; + + // single-byte slice needle — should semantically equal u8 arm + let n6: [1]u8; n6[0] = 7u8; + match (bytes.index(h2[0:4], n6[0:1])) { + case let i: i32 => { assert(!(i != 3)); }; + case void => abort(); + }; +}; + +// ref/hare/bytes/index.ha:118. + +@test fn rindex_byte_cases() void = { + let a: [4]u8; a[0] = 1u8; a[1] = 3u8; a[2] = 3u8; a[3] = 7u8; + match (bytes.rindex(a[0:4], 3u8)) { + case let i: i32 => { assert(!(i != 2)); }; + case void => abort(); + }; + match (bytes.rindex(a[0:4], 42u8)) { + case let i: i32 => abort(); + case void => void; + }; + let z: [1]u8; + match (bytes.rindex(z[0:0], 42u8)) { + case let i: i32 => abort(); + case void => void; + }; +}; + +// ref/hare/bytes/index.ha:123-125. Distinguishes from index when the +// needle appears more than once. + +@test fn rindex_slice_cases() void = { + let a: [4]u8; a[0] = 1u8; a[1] = 1u8; a[2] = 1u8; a[3] = 2u8; + let n11: [2]u8; n11[0] = 1u8; n11[1] = 1u8; + match (bytes.rindex(a[0:4], n11[0:2])) { + case let i: i32 => { assert(!(i != 1)); }; + case void => abort(); + }; + let n12: [2]u8; n12[0] = 1u8; n12[1] = 2u8; + match (bytes.rindex(a[0:4], n12[0:2])) { + case let i: i32 => { assert(!(i != 2)); }; + case void => abort(); + }; + // absent + let n99: [2]u8; n99[0] = 9u8; n99[1] = 9u8; + match (bytes.rindex(a[0:4], n99[0:2])) { + case let i: i32 => abort(); + case void => void; + }; +}; diff --git a/lib/bytes/bytes_test.ww b/lib/bytes/tokenize_test.ww similarity index 61% rename from lib/bytes/bytes_test.ww rename to lib/bytes/tokenize_test.ww index 89f43eaa..4c289725 100644 --- a/lib/bytes/bytes_test.ww +++ b/lib/bytes/tokenize_test.ww @@ -1,243 +1,12 @@ -// bytestest — exercises lib/bytes. Run with -// `out/bin/ww run lib/bytes/bytestest.ww`. A failing row aborts via the -// assert/abort builtin (task #5 @test conversion). -// -// Vectors mirror Hare's @test fns in ref/hare/bytes/equal.ha, -// ref/hare/bytes/index.ha, ref/hare/bytes/contains.ha. +// tokenizetest — exercises the bytes tokenize/splitn/cut families. +// A failing row aborts via the assert/abort builtin (task #5 @test +// conversion). Vectors mirror ref/hare/bytes/tokenize.ha. package bytes_test; import bytes; import os; -// ---- equal ------------------------------------------------------------ -// ref/hare/bytes/equal.ha:21. - -@test fn equal_cases() void = { - let a: [3]u8; a[0] = 1u8; a[1] = 2u8; a[2] = 3u8; - let b: [3]u8; b[0] = 1u8; b[1] = 2u8; b[2] = 3u8; - let c: [3]u8; c[0] = 1u8; c[1] = 4u8; c[2] = 5u8; - let d: [4]u8; d[0] = 1u8; d[1] = 2u8; d[2] = 3u8; d[3] = 4u8; - let e: [2]u8; e[0] = 1u8; e[1] = 2u8; - let z: [1]u8; - assert(!(!bytes.equal(a[0:3], b[0:3]))); - assert(!( bytes.equal(a[0:3], c[0:3]))); - assert(!( bytes.equal(a[0:3], d[0:4]))); - assert(!( bytes.equal(a[0:3], e[0:2]))); - assert(!(!bytes.equal(z[0:0], z[0:0]))); // empty-empty -}; - -// ---- index(u8) -------------------------------------------------------- -// ref/hare/bytes/index.ha:112. - -@test fn index_byte_cases() void = { - let a: [4]u8; a[0] = 1u8; a[1] = 3u8; a[2] = 3u8; a[3] = 7u8; - match (bytes.index(a[0:4], 1u8)) { - case let i: i32 => { assert(!(i != 0)); }; - case void => abort(); - }; - match (bytes.index(a[0:4], 3u8)) { - case let i: i32 => { assert(!(i != 1)); }; - case void => abort(); - }; - match (bytes.index(a[0:4], 7u8)) { - case let i: i32 => { assert(!(i != 3)); }; - case void => abort(); - }; - match (bytes.index(a[0:4], 42u8)) { - case let i: i32 => abort(); - case void => void; - }; - let z: [1]u8; - match (bytes.index(z[0:0], 42u8)) { - case let i: i32 => abort(); - case void => void; - }; -}; - -// ---- index([]u8) ------------------------------------------------------ -// ref/hare/bytes/index.ha:128-139. Vector strings copied verbatim where -// representable as ASCII byte sequences. - -@test fn index_slice_cases() void = { - let h1: [4]u8; h1[0] = 1u8; h1[1] = 42u8; h1[2] = 24u8; h1[3] = 0u8; - let n1: [2]u8; n1[0] = 42u8; n1[1] = 24u8; - match (bytes.index(h1[0:3], n1[0:2])) { - case let i: i32 => { assert(!(i != 1)); }; - case void => abort(); - }; - - let h2: [4]u8; h2[0] = 1u8; h2[1] = 3u8; h2[2] = 3u8; h2[3] = 7u8; - let n2: [2]u8; n2[0] = 3u8; n2[1] = 3u8; - match (bytes.index(h2[0:4], n2[0:2])) { - case let i: i32 => { assert(!(i != 1)); }; - case void => abort(); - }; - - // needle longer than haystack — void - let h3: [3]u8; h3[0] = 1u8; h3[1] = 2u8; h3[2] = 3u8; - let n3: [4]u8; n3[0] = 1u8; n3[1] = 2u8; n3[2] = 3u8; n3[3] = 4u8; - match (bytes.index(h3[0:3], n3[0:4])) { - case let i: i32 => abort(); - case void => void; - }; - - // len(haystack) == len(needle), match — offset 0 - let h4: [2]u8; h4[0] = 42u8; h4[1] = 20u8; - let n4: [2]u8; n4[0] = 42u8; n4[1] = 20u8; - match (bytes.index(h4[0:2], n4[0:2])) { - case let i: i32 => { assert(!(i != 0)); }; - case void => abort(); - }; - - // len(haystack) == len(needle), no match — void - let h5: [4]u8; h5[0] = 1u8; h5[1] = 1u8; h5[2] = 1u8; h5[3] = 2u8; - let n5: [4]u8; n5[0] = 1u8; n5[1] = 1u8; n5[2] = 1u8; n5[3] = 3u8; - match (bytes.index(h5[0:4], n5[0:4])) { - case let i: i32 => abort(); - case void => void; - }; - - // Partial-prefix recovery — needle [1,1,2] aligns at i=1 after the - // false-start at i=0 ([1,1,1] mismatches at byte 2). Pins the - // naive scanner's restart discipline. - let h6: [4]u8; h6[0] = 1u8; h6[1] = 1u8; h6[2] = 1u8; h6[3] = 2u8; - let n6s: [3]u8; n6s[0] = 1u8; n6s[1] = 1u8; n6s[2] = 2u8; - match (bytes.index(h6[0:4], n6s[0:3])) { - case let i: i32 => { assert(!(i != 1)); }; - case void => abort(); - }; - - // Same shape, longer haystack with no match anywhere. - let h7: [5]u8; h7[0] = 1u8; h7[1] = 1u8; h7[2] = 1u8; h7[3] = 3u8; h7[4] = 2u8; - let n7: [4]u8; n7[0] = 1u8; n7[1] = 1u8; n7[2] = 1u8; n7[3] = 2u8; - match (bytes.index(h7[0:5], n7[0:4])) { - case let i: i32 => abort(); - case void => void; - }; - - // empty needle — Hare returns 0 (ref/hare/bytes/index.ha:63). - let z: [1]u8; - let zn: [1]u8; - match (bytes.index(h2[0:4], zn[0:0])) { - case let i: i32 => { assert(!(i != 0)); }; - case void => abort(); - }; - // empty haystack, non-empty needle — void - match (bytes.index(z[0:0], n3[0:3])) { - case let i: i32 => abort(); - case void => void; - }; - - // single-byte slice needle — should semantically equal u8 arm - let n6: [1]u8; n6[0] = 7u8; - match (bytes.index(h2[0:4], n6[0:1])) { - case let i: i32 => { assert(!(i != 3)); }; - case void => abort(); - }; -}; - -// ---- rindex(u8) ------------------------------------------------------- -// ref/hare/bytes/index.ha:118. - -@test fn rindex_byte_cases() void = { - let a: [4]u8; a[0] = 1u8; a[1] = 3u8; a[2] = 3u8; a[3] = 7u8; - match (bytes.rindex(a[0:4], 3u8)) { - case let i: i32 => { assert(!(i != 2)); }; - case void => abort(); - }; - match (bytes.rindex(a[0:4], 42u8)) { - case let i: i32 => abort(); - case void => void; - }; - let z: [1]u8; - match (bytes.rindex(z[0:0], 42u8)) { - case let i: i32 => abort(); - case void => void; - }; -}; - -// ---- rindex([]u8) ----------------------------------------------------- -// ref/hare/bytes/index.ha:123-125. Distinguishes from index when the -// needle appears more than once. - -@test fn rindex_slice_cases() void = { - let a: [4]u8; a[0] = 1u8; a[1] = 1u8; a[2] = 1u8; a[3] = 2u8; - let n11: [2]u8; n11[0] = 1u8; n11[1] = 1u8; - match (bytes.rindex(a[0:4], n11[0:2])) { - case let i: i32 => { assert(!(i != 1)); }; - case void => abort(); - }; - let n12: [2]u8; n12[0] = 1u8; n12[1] = 2u8; - match (bytes.rindex(a[0:4], n12[0:2])) { - case let i: i32 => { assert(!(i != 2)); }; - case void => abort(); - }; - // absent - let n99: [2]u8; n99[0] = 9u8; n99[1] = 9u8; - match (bytes.rindex(a[0:4], n99[0:2])) { - case let i: i32 => abort(); - case void => void; - }; -}; - -// ---- contains --------------------------------------------------------- - -@test fn contains_cases() void = { - let a: [4]u8; a[0] = 1u8; a[1] = 3u8; a[2] = 3u8; a[3] = 7u8; - assert(!(!bytes.contains(a[0:4], 7u8))); - assert(!( bytes.contains(a[0:4], 42u8))); - let n: [2]u8; n[0] = 3u8; n[1] = 3u8; - assert(!(!bytes.contains(a[0:4], n[0:2]))); - let m: [2]u8; m[0] = 9u8; m[1] = 9u8; - assert(!( bytes.contains(a[0:4], m[0:2]))); - - // Variadic rows. ref/hare/bytes/contains.ha:6. - assert(!( bytes.contains(a[0:4]))); - assert(!(!bytes.contains(a[0:4], n[0:2]))); - assert(!(!bytes.contains(a[0:4], 7u8))); - assert(!(!bytes.contains(a[0:4], m[0:2], n[0:2], 42u8))); - assert(!( bytes.contains(a[0:4], m[0:2], 42u8, m[0:2]))); -}; - -// ---- hasprefix -------------------------------------------------------- -// ref/hare/bytes/contains.ha:25. - -@test fn hasprefix_cases() void = { - let z: [1]u8; - assert(!(!bytes.hasprefix(z[0:0], z[0:0]))); - let one: [1]u8; one[0] = 0u8; - assert(!(!bytes.hasprefix(one[0:1], z[0:0]))); - assert(!( bytes.hasprefix(z[0:0], one[0:1]))); - let a: [3]u8; a[0] = 1u8; a[1] = 2u8; a[2] = 3u8; - let p12: [2]u8; p12[0] = 1u8; p12[1] = 2u8; - assert(!(!bytes.hasprefix(a[0:3], p12[0:2]))); - let p11: [2]u8; p11[0] = 1u8; p11[1] = 1u8; - assert(!( bytes.hasprefix(a[0:3], p11[0:2]))); - let pl: [4]u8; pl[0] = 1u8; pl[1] = 2u8; pl[2] = 3u8; pl[3] = 4u8; - assert(!( bytes.hasprefix(a[0:3], pl[0:4]))); -}; - -// ---- hassuffix -------------------------------------------------------- -// ref/hare/bytes/contains.ha:40. - -@test fn hassuffix_cases() void = { - let z: [1]u8; - assert(!(!bytes.hassuffix(z[0:0], z[0:0]))); - let one: [1]u8; one[0] = 0u8; - assert(!(!bytes.hassuffix(one[0:1], z[0:0]))); - assert(!( bytes.hassuffix(z[0:0], one[0:1]))); - let a: [3]u8; a[0] = 1u8; a[1] = 2u8; a[2] = 3u8; - let s23: [2]u8; s23[0] = 2u8; s23[1] = 3u8; - assert(!(!bytes.hassuffix(a[0:3], s23[0:2]))); - let s22: [2]u8; s22[0] = 2u8; s22[1] = 2u8; - assert(!( bytes.hassuffix(a[0:3], s22[0:2]))); - let a4: [4]u8; a4[0] = 1u8; a4[1] = 2u8; a4[2] = 3u8; a4[3] = 4u8; - let s234: [3]u8; s234[0] = 2u8; s234[1] = 3u8; s234[2] = 4u8; - assert(!(!bytes.hassuffix(a4[0:4], s234[0:3]))); -}; - -// ---- tokenize / rtokenize / peektoken / remainingtokens ----------- // ref/hare/bytes/tokenize.ha:258. Hare's @test fn tokenize / rtokenize // drives the iterator through an expected-token sequence and asserts // `equal(p, n)` (peek == next), `equal(n, want)` (next == expected). @@ -441,96 +210,6 @@ fn expect_done(t: *bytes.tokenizer) void = { assert(!(!bytes.equal(r2, e_12[0:2]))); }; -// ---- ltrim / rtrim / trim --------------------------------------------- -// ref/hare/bytes/trim.ha:29 — Hare's @test fn trim pins -// `trim([0,1,2,3,5,0], 0) == [1,2,3,5]`, `trim([0,0,0], 0) == []`, -// `trim([], 0) == []`. ww spreads the matrix across ltrim/rtrim/trim. - -fn beq(got: []u8, want: []u8) bool = { - if (got.len != want.len) { return false; }; - let i: i32 = 0; - for (i < got.len) { - if (got[i] != want[i]) { return false; }; - i += 1; - }; - return true; -}; - -@test fn ltrim_cases() void = { - let z: [1]u8; - - // [0,0,1,2] / 0 -> [1,2] - let a: [4]u8; a[0] = 0u8; a[1] = 0u8; a[2] = 1u8; a[3] = 2u8; - let ea: [2]u8; ea[0] = 1u8; ea[1] = 2u8; - assert(!(!beq(bytes.ltrim(a[0:4], 0u8), ea[0:2]))); - - // [1,2,3] / 0 -> [1,2,3] (no leading match) - let b: [3]u8; b[0] = 1u8; b[1] = 2u8; b[2] = 3u8; - assert(!(!beq(bytes.ltrim(b[0:3], 0u8), b[0:3]))); - - // [0,0,0] / 0 -> [] (full match) — the bare `let c: [3]u8;` zero-init - // row that surfaced #16 (a dirtied slot read non-zero, ltrim trimmed - // nothing). Now reads {0,0,0} and trims to empty. - let c: [3]u8; - assert(!(!beq(bytes.ltrim(c[0:3], 0u8), z[0:0]))); - - // [] / 0 -> [] (empty input) - assert(!(!beq(bytes.ltrim(z[0:0], 0u8), z[0:0]))); -}; - -@test fn rtrim_cases() void = { - let z: [1]u8; - - // [1,2,0,0] / 0 -> [1,2] - let a: [4]u8; a[0] = 1u8; a[1] = 2u8; a[2] = 0u8; a[3] = 0u8; - let ea: [2]u8; ea[0] = 1u8; ea[1] = 2u8; - assert(!(!beq(bytes.rtrim(a[0:4], 0u8), ea[0:2]))); - - // [1,2,3] / 0 -> [1,2,3] (no trailing match) - let b: [3]u8; b[0] = 1u8; b[1] = 2u8; b[2] = 3u8; - assert(!(!beq(bytes.rtrim(b[0:3], 0u8), b[0:3]))); - - // [0,0,0] / 0 -> [] (full match) - let c: [3]u8; - assert(!(!beq(bytes.rtrim(c[0:3], 0u8), z[0:0]))); - - // [] / 0 -> [] (empty input) - assert(!(!beq(bytes.rtrim(z[0:0], 0u8), z[0:0]))); -}; - -@test fn trim_cases() void = { - let z: [1]u8; - - // [0,1,2,3,5,0] / 0 -> [1,2,3,5] - let a: [6]u8; - a[0] = 0u8; a[1] = 1u8; a[2] = 2u8; - a[3] = 3u8; a[4] = 5u8; a[5] = 0u8; - let ea: [4]u8; ea[0] = 1u8; ea[1] = 2u8; ea[2] = 3u8; ea[3] = 5u8; - assert(!(!beq(bytes.trim(a[0:6], 0u8), ea[0:4]))); - - // [0,5,0] / 5 -> [0,5,0] (only 5 in trim set; boundary mismatch) - let b: [3]u8; b[0] = 0u8; b[1] = 5u8; b[2] = 0u8; - assert(!(!beq(bytes.trim(b[0:3], 5u8), b[0:3]))); - - // [0,1,42,1,0] / {0,42} -> [1,42,1] (multi-byte trim set) - let c: [5]u8; - c[0] = 0u8; c[1] = 1u8; c[2] = 42u8; c[3] = 1u8; c[4] = 0u8; - let ec: [3]u8; ec[0] = 1u8; ec[1] = 42u8; ec[2] = 1u8; - assert(!(!beq(bytes.trim(c[0:5], 0u8, 42u8), ec[0:3]))); - - // [0,0,0] / 0 -> [] (full match) - let d: [3]u8; - assert(!(!beq(bytes.trim(d[0:3], 0u8), z[0:0]))); - - // [] / 0 -> [] (empty input, Hare ref/hare/bytes/trim.ha:34) - assert(!(!beq(bytes.trim(z[0:0], 0u8), z[0:0]))); - - // [1,2,3,5] / 0 -> [1,2,3,5] (Hare ref/hare/bytes/trim.ha:31) - let e: [4]u8; e[0] = 1u8; e[1] = 2u8; e[2] = 3u8; e[3] = 5u8; - assert(!(!beq(bytes.trim(e[0:4], 0u8), e[0:4]))); -}; - -// ---- splitn / rsplitn / split ----------------------------------------- // ref/hare/bytes/tokenize.ha:330 (@test fn split). Hare's table mixes // strings; ww spells the vectors as byte arrays explicitly. // @@ -697,7 +376,6 @@ fn expect_tok(toks: [][]u8, i: i32, want: []u8) void = { os.free(t2.ptr: *void, (t2.cap: u64) * 24u64); }; -// ---- cut / rcut ------------------------------------------------------- // ref/hare/bytes/tokenize.ha:429 (@test fn cut). Borrowed views; each // half asserted via equal(). Needle order is ww's (u8 | []u8). Rows use // the destructure form `let (before, after) = cut(...)` to drive the #10 diff --git a/lib/bytes/trim_test.ww b/lib/bytes/trim_test.ww new file mode 100644 index 00000000..7e1a25cc --- /dev/null +++ b/lib/bytes/trim_test.ww @@ -0,0 +1,95 @@ +// trimtest — exercises bytes.ltrim/rtrim/trim. A failing row aborts +// via the assert/abort builtin (task #5 @test conversion). +// Vectors mirror ref/hare/bytes/trim.ha. + +package bytes_test; + +import bytes; + +// ref/hare/bytes/trim.ha:29 — Hare's @test fn trim pins +// `trim([0,1,2,3,5,0], 0) == [1,2,3,5]`, `trim([0,0,0], 0) == []`, +// `trim([], 0) == []`. ww spreads the matrix across ltrim/rtrim/trim. + +fn beq(got: []u8, want: []u8) bool = { + if (got.len != want.len) { return false; }; + let i: i32 = 0; + for (i < got.len) { + if (got[i] != want[i]) { return false; }; + i += 1; + }; + return true; +}; + +@test fn ltrim_cases() void = { + let z: [1]u8; + + // [0,0,1,2] / 0 -> [1,2] + let a: [4]u8; a[0] = 0u8; a[1] = 0u8; a[2] = 1u8; a[3] = 2u8; + let ea: [2]u8; ea[0] = 1u8; ea[1] = 2u8; + assert(!(!beq(bytes.ltrim(a[0:4], 0u8), ea[0:2]))); + + // [1,2,3] / 0 -> [1,2,3] (no leading match) + let b: [3]u8; b[0] = 1u8; b[1] = 2u8; b[2] = 3u8; + assert(!(!beq(bytes.ltrim(b[0:3], 0u8), b[0:3]))); + + // [0,0,0] / 0 -> [] (full match) — the bare `let c: [3]u8;` zero-init + // row that surfaced #16 (a dirtied slot read non-zero, ltrim trimmed + // nothing). Now reads {0,0,0} and trims to empty. + let c: [3]u8; + assert(!(!beq(bytes.ltrim(c[0:3], 0u8), z[0:0]))); + + // [] / 0 -> [] (empty input) + assert(!(!beq(bytes.ltrim(z[0:0], 0u8), z[0:0]))); +}; + +@test fn rtrim_cases() void = { + let z: [1]u8; + + // [1,2,0,0] / 0 -> [1,2] + let a: [4]u8; a[0] = 1u8; a[1] = 2u8; a[2] = 0u8; a[3] = 0u8; + let ea: [2]u8; ea[0] = 1u8; ea[1] = 2u8; + assert(!(!beq(bytes.rtrim(a[0:4], 0u8), ea[0:2]))); + + // [1,2,3] / 0 -> [1,2,3] (no trailing match) + let b: [3]u8; b[0] = 1u8; b[1] = 2u8; b[2] = 3u8; + assert(!(!beq(bytes.rtrim(b[0:3], 0u8), b[0:3]))); + + // [0,0,0] / 0 -> [] (full match) + let c: [3]u8; + assert(!(!beq(bytes.rtrim(c[0:3], 0u8), z[0:0]))); + + // [] / 0 -> [] (empty input) + assert(!(!beq(bytes.rtrim(z[0:0], 0u8), z[0:0]))); +}; + +@test fn trim_cases() void = { + let z: [1]u8; + + // [0,1,2,3,5,0] / 0 -> [1,2,3,5] + let a: [6]u8; + a[0] = 0u8; a[1] = 1u8; a[2] = 2u8; + a[3] = 3u8; a[4] = 5u8; a[5] = 0u8; + let ea: [4]u8; ea[0] = 1u8; ea[1] = 2u8; ea[2] = 3u8; ea[3] = 5u8; + assert(!(!beq(bytes.trim(a[0:6], 0u8), ea[0:4]))); + + // [0,5,0] / 5 -> [0,5,0] (only 5 in trim set; boundary mismatch) + let b: [3]u8; b[0] = 0u8; b[1] = 5u8; b[2] = 0u8; + assert(!(!beq(bytes.trim(b[0:3], 5u8), b[0:3]))); + + // [0,1,42,1,0] / {0,42} -> [1,42,1] (multi-byte trim set) + let c: [5]u8; + c[0] = 0u8; c[1] = 1u8; c[2] = 42u8; c[3] = 1u8; c[4] = 0u8; + let ec: [3]u8; ec[0] = 1u8; ec[1] = 42u8; ec[2] = 1u8; + assert(!(!beq(bytes.trim(c[0:5], 0u8, 42u8), ec[0:3]))); + + // [0,0,0] / 0 -> [] (full match) + let d: [3]u8; + assert(!(!beq(bytes.trim(d[0:3], 0u8), z[0:0]))); + + // [] / 0 -> [] (empty input, Hare ref/hare/bytes/trim.ha:34) + assert(!(!beq(bytes.trim(z[0:0], 0u8), z[0:0]))); + + // [1,2,3,5] / 0 -> [1,2,3,5] (Hare ref/hare/bytes/trim.ha:31) + let e: [4]u8; e[0] = 1u8; e[1] = 2u8; e[2] = 3u8; e[3] = 5u8; + assert(!(!beq(bytes.trim(e[0:4], 0u8), e[0:4]))); +}; diff --git a/test/byteid/libbyteid_test.ww b/test/byteid/libbyteid_test.ww index 47f9ea00..9b10ed13 100644 --- a/test/byteid/libbyteid_test.ww +++ b/test/byteid/libbyteid_test.ww @@ -43,7 +43,7 @@ import time; def MID: i32 = 0; def MDIVERGE: i32 = 1; def MWWREJECT: i32 = 2; -def NENTEXPECT: i32 = 51; +def NENTEXPECT: i32 = 55; type ent = struct { fixture: str, // repo-relative .ww; "" -> probe entry @@ -83,12 +83,16 @@ fn pri(p: str, inc: str, sentinel: str, moddir: str) ent = { return e; }; -// The 51-unit roster. Graduation history lives in git (the retired C +// The 55-unit roster. Graduation history lives in git (the retired C // carrier's table comments); cites are kept only where a non-ID pin // would need them. fn corpus() []ent = { let es: []ent = alloc([], NENTEXPECT: u64)!; - append(es, fx("lib/bytes/bytes_test.ww")); + append(es, fx("lib/bytes/equal_test.ww")); + append(es, fx("lib/bytes/index_test.ww")); + append(es, fx("lib/bytes/contains_test.ww")); + append(es, fx("lib/bytes/tokenize_test.ww")); + append(es, fx("lib/bytes/trim_test.ww")); append(es, fx("lib/dirs/dirs_test.ww")); append(es, fx("lib/encoding/base32/base32_test.ww")); append(es, fx("lib/encoding/hex/hex_test.ww"));