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

303 lines
7.4 KiB
Go

package browser
import (
"fmt"
"testing"
"time"
"pad/internal/ui"
)
// --- Helper: create a browser state with known entries ---
func makeTestState(t *testing.T, entryCount int, scrollIndex int, visibleCount int) *BrowserState {
t.Helper()
s := NewBrowserState()
s.CurrentPath = "/test/path"
s.EntryHeight = 48.0
s.ScrollOffset = float64(scrollIndex) * s.EntryHeight
s.VisibleCount = visibleCount
s.TotalEntries = entryCount
entries := make([]Entry, entryCount)
for i := 0; i < entryCount; i++ {
entries[i] = NewEntry(
fmt.Sprintf("/test/path/file%d.txt", i),
fmt.Sprintf("file%d.txt", i),
int64(i*100),
time.Time{},
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),
},
}
// Load pages
for pageIdx := 0; pageIdx <= entryCount/PageSize; pageIdx++ {
p := loadPageFromIndex(s, pageIdx)
if p != nil {
s.Pages[pageIdx] = p
}
}
return s
}
// --- Helper: find ListView from elements ---
func findListView(elements []ui.Element) (ui.ListView, bool) {
for _, el := range elements {
if lv, ok := el.(ui.ListView); ok {
return lv, true
}
}
return ui.ListView{}, false
}
// --- Test: Browser Layout - Element Count ---
func TestBrowserLayout_ElementCount(t *testing.T) {
s := makeTestState(t, 200, 0, 20)
elements := BrowserLayout(ui.Dp(800), ui.Dp(1200), s, nil, nil)
// Should produce: header + search bar + list view = 3 elements
if len(elements) < 3 {
t.Errorf("expected at least 3 elements, got %d", len(elements))
}
}
// --- Test: Browser Layout - Header Region ---
func TestBrowserLayout_HeaderRegion(t *testing.T) {
s := makeTestState(t, 200, 0, 20)
elements := BrowserLayout(ui.Dp(800), ui.Dp(1200), s, nil, nil)
// First element should be the header container
if len(elements) == 0 {
t.Fatal("no elements returned")
}
header := elements[0]
region := header.Region()
// Header should be near the top
if region.Y > ui.Dp(50) {
t.Errorf("expected header Y <= 50, got %d", int(region.Y))
}
// Header should span most of the width
if region.W < ui.Dp(700) {
t.Errorf("expected header W >= 700, got %d", int(region.W))
}
}
// --- Test: Browser Layout - List Region ---
func TestBrowserLayout_ListRegion(t *testing.T) {
s := makeTestState(t, 200, 0, 20)
elements := BrowserLayout(ui.Dp(800), ui.Dp(1200), s, nil, nil)
listView, found := findListView(elements)
if !found {
t.Fatal("ListView element not found in layout")
}
region := listView.Region()
// List should be below the header and search bar
if region.Y < ui.Dp(50) {
t.Errorf("expected list Y >= 50, got %d", int(region.Y))
}
// List should have significant height
if region.H < ui.Dp(500) {
t.Errorf("expected list H >= 500, got %d", int(region.H))
}
}
// --- Test: Browser Layout - Visible Entries Count ---
func TestBrowserLayout_VisibleEntriesCount(t *testing.T) {
s := makeTestState(t, 500, 100, 20)
elements := BrowserLayout(ui.Dp(800), ui.Dp(1200), s, nil, nil)
listView, found := findListView(elements)
if !found {
t.Fatal("ListView element not found in layout")
}
// Should only render visible entries (approximately VisibleCount)
// Allow some tolerance for partial pages
maxExpected := s.VisibleCount + PageSize
if len(listView.Items) > maxExpected {
t.Errorf("expected at most %d visible items, got %d", maxExpected, len(listView.Items))
}
}
// --- Test: Browser Layout - Empty Directory ---
func TestBrowserLayout_EmptyDirectory(t *testing.T) {
s := NewBrowserState()
s.CurrentPath = "/empty/dir"
s.TotalEntries = 0
elements := BrowserLayout(ui.Dp(800), ui.Dp(1200), s, nil, nil)
if len(elements) < 3 {
t.Errorf("expected at least 3 elements for empty dir, got %d", len(elements))
}
listView, found := findListView(elements)
if !found {
t.Fatal("ListView element not found in layout")
}
if len(listView.Items) != 0 {
t.Errorf("expected 0 items for empty directory, got %d", len(listView.Items))
}
}
// --- Test: Browser Layout - Single Entry ---
func TestBrowserLayout_SingleEntry(t *testing.T) {
s := NewBrowserState()
s.CurrentPath = "/test"
s.TotalEntries = 1
s.VisibleCount = 20
s.EntryHeight = 48.0
entries := []Entry{
NewEntry("/test/only.txt", "only.txt", 1024, time.Time{}, false),
}
s.Pages[0] = NewPage(0, entries)
elements := BrowserLayout(ui.Dp(800), ui.Dp(1200), s, nil, nil)
listView, found := findListView(elements)
if !found {
t.Fatal("ListView element not found in layout")
}
if len(listView.Items) != 1 {
t.Errorf("expected 1 item, got %d", len(listView.Items))
}
}
// --- Test: Browser Layout - Partial Page ---
func TestBrowserLayout_PartialPage(t *testing.T) {
s := NewBrowserState()
s.CurrentPath = "/test"
s.TotalEntries = 150 // 1 full page + 50 in second page
s.EntryHeight = 48.0
s.ScrollOffset = 120 * 48 // Near the end
s.VisibleCount = 20
entries := make([]Entry, 150)
for i := 0; i < 150; i++ {
entries[i] = NewEntry(
fmt.Sprintf("/test/file%d.txt", i),
fmt.Sprintf("file%d.txt", i),
int64(i*100),
time.Time{},
false,
)
}
s.Pages[0] = NewPage(0, entries[:100])
s.Pages[1] = NewPage(1, entries[100:])
elements := BrowserLayout(ui.Dp(800), ui.Dp(1200), s, nil, nil)
listView, found := findListView(elements)
if !found {
t.Fatal("ListView element not found in layout")
}
// Should have entries from the partial page
if len(listView.Items) == 0 {
t.Error("expected items from partial page")
}
}
// --- Test: Browser Layout - Unloaded Page Shows Placeholder ---
func TestBrowserLayout_UnloadedPage(t *testing.T) {
s := NewBrowserState()
s.CurrentPath = "/test"
s.TotalEntries = 500
s.EntryHeight = 48.0
s.ScrollOffset = 250 * 48
s.VisibleCount = 20
// Only load page 0, not page 2 or 3
entries := make([]Entry, 100)
s.Pages[0] = NewPage(0, entries)
elements := BrowserLayout(ui.Dp(800), ui.Dp(1200), s, nil, nil)
// Layout should not crash with unloaded pages
if len(elements) < 3 {
t.Errorf("expected at least 3 elements, got %d", len(elements))
}
}
// --- Test: Browser Layout - With Search Query ---
func TestBrowserLayout_WithSearchQuery(t *testing.T) {
s := makeTestState(t, 100, 0, 20)
s.Query = "file1"
// Set up search results
for i := 0; i < s.TotalEntries; i++ {
if i == 1 || i == 10 || i == 11 || i == 12 || i == 13 || i == 14 || i == 15 || i == 16 || i == 17 || i == 18 || i == 19 {
s.SearchResults = append(s.SearchResults, i)
}
}
elements := BrowserLayout(ui.Dp(800), ui.Dp(1200), s, nil, nil)
// Should still produce valid layout
if len(elements) < 3 {
t.Errorf("expected at least 3 elements with search, got %d", len(elements))
}
}
// --- Test: Browser Layout - Screen Dimensions ---
func TestBrowserLayout_ScreenDimensions(t *testing.T) {
s := makeTestState(t, 100, 0, 20)
// Test with different screen sizes
for _, w := range []ui.Dp{400, 800, 1200} {
for _, h := range []ui.Dp{600, 1200, 1800} {
elements := BrowserLayout(w, h, s, nil, nil)
if len(elements) < 3 {
t.Errorf("layout failed for %dx%d: expected >= 3 elements, got %d", int(w), int(h), len(elements))
}
// All elements should fit within screen
for _, el := range elements {
region := el.Region()
if region.X+region.W > w {
t.Errorf("element exceeds screen width at %dx%d", int(w), int(h))
}
if region.Y+region.H > h {
t.Errorf("element exceeds screen height at %dx%d", int(w), int(h))
}
}
}
}
}