package pool import ( "reflect" "testing" ) func TestFindSubstring_Basic(t *testing.T) { text := "hello world hello" got := FindSubstring(text, "hello") want := [][2]int{{0, 5}, {12, 17}} if !reflect.DeepEqual(got, want) { t.Fatalf("got %v, want %v", got, want) } } func TestFindSubstring_CaseInsensitive(t *testing.T) { got := FindSubstring("Hello HELLo hellO", "hEllO") want := [][2]int{{0, 5}, {6, 11}, {12, 17}} if !reflect.DeepEqual(got, want) { t.Fatalf("got %v, want %v", got, want) } } func TestFindSubstring_NonASCIIFold(t *testing.T) { // Only the ASCII-foldable "STRASSE" matches "strasse" (lower-cased to // "strasse"); "Straße" lower-cases to "straße", which does not contain it. // Byte offset 8: "ß" is two UTF-8 bytes, so "Straße" is 7 bytes. got := FindSubstring("Straße STRASSE", "strasse") want := [][2]int{{8, 15}} if !reflect.DeepEqual(got, want) { t.Fatalf("got %v, want %v", got, want) } // And a query containing a multibyte rune still folds its ASCII parts. got = FindSubstring("Straße", "STRA") want = [][2]int{{0, 4}} if !reflect.DeepEqual(got, want) { t.Fatalf("got %v, want %v", got, want) } } func TestFindSubstring_NoMatch(t *testing.T) { if got := FindSubstring("abc", "xyz"); got != nil { t.Fatalf("got %v, want nil", got) } } func TestFindSubstring_EmptyQuery(t *testing.T) { if got := FindSubstring("abc", ""); got != nil { t.Fatalf("got %v, want nil for empty query", got) } } func TestFindSubstring_OverlappingConsumed(t *testing.T) { // "aa" in "aaa": one match; the match consumes its range. got := FindSubstring("aaa", "aa") want := [][2]int{{0, 2}} if !reflect.DeepEqual(got, want) { t.Fatalf("got %v, want %v", got, want) } // "...abaaba": matches at 3 and 6, not at 4. got = FindSubstring("abaaba", "aba") want = [][2]int{{0, 3}, {3, 6}} if !reflect.DeepEqual(got, want) { t.Fatalf("got %v, want %v", got, want) } } func TestFindSubstring_Multibyte(t *testing.T) { // Offsets are BYTE offsets. "é" is 2 bytes. text := "éxéx" // bytes: 0-1 é, 2 x, 3-4 é, 5 x got := FindSubstring(text, "xé") want := [][2]int{{2, 5}} if !reflect.DeepEqual(got, want) { t.Fatalf("got %v, want %v", got, want) } } func TestFindSubstring_WholeText(t *testing.T) { got := FindSubstring("abc", "ABC") want := [][2]int{{0, 3}} if !reflect.DeepEqual(got, want) { t.Fatalf("got %v, want %v", got, want) } } func TestSearchTask_Execute(t *testing.T) { task := NewSearchTask("one two One TWO", "two", 7) res := task.Execute() if !res.Success { t.Fatalf("unexpected error: %v", res.Error) } if res.TaskType != TypeSearch { t.Fatalf("type %v", res.TaskType) } sd, ok := res.Data.(SearchData) if !ok { t.Fatalf("data type %T", res.Data) } if sd.Gen != 7 { t.Fatalf("gen %d", sd.Gen) } want := [][2]int{{4, 7}, {12, 15}} if !reflect.DeepEqual(sd.Matches, want) { t.Fatalf("matches %v, want %v", sd.Matches, want) } }