Pad/internal/browser/index_test.go
Greg Pomerantz 06b1444207 gofmt: format all remaining files with the go1.27 toolchain
The tree was formatted with an older gofmt; go1.27's gofmt additionally
wants: EOF exactly one newline (no trailing blank lines), imports sorted
alphabetically within a block, mixed-precedence binary expressions
re-spaced for grouping ((a+b)/c), single-field composite literals
un-aligned, adjacent one-line method signatures aligned, and one-line
bodies containing a compound statement expanded. Applied repo-wide
(31 files under internal/); pure formatting, no semantic changes —
build and the full test suite pass.
2026-08-23 10:03:27 -04:00

227 lines
5.3 KiB
Go

package browser
import (
"fmt"
"os"
"path/filepath"
"testing"
"time"
)
// --- Fixture setup ---
type testEntry struct {
name string
isDir bool
size int64
}
func setupTestDir(t *testing.T, entries []testEntry) string {
t.Helper()
dir := t.TempDir()
for _, e := range entries {
path := filepath.Join(dir, e.name)
if e.isDir {
err := os.Mkdir(path, 0755)
if err != nil {
t.Fatalf("failed to create dir %s: %v", e.name, err)
}
} else {
err := os.WriteFile(path, make([]byte, e.size), 0644)
if err != nil {
t.Fatalf("failed to create file %s: %v", e.name, err)
}
}
}
return dir
}
// --- Test: Build Index - Empty Dir ---
func TestBuildIndex_EmptyDir(t *testing.T) {
dir := setupTestDir(t, nil)
idx, err := buildIndex(dir)
if err != nil {
t.Fatalf("buildIndex(empty) returned error: %v", err)
}
if idx.EntryCount != 0 {
t.Errorf("expected EntryCount=0, got %d", idx.EntryCount)
}
if len(idx.Entries) != 0 {
t.Errorf("expected 0 entries, got %d", len(idx.Entries))
}
}
// --- Test: Build Index - Unsorted (raw metadata) ---
// Per design: index stores raw metadata; sorting happens at page-load time.
func TestBuildIndex_UnsortedRawMetadata(t *testing.T) {
dir := setupTestDir(t, []testEntry{
{name: "Zebra.txt", size: 100},
{name: "apple.txt", size: 200},
{name: "Banana.txt", size: 300},
{name: "cherry.txt", size: 400},
})
idx, err := buildIndex(dir)
if err != nil {
t.Fatalf("buildIndex returned error: %v", err)
}
// Index should contain all entries (order not guaranteed - raw metadata)
if len(idx.Entries) != 4 {
t.Fatalf("expected 4 entries, got %d", len(idx.Entries))
}
// Verify all entries are present (regardless of order)
names := make(map[string]bool)
for _, e := range idx.Entries {
names[e.Name] = true
}
for _, want := range []string{"Zebra.txt", "apple.txt", "Banana.txt", "cherry.txt"} {
if !names[want] {
t.Errorf("expected entry %q not found in index", want)
}
}
}
// --- Test: Build Index - Dirs and Files Both Present ---
// Per design: index stores raw metadata; dir/file ordering happens at page-load time.
func TestBuildIndex_DirsAndFilesPresent(t *testing.T) {
dir := setupTestDir(t, []testEntry{
{name: "file.txt", size: 100},
{name: "adir", isDir: true},
{name: "another.txt", size: 200},
{name: "bdir", isDir: true},
})
idx, err := buildIndex(dir)
if err != nil {
t.Fatalf("buildIndex returned error: %v", err)
}
// Both dirs and files should be present
var gotDirs, gotFiles int
for _, e := range idx.Entries {
if e.IsDir {
gotDirs++
} else {
gotFiles++
}
}
if gotDirs != 2 {
t.Errorf("expected 2 directories, got %d", gotDirs)
}
if gotFiles != 2 {
t.Errorf("expected 2 files, got %d", gotFiles)
}
}
// --- Test: Build Index - Cache Written ---
func TestBuildIndex_CacheWritten(t *testing.T) {
dir := setupTestDir(t, []testEntry{
{name: "test.txt", size: 100},
})
_, err := buildIndex(dir)
if err != nil {
t.Fatalf("buildIndex returned error: %v", err)
}
// Verify cache file exists
cachePath := getCachePath(dir)
if _, err := os.Stat(cachePath); os.IsNotExist(err) {
t.Errorf("expected cache file at %s, but it does not exist", cachePath)
}
}
// --- Test: Build Index - Cache Invalidated On Mtime Change ---
func TestBuildIndex_CacheInvalidatedOnMtimeChange(t *testing.T) {
dir := setupTestDir(t, []testEntry{
{name: "test.txt", size: 100},
})
// First build
idx1, err := buildIndex(dir)
if err != nil {
t.Fatalf("first buildIndex returned error: %v", err)
}
// Modify directory (add a file)
newFile := filepath.Join(dir, "newfile.txt")
if err := os.WriteFile(newFile, []byte("new"), 0644); err != nil {
t.Fatalf("failed to create new file: %v", err)
}
// Second build should detect change and rebuild
idx2, err := buildIndex(dir)
if err != nil {
t.Fatalf("second buildIndex returned error: %v", err)
}
if idx2.EntryCount <= idx1.EntryCount {
t.Errorf("expected entry count to increase after adding file; before=%d, after=%d",
idx1.EntryCount, idx2.EntryCount)
}
}
// --- Test: Build Index - Cache Reused When Unchanged ---
func TestBuildIndex_CacheReusedWhenUnchanged(t *testing.T) {
dir := setupTestDir(t, []testEntry{
{name: "test.txt", size: 100},
})
// First build
idx1, err := buildIndex(dir)
if err != nil {
t.Fatalf("first buildIndex returned error: %v", err)
}
// Second build (no changes)
idx2, err := buildIndex(dir)
if err != nil {
t.Fatalf("second buildIndex returned error: %v", err)
}
if idx1.EntryCount != idx2.EntryCount {
t.Errorf("expected same entry count; first=%d, second=%d",
idx1.EntryCount, idx2.EntryCount)
}
}
// --- Test: Build Index - Large Directory ---
func TestBuildIndex_LargeDirectory(t *testing.T) {
const count = 10000
entries := make([]testEntry, count)
for i := 0; i < count; i++ {
entries[i] = testEntry{
name: fmt.Sprintf("file_%05d.txt", i),
size: int64(i * 10),
}
}
dir := setupTestDir(t, entries)
start := time.Now()
idx, err := buildIndex(dir)
elapsed := time.Since(start)
if err != nil {
t.Fatalf("buildIndex returned error: %v", err)
}
if idx.EntryCount != count {
t.Errorf("expected %d entries, got %d", count, idx.EntryCount)
}
// Time budget: 5 seconds for 10k entries
if elapsed > 5*time.Second {
t.Errorf("buildIndex took %v, expected < 5s", elapsed)
}
}