Pad/internal/io/pool/mock/filesystem_test.go
Greg Pomerantz 6a43e3c0db Add e2e test harness for testing editor logic without Gio display
- internal/test/e2e/: FrameCapture, Harness, ElementAssertions, helpers
- internal/editor/logic.go: Add done channel and Done() method for graceful shutdown
- internal/editor/mock_setup.go: Mock filesystem for tests
- internal/browser/: Browser layout and search logic
- internal/io/: Worker pool for async tasks
- Update architecture docs and spec
2026-05-31 08:56:30 -04:00

312 lines
7.2 KiB
Go

package mock
import (
"fmt"
"sync"
"testing"
"time"
)
func TestFileSystem_CreateFile(t *testing.T) {
fs := NewFileSystem()
content := []byte("hello world")
err := fs.CreateFile("/test/hello.txt", content)
if err != nil {
t.Fatalf("CreateFile failed: %v", err)
}
f := fs.GetFile("/test/hello.txt")
if f == nil {
t.Fatal("File not found after creation")
}
if string(f.Content) != "hello world" {
t.Errorf("Content = %q, want %q", string(f.Content), "hello world")
}
if f.Name != "hello.txt" {
t.Errorf("Name = %q, want %q", f.Name, "hello.txt")
}
if f.Size != int64(len(content)) {
t.Errorf("Size = %d, want %d", f.Size, len(content))
}
if f.IsDir {
t.Error("IsDir should be false for a file")
}
}
func TestFileSystem_ReadFile(t *testing.T) {
fs := NewFileSystem()
fs.CreateFile("/test/data.txt", []byte("data"))
content, err := fs.ReadFile("/test/data.txt")
if err != nil {
t.Fatalf("ReadFile failed: %v", err)
}
if string(content) != "data" {
t.Errorf("ReadFile returned %q, want %q", string(content), "data")
}
}
func TestFileSystem_ReadFile_NotFound(t *testing.T) {
fs := NewFileSystem()
_, err := fs.ReadFile("/nonexistent.txt")
if err == nil {
t.Fatal("Expected error for nonexistent file, got nil")
}
}
func TestFileSystem_WriteFile(t *testing.T) {
fs := NewFileSystem()
fs.CreateFile("/test/update.txt", []byte("original"))
err := fs.WriteFile("/test/update.txt", []byte("updated"))
if err != nil {
t.Fatalf("WriteFile failed: %v", err)
}
content, _ := fs.ReadFile("/test/update.txt")
if string(content) != "updated" {
t.Errorf("Content = %q, want %q", string(content), "updated")
}
}
func TestFileSystem_WriteFile_NotFound(t *testing.T) {
fs := NewFileSystem()
err := fs.WriteFile("/nonexistent.txt", []byte("data"))
if err == nil {
t.Fatal("Expected error for nonexistent file, got nil")
}
}
func TestFileSystem_DeleteFile(t *testing.T) {
fs := NewFileSystem()
fs.CreateFile("/test/delete.txt", []byte("to delete"))
err := fs.DeleteFile("/test/delete.txt")
if err != nil {
t.Fatalf("DeleteFile failed: %v", err)
}
if fs.FileExists("/test/delete.txt") {
t.Error("File should not exist after deletion")
}
}
func TestFileSystem_DeleteFile_NotFound(t *testing.T) {
fs := NewFileSystem()
err := fs.DeleteFile("/nonexistent.txt")
if err == nil {
t.Fatal("Expected error for nonexistent file, got nil")
}
}
func TestFileSystem_CreateDir(t *testing.T) {
fs := NewFileSystem()
err := fs.CreateDir("/test/dir")
if err != nil {
t.Fatalf("CreateDir failed: %v", err)
}
if !fs.DirExists("/test/dir") {
t.Error("Dir should exist after creation")
}
f := fs.GetFile("/test/dir")
if f == nil {
t.Fatal("Directory file not found")
}
if !f.IsDir {
t.Error("IsDir should be true for a directory")
}
if f.Name != "dir" {
t.Errorf("Name = %q, want %q", f.Name, "dir")
}
}
func TestFileSystem_ReadDir(t *testing.T) {
fs := NewFileSystem()
fs.CreateDir("/test/dir")
fs.CreateFile("/test/dir/a.txt", []byte("a"))
fs.CreateFile("/test/dir/b.txt", []byte("b"))
fs.CreateFile("/test/dir/c.txt", []byte("c"))
entries, err := fs.ReadDir("/test/dir")
if err != nil {
t.Fatalf("ReadDir failed: %v", err)
}
if len(entries) != 3 {
t.Fatalf("Expected 3 entries, got %d", len(entries))
}
// Check alphabetical order
if entries[0].Name() != "a.txt" {
t.Errorf("First entry = %q, want %q", entries[0].Name(), "a.txt")
}
if entries[1].Name() != "b.txt" {
t.Errorf("Second entry = %q, want %q", entries[1].Name(), "b.txt")
}
if entries[2].Name() != "c.txt" {
t.Errorf("Third entry = %q, want %q", entries[2].Name(), "c.txt")
}
}
func TestFileSystem_ReadDir_Empty(t *testing.T) {
fs := NewFileSystem()
fs.CreateDir("/test/empty")
entries, err := fs.ReadDir("/test/empty")
if err != nil {
t.Fatalf("ReadDir failed: %v", err)
}
if len(entries) != 0 {
t.Errorf("Expected 0 entries, got %d", len(entries))
}
}
func TestFileSystem_FileExists(t *testing.T) {
fs := NewFileSystem()
fs.CreateFile("/test/exist.txt", []byte("data"))
if !fs.FileExists("/test/exist.txt") {
t.Error("File should exist")
}
if fs.FileExists("/test/noexist.txt") {
t.Error("Nonexistent file should not exist")
}
}
func TestFileSystem_DirExists(t *testing.T) {
fs := NewFileSystem()
fs.CreateDir("/test/dir")
if !fs.DirExists("/test/dir") {
t.Error("Directory should exist")
}
if fs.DirExists("/test/noexist") {
t.Error("Nonexistent directory should not exist")
}
}
func TestFileSystem_Count(t *testing.T) {
fs := NewFileSystem()
fs.CreateFile("/test/a.txt", []byte("a"))
fs.CreateFile("/test/b.txt", []byte("b"))
fs.CreateDir("/test/dir")
files, dirs := fs.Count()
if files != 2 {
t.Errorf("Files = %d, want 2", files)
}
if dirs != 1 {
t.Errorf("Dirs = %d, want 1", dirs)
}
}
func TestFileSystem_SetDelay(t *testing.T) {
fs := NewFileSystem()
fs.SetDelay(50 * time.Millisecond)
start := time.Now()
fs.ReadFile("/nonexistent.txt") // Will fail but delay should still apply
elapsed := time.Since(start)
if elapsed < 40*time.Millisecond {
t.Errorf("Expected delay ~50ms, got %v", elapsed)
}
}
func TestFileSystem_SetChangeEvents(t *testing.T) {
fs := NewFileSystem()
ch := make(chan FileChangeEvent, 10)
fs.SetChangeEvents(ch)
fs.CreateFile("/test/notify.txt", []byte("data"))
select {
case event := <-ch:
if event.Path != "/test/notify.txt" {
t.Errorf("Event path = %q, want %q", event.Path, "/test/notify.txt")
}
if event.EventType != "Created" {
t.Errorf("Event type = %q, want %q", event.EventType, "Created")
}
case <-time.After(100 * time.Millisecond):
t.Fatal("Expected change event, got none")
}
}
func TestFileSystem_SetChangeEvents_NilChannel(t *testing.T) {
fs := NewFileSystem()
fs.SetChangeEvents(nil) // Disable notifications
// Should not panic
fs.CreateFile("/test/silent.txt", []byte("data"))
}
func TestFileSystem_AddFile(t *testing.T) {
fs := NewFileSystem()
modTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
fs.AddFile("/test/pre.txt", []byte("pre"), modTime)
f := fs.GetFile("/test/pre.txt")
if f == nil {
t.Fatal("File not found after AddFile")
}
if !f.ModTime.Equal(modTime) {
t.Errorf("ModTime = %v, want %v", f.ModTime, modTime)
}
}
func TestFileSystem_RemoveFile(t *testing.T) {
fs := NewFileSystem()
fs.AddFile("/test/remove.txt", []byte("data"), time.Now())
fs.RemoveFile("/test/remove.txt")
if fs.FileExists("/test/remove.txt") {
t.Error("File should not exist after RemoveFile")
}
}
func TestFileSystem_ListPaths(t *testing.T) {
fs := NewFileSystem()
fs.CreateFile("/test/a.txt", []byte("a"))
fs.CreateFile("/test/b.txt", []byte("b"))
fs.CreateFile("/other/c.txt", []byte("c"))
paths := fs.ListPaths("/test/")
if len(paths) != 2 {
t.Errorf("ListPaths returned %d paths, want 2", len(paths))
}
pathsAll := fs.ListPaths("")
if len(pathsAll) != 3 {
t.Errorf("ListPaths with empty prefix returned %d paths, want 3", len(pathsAll))
}
}
func TestFileSystem_ConcurrentAccess(t *testing.T) {
fs := NewFileSystem()
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
path := fmt.Sprintf("/test/concurrent_%d.txt", n)
fs.CreateFile(path, []byte(fmt.Sprintf("content %d", n)))
fs.ReadFile(path)
fs.DeleteFile(path)
}(i)
}
wg.Wait()
}