返回 DeepSeek-Reasonix
tabs_locale_test.go
根目录 / desktop / tabs_locale_test.go
1 package main
2
3 import (
4 "context"
5 "os"
6 "testing"
7 "time"
8
9 "reasonix/internal/config"
10 "reasonix/internal/control"
11 "reasonix/internal/sessioncatalog"
12 )
13
14 func TestDefaultTopicTitleLocalizesAtAPIBoundary(t *testing.T) {
15 app := &App{}
16 for _, tt := range []struct {
17 locale string
18 want string
19 }{
20 {locale: "en-US", want: defaultTopicTitleEn},
21 {locale: "zh-CN", want: defaultTopicTitle},
22 {locale: "zh-TW", want: defaultTopicTitleZhTW},
23 } {
24 app.setDesktopLocale(tt.locale)
25 if got := app.localizedTopicTitle(defaultTopicTitle, topicTitleSourceAuto); got != tt.want {
26 t.Fatalf("locale %q title = %q, want %q", tt.locale, got, tt.want)
27 }
28 }
29 }
30
31 func TestManualDefaultTopicTitleIsNotLocalized(t *testing.T) {
32 app := &App{}
33 for _, tt := range []struct {
34 locale string
35 title string
36 }{
37 {locale: "zh-CN", title: defaultTopicTitleEn},
38 {locale: "en-US", title: defaultTopicTitle},
39 {locale: "zh-CN", title: defaultTopicTitleZhTW},
40 } {
41 app.setDesktopLocale(tt.locale)
42 if got := app.localizedTopicTitle(tt.title, topicTitleSourceManual); got != tt.title {
43 t.Fatalf("locale %q manual title = %q, want %q", tt.locale, got, tt.title)
44 }
45 }
46 }
47
48 func TestCreateTopicPreservesManualDefaultTitle(t *testing.T) {
49 isolateDesktopUserDirs(t)
50 app := &App{}
51 app.projectTreeChangedHook = func() {}
52 app.setDesktopLocale("zh-CN")
53
54 manual, err := app.CreateTopic("global", "", defaultTopicTitleEn)
55 if err != nil {
56 t.Fatalf("CreateTopic manual: %v", err)
57 }
58 if manual.Title != defaultTopicTitleEn {
59 t.Fatalf("manual title = %q, want %q", manual.Title, defaultTopicTitleEn)
60 }
61 if got := loadTopicTitleSource("", manual.ID); got != topicTitleSourceManual {
62 t.Fatalf("manual title source = %q, want %q", got, topicTitleSourceManual)
63 }
64 tree := app.ListProjectTree()
65 if len(tree) == 0 || len(tree[0].Children) == 0 || tree[0].Children[0].Label != defaultTopicTitleEn {
66 t.Fatalf("manual project-tree title was localized: %+v", tree)
67 }
68
69 automatic, err := app.CreateTopic("global", "", "")
70 if err != nil {
71 t.Fatalf("CreateTopic automatic: %v", err)
72 }
73 if automatic.Title != defaultTopicTitle {
74 t.Fatalf("automatic title = %q, want localized %q", automatic.Title, defaultTopicTitle)
75 }
76 if err := app.RenameTopic(automatic.ID, defaultTopicTitleEn); err != nil {
77 t.Fatalf("RenameTopic manual default: %v", err)
78 }
79 if got := loadTopicTitleSource("", automatic.ID); got != topicTitleSourceManual {
80 t.Fatalf("renamed title source = %q, want %q", got, topicTitleSourceManual)
81 }
82 tree = app.ListProjectTree()
83 if len(tree) == 0 || len(tree[0].Children) == 0 || tree[0].Children[0].Label != defaultTopicTitleEn {
84 t.Fatalf("renamed project-tree title was localized: %+v", tree)
85 }
86 }
87
88 func TestDefaultTopicTitleVariantsRemainPersistenceSentinels(t *testing.T) {
89 for _, title := range []string{defaultTopicTitle, defaultTopicTitleEn, defaultTopicTitleZhTW} {
90 if !isDefaultTopicTitle(title) {
91 t.Fatalf("title %q was not recognized as a default sentinel", title)
92 }
93 }
94 if got := topicTitleFromText(defaultTopicTitleEn); got != "" {
95 t.Fatalf("English default title became a generated title: %q", got)
96 }
97 }
98
99 func TestForkTopicTitleUsesHarnessNumbering(t *testing.T) {
100 app := &App{}
101 app.setDesktopLocale("en")
102 if got := app.forkTopicTitle("New session"); got != "New session (1)" {
103 t.Fatalf("English fork title = %q", got)
104 }
105 app.setDesktopLocale("zh-TW")
106 if got := app.forkTopicTitle(defaultTopicTitle); got != "新的會話 (1)" {
107 t.Fatalf("Traditional Chinese fork title = %q", got)
108 }
109 app.desktopLocale.Store(desktopLocaleUnknown)
110 if got := app.forkTopicTitle(""); got != "新的会话 (1)" {
111 t.Fatalf("legacy fallback fork title = %q", got)
112 }
113 if got := app.forkTopicTitle("Roadmap (1)"); got != "Roadmap (2)" {
114 t.Fatalf("numbered fork title = %q", got)
115 }
116 if got := app.forkTopicTitle("计划(9)"); got != "计划(10)" {
117 t.Fatalf("fullwidth numbered fork title = %q", got)
118 }
119 }
120
121 func TestSetTrayLocaleDoesNotChangeAutoCurrency(t *testing.T) {
122 isolateDesktopUserDirs(t)
123 cfg := config.Default()
124 if err := cfg.SaveTo(config.UserConfigPath()); err != nil {
125 t.Fatalf("save auto config: %v", err)
126 }
127
128 app := NewApp()
129 app.projectTreeChangedHook = func() {}
130 activeCtrl := control.New(control.Options{Label: "active"})
131 inactiveCtrl := control.New(control.Options{Label: "inactive"})
132 t.Cleanup(activeCtrl.Close)
133 t.Cleanup(inactiveCtrl.Close)
134 app.tabs = map[string]*WorkspaceTab{
135 "active": {ID: "active", Ctrl: activeCtrl},
136 "inactive": {ID: "inactive", Ctrl: inactiveCtrl},
137 }
138 app.activeTabID = "active"
139 app.setDesktopLocale("en")
140
141 if err := app.SetTrayLocale("zh-CN"); err != nil {
142 t.Fatalf("SetTrayLocale: %v", err)
143 }
144 for _, tabID := range []string{"active", "inactive"} {
145 if app.deferredRebuildPending(tabID) {
146 t.Fatalf("locale change scheduled currency refresh for %q", tabID)
147 }
148 }
149 }
150
151 func TestSetTrayLocaleKeepsExplicitCurrencyRuntime(t *testing.T) {
152 isolateDesktopUserDirs(t)
153 cfg := config.Default()
154 cfg.Desktop.Currency = "USD"
155 cfg.ApplyDeepSeekOfficialDefaultPricing()
156 if err := cfg.SaveTo(config.UserConfigPath()); err != nil {
157 t.Fatalf("save explicit currency config: %v", err)
158 }
159
160 app := NewApp()
161 app.projectTreeChangedHook = func() {}
162 ctrl := control.New(control.Options{Label: "active"})
163 t.Cleanup(ctrl.Close)
164 app.tabs = map[string]*WorkspaceTab{"active": {ID: "active", Ctrl: ctrl}}
165 app.activeTabID = "active"
166 app.setDesktopLocale("en")
167
168 if err := app.SetTrayLocale("zh-CN"); err != nil {
169 t.Fatalf("SetTrayLocale: %v", err)
170 }
171 if app.deferredRebuildPending("active") {
172 t.Fatal("explicit USD currency scheduled an automatic locale refresh")
173 }
174 }
175
176 func TestDesktopEffectivePricingCurrencyUsesLocaleOnlyForAuto(t *testing.T) {
177 app := NewApp()
178 app.setDesktopLocale("zh-CN")
179
180 cfg := config.Default()
181 if got := app.desktopEffectivePricingCurrency(cfg); got != "" {
182 t.Fatalf("auto pricing currency = %q, want unresolved auto", got)
183 }
184
185 cfg.Desktop.Language = "en"
186 cfg.ApplyDeepSeekOfficialDefaultPricing()
187 if got := app.desktopEffectivePricingCurrency(cfg); got != "" {
188 t.Fatalf("desktop language changed pricing currency = %q", got)
189 }
190
191 cfg.Desktop.Language = ""
192 cfg.Language = "en"
193 cfg.ApplyDeepSeekOfficialDefaultPricing()
194 if got := app.desktopEffectivePricingCurrency(cfg); got != "" {
195 t.Fatalf("CLI language changed pricing currency = %q", got)
196 }
197
198 cfg.Language = ""
199 cfg.Desktop.Currency = "USD"
200 cfg.ApplyDeepSeekOfficialDefaultPricing()
201 if got := app.desktopEffectivePricingCurrency(cfg); got != "USD" {
202 t.Fatalf("explicit currency pricing currency = %q, want USD", got)
203 }
204 }
205
206 func installLocaleTestCatalog(t *testing.T, app *App) *sessioncatalog.Catalog {
207 t.Helper()
208 catalog, err := sessioncatalog.Open(context.Background(), sessioncatalog.Options{InMemory: true, DisableRepair: true})
209 if err != nil {
210 t.Fatalf("open catalog: %v", err)
211 }
212 app.sessionCatalog.Store(catalog)
213 t.Cleanup(func() {
214 app.sessionCatalog.CompareAndSwap(catalog, nil)
215 _ = catalog.Close(context.Background())
216 })
217 if err := catalog.ReconcileDirectory(context.Background(), sessioncatalog.DirectoryTarget{Path: desktopSessionDir(globalWorkspaceRoot()), Scope: "global", WorkspaceRoot: ""}); err != nil {
218 t.Fatalf("reconcile catalog: %v", err)
219 }
220 if err := app.syncSessionCatalogMetadataBounded(context.Background(), catalog); err != nil {
221 t.Fatalf("sync catalog metadata: %v", err)
222 }
223 return catalog
224 }
225
226 func TestCatalogManualDefaultTitleIsNotLocalized(t *testing.T) {
227 isolateDesktopUserDirs(t)
228 app := NewApp()
229 app.projectTreeChangedHook = func() {}
230 app.setDesktopLocale("en-US")
231
232 manual, err := app.CreateTopic("global", "", defaultTopicTitle)
233 if err != nil {
234 t.Fatalf("CreateTopic manual: %v", err)
235 }
236 if manual.Title != defaultTopicTitle {
237 t.Fatalf("manual title = %q, want %q", manual.Title, defaultTopicTitle)
238 }
239 sessionDir := desktopSessionDir(globalWorkspaceRoot())
240 if err := os.MkdirAll(sessionDir, 0o755); err != nil {
241 t.Fatalf("mkdir global sessions: %v", err)
242 }
243 writeTopicSessionWithPrompt(
244 t, sessionDir, "manual-default.jsonl", manual.ID, defaultTopicTitle, "",
245 "manual default title should remain unchanged", time.Now(),
246 )
247 catalog := installLocaleTestCatalog(t, app)
248 page, err := app.catalogTopicPage(catalog, ProjectTopicPageRequest{Scope: "global", WorkspaceRoot: "", Limit: 100})
249 if err != nil {
250 t.Fatalf("catalogTopicPage: %v", err)
251 }
252 if len(page.Items) != 1 || page.Items[0].TopicID != manual.ID || page.Items[0].Label != defaultTopicTitle {
253 t.Fatalf("manual catalog topic = %+v, want topic %q with untouched label %q", page.Items, manual.ID, defaultTopicTitle)
254 }
255 }
256
256 lines GO