1package modes
2
3import (
4 "context"
5 "errors"
6 "strings"
7 "testing"
8
9 "github.com/bnema/zut/packages/core"
10 "github.com/bnema/zut/packages/provider"
11)
12
13type recordingFastModeSettingsStore struct {
14 SettingsStore
15 setCalls int
16 last bool
17}
18
19func (s *recordingFastModeSettingsStore) SetFastMode(enabled bool) error {
20 s.setCalls++
21 s.last = enabled
22 return nil
23}
24
25type failingFastModeSettingsStore struct {
26 SettingsStore
27 err error
28}
29
30func (s *failingFastModeSettingsStore) SetFastMode(bool) error { return s.err }
31
32type fastModeProviderClient struct{}
33
34func (fastModeProviderClient) Name() string { return "openai" }
35func (fastModeProviderClient) Stream(_ context.Context, _ provider.Request) (<-chan provider.Event, error) {
36 out := make(chan provider.Event)
37 close(out)
38 return out, nil
39}
40
41func TestSettingsDialogOffersFastModeOffByDefault(t *testing.T) {
42 interactive := NewInteractive(InteractiveConfig{Provider: "openai", Model: "gpt-5"})
43 interactive.openSettingsDialog()
44
45 item := findSettingsItem(interactive.settingsDialog.items, "fast_mode")
46 if item == nil {
47 t.Fatal("settings dialog is missing fast mode")
48 }
49 if item.value {
50 t.Fatal("fast mode is enabled by default")
51 }
52}
53
54func TestApplyFastModeUpdatesAgentAndStore(t *testing.T) {
55 store := &recordingFastModeSettingsStore{}
56 agent := core.NewAgent(fastModeProviderClient{}, "gpt-5", "", nil)
57 interactive := NewInteractive(InteractiveConfig{
58 Provider: "openai",
59 Model: "gpt-5",
60 SettingsStore: store,
61 Agent: agent,
62 })
63 interactive.openSettingsDialog()
64 interactive.rend = nil
65
66 interactive.applySettingToggle("fast_mode", true)
67
68 if interactive.cfg.FastMode == nil || !*interactive.cfg.FastMode {
69 t.Fatal("interactive FastMode was not enabled")
70 }
71 if !agent.FastMode {
72 t.Fatal("agent FastMode was not enabled")
73 }
74 if store.setCalls != 1 || !store.last {
75 t.Fatalf("store calls = %d/%v, want one enabled write", store.setCalls, store.last)
76 }
77}
78
79func TestApplyFastModeRejectsUnsupportedProvider(t *testing.T) {
80 store := &recordingFastModeSettingsStore{}
81 interactive := NewInteractive(InteractiveConfig{
82 Provider: "anthropic",
83 Model: "claude-sonnet-4-5",
84 SettingsStore: store,
85 })
86 interactive.openSettingsDialog()
87 interactive.rend = nil
88
89 interactive.applySettingToggle("fast_mode", true)
90
91 if interactive.cfg.FastMode != nil && *interactive.cfg.FastMode {
92 t.Fatal("unsupported fast mode was enabled")
93 }
94 if store.setCalls != 0 {
95 t.Fatalf("store calls = %d, want none", store.setCalls)
96 }
97 if !strings.Contains(interactive.statusErr, "only supported for OpenAI providers") {
98 t.Fatalf("status error = %q, want unsupported-provider error", interactive.statusErr)
99 }
100}
101
102func TestApplyFastModeCanDisableUnsupportedProvider(t *testing.T) {
103 enabled := true
104 store := &recordingFastModeSettingsStore{}
105 agent := core.NewAgent(fastModeProviderClient{}, "claude-sonnet-4-5", "", nil)
106 agent.FastMode = true
107 interactive := NewInteractive(InteractiveConfig{
108 Provider: "anthropic",
109 Model: "claude-sonnet-4-5",
110 FastMode: &enabled,
111 SettingsStore: store,
112 Agent: agent,
113 })
114 interactive.openSettingsDialog()
115 interactive.rend = nil
116
117 interactive.applySettingToggle("fast_mode", false)
118
119 if interactive.cfg.FastMode == nil || *interactive.cfg.FastMode {
120 t.Fatal("fast mode was not disabled")
121 }
122 if agent.FastMode {
123 t.Fatal("agent fast mode was not disabled")
124 }
125 if store.setCalls != 1 || store.last {
126 t.Fatalf("store calls = %d/%v, want one disabled write", store.setCalls, store.last)
127 }
128}
129
130func TestApplyFastModeLeavesLiveStateWhenPersistenceFails(t *testing.T) {
131 store := &failingFastModeSettingsStore{err: errors.New("disk full")}
132 agent := core.NewAgent(fastModeProviderClient{}, "gpt-5", "", nil)
133 interactive := NewInteractive(InteractiveConfig{
134 Provider: "openai",
135 Model: "gpt-5",
136 SettingsStore: store,
137 Agent: agent,
138 })
139 interactive.openSettingsDialog()
140 interactive.rend = nil
141
142 interactive.applySettingToggle("fast_mode", true)
143
144 if interactive.cfg.FastMode != nil && *interactive.cfg.FastMode {
145 t.Fatal("fast mode changed despite persistence failure")
146 }
147 if agent.FastMode {
148 t.Fatal("agent fast mode changed despite persistence failure")
149 }
150 if !strings.Contains(interactive.statusErr, "disk full") {
151 t.Fatalf("status error = %q, want persistence error", interactive.statusErr)
152 }
153}
154
155func findSettingsItem(items []settingsItem, key string) *settingsItem {
156 for idx := range items {
157 if items[idx].key == key {
158 return &items[idx]
159 }
160 }
161 return nil
162}