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.
123 lines
3.1 KiB
Go
123 lines
3.1 KiB
Go
package browser
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"pad/internal/io/pool"
|
|
"pad/internal/io/pool/mock"
|
|
)
|
|
|
|
// TestLazyLoadingLargeDirectory verifies that page-based loading works
|
|
// correctly for large directories (10,000 entries), ensuring only visible
|
|
// and prefetched pages are kept in memory.
|
|
func TestLazyLoadingLargeDirectory(t *testing.T) {
|
|
state := NewBrowserState()
|
|
state.TotalEntries = 10000
|
|
state.EntryHeight = 48.0
|
|
state.VisibleCount = 10
|
|
mfs := mock.NewFileSystem()
|
|
wp := pool.NewWorkerPool(4)
|
|
wp.Start()
|
|
|
|
// Populate mock filesystem with 10k entries
|
|
mfs.AddDir("/dir", time.Now())
|
|
for i := 0; i < 10000; i++ {
|
|
mfs.AddFile(fmt.Sprintf("/dir/file_%d.txt", i), []byte("data"), time.Now())
|
|
}
|
|
|
|
bm, err := NewBrowserManager(state, wp, mfs)
|
|
if err != nil {
|
|
t.Fatalf("NewBrowserManager failed: %v", err)
|
|
}
|
|
|
|
// 1. Navigate to directory
|
|
bm.NavigateTo("/dir")
|
|
|
|
// Helper to get result with timeout
|
|
getResult := func(timeout time.Duration) (pool.Result, bool) {
|
|
select {
|
|
case res := <-wp.ResultChan():
|
|
return res, true
|
|
case <-time.After(timeout):
|
|
return pool.Result{}, false
|
|
}
|
|
}
|
|
|
|
// Wait for index build result and process it
|
|
res, ok := getResult(15 * time.Second)
|
|
if !ok {
|
|
t.Fatal("Timeout waiting for BuildIndex result")
|
|
}
|
|
bm.HandleResult(res)
|
|
|
|
// Wait for initial page load result and process it
|
|
res, ok = getResult(15 * time.Second)
|
|
if !ok {
|
|
t.Fatal("Timeout waiting for initial LoadPages result")
|
|
}
|
|
bm.HandleResult(res)
|
|
|
|
// 2. Verify only initial pages loaded (visible + prefetch)
|
|
if len(state.Pages) == 0 {
|
|
t.Error("Expected pages to be loaded")
|
|
}
|
|
|
|
// 3. Scroll down to page 50
|
|
state.ScrollOffset = 50 * 100 * state.EntryHeight // Scroll to middle
|
|
bm.OnScroll()
|
|
|
|
// Wait for load pages result for scroll
|
|
res, ok = getResult(15 * time.Second)
|
|
if !ok {
|
|
t.Fatal("Timeout waiting for scroll LoadPages result")
|
|
}
|
|
bm.HandleResult(res)
|
|
|
|
// 5. Verify old pages are evicted (e.g., page 0)
|
|
if page, ok := state.Pages[0]; ok && page.Loaded {
|
|
t.Error("Expected page 0 to be evicted")
|
|
}
|
|
}
|
|
|
|
// TestPrefetchOnScroll verifies that scroll triggers prefetch for
|
|
// pages within PrefetchDist.
|
|
func TestPrefetchOnScroll(t *testing.T) {
|
|
state := NewBrowserState()
|
|
state.TotalEntries = 1000
|
|
state.EntryHeight = 48.0
|
|
state.VisibleCount = 10
|
|
mfs := mock.NewFileSystem()
|
|
wp := pool.NewWorkerPool(4)
|
|
wp.Start()
|
|
|
|
// Populate mock filesystem
|
|
mfs.AddDir("/dir", time.Now())
|
|
for i := 0; i < 1000; i++ {
|
|
mfs.AddFile(fmt.Sprintf("/dir/file_%d.txt", i), []byte("data"), time.Now())
|
|
}
|
|
|
|
bm, err := NewBrowserManager(state, wp, mfs)
|
|
if err != nil {
|
|
t.Fatalf("NewBrowserManager failed: %v", err)
|
|
}
|
|
|
|
bm.NavigateTo("/dir")
|
|
// Process BuildIndex and initial load
|
|
bm.HandleResult(<-wp.ResultChan())
|
|
bm.HandleResult(<-wp.ResultChan())
|
|
|
|
// Current visible ~page 0. Pages 0, 1, 2 should be loaded.
|
|
// Scroll to page 5.
|
|
state.ScrollOffset = 5 * 100 * state.EntryHeight
|
|
bm.OnScroll()
|
|
// Process prefetch load
|
|
bm.HandleResult(<-wp.ResultChan())
|
|
|
|
// Prefetch should load pages around 5 (e.g., 3, 4, 5, 6, 7)
|
|
if _, ok := state.Pages[6]; !ok {
|
|
t.Error("Expected page 6 to be prefetched")
|
|
}
|
|
}
|