package editor import "testing" func TestSetFindQueryFindsAllMatches(t *testing.T) { e := newEditorWith("foo bar foo", "baz foo") if n := e.SetFindQuery("foo"); n != 3 { t.Fatalf("want 3 matches, got %d", n) } if e.FindCount() != 3 { t.Errorf("FindCount = %d, want 3", e.FindCount()) } } func TestFindIsCaseInsensitive(t *testing.T) { e := newEditorWith("Foo foo FOO") if n := e.SetFindQuery("foo"); n != 3 { t.Fatalf("case-insensitive find: want 3, got %d", n) } } func TestFindMatchesAreNonOverlapping(t *testing.T) { e := newEditorWith("aaaa") if n := e.SetFindQuery("aa"); n != 2 { t.Fatalf("non-overlapping: want 2, got %d", n) } } func TestSetFindQueryActivatesFirstMatchFromCursor(t *testing.T) { e := newEditorWith("foo", "foo", "foo") e.Cursor = Position{Row: 1, Col: 0} e.SetFindQuery("foo") row, _, _, ok := e.ActiveMatch() if !ok || row != 1 { t.Fatalf("active match row = %d ok=%v, want row 1", row, ok) } } func TestSetFindQueryMovesCursorToActiveMatch(t *testing.T) { e := newEditorWith("alpha", "beta target", "gamma") e.SetFindQuery("target") if e.Cursor.Row != 1 || e.Cursor.Col != 5 { t.Fatalf("cursor = %+v, want {1,5}", e.Cursor) } } func TestFindNextWraps(t *testing.T) { e := newEditorWith("x", "x", "x") e.SetFindQuery("x") // active 0 e.FindNext() // 1 e.FindNext() // 2 if r, _, _, _ := e.ActiveMatch(); r != 2 { t.Fatalf("after 2 next, active row = %d, want 2", r) } e.FindNext() // wraps to 0 if r, _, _, _ := e.ActiveMatch(); r != 0 { t.Fatalf("FindNext should wrap to row 0, got %d", r) } } func TestFindPrevWraps(t *testing.T) { e := newEditorWith("x", "x", "x") e.Cursor = Position{Row: 0, Col: 0} e.SetFindQuery("x") // active 0 e.FindPrev() // wraps to last if r, _, _, _ := e.ActiveMatch(); r != 2 { t.Fatalf("FindPrev should wrap to row 2, got %d", r) } } func TestFindNextScrollsToMatch(t *testing.T) { lines := make([]string, 40) for i := range lines { lines[i] = "line" } lines[30] = "needle" e := newEditorWith(lines...) e.SetSize(80, 5) // only 5 visible rows e.SetFindQuery("needle") if e.Scroll == 0 { t.Fatalf("view should scroll so the match is visible, Scroll=%d", e.Scroll) } ci := cursorVIndex(e.buildVisual(), e.Cursor) if ci < e.Scroll || ci >= e.Scroll+e.Height { t.Fatalf("active match (vrow %d) not in viewport [%d,%d)", ci, e.Scroll, e.Scroll+e.Height) } } func TestEmptyQueryClearsMatches(t *testing.T) { e := newEditorWith("foo foo") e.SetFindQuery("foo") if e.SetFindQuery(""); e.FindCount() != 0 { t.Fatalf("empty query should clear matches, got %d", e.FindCount()) } if _, _, _, ok := e.ActiveMatch(); ok { t.Error("empty query should clear the active match") } } func TestClearFindResetsState(t *testing.T) { e := newEditorWith("foo foo") e.SetFindQuery("foo") e.ClearFind() if e.FindCount() != 0 { t.Fatalf("ClearFind should drop matches, got %d", e.FindCount()) } if _, _, _, ok := e.ActiveMatch(); ok { t.Error("ClearFind should clear the active match") } } func TestFindNoMatches(t *testing.T) { e := newEditorWith("hello world") if n := e.SetFindQuery("zzz"); n != 0 { t.Fatalf("want 0 matches, got %d", n) } if _, _, _, ok := e.ActiveMatch(); ok { t.Error("no matches should mean no active match") } e.FindNext() // must not panic e.FindPrev() } func TestSetContentClearsFind(t *testing.T) { e := newEditorWith("foo foo") e.SetFindQuery("foo") e.SetContent([]byte("bar")) if e.FindCount() != 0 { t.Fatalf("SetContent should clear find state, got %d", e.FindCount()) } }