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_CreatesFile(t *testing.T) { fs := NewFileSystem() err := fs.WriteFile("/newfile.txt", []byte("data")) if err != nil { t.Fatalf("WriteFile should create file, got error: %v", err) } content, err := fs.ReadFile("/newfile.txt") if err != nil { t.Fatalf("File should exist after write: %v", err) } if string(content) != "data" { t.Errorf("Content = %q, want %q", string(content), "data") } } 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() }