返回 DeepSeek-Reasonix
checkpoints_round_trip_test.go
根目录 / internal / config / checkpoints_round_trip_test.go
1 package config
2
3 import (
4 "os"
5 "path/filepath"
6 "strings"
7 "testing"
8
9 "github.com/BurntSushi/toml"
10 )
11
12 func TestCheckpointRetentionSurvivesUnrelatedUserConfigSave(t *testing.T) {
13 isolateUserConfigHome(t)
14 path := UserConfigPath()
15 if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
16 t.Fatal(err)
17 }
18 if err := os.WriteFile(path, []byte("[checkpoints]\nretain_turns = 200\nblob_quota_bytes = 2147483648\n"), 0600); err != nil {
19 t.Fatal(err)
20 }
21 cfg := LoadForEditWithoutCredentials(path)
22 want := cfg.Checkpoints
23 if want.RetainTurns != 200 {
24 t.Fatalf("load = %+v", want)
25 }
26 cfg.UI.Theme = "dark"
27 if err := cfg.SaveTo(path); err != nil {
28 t.Fatal(err)
29 }
30 got := LoadForEditWithoutCredentials(path).Checkpoints
31 if got != want {
32 t.Fatalf("save unrelated theme lost retention: got %+v want %+v", got, want)
33 }
34 }
35
36 func TestCheckpointRetentionProjectSavePreservesInheritance(t *testing.T) {
37 isolateUserConfigHome(t)
38 root := t.TempDir()
39 userPath := UserConfigPath()
40 if err := os.MkdirAll(filepath.Dir(userPath), 0700); err != nil {
41 t.Fatal(err)
42 }
43 if err := os.WriteFile(userPath, []byte("[checkpoints]\nretain_turns = 200\nblob_quota_bytes = 2147483648\n"), 0600); err != nil {
44 t.Fatal(err)
45 }
46 path := filepath.Join(root, "reasonix.toml")
47 cfg := Default()
48 cfg.Checkpoints.RetainTurns = 300
49 if err := cfg.SaveTo(path); err != nil {
50 t.Fatal(err)
51 }
52 // Exercise both new-file rendering and the existing-file delta writer.
53 cfg = LoadForEditWithoutCredentials(path)
54 cfg.Checkpoints.RetainTurns = 400
55 if err := cfg.SaveTo(path); err != nil {
56 t.Fatal(err)
57 }
58 raw, err := os.ReadFile(path)
59 if err != nil {
60 t.Fatal(err)
61 }
62 if strings.Contains(string(raw), "blob_quota_bytes") {
63 t.Fatal("project save materialized an unset quota")
64 }
65 effective, err := LoadForRootWithoutCredentialsReadOnly(root)
66 if err != nil {
67 t.Fatal(err)
68 }
69 want := CheckpointsConfig{RetainTurns: 400, BlobQuotaBytes: 2147483648}
70 if effective.Checkpoints != want {
71 t.Fatalf("effective retention = %+v, want %+v", effective.Checkpoints, want)
72 }
73 }
74
75 func TestCheckpointRetentionRenderingKeepsUnsetKeysAbsent(t *testing.T) {
76 isolateUserConfigHome(t)
77 for _, retention := range []CheckpointsConfig{{}, {RetainTurns: 200}, {BlobQuotaBytes: 2147483648}, {RetainTurns: -1, BlobQuotaBytes: -1}} {
78 cfg := Default()
79 cfg.Checkpoints = retention
80 for _, body := range []string{RenderTOML(cfg), RenderTOMLForScope(cfg, RenderScopeUser), RenderTOMLForScope(cfg, RenderScopeProject), RenderTOMLProjectDelta(cfg)} {
81 var got Config
82 meta, err := toml.Decode(body, &got)
83 if err != nil {
84 t.Fatal(err)
85 }
86 if got.Checkpoints != retention {
87 t.Fatalf("round trip = %+v, want %+v", got.Checkpoints, retention)
88 }
89 if meta.IsDefined("checkpoints", "retain_turns") != (retention.RetainTurns != 0) || meta.IsDefined("checkpoints", "blob_quota_bytes") != (retention.BlobQuotaBytes != 0) {
90 t.Fatalf("render changed key presence for %+v", retention)
91 }
92 }
93 }
94 }
95
96 func TestCheckpointRetentionRenderScopes(t *testing.T) {
97 isolateUserConfigHome(t)
98 cfg := Default()
99 cfg.Checkpoints = CheckpointsConfig{RetainTurns: 200, BlobQuotaBytes: 2147483648}
100 for _, scope := range []RenderScope{RenderScopeFull, RenderScopeUser, RenderScopeProject} {
101 var got Config
102 if _, err := toml.Decode(RenderTOMLForScope(cfg, scope), &got); err != nil {
103 t.Fatal(err)
104 }
105 if got.Checkpoints != cfg.Checkpoints {
106 t.Errorf("scope %v lost retention: %+v", scope, got.Checkpoints)
107 }
108 }
109 var got Config
110 if _, err := toml.Decode(RenderTOMLProjectDelta(cfg), &got); err != nil {
111 t.Fatal(err)
112 }
113 if got.Checkpoints != cfg.Checkpoints {
114 t.Errorf("project delta lost retention: %+v", got.Checkpoints)
115 }
116 }
117
117 lines GO