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.
227 lines
5.3 KiB
Go
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)
|
|
}
|
|
}
|