Pad/internal/browser/scroll_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

265 lines
7.0 KiB
Go

package browser
import (
"testing"
)
// --- Test: Scroll Clamp Minimum ---
func TestScrollClamp_Minimum(t *testing.T) {
s := NewBrowserState()
s.TotalEntries = 500
s.VisibleCount = 20
s.EntryHeight = 48.0
s.ScrollOffset = 0
// Try to scroll above the top
HandlePixelScroll(s, -5*48)
// ScrollOffset should be clamped to 0
if s.ScrollOffset != 0 {
t.Errorf("expected ScrollOffset=0 (clamped), got %.1f", s.ScrollOffset)
}
}
// --- Test: Scroll Clamp Maximum ---
func TestScrollClamp_Maximum(t *testing.T) {
s := NewBrowserState()
s.TotalEntries = 500
s.VisibleCount = 20
s.EntryHeight = 48.0
s.ScrollOffset = 0
// Scroll past the maximum to trigger clamp
maxScroll := float64(s.TotalEntries-s.VisibleCount) * s.EntryHeight
HandlePixelScroll(s, int(maxScroll)+1000)
// ScrollOffset should be clamped to max (TotalEntries - VisibleCount) * EntryHeight
if s.ScrollOffset != maxScroll {
t.Errorf("expected ScrollOffset=%.1f (clamped to max), got %.1f", maxScroll, s.ScrollOffset)
}
}
// --- Test: Scroll Delta Computation ---
func TestScrollDelta_Computation(t *testing.T) {
s := NewBrowserState()
s.TotalEntries = 1000
s.VisibleCount = 20
s.EntryHeight = 48.0
s.ScrollOffset = 100 * 48
// Scroll down by 5 entries (positive delta)
HandlePixelScroll(s, 5*48)
expectedOffset := float64(105 * 48)
if s.ScrollOffset != expectedOffset {
t.Errorf("expected ScrollOffset=%.1f after scrolling down 5 entries, got %.1f", expectedOffset, s.ScrollOffset)
}
// Scroll up by 3 entries (negative delta)
HandlePixelScroll(s, -3*48)
expectedOffset = float64(102 * 48)
if s.ScrollOffset != expectedOffset {
t.Errorf("expected ScrollOffset=%.1f after scrolling up 3 entries, got %.1f", expectedOffset, s.ScrollOffset)
}
}
// --- Test: Scroll Prefetch Triggered ---
func TestScroll_PrefetchTriggered(t *testing.T) {
s := NewBrowserState()
s.TotalEntries = 2000
s.VisibleCount = 20
s.EntryHeight = 48.0
s.ScrollOffset = 500 * 48 // Page 5
// Load some pages around current position
entries := make([]Entry, 2000)
for i := 0; i < 2000; i++ {
entries[i] = NewEntry("/test/file.txt", "file.txt", 100, s.TapTimestamp, false)
}
// Build position maps for sort modes
s.SortIndex = &DirectoryIndex{
Entries: entries,
SortOrders: map[string][]int{
"name_asc": buildPositionMap(entries, SortModeNameAsc),
"date_desc": buildPositionMap(entries, SortModeDateDesc),
},
}
for pageIdx := 3; pageIdx <= 7; pageIdx++ {
p := loadPageFromIndex(s, pageIdx)
if p != nil {
s.Pages[pageIdx] = p
}
}
// Record current page count
pagesBefore := len(s.Pages)
// Scroll to trigger prefetch
HandlePixelScroll(s, 200*48) // Scroll to page 7+
// After scroll, prefetch should have been triggered
// (exact behavior depends on implementation)
// For now, verify that scroll happened correctly
if s.GetScrollIndex() <= 500 {
t.Errorf("expected GetScrollIndex() > 500 after scrolling, got %d", s.GetScrollIndex())
}
// Page count may have increased due to prefetch
if len(s.Pages) < pagesBefore {
t.Errorf("expected page count to not decrease after scroll, before=%d, after=%d", pagesBefore, len(s.Pages))
}
}
// --- Test: Scroll Eviction Triggered ---
func TestScroll_EvictionTriggered(t *testing.T) {
s := NewBrowserState()
s.TotalEntries = 5000
s.VisibleCount = 20
s.EntryHeight = 48.0
s.ScrollOffset = 0
// Load pages at various positions
entries := make([]Entry, 5000)
for i := 0; i < 5000; i++ {
entries[i] = NewEntry("/test/file.txt", "file.txt", 100, s.TapTimestamp, false)
}
// Build position maps for sort modes
s.SortIndex = &DirectoryIndex{
Entries: entries,
SortOrders: map[string][]int{
"name_asc": buildPositionMap(entries, SortModeNameAsc),
"date_desc": buildPositionMap(entries, SortModeDateDesc),
},
}
for pageIdx := 0; pageIdx <= 10; pageIdx++ {
p := loadPageFromIndex(s, pageIdx)
if p != nil {
s.Pages[pageIdx] = p
}
}
// Scroll far away from initial position
HandlePixelScroll(s, 4000*48) // Scroll to page 40+
// Pages far from current position should be evicted
// Check that page 0 was evicted (it's far from page 40)
if page, exists := s.Pages[0]; exists && page.Loaded {
t.Error("expected page 0 to be evicted after scrolling far away")
}
}
// --- Test: Scroll With Search Results ---
func TestScroll_WithSearchResults(t *testing.T) {
s := NewBrowserState()
s.TotalEntries = 100
s.VisibleCount = 20
s.EntryHeight = 48.0
s.ScrollOffset = 0
// Set up search results (larger than VisibleCount to allow scrolling)
s.SearchResults = make([]int, 25)
for i := 0; i < 25; i++ {
s.SearchResults[i] = i
}
// Scroll should work normally since search results (25) > VisibleCount (20)
HandlePixelScroll(s, 10*48)
expectedOffset := float64(10 * 48)
if s.ScrollOffset != expectedOffset {
t.Errorf("expected ScrollOffset=%.1f, got %.1f", expectedOffset, s.ScrollOffset)
}
}
// --- Test: Scroll To Beginning ---
func TestScroll_ToBeginning(t *testing.T) {
s := NewBrowserState()
s.TotalEntries = 1000
s.VisibleCount = 20
s.EntryHeight = 48.0
s.ScrollOffset = 500 * 48
// Scroll all the way to the beginning
HandlePixelScroll(s, -100000)
if s.ScrollOffset != 0 {
t.Errorf("expected ScrollOffset=0 at beginning, got %.1f", s.ScrollOffset)
}
}
// --- Test: Scroll To End ---
func TestScroll_ToEnd(t *testing.T) {
s := NewBrowserState()
s.TotalEntries = 1000
s.VisibleCount = 20
s.EntryHeight = 48.0
s.ScrollOffset = 0
// Scroll all the way to the end
maxScroll := float64(s.TotalEntries-s.VisibleCount) * s.EntryHeight
HandlePixelScroll(s, int(maxScroll)+1000)
if s.ScrollOffset != maxScroll {
t.Errorf("expected ScrollOffset=%.1f at end, got %.1f", maxScroll, s.ScrollOffset)
}
}
// --- Test: Scroll With Small Directory ---
func TestScroll_SmallDirectory(t *testing.T) {
s := NewBrowserState()
s.TotalEntries = 10 // Smaller than VisibleCount
s.VisibleCount = 20
s.EntryHeight = 48.0
s.ScrollOffset = 0
// Try to scroll down (should be clamped)
HandlePixelScroll(s, 1000)
// ScrollOffset should be 0 (can't scroll beyond available entries)
if s.ScrollOffset != 0 {
t.Errorf("expected ScrollOffset=0 for small directory, got %.1f", s.ScrollOffset)
}
}
// --- Test: Scroll Prefetch Triggered On Page Boundary ---
func TestScroll_PrefetchTriggeredOnPageBoundary(t *testing.T) {
s := NewBrowserState()
s.TotalEntries = 500
s.VisibleCount = 20
s.EntryHeight = 48.0
s.ScrollOffset = 90 * 48 // Near page boundary (page 0 ends at 100)
// Load page 0
entries := make([]Entry, 500)
for i := 0; i < 500; i++ {
entries[i] = NewEntry("/test/file.txt", "file.txt", 100, s.TapTimestamp, false)
}
// Build position maps for sort modes
s.SortIndex = &DirectoryIndex{
Entries: entries,
SortOrders: map[string][]int{
"name_asc": buildPositionMap(entries, SortModeNameAsc),
"date_desc": buildPositionMap(entries, SortModeDateDesc),
},
}
s.Pages[0] = loadPageFromIndex(s, 0)
// Scroll across page boundary
HandlePixelScroll(s, 15*48) // Should cross into page 1
// Verify scroll happened
if s.GetScrollIndex() != 105 {
t.Errorf("expected GetScrollIndex()=105, got %d", s.GetScrollIndex())
}
}