90 lines
2.6 KiB
Go
90 lines
2.6 KiB
Go
// Tests for the /rewind command wiring: listing restore points and restoring
|
|
// files + conversation. The file-snapshot journal itself is tested in
|
|
// agenttool; here we exercise runRewind's REPL-level behavior over a replDeps.
|
|
package repl
|
|
|
|
import (
|
|
"bytes"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/smallnest/pigo/internal/agentcore"
|
|
"github.com/smallnest/pigo/internal/agenttool"
|
|
)
|
|
|
|
// /rewind with no argument lists the committed restore points.
|
|
func TestREPLRewindListsPoints(t *testing.T) {
|
|
p := &replProvider{reply: "hi"}
|
|
deps, _ := newTestDeps(t, p)
|
|
deps.snap = agenttool.NewFileSnapshotRecorder()
|
|
|
|
dir := t.TempDir()
|
|
f := filepath.Join(dir, "a.txt")
|
|
if err := os.WriteFile(f, []byte("v0"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
deps.snap.Record(f)
|
|
deps.snap.Commit("", "add feature X")
|
|
|
|
var out bytes.Buffer
|
|
runRewind(&out, &deps, "/rewind")
|
|
got := out.String()
|
|
if !strings.Contains(got, "restore points") || !strings.Contains(got, "add feature X") {
|
|
t.Errorf("listing missing expected content:\n%s", got)
|
|
}
|
|
}
|
|
|
|
// /rewind N restores the file to its baseline and resets the conversation when
|
|
// the point's leaf is empty (it was the session's first turn).
|
|
func TestREPLRewindRestoresFiles(t *testing.T) {
|
|
p := &replProvider{reply: "hi"}
|
|
deps, _ := newTestDeps(t, p)
|
|
deps.snap = agenttool.NewFileSnapshotRecorder()
|
|
deps.agentCtx.Messages = agentcore.MessageList{
|
|
agentcore.UserMessage{RoleField: agentcore.RoleUser},
|
|
}
|
|
deps.persisted = 1
|
|
|
|
dir := t.TempDir()
|
|
f := filepath.Join(dir, "a.txt")
|
|
if err := os.WriteFile(f, []byte("original"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
deps.snap.Record(f) // baseline "original"
|
|
if err := os.WriteFile(f, []byte("changed"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
deps.snap.Commit("", "edit a.txt")
|
|
|
|
var out bytes.Buffer
|
|
runRewind(&out, &deps, "/rewind 1")
|
|
|
|
if data, _ := os.ReadFile(f); string(data) != "original" {
|
|
t.Errorf("file not restored: got %q, want original", string(data))
|
|
}
|
|
if len(deps.agentCtx.Messages) != 0 {
|
|
t.Errorf("conversation not reset: %d messages remain", len(deps.agentCtx.Messages))
|
|
}
|
|
if len(deps.snap.Points()) != 0 {
|
|
t.Errorf("journal not truncated after rewind")
|
|
}
|
|
if !strings.Contains(out.String(), "rewound to before point 1") {
|
|
t.Errorf("missing confirmation:\n%s", out.String())
|
|
}
|
|
}
|
|
|
|
// /rewind is unavailable when file tools are disabled (nil recorder).
|
|
func TestREPLRewindDisabled(t *testing.T) {
|
|
p := &replProvider{reply: "hi"}
|
|
deps, _ := newTestDeps(t, p)
|
|
deps.snap = nil
|
|
|
|
var out bytes.Buffer
|
|
runRewind(&out, &deps, "/rewind")
|
|
if !strings.Contains(out.String(), "unavailable") {
|
|
t.Errorf("want unavailable message, got:\n%s", out.String())
|
|
}
|
|
}
|