package picker import ( "os" "path/filepath" "sort" "strings" "testing" "time" "glint/internal/theme" ) func TestFuzzyMatchSubsequence(t *testing.T) { if _, ok := fuzzyMatch("abc", "axbxc"); !ok { t.Error("abc should match axbxc as a subsequence") } if _, ok := fuzzyMatch("abc", "acb"); ok { t.Error("abc should NOT match acb (out of order)") } if _, ok := fuzzyMatch("", "anything"); !ok { t.Error("empty query should match anything") } } func TestFuzzyMatchCaseInsensitive(t *testing.T) { if _, ok := fuzzyMatch("DOC", "my-document"); !ok { t.Error("DOC should match my-document case-insensitively") } } func TestFuzzyMatchContiguousScoresHigher(t *testing.T) { tight, ok1 := fuzzyMatch("ab", "abxx") loose, ok2 := fuzzyMatch("ab", "axxb") if !ok1 || !ok2 { t.Fatal("both should match") } if tight <= loose { t.Errorf("contiguous match (%d) should score higher than gapped (%d)", tight, loose) } } func TestWalkMarkdownSkipsDotDirsAndNonMarkdown(t *testing.T) { root := t.TempDir() os.WriteFile(filepath.Join(root, "a.md"), nil, 0o644) os.WriteFile(filepath.Join(root, "b.txt"), nil, 0o644) os.MkdirAll(filepath.Join(root, ".git"), 0o755) os.WriteFile(filepath.Join(root, ".git", "c.md"), nil, 0o644) os.MkdirAll(filepath.Join(root, "sub"), 0o755) os.WriteFile(filepath.Join(root, "sub", "d.md"), nil, 0o644) entries, err := walkMarkdown(root) if err != nil { t.Fatal(err) } var got []string for _, e := range entries { got = append(got, e.path) } sort.Strings(got) want := []string{ filepath.Join(root, "a.md"), filepath.Join(root, "sub", "d.md"), } if len(got) != len(want) { t.Fatalf("walkMarkdown = %v, want %v", got, want) } for i := range want { if got[i] != want[i] { t.Errorf("got[%d] = %q, want %q", i, got[i], want[i]) } } } func TestRankEntriesMtimeDescending(t *testing.T) { base := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC) all := []fileEntry{ {path: "/v/old.md", mod: base}, {path: "/v/new.md", mod: base.Add(48 * time.Hour)}, {path: "/v/mid.md", mod: base.Add(24 * time.Hour)}, } got := rankEntries(all, "", "") want := []string{"/v/new.md", "/v/mid.md", "/v/old.md"} for i := range want { if got[i] != want[i] { t.Errorf("got[%d] = %q, want %q", i, got[i], want[i]) } } } func TestRankEntriesTodayFloatsToTop(t *testing.T) { base := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC) all := []fileEntry{ {path: "/v/new.md", mod: base.Add(48 * time.Hour)}, {path: "/v/Daily/2026-06-28.md", mod: base}, // oldest, but today } got := rankEntries(all, "", "/v/Daily/2026-06-28.md") if got[0] != "/v/Daily/2026-06-28.md" { t.Errorf("today's note should float to top, got %q", got[0]) } } func TestRankEntriesQueryFiltersAndTieBreaksByMtime(t *testing.T) { base := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC) all := []fileEntry{ {path: "/v/alpha.md", mod: base}, {path: "/v/alpha-new.md", mod: base.Add(24 * time.Hour)}, {path: "/v/zzz.md", mod: base.Add(72 * time.Hour)}, } got := rankEntries(all, "alpha", "") // zzz filtered out; both "alpha" files present, newer first on equal score is // not guaranteed (scores differ), but zzz must be absent. for _, p := range got { if p == "/v/zzz.md" { t.Error("zzz.md should not match query 'alpha'") } } if len(got) != 2 { t.Fatalf("got %d matches, want 2", len(got)) } } func TestPickerPreviewRendersSelectedFile(t *testing.T) { root := t.TempDir() p := filepath.Join(root, "note.md") os.WriteFile(p, []byte("# Heading\n\nbody text"), 0o644) m, err := New(root, theme.FlexokiDark(), "", "dark") if err != nil { t.Fatal(err) } m.SetSize(120, 30) m.recompute() // selects note.md view := m.View() if !strings.Contains(view, "Heading") { t.Errorf("preview pane should render the selected file's heading; view:\n%s", view) } } func TestNewNotePath(t *testing.T) { root := "/v" cases := map[string]string{ "foo": filepath.Join("/v", "foo.md"), "Folder/Bar": filepath.Join("/v", "Folder", "Bar.md"), "x.md": filepath.Join("/v", "x.md"), " spaced ": filepath.Join("/v", "spaced.md"), } for q, want := range cases { if got := NewNotePath(root, q); got != want { t.Errorf("NewNotePath(%q) = %q, want %q", q, got, want) } } if NewNotePath(root, " ") != "" { t.Error("blank query should yield empty path") } }