package tools import ( "context" "encoding/json" "testing" "github.com/voocel/ainovel-cli/domain" "github.com/voocel/ainovel-cli/state" ) func TestSaveFoundationPersistsPlanningTier(t *testing.T) { dir := t.TempDir() store := state.NewStore(dir) if err := store.Init(); err != nil { t.Fatalf("Init: %v", err) } tool := NewSaveFoundationTool(store) args, err := json.Marshal(map[string]any{ "type": "premise", "content": "# Premise\n\n测试", "scale": "long", }) if err != nil { t.Fatalf("Marshal: %v", err) } if _, err := tool.Execute(context.Background(), args); err != nil { t.Fatalf("Execute: %v", err) } meta, err := store.LoadRunMeta() if err != nil { t.Fatalf("LoadRunMeta: %v", err) } if meta == nil { t.Fatal("expected run meta to exist") } if meta.PlanningTier != domain.PlanningTierLong { t.Fatalf("expected planning tier %q, got %q", domain.PlanningTierLong, meta.PlanningTier) } } func TestSaveFoundationOutlineClearsLayeredStateWhenDowngrading(t *testing.T) { dir := t.TempDir() store := state.NewStore(dir) if err := store.Init(); err != nil { t.Fatalf("Init: %v", err) } if err := store.InitProgress("test", 0); err != nil { t.Fatalf("InitProgress: %v", err) } tool := NewSaveFoundationTool(store) layeredArgs, err := json.Marshal(map[string]any{ "type": "layered_outline", "content": `[{"index":1,"title":"第一卷","theme":"主题","arcs":[{"index":1,"title":"第一弧","goal":"目标","chapters":[{"chapter":1,"title":"第一章","core_event":"开局","hook":"继续"}]}]}]`, "scale": "long", }) if err != nil { t.Fatalf("Marshal layered args: %v", err) } if _, err := tool.Execute(context.Background(), layeredArgs); err != nil { t.Fatalf("Execute layered outline: %v", err) } outlineArgs, err := json.Marshal(map[string]any{ "type": "outline", "content": `[{"chapter":1,"title":"第一章","core_event":"改为中篇","hook":"继续"}]`, "scale": "mid", }) if err != nil { t.Fatalf("Marshal outline args: %v", err) } if _, err := tool.Execute(context.Background(), outlineArgs); err != nil { t.Fatalf("Execute outline: %v", err) } progress, err := store.LoadProgress() if err != nil { t.Fatalf("LoadProgress: %v", err) } if progress == nil { t.Fatal("expected progress to exist") } if progress.Layered { t.Fatal("expected layered mode to be disabled") } if progress.CurrentVolume != 0 || progress.CurrentArc != 0 { t.Fatalf("expected volume/arc reset, got volume=%d arc=%d", progress.CurrentVolume, progress.CurrentArc) } volumes, err := store.LoadLayeredOutline() if err != nil { t.Fatalf("LoadLayeredOutline: %v", err) } if len(volumes) != 0 { t.Fatalf("expected layered outline cleared, got %d volumes", len(volumes)) } meta, err := store.LoadRunMeta() if err != nil { t.Fatalf("LoadRunMeta: %v", err) } if meta == nil { t.Fatal("expected run meta to exist") } if meta.PlanningTier != domain.PlanningTierMid { t.Fatalf("expected planning tier %q, got %q", domain.PlanningTierMid, meta.PlanningTier) } } func TestSaveFoundationAcceptsDirectJSONArrayContent(t *testing.T) { dir := t.TempDir() store := state.NewStore(dir) if err := store.Init(); err != nil { t.Fatalf("Init: %v", err) } tool := NewSaveFoundationTool(store) args, err := json.Marshal(map[string]any{ "type": "outline", "content": []map[string]any{ { "chapter": 1, "title": "第一章", "core_event": "主角登场", "hook": "继续", "scenes": []string{"场景一", "场景二"}, }, }, "scale": "short", }) if err != nil { t.Fatalf("Marshal: %v", err) } if _, err := tool.Execute(context.Background(), args); err != nil { t.Fatalf("Execute: %v", err) } outline, err := store.LoadOutline() if err != nil { t.Fatalf("LoadOutline: %v", err) } if len(outline) != 1 || outline[0].Title != "第一章" { t.Fatalf("unexpected outline: %+v", outline) } }