Pad/internal/browser/navigation_test.go
Greg Pomerantz d73cb0be2c Integrate real filesystem with interface abstraction
- Define pool.FileSystem interface in internal/io/pool/filesystem.go
- Move DirEntry interface to internal/io/pool/types/types.go to break
  the pool <-> mock import cycle
- Implement real.FileSystem with atomic writes (temp file + os.Rename)
- Update mock.FileSystem to satisfy pool.FileSystem interface
- Update worker pool tasks to accept pool.FileSystem interface
- Update main.go to use RealFileSystem by default, with -root flag
- Update all browser/editor/test references to types.DirEntry
2026-06-04 16:19:38 -04:00

133 lines
4.1 KiB
Go

package browser
import (
"testing"
"time"
"pad/internal/io/pool"
"pad/internal/io/pool/mock"
)
// TestTapDirectory verifies that tapping a directory entry updates the
// BrowserState.CurrentPath.
func TestTapDirectory(t *testing.T) {
state := NewBrowserState()
mfs := mock.NewFileSystem()
wp := pool.NewWorkerPool(1)
bm, _ := NewBrowserManager(state, wp, mfs)
state.CurrentPath = "/root"
// Mock entries: a subdirectory "sub" and a file
entries := []Entry{
NewEntry("/root/sub", "sub", 0, time.Time{}, true),
NewEntry("/root/file.txt", "file.txt", 100, time.Time{}, false),
}
// Inject entries into the state
state.Pages[0] = NewPage(0, entries)
state.TotalEntries = 2
// Simulate tapping the directory at index 0
HandleBrowserTap(bm, state, 0)
if state.CurrentPath != "/root/sub" {
t.Errorf("expected CurrentPath='/root/sub', got %s", state.CurrentPath)
}
}
// TestTapUp verifies that tapping a ".." entry updates the
// BrowserState.CurrentPath to the parent directory.
func TestTapUp(t *testing.T) {
state := NewBrowserState()
mfs := mock.NewFileSystem()
wp := pool.NewWorkerPool(1)
bm, _ := NewBrowserManager(state, wp, mfs)
state.CurrentPath = "/root/sub"
// Mock entries: ".." and a file
entries := []Entry{
NewEntry("/root", "..", 0, time.Time{}, true),
NewEntry("/root/sub/file.txt", "file.txt", 100, time.Time{}, false),
}
state.Pages[0] = NewPage(0, entries)
state.TotalEntries = 2
// Simulate tapping the ".." entry at index 0
HandleBrowserTap(bm, state, 0)
if state.CurrentPath != "/root" {
t.Errorf("expected CurrentPath='/root', got %s", state.CurrentPath)
}
}
// TestTapWithSearchResults verifies that tapping a file in the search
// results list opens the correct file, not the file at the same index
// in the full directory listing.
func TestTapWithSearchResults(t *testing.T) {
state := NewBrowserState()
mfs := mock.NewFileSystem()
wp := pool.NewWorkerPool(1)
bm, _ := NewBrowserManager(state, wp, mfs)
state.CurrentPath = "/root"
// Mock entries: 5 files, sorted by name
entries := []Entry{
NewEntry("/root/alpha.txt", "alpha.txt", 100, time.Time{}, false),
NewEntry("/root/beta.txt", "beta.txt", 200, time.Time{}, false),
NewEntry("/root/gamma.txt", "gamma.txt", 300, time.Time{}, false),
NewEntry("/root/delta.txt", "delta.txt", 400, time.Time{}, false),
NewEntry("/root/epsilon.txt", "epsilon.txt", 500, time.Time{}, false),
}
state.Pages[0] = NewPage(0, entries)
state.TotalEntries = 5
// Simulate a search for "beta" that matches only index 1
state.Query = "beta"
state.SearchResults = []int{1}
// Tapping row 0 of the search results should open beta.txt (entry index 1),
// NOT alpha.txt (entry index 0).
HandleBrowserTap(bm, state, 0)
// Verify SelectedIndex was set to the resolved entry index (1), not the row index (0).
if state.SelectedIndex != 1 {
t.Errorf("expected SelectedIndex=1, got %d", state.SelectedIndex)
}
}
// TestTapWithMultipleSearchResults verifies tapping different rows of
// search results resolves to the correct entries.
func TestTapWithMultipleSearchResults(t *testing.T) {
state := NewBrowserState()
mfs := mock.NewFileSystem()
wp := pool.NewWorkerPool(1)
bm, _ := NewBrowserManager(state, wp, mfs)
state.CurrentPath = "/root"
// Mock entries: 5 files
entries := []Entry{
NewEntry("/root/aaa.txt", "aaa.txt", 100, time.Time{}, false),
NewEntry("/root/zzz.txt", "zzz.txt", 200, time.Time{}, false),
NewEntry("/root/aaa2.txt", "aaa2.txt", 300, time.Time{}, false),
NewEntry("/root/zzz2.txt", "zzz2.txt", 400, time.Time{}, false),
NewEntry("/root/mid.txt", "mid.txt", 500, time.Time{}, false),
}
state.Pages[0] = NewPage(0, entries)
state.TotalEntries = 5
// Simulate a search for "zzz" that matches indices 1 and 3
state.Query = "zzz"
state.SearchResults = []int{1, 3}
// Tapping row 0 should resolve to entry index 1 (zzz.txt)
HandleBrowserTap(bm, state, 0)
if state.SelectedIndex != 1 {
t.Errorf("row 0: expected SelectedIndex=1, got %d", state.SelectedIndex)
}
// Tapping row 1 should resolve to entry index 3 (zzz2.txt)
HandleBrowserTap(bm, state, 1)
if state.SelectedIndex != 3 {
t.Errorf("row 1: expected SelectedIndex=3, got %d", state.SelectedIndex)
}
}