1package agent
2
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "strings"
8 "testing"
9
10 "github.com/bnema/zut/packages/provider"
11)
12
13func TestParseArgsRejectsLegacyFastModeChildFlags(t *testing.T) {
14 if _, err := ParseArgs([]string{"--fast-mode"}); err == nil {
15 t.Fatal("ParseArgs accepted removed --fast-mode child flag")
16 }
17 if _, err := ParseArgs([]string{"--no-fast-mode"}); err == nil {
18 t.Fatal("ParseArgs accepted removed --no-fast-mode child flag")
19 }
20}
21
22func TestResolveFastModeDefaultsOff(t *testing.T) {
23 t.Setenv("ZUT_HOME", t.TempDir())
24 if err := SaveConfig(Config{Provider: "openai", Model: "gpt-5"}); err != nil {
25 t.Fatal(err)
26 }
27
28 r, err := Resolve(Args{}, false)
29 if err != nil {
30 t.Fatalf("Resolve failed: %v", err)
31 }
32 if r.FastMode {
33 t.Fatal("FastMode = true by default, want false")
34 }
35}
36
37func TestResolveFastModeFromConfig(t *testing.T) {
38 t.Setenv("ZUT_HOME", t.TempDir())
39 enabled := true
40 if err := SaveConfig(Config{Provider: "openai", Model: "gpt-5", FastMode: &enabled}); err != nil {
41 t.Fatal(err)
42 }
43
44 r, err := Resolve(Args{}, false)
45 if err != nil {
46 t.Fatalf("Resolve failed: %v", err)
47 }
48 if !r.FastMode {
49 t.Fatal("FastMode = false, want true from config")
50 }
51}
52
53func TestResolveFastModeRemainsEnabledForUnsupportedProviderUntilRequest(t *testing.T) {
54 t.Setenv("ZUT_HOME", t.TempDir())
55 enabled := true
56 if err := SaveConfig(Config{Provider: "anthropic", Model: "claude-sonnet-4-5", FastMode: &enabled}); err != nil {
57 t.Fatal(err)
58 }
59
60 r, err := Resolve(Args{}, false)
61 if err != nil {
62 t.Fatalf("Resolve failed: %v", err)
63 }
64 if !r.FastMode {
65 t.Fatal("FastMode = false, want true from config")
66 }
67}
68
69func TestResolveFastModeFromActiveModelProfile(t *testing.T) {
70 for _, want := range []bool{true, false} {
71 t.Run(fmt.Sprintf("%v", want), func(t *testing.T) {
72 t.Setenv("ZUT_HOME", t.TempDir())
73 global := !want
74 if err := SaveConfig(Config{
75 Provider: "openai", Model: "gpt-5", FastMode: &global,
76 ActiveModelProfile: 1,
77 QuickModelShortcuts: []QuickModelShortcut{{
78 Provider: "openai", Model: "gpt-5", FastMode: want,
79 }},
80 }); err != nil {
81 t.Fatal(err)
82 }
83 r, err := Resolve(Args{}, false)
84 if err != nil {
85 t.Fatalf("Resolve failed: %v", err)
86 }
87 if r.FastMode != want {
88 t.Fatalf("FastMode = %v, want %v", r.FastMode, want)
89 }
90 })
91 }
92}
93
94func TestResolveFastModeRequiresExplicitChildOverride(t *testing.T) {
95 t.Setenv("ZUT_HOME", t.TempDir())
96 if err := SaveConfig(Config{Provider: "openai", Model: "gpt-5"}); err != nil {
97 t.Fatal(err)
98 }
99
100 r, err := Resolve(Args{FastMode: true}, false)
101 if err != nil {
102 t.Fatalf("Resolve failed: %v", err)
103 }
104 if r.FastMode {
105 t.Fatal("FastMode = true, want unmarked programmatic value to be ignored")
106 }
107}
108
109func TestResolveFastModeDurableChildDisableOverridesConfig(t *testing.T) {
110 t.Setenv("ZUT_HOME", t.TempDir())
111 enabled := true
112 if err := SaveConfig(Config{Provider: "openai", Model: "gpt-5", FastMode: &enabled}); err != nil {
113 t.Fatal(err)
114 }
115 r, err := Resolve(Args{FastModeSet: true}, false)
116 if err != nil {
117 t.Fatalf("Resolve failed: %v", err)
118 }
119 if r.FastMode {
120 t.Fatal("FastMode = true, want explicit child disable to override config")
121 }
122}
123
124func TestConfigSettingsStorePersistsFastMode(t *testing.T) {
125 t.Setenv("ZUT_HOME", t.TempDir())
126 if err := SaveConfig(Config{Theme: "dark"}); err != nil {
127 t.Fatal(err)
128 }
129
130 if err := (configSettingsStore{}).SetFastMode(true); err != nil {
131 t.Fatal(err)
132 }
133 cfg, err := LoadConfig()
134 if err != nil {
135 t.Fatal(err)
136 }
137 if cfg.FastMode == nil || !*cfg.FastMode {
138 t.Fatalf("fast_mode = %v, want true", cfg.FastMode)
139 }
140 if cfg.Theme != "dark" {
141 t.Fatalf("unrelated config changed: theme = %q, want dark", cfg.Theme)
142 }
143}
144
145func TestFastModeConfigJSONUsesSnakeCase(t *testing.T) {
146 enabled := true
147 data, err := json.Marshal(Config{FastMode: &enabled})
148 if err != nil {
149 t.Fatal(err)
150 }
151 if !strings.Contains(string(data), `"fast_mode":true`) {
152 t.Fatalf("config JSON = %s, want fast_mode", data)
153 }
154}
155
156func TestResolvedOllamaClientRejectsFastMode(t *testing.T) {
157 client := (Resolved{
158 Provider: "ollama",
159 Credential: "ollama",
160 BaseURL: "http://localhost:11434",
161 }).NewClient()
162 if client.Name() != "ollama" {
163 t.Fatalf("client name = %q, want ollama", client.Name())
164 }
165 _, err := client.Stream(context.Background(), provider.Request{Model: "local", FastMode: true})
166 if err == nil || !strings.Contains(err.Error(), "only supported for OpenAI providers") {
167 t.Fatalf("Stream error = %v, want unsupported-provider error", err)
168 }
169}