Files
2026-07-13 13:00:08 +08:00

155 lines
5.4 KiB
Go

package fileref
import (
"os"
"path/filepath"
"testing"
)
// writeFile is a tiny helper that creates a regular file with placeholder
// content. Tests use it to scaffold the workspace layout before each Search
// call.
func writeFile(t *testing.T, path string) {
t.Helper()
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
t.Fatalf("mkdir: %v", err)
}
if err := os.WriteFile(path, []byte("ok"), 0o644); err != nil {
t.Fatalf("write: %v", err)
}
}
// resultPaths extracts just the Path fields from a slice of SearchResult for
// easy assertion against expected path lists.
func resultPaths(results []SearchResult) []string {
paths := make([]string, len(results))
for i, r := range results {
paths[i] = r.Path
}
return paths
}
// containsPath reports whether want appears in the results by Path field.
func containsPath(got []SearchResult, want string) bool {
for _, r := range got {
if r.Path == want {
return true
}
}
return false
}
// containsDirHit reports whether a result with the given Path and IsDir=true
// exists in the results.
func containsDirHit(got []SearchResult, wantPath string) bool {
for _, r := range got {
if r.Path == wantPath && r.IsDir {
return true
}
}
return false
}
// TestSearchMatchesPathSegment verifies the fix for issue #3769: a query
// matching an intermediate directory segment (here "planind") should now
// surface files under that directory, even when the basename does not
// contain the query.
func TestSearchMatchesPathSegment(t *testing.T) {
root := t.TempDir()
writeFile(t, filepath.Join(root, "src", "planind", "index.tsx"))
got := Search(root, "planind", 50)
if !containsPath(got, "src/planind/index.tsx") {
t.Fatalf("Search(%q) should return %q (path-segment match), got %v", "planind", "src/planind/index.tsx", resultPaths(got))
}
}
// TestSearchMatchesDirectories verifies that a query matching a directory
// name returns the directory itself with IsDir=true, not just its contents.
func TestSearchMatchesDirectories(t *testing.T) {
root := t.TempDir()
writeFile(t, filepath.Join(root, "docs", "assets", "readme.md"))
writeFile(t, filepath.Join(root, "docs", "assets", "image.png"))
got := Search(root, "assets", 50)
if !containsDirHit(got, "docs/assets") {
t.Fatalf("Search(%q) should return directory %q with IsDir=true, got %v", "assets", "docs/assets", resultPaths(got))
}
// Directory hits come after basename and segment hits.
if !containsPath(got, "docs/assets/readme.md") {
t.Fatalf("Search(%q) should still return files under the directory, got %v", "assets", resultPaths(got))
}
}
// TestSearchKeepsBasenameMatch guards the legacy behavior: when the query
// matches the file's basename, the file must still appear in the results,
// and basename hits must sort strictly before path-segment and directory
// hits so the most relevant matches surface at the top of the completion
// menu.
func TestSearchKeepsBasenameMatch(t *testing.T) {
root := t.TempDir()
writeFile(t, filepath.Join(root, "planind.go"))
writeFile(t, filepath.Join(root, "src", "planind", "index.tsx")) // also a segment hit
got := Search(root, "planind", 50)
gotPaths := resultPaths(got)
want := []string{"src/planind", "planind.go", "src/planind/index.tsx"}
if !equalSlices(gotPaths, want) {
t.Fatalf("Search(%q) order mismatch:\n want %v\n got %v", "planind", want, gotPaths)
}
// Verify the directory hit has IsDir=true.
if !containsDirHit(got, "src/planind") {
t.Fatalf("Search(%q) should return %q with IsDir=true", "planind", "src/planind")
}
}
// equalSlices reports whether two []string are element-wise equal.
func equalSlices(a, b []string) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
// TestSearchHandlesBasenamePathQuery verifies that searching for the basename
// part of a nested file still surfaces the file (regression guard).
func TestSearchHandlesBasenamePathQuery(t *testing.T) {
root := t.TempDir()
writeFile(t, filepath.Join(root, "src", "planind", "index.tsx"))
got := Search(root, "index", 50)
if !containsPath(got, "src/planind/index.tsx") {
t.Fatalf("Search(%q) should return %q (basename of nested file), got %v", "index", "src/planind/index.tsx", resultPaths(got))
}
}
// TestSearchSkipsNoiseStillWorks ensures the noise-directory skip list still
// applies to path-segment matches. Files under node_modules must not surface
// even when an intermediate segment matches the query.
func TestSearchSkipsNoiseStillWorks(t *testing.T) {
root := t.TempDir()
writeFile(t, filepath.Join(root, "src", "planind", "index.tsx")) // legitimate hit
writeFile(t, filepath.Join(root, "node_modules", "planind", "index.tsx")) // must be skipped
writeFile(t, filepath.Join(root, "build", "planind", "index.tsx")) // skipDirNames
writeFile(t, filepath.Join(root, "dist", "planind", "index.tsx")) // skipDirNames
got := Search(root, "planind", 50)
if containsPath(got, "node_modules/planind/index.tsx") {
t.Fatalf("Search should skip node_modules, got %v", resultPaths(got))
}
if containsPath(got, "build/planind/index.tsx") {
t.Fatalf("Search should skip build/, got %v", resultPaths(got))
}
if containsPath(got, "dist/planind/index.tsx") {
t.Fatalf("Search should skip dist/, got %v", resultPaths(got))
}
if !containsPath(got, "src/planind/index.tsx") {
t.Fatalf("Search should still return legitimate hit, got %v", resultPaths(got))
}
}