package browser import ( "testing" ) // --- Test: Scroll Clamp Minimum --- func TestScrollClamp_Minimum(t *testing.T) { s := NewBrowserState() s.TotalEntries = 500 s.VisibleCount = 20 // Set scroll index below minimum s.ScrollIndex = -10 // Apply scroll clamp HandleScroll(s, -5) // ScrollIndex should be clamped to 0 if s.ScrollIndex != 0 { t.Errorf("expected ScrollIndex=0 (clamped), got %d", s.ScrollIndex) } } // --- Test: Scroll Clamp Maximum --- func TestScrollClamp_Maximum(t *testing.T) { s := NewBrowserState() s.TotalEntries = 500 s.VisibleCount = 20 // Set scroll index above maximum s.ScrollIndex = 1000 // Apply scroll clamp HandleScroll(s, 100) // ScrollIndex should be clamped to max (TotalEntries - VisibleCount) maxScroll := s.TotalEntries - s.VisibleCount if s.ScrollIndex != maxScroll { t.Errorf("expected ScrollIndex=%d (clamped to max), got %d", maxScroll, s.ScrollIndex) } } // --- Test: Scroll Delta Computation --- func TestScrollDelta_Computation(t *testing.T) { s := NewBrowserState() s.TotalEntries = 1000 s.VisibleCount = 20 s.ScrollIndex = 100 // Scroll down by 5 entries (positive delta) HandleScroll(s, 5) if s.ScrollIndex != 105 { t.Errorf("expected ScrollIndex=105 after scrolling down 5, got %d", s.ScrollIndex) } // Scroll up by 3 entries (negative delta) HandleScroll(s, -3) if s.ScrollIndex != 102 { t.Errorf("expected ScrollIndex=102 after scrolling up 3, got %d", s.ScrollIndex) } } // --- Test: Scroll Prefetch Triggered --- func TestScroll_PrefetchTriggered(t *testing.T) { s := NewBrowserState() s.TotalEntries = 2000 s.VisibleCount = 20 s.ScrollIndex = 500 // 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 map for the default sort mode (NameAsc) 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 HandleScroll(s, 200) // 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.ScrollIndex <= 500 { t.Errorf("expected ScrollIndex > 500 after scrolling, got %d", s.ScrollIndex) } // 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.ScrollIndex = 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 map for the default sort mode (NameAsc) 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 from initial position HandleScroll(s, 4000) // 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.ScrollIndex = 0 // Set up search results s.SearchResults = []int{5, 15, 25, 35, 45} // Scroll should work normally even with search results HandleScroll(s, 10) if s.ScrollIndex != 10 { t.Errorf("expected ScrollIndex=10, got %d", s.ScrollIndex) } } // --- Test: Scroll To Beginning --- func TestScroll_ToBeginning(t *testing.T) { s := NewBrowserState() s.TotalEntries = 1000 s.VisibleCount = 20 s.ScrollIndex = 500 // Scroll all the way to the beginning HandleScroll(s, -500) if s.ScrollIndex != 0 { t.Errorf("expected ScrollIndex=0 at beginning, got %d", s.ScrollIndex) } } // --- Test: Scroll To End --- func TestScroll_ToEnd(t *testing.T) { s := NewBrowserState() s.TotalEntries = 1000 s.VisibleCount = 20 s.ScrollIndex = 0 // Scroll all the way to the end HandleScroll(s, 1000) maxScroll := s.TotalEntries - s.VisibleCount if s.ScrollIndex != maxScroll { t.Errorf("expected ScrollIndex=%d at end, got %d", maxScroll, s.ScrollIndex) } } // --- Test: Scroll With Small Directory --- func TestScroll_SmallDirectory(t *testing.T) { s := NewBrowserState() s.TotalEntries = 10 // Smaller than VisibleCount s.VisibleCount = 20 s.ScrollIndex = 0 // Try to scroll down (should be clamped) HandleScroll(s, 100) // ScrollIndex should be 0 (can't scroll beyond available entries) if s.ScrollIndex != 0 { t.Errorf("expected ScrollIndex=0 for small directory, got %d", s.ScrollIndex) } } // --- Test: Scroll Prefetch Triggered On Page Boundary --- func TestScroll_PrefetchTriggeredOnPageBoundary(t *testing.T) { s := NewBrowserState() s.TotalEntries = 500 s.VisibleCount = 20 s.ScrollIndex = 90 // 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 map for the default sort mode (NameAsc) s.SortIndex = &DirectoryIndex{ Entries: entries, SortOrders: map[string][]int{"name_asc": buildPositionMap(entries, SortModeNameAsc)}, } s.Pages[0] = loadPageFromIndex(s, 0) // Scroll across page boundary HandleScroll(s, 15) // Should cross into page 1 // Verify scroll happened if s.ScrollIndex != 105 { t.Errorf("expected ScrollIndex=105, got %d", s.ScrollIndex) } }