Pad/internal/editor/auto_save_test.go
Greg Pomerantz 93a5f879f5 feat: implement atomic writes for filesystem backend
- Add WriteFile method to mock filesystem (non-atomic path, creates files)
- Implement WriteFileAtomic in mock with temp file + rename pattern
  using .tmp/ directory, matching real filesystem semantics
- Update WriteFileTask.Execute() to use WriteFileAtomic
- Update FlushAll() to use WriteFileAtomic
- Fix mock to create files on write (matching os.WriteFile behavior)
- Update tests to match new semantics (create-if-not-exists)
2026-06-04 18:01:51 -04:00

82 lines
1.9 KiB
Go

package editor
import (
"log"
"testing"
"time"
"pad/internal/io/pool"
"pad/internal/io/pool/mock"
)
// TestWriteFailureTracking verifies that a write failure updates WriteFailed status
func TestWriteFailureTracking(t *testing.T) {
state := NewState()
filename := "test.txt"
state.Editor.Filename = filename
// Simulate a write failure
state.Editor.SetWriteFailed(filename, true)
if !state.Editor.WriteFailed() {
t.Errorf("Expected WriteFailed() to be true")
}
// Reset
state.Editor.SetWriteFailed(filename, false)
if state.Editor.WriteFailed() {
t.Errorf("Expected WriteFailed() to be false")
}
}
// TestAutoSave_RetryFails verifies that failed writes trigger retry mechanism.
// TestAutoSave_RetryFails verifies that failed writes trigger retry mechanism.
func TestAutoSave_RetryFails(t *testing.T) {
// Setup: New Logic, set mock FS to fail
l := NewLogic(nil)
// Start a goroutine to drain frameChan to prevent deadlocks
go func() {
for range l.frameChan {
}
}()
filename := "test.txt"
l.state.Editor.Filename = filename
l.state.Editor.Buffer = "hello"
// Mock FS to fail on Write
mfs, ok := l.mockFS.(*mock.FileSystem)
if !ok {
t.Fatal("mockFS is not a *mock.FileSystem")
}
mfs.SetWriteError(true)
// 1. Manually dispatch a write task
task := pool.NewWriteFileTask(filename, []byte("hello"), l.mockFS)
l.workerPool.Dispatch(task)
// 2. Manually process the result to trigger the failure state
res := <-l.workerPool.ResultChan()
l.handleWorkerResult(res)
// 3. Assert failure
if !l.state.Editor.WriteFailed() {
t.Errorf("Expected WriteFailed() to be true")
}
// 4. Assert retry scheduled
retryTriggered := false
select {
case filename := <-l.retryChan:
log.Printf("Test: Received retry for %s", filename)
retryTriggered = true
case <-time.After(5 * time.Second):
t.Log("Test: Timed out waiting for retry trigger in retryChan")
}
if !retryTriggered {
t.Errorf("Retry was not triggered")
}
}