- 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
312 lines
7.2 KiB
Go
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()
|
|
}
|