package browser import ( "testing" ) // --- Test: Per-Pixel Scroll Delta Applied Correctly --- func TestPixelScroll_DeltaApplied(t *testing.T) { s := NewBrowserState() s.TotalEntries = 1000 s.VisibleCount = 20 s.EntryHeight = 48.0 // pixels per entry s.ScrollOffset = 0 // Scroll down by 100 pixels (should be precise, not rounded to entries) HandlePixelScroll(s, 100) // ScrollOffset should be 100.0 (exact pixel delta) expected := 100.0 if s.ScrollOffset != expected { t.Errorf("expected ScrollOffset=%.1f, got %.1f", expected, s.ScrollOffset) } // Scroll up by 50 pixels HandlePixelScroll(s, -50) expected = 50.0 if s.ScrollOffset != expected { t.Errorf("expected ScrollOffset=%.1f, got %.1f", expected, s.ScrollOffset) } } // --- Test: Per-Pixel Scroll Clamped to Minimum --- func TestPixelScroll_ClampMinimum(t *testing.T) { s := NewBrowserState() s.TotalEntries = 1000 s.VisibleCount = 20 s.EntryHeight = 48.0 s.ScrollOffset = 0 // Try to scroll above the top HandlePixelScroll(s, -100) // ScrollOffset should be clamped to 0 if s.ScrollOffset != 0 { t.Errorf("expected ScrollOffset=0 (clamped), got %.1f", s.ScrollOffset) } } // --- Test: Per-Pixel Scroll Clamped to Maximum --- func TestPixelScroll_ClampMaximum(t *testing.T) { s := NewBrowserState() s.TotalEntries = 1000 s.VisibleCount = 20 s.EntryHeight = 48.0 s.ScrollOffset = 0 // Maximum scroll = (TotalEntries - VisibleCount) * EntryHeight maxScroll := float64(s.TotalEntries-s.VisibleCount) * s.EntryHeight // Try to scroll past the bottom HandlePixelScroll(s, int(maxScroll)+1000) // ScrollOffset should be clamped to max if s.ScrollOffset != maxScroll { t.Errorf("expected ScrollOffset=%.1f (clamped to max), got %.1f", maxScroll, s.ScrollOffset) } } // --- Test: Per-Pixel Scroll Preserves Sub-Entry Precision --- func TestPixelScroll_SubEntryPrecision(t *testing.T) { s := NewBrowserState() s.TotalEntries = 1000 s.VisibleCount = 20 s.EntryHeight = 48.0 s.ScrollOffset = 0 // Scroll by a value that doesn't align to entry boundaries // 73 pixels = 1 full entry (48px) + 25 pixels into the next entry HandlePixelScroll(s, 73) expected := 73.0 if s.ScrollOffset != expected { t.Errorf("expected ScrollOffset=%.1f (sub-entry precision), got %.1f", expected, s.ScrollOffset) } // Scroll another 100 pixels (total 173 = 3 entries + 29px) HandlePixelScroll(s, 100) expected = 173.0 if s.ScrollOffset != expected { t.Errorf("expected ScrollOffset=%.1f (accumulated sub-entry precision), got %.1f", expected, s.ScrollOffset) } } // --- Test: Pixel Scroll Index Derived from Offset --- func TestPixelScroll_IndexFromOffset(t *testing.T) { s := NewBrowserState() s.TotalEntries = 1000 s.VisibleCount = 20 s.EntryHeight = 48.0 s.ScrollOffset = 0 // Initial index should be 0 if s.GetScrollIndex() != 0 { t.Errorf("expected initial ScrollIndex=0, got %d", s.GetScrollIndex()) } // Scroll down by 100 pixels HandlePixelScroll(s, 100) // ScrollIndex should be floor(100 / 48) = 2 expectedIndex := 2 if s.GetScrollIndex() != expectedIndex { t.Errorf("expected ScrollIndex=%d (from offset 100 / height 48), got %d", expectedIndex, s.GetScrollIndex()) } // Scroll up by 50 pixels (offset now 50) HandlePixelScroll(s, -50) // ScrollIndex should be floor(50 / 48) = 1 expectedIndex = 1 if s.GetScrollIndex() != expectedIndex { t.Errorf("expected ScrollIndex=%d (from offset 50 / height 48), got %d", expectedIndex, s.GetScrollIndex()) } } // --- Test: Pixel Scroll Eviction Triggered --- func TestPixelScroll_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) } s.SortIndex = &DirectoryIndex{ Entries: entries, SortOrders: map[string][]int{"name_asc": buildPositionMap(entries, SortModeNameAsc)}, } for pageIdx := 0; pageIdx <= 10; pageIdx++ { p := loadPageFromIndex(s, pageIdx) if p != nil { s.Pages[pageIdx] = p } } // Scroll far away using pixel offset // Scroll to page 40+ (40 * 100 * 48 = 192000 pixels) HandlePixelScroll(s, 192000) // 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: Pixel Scroll Prefetch Triggered --- func TestPixelScroll_PrefetchTriggered(t *testing.T) { s := NewBrowserState() s.TotalEntries = 2000 s.VisibleCount = 20 s.EntryHeight = 48.0 s.ScrollOffset = 0 // 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) } s.SortIndex = &DirectoryIndex{ Entries: entries, SortOrders: map[string][]int{"name_asc": buildPositionMap(entries, SortModeNameAsc)}, } 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 using pixel offset HandlePixelScroll(s, 200*48) // Scroll to page ~7 // After scroll, prefetch should have been triggered // 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: Pixel Scroll With Small Directory --- func TestPixelScroll_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 since no scrollable area) 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: Pixel Scroll To Beginning --- func TestPixelScroll_ToBeginning(t *testing.T) { s := NewBrowserState() s.TotalEntries = 1000 s.VisibleCount = 20 s.EntryHeight = 48.0 s.ScrollOffset = 500 * 48 // Somewhere in the middle // 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: Pixel Scroll To End --- func TestPixelScroll_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) } }