// indextest — exercises strings.byteindex/rbyteindex/index/rindex. // A failing row aborts via the assert/abort builtin (task #5 @test // conversion). Vectors mirror ref/hare/strings/index.ha. package strings_test; import strings; // ref/hare/strings/index.ha:147 (byteindex tests, both arms). @test fn byteindex_str_cases() void = { match (strings.byteindex("hello", "hello")) { case let i: i32 => { assert(!(i != 0)); }; case void => { abort(); }; }; match (strings.byteindex("hello world!", "world")) { case let i: i32 => { assert(!(i != 6)); }; case void => { abort(); }; }; match (strings.byteindex("hello world!", "orld!")) { case let i: i32 => { assert(!(i != 7)); }; case void => { abort(); }; }; match (strings.byteindex("hello world!", "word")) { case let i: i32 => { abort(); }; case void => void; }; // empty needle hits at 0 (ref/hare/bytes/index.ha:63). match (strings.byteindex("hello", "")) { case let i: i32 => { assert(!(i != 0)); }; case void => { abort(); }; }; // empty haystack, non-empty needle — absent. match (strings.byteindex("", "x")) { case let i: i32 => { abort(); }; case void => void; }; // multibyte substring in multibyte haystack. match (strings.byteindex("こんにちは", "ちは")) { case let i: i32 => { assert(!(i != 9)); }; case void => { abort(); }; }; }; @test fn byteindex_rune_cases() void = { // ASCII rune (1-byte encoding). match (strings.byteindex("hello world", 'w')) { case let i: i32 => { assert(!(i != 6)); }; case void => { abort(); }; }; // 2-byte rune U+00E9 'é' inside "café". match (strings.byteindex("café", 0xE9u32: rune)) { case let i: i32 => { assert(!(i != 3)); }; case void => { abort(); }; }; // 3-byte rune U+3061 'ち' inside "こんにちは". match (strings.byteindex("こんにちは", 0x3061u32: rune)) { case let i: i32 => { assert(!(i != 9)); }; case void => { abort(); }; }; // 4-byte rune U+1F980 '🦀' inside "ab🦀cd". match (strings.byteindex("ab🦀cd", 0x1F980u32: rune)) { case let i: i32 => { assert(!(i != 2)); }; case void => { abort(); }; }; // absent. match (strings.byteindex("こんにちは", 'q')) { case let i: i32 => { abort(); }; case void => void; }; }; @test fn rbyteindex_cases() void = { // Two 'た' in "またあったね" — ref/hare/strings/index.ha:160-161. match (strings.byteindex("またあったね", "た")) { case let i: i32 => { assert(!(i != 3)); }; case void => { abort(); }; }; match (strings.rbyteindex("またあったね", "た")) { case let i: i32 => { assert(!(i != 12)); }; case void => { abort(); }; }; // Rune arm, multi-byte 'に' U+306B. match (strings.rbyteindex("こんにちは", 0x306Bu32: rune)) { case let i: i32 => { assert(!(i != 6)); }; case void => { abort(); }; }; // Absent. match (strings.rbyteindex("abc", 'z')) { case let i: i32 => { abort(); }; case void => void; }; }; // ref/hare/strings/index.ha:108. Rune-wise offset, NOT byte-wise — the // multibyte rows pin that distinction (Hare doc at index.ha:7). @test fn index_cases() void = { // str-arm: ASCII haystack/needle, mid-string match. match (strings.index("hello", "ll")) { case let i: i32 => { assert(!(i != 2)); }; case void => { abort(); }; }; // str-arm: absent needle. match (strings.index("hello", "world")) { case let i: i32 => { abort(); }; case void => void; }; // Hare vectors at ref/hare/strings/index.ha:113-119. match (strings.index("hello world!", "hello")) { case let i: i32 => { assert(!(i != 0)); }; case void => { abort(); }; }; match (strings.index("hello world!", "world")) { case let i: i32 => { assert(!(i != 6)); }; case void => { abort(); }; }; match (strings.index("hello world!", "orld!")) { case let i: i32 => { assert(!(i != 7)); }; case void => { abort(); }; }; // Multibyte haystack + str needle: "ちは" at rune index 3 // in "こんにちは" (byteindex returns 9, rune-index is 3). match (strings.index("こんにちは", "ちは")) { case let i: i32 => { assert(!(i != 3)); }; case void => { abort(); }; }; // rune-arm. match (strings.index("hello", 'l')) { case let i: i32 => { assert(!(i != 2)); }; case void => { abort(); }; }; match (strings.index("hello world", 'w')) { case let i: i32 => { assert(!(i != 6)); }; case void => { abort(); }; }; // Multibyte rune: 'é' U+00E9 at rune 1 in "héllo" — pins // rune-index vs byte-index (byteindex returns 1; rune-index is // 1 also — but the str-arm's 1405 row covers the distinction). match (strings.index("héllo", 0xE9u32: rune)) { case let i: i32 => { assert(!(i != 1)); }; case void => { abort(); }; }; // Multibyte rune in multibyte haystack: 'ち' U+3061 at rune 3 // in "こんにちは" (byteindex returns 9, rune-index is 3). match (strings.index("こんにちは", 0x3061u32: rune)) { case let i: i32 => { assert(!(i != 3)); }; case void => { abort(); }; }; match (strings.index("こんにちは", 'q')) { case let i: i32 => { abort(); }; case void => void; }; // str-arm: rune-index ≠ byte-index again, mid-string match. // "あった" starts at rune 2 (byte 6) in "またあったね" // (each kana is 3 bytes; ref/hare/strings/index.ha:60). Pins // the dual-iterator walk against the discarded byteindex-and-walk // shape (#10). match (strings.index("またあったね", "あった")) { case let i: i32 => { assert(!(i != 2)); }; case void => { abort(); }; }; // str-arm: tail-anchored multibyte needle. "は" is at rune 4 // (byte 12) in "こんにちは". match (strings.index("こんにちは", "は")) { case let i: i32 => { assert(!(i != 4)); }; case void => { abort(); }; }; // Empty needle hits at rune 0 — Hare's `index_string` falls into // the `needle_rune is done` branch on the very first inner step // (ref/hare/strings/index.ha:70). match (strings.index("hello", "")) { case let i: i32 => { assert(!(i != 0)); }; case void => { abort(); }; }; match (strings.index("", "")) { case let i: i32 => { assert(!(i != 0)); }; case void => { abort(); }; }; // Empty haystack, non-empty needle — absent. match (strings.index("", "x")) { case let i: i32 => { abort(); }; case void => void; }; // Multibyte haystack, multibyte absent needle — exercises the // inner-loop mismatch-break across runes (#10, Hare row // ref/hare/strings/index.ha:119). match (strings.index("こんにちは", "きょうは")) { case let i: i32 => { abort(); }; case void => void; }; // Self-match: haystack == needle, Hare row index.ha:113. match (strings.index("hello", "hello")) { case let i: i32 => { assert(!(i != 0)); }; case void => { abort(); }; }; }; // ref/hare/strings/index.ha:22. Symmetric: last-occurrence rune index. @test fn rindex_cases() void = { // str-arm. match (strings.rindex("hello", "lo")) { case let i: i32 => { assert(!(i != 3)); }; case void => { abort(); }; }; // Hare vector at ref/hare/strings/index.ha:122. match (strings.rindex("hello world!", "o")) { case let i: i32 => { assert(!(i != 7)); }; case void => { abort(); }; }; match (strings.rindex("hello", "world")) { case let i: i32 => { abort(); }; case void => void; }; // Multibyte: last "た" in "またあったね" — rbyteindex returns // 12, rune-index is 4 (ま=0 た=1 あ=2 っ=3 た=4 ね=5). match (strings.rindex("またあったね", "た")) { case let i: i32 => { assert(!(i != 4)); }; case void => { abort(); }; }; // rune-arm. match (strings.rindex("hello", 'l')) { case let i: i32 => { assert(!(i != 3)); }; case void => { abort(); }; }; match (strings.rindex("aaaaa", 'a')) { case let i: i32 => { assert(!(i != 4)); }; case void => { abort(); }; }; // Multibyte rune: 'に' U+306B at rune 2 in "こんにちは". match (strings.rindex("こんにちは", 0x306Bu32: rune)) { case let i: i32 => { assert(!(i != 2)); }; case void => { abort(); }; }; match (strings.rindex("hello", 'z')) { case let i: i32 => { abort(); }; case void => void; }; };