155 lines
5.4 KiB
Go
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))
|
|
}
|
|
}
|