This commit is contained in:
voocel
2026-03-07 21:25:55 +08:00
commit 27bd85ef90
60 changed files with 5658 additions and 0 deletions

183
state/run_meta_test.go Normal file
View File

@@ -0,0 +1,183 @@
package state
import (
"os"
"testing"
"github.com/voocel/ainovel-cli/domain"
)
func TestSaveAndLoadRunMeta(t *testing.T) {
dir := t.TempDir()
store := NewStore(dir)
meta := domain.RunMeta{
StartedAt: "2026-03-07T10:00:00+08:00",
Style: "fantasy",
Model: "gpt-4o",
}
if err := store.SaveRunMeta(meta); err != nil {
t.Fatalf("SaveRunMeta: %v", err)
}
loaded, err := store.LoadRunMeta()
if err != nil {
t.Fatalf("LoadRunMeta: %v", err)
}
if loaded.Style != "fantasy" {
t.Errorf("style mismatch: %s", loaded.Style)
}
if loaded.Model != "gpt-4o" {
t.Errorf("model mismatch: %s", loaded.Model)
}
}
func TestLoadRunMeta_Empty(t *testing.T) {
dir := t.TempDir()
store := NewStore(dir)
meta, err := store.LoadRunMeta()
if err != nil {
t.Fatalf("LoadRunMeta on empty: %v", err)
}
if meta != nil {
t.Fatalf("expected nil, got %+v", meta)
}
}
func TestAppendSteerEntry(t *testing.T) {
dir := t.TempDir()
store := NewStore(dir)
// 首次追加meta/run.json 不存在)
e1 := domain.SteerEntry{Input: "主角改成女性", Timestamp: "2026-03-07T10:01:00+08:00"}
if err := store.AppendSteerEntry(e1); err != nil {
t.Fatalf("AppendSteerEntry 1: %v", err)
}
meta, _ := store.LoadRunMeta()
if len(meta.SteerHistory) != 1 {
t.Fatalf("expected 1 entry, got %d", len(meta.SteerHistory))
}
if meta.SteerHistory[0].Input != "主角改成女性" {
t.Errorf("input mismatch: %s", meta.SteerHistory[0].Input)
}
// 追加第二条
e2 := domain.SteerEntry{Input: "加入反转", Timestamp: "2026-03-07T10:02:00+08:00"}
_ = store.AppendSteerEntry(e2)
meta, _ = store.LoadRunMeta()
if len(meta.SteerHistory) != 2 {
t.Fatalf("expected 2 entries, got %d", len(meta.SteerHistory))
}
}
func TestAppendSteerEntry_PreservesExistingMeta(t *testing.T) {
dir := t.TempDir()
store := NewStore(dir)
// 先保存 RunMeta
_ = store.SaveRunMeta(domain.RunMeta{
StartedAt: "2026-03-07T10:00:00+08:00",
Style: "suspense",
Model: "gpt-4o",
})
// 追加 Steer 不应覆盖其他字段
_ = store.AppendSteerEntry(domain.SteerEntry{Input: "test", Timestamp: "now"})
meta, _ := store.LoadRunMeta()
if meta.Style != "suspense" {
t.Errorf("style should be preserved, got %s", meta.Style)
}
if meta.Model != "gpt-4o" {
t.Errorf("model should be preserved, got %s", meta.Model)
}
if len(meta.SteerHistory) != 1 {
t.Errorf("expected 1 steer entry, got %d", len(meta.SteerHistory))
}
}
func TestInitRunMeta_PreservesHistory(t *testing.T) {
dir := t.TempDir()
store := NewStore(dir)
// 先建立带历史的 RunMeta
_ = store.SaveRunMeta(domain.RunMeta{
StartedAt: "old",
Style: "fantasy",
Model: "old-model",
SteerHistory: []domain.SteerEntry{{Input: "历史干预", Timestamp: "ts"}},
PendingSteer: "待处理",
})
// InitRunMeta 应保留 SteerHistory 和 PendingSteer
_ = store.InitRunMeta("suspense", "new-model")
meta, _ := store.LoadRunMeta()
if meta.Style != "suspense" {
t.Errorf("style should be updated, got %s", meta.Style)
}
if meta.Model != "new-model" {
t.Errorf("model should be updated, got %s", meta.Model)
}
if len(meta.SteerHistory) != 1 || meta.SteerHistory[0].Input != "历史干预" {
t.Errorf("steer history should be preserved, got %v", meta.SteerHistory)
}
if meta.PendingSteer != "待处理" {
t.Errorf("pending steer should be preserved, got %s", meta.PendingSteer)
}
}
func TestSetAndClearPendingSteer(t *testing.T) {
dir := t.TempDir()
store := NewStore(dir)
// 设置 PendingSteer
if err := store.SetPendingSteer("主角改成女性"); err != nil {
t.Fatalf("SetPendingSteer: %v", err)
}
meta, _ := store.LoadRunMeta()
if meta.PendingSteer != "主角改成女性" {
t.Errorf("expected pending steer, got %s", meta.PendingSteer)
}
// 清除
if err := store.ClearPendingSteer(); err != nil {
t.Fatalf("ClearPendingSteer: %v", err)
}
meta, _ = store.LoadRunMeta()
if meta.PendingSteer != "" {
t.Errorf("expected empty pending steer, got %s", meta.PendingSteer)
}
}
func TestClearPendingSteer_Noop(t *testing.T) {
dir := t.TempDir()
store := NewStore(dir)
// 空 meta 上调用不报错
if err := store.ClearPendingSteer(); err != nil {
t.Fatalf("ClearPendingSteer on empty: %v", err)
}
}
func TestSaveCheckpoint(t *testing.T) {
dir := t.TempDir()
store := NewStore(dir)
_ = store.InitProgress("test", 10)
if err := store.SaveCheckpoint("ch01-commit"); err != nil {
t.Fatalf("SaveCheckpoint: %v", err)
}
// 验证 checkpoint 目录下有文件
entries, err := os.ReadDir(dir + "/meta/checkpoints")
if err != nil {
t.Fatalf("read checkpoints dir: %v", err)
}
if len(entries) != 1 {
t.Fatalf("expected 1 checkpoint, got %d", len(entries))
}
}