nandi/oripublic Fork 0
7895c1d1c9bb1048807dc04f7246dc456c47e025
Commits
Clone
git clone https://git.rickub.com/nandi/ori.git
git clone ssh://git@rickub.com/nandi/ori.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

forked from bots-garden/ori

search_test.go · 121 lines · 3.5 KBGo Blame HistoryRaw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package files_test

import (
	"net/http"
	"os"
	"path/filepath"
	"testing"

	"rickub.com/bots-garden/ori/internal/files"
)

// searchWorkspace extends the basic tree with nested and noisy directories.
func searchWorkspace(t *testing.T) (string, http.Handler) {
	t.Helper()
	root, h := workspace(t)
	for _, rel := range []string{
		"src/server/main_test.go",
		"docs/guide.md",
		"node_modules/pkg/index.js",
		".git/HEAD",
	} {
		full := filepath.Join(root, rel)
		if err := os.MkdirAll(filepath.Dir(full), 0o755); err != nil {
			t.Fatal(err)
		}
		if err := os.WriteFile(full, []byte("x"), 0o644); err != nil {
			t.Fatal(err)
		}
	}
	return root, h
}

func relPaths(hits []files.Hit) []string {
	out := make([]string, 0, len(hits))
	for _, h := range hits {
		out = append(out, h.RelPath)
	}
	return out
}

func TestSearchIsRecursiveAndSkipsNoise(t *testing.T) {
	root, _ := searchWorkspace(t)
	hits := files.New(root).Search("", 0)
	got := relPaths(hits)
	// Ranked: shorter relative paths first, alphabetical among equals.
	want := []string{"README.md", "src/main.go", "docs/guide.md", "src/server/main_test.go"}
	if len(got) != len(want) {
		t.Fatalf("hits = %v, want %v", got, want)
	}
	for i := range want {
		if got[i] != want[i] {
			t.Errorf("hit[%d] = %q, want %q", i, got[i], want[i])
		}
	}
	if hits[1].Path != filepath.Join(root, "src", "main.go") || hits[1].Name != "main.go" {
		t.Errorf("hit = %+v, want absolute path and base name", hits[1])
	}
}

func TestSearchFiltersCaseInsensitivelyAndRanksBaseNames(t *testing.T) {
	root, _ := searchWorkspace(t)
	cases := []struct {
		query string
		want  []string
	}{
		{"MAIN", []string{"src/main.go", "src/server/main_test.go"}},
		// "src" matches only through the directory: still found.
		{"src/", []string{"src/main.go", "src/server/main_test.go"}},
		{"guide", []string{"docs/guide.md"}},
		{"nothing-here", []string{}},
	}
	for _, tc := range cases {
		got := relPaths(files.New(root).Search(tc.query, 10))
		if len(got) != len(tc.want) {
			t.Errorf("Search(%q) = %v, want %v", tc.query, got, tc.want)
			continue
		}
		for i := range tc.want {
			if got[i] != tc.want[i] {
				t.Errorf("Search(%q)[%d] = %q, want %q", tc.query, i, got[i], tc.want[i])
			}
		}
	}
}

func TestSearchHonoursLimit(t *testing.T) {
	root, _ := searchWorkspace(t)
	if got := files.New(root).Search("", 2); len(got) != 2 {
		t.Errorf("limit 2 returned %d hits", len(got))
	}
	if got := files.New(root).Search("", 100000); len(got) != 4 {
		t.Errorf("oversized limit returned %d hits, want all 4", len(got))
	}
}

func TestSearchEndpoint(t *testing.T) {
	_, h := searchWorkspace(t)
	rec := do(t, h, http.MethodGet, "/api/files/search?q=main&limit=1", "")
	if rec.Code != http.StatusOK {
		t.Fatalf("GET search = %d (%s)", rec.Code, rec.Body.String())
	}
	hits := decodeBody(t, rec)["files"].([]any)
	if len(hits) != 1 || hits[0].(map[string]any)["relPath"] != "src/main.go" {
		t.Errorf("files = %v, want [src/main.go]", hits)
	}

	rec = do(t, h, http.MethodGet, "/api/files/search?q=zzz", "")
	if got := decodeBody(t, rec)["files"].([]any); len(got) != 0 {
		t.Errorf("no-match search = %v, want an empty array", got)
	}
}

func TestSearchEndpointOnMissingRootIs404(t *testing.T) {
	mux := http.NewServeMux()
	for pattern, handler := range files.New(filepath.Join(t.TempDir(), "gone")).Routes() {
		mux.Handle(pattern, handler)
	}
	if rec := do(t, mux, http.MethodGet, "/api/files/search", ""); rec.Code != http.StatusNotFound {
		t.Errorf("search on missing root = %d, want 404", rec.Code)
	}
}