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.
265 lines
7.0 KiB
Go
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())
|
|
}
|
|
}
|