|
5 | 5 | "context" |
6 | 6 | "encoding/json" |
7 | 7 | "errors" |
| 8 | + "fmt" |
8 | 9 | "io" |
9 | 10 | "os" |
10 | 11 | "path/filepath" |
@@ -157,6 +158,80 @@ func TestRunNoArgsLaunchesSetupTUIWithNilProviderWhenNoProviderConfigured(t *tes |
157 | 158 | assertAgentOptions(t, launchedOptions, 12, agent.PermissionModeAsk) |
158 | 159 | } |
159 | 160 |
|
| 161 | +func TestRunNoArgsEntersSetupWhenResolveReportsNoActiveProvider(t *testing.T) { |
| 162 | + var stdout bytes.Buffer |
| 163 | + var stderr bytes.Buffer |
| 164 | + cwd := t.TempDir() |
| 165 | + setCLIUserConfigRoot(t) |
| 166 | + userConfigPath := filepath.Join(t.TempDir(), "zero", "config.json") |
| 167 | + var launchedOptions tui.Options |
| 168 | + launched := false |
| 169 | + |
| 170 | + exitCode := runWithDeps([]string{}, &stdout, &stderr, appDeps{ |
| 171 | + getwd: func() (string, error) { |
| 172 | + return cwd, nil |
| 173 | + }, |
| 174 | + resolveConfig: func(workspaceRoot string, overrides config.Overrides) (config.ResolvedConfig, error) { |
| 175 | + return config.ResolvedConfig{}, fmt.Errorf("%w: active provider %q not found", config.ErrNoActiveProvider, "ghost") |
| 176 | + }, |
| 177 | + newProvider: func(config.ProviderProfile) (zeroruntime.Provider, error) { |
| 178 | + t.Fatal("newProvider should not be called without a resolved provider") |
| 179 | + return nil, nil |
| 180 | + }, |
| 181 | + userConfigPath: func() (string, error) { |
| 182 | + return userConfigPath, nil |
| 183 | + }, |
| 184 | + registerMCPTools: func(context.Context, *tools.Registry, config.MCPConfig, mcp.RegisterOptions) (mcpToolRuntime, error) { |
| 185 | + return noopMCPRuntime{}, nil |
| 186 | + }, |
| 187 | + runTUI: func(ctx context.Context, options tui.Options) int { |
| 188 | + launched = true |
| 189 | + launchedOptions = options |
| 190 | + return 0 |
| 191 | + }, |
| 192 | + }) |
| 193 | + |
| 194 | + if exitCode != 0 { |
| 195 | + t.Fatalf("exit code = %d, want 0 (setup TUI launched), stderr=%q", exitCode, stderr.String()) |
| 196 | + } |
| 197 | + if !launched { |
| 198 | + t.Fatal("TUI was not launched; expected fallback into setup instead of a fatal error") |
| 199 | + } |
| 200 | + if !launchedOptions.Setup.Visible || !launchedOptions.Setup.Required { |
| 201 | + t.Fatalf("Setup = %#v, want visible required setup", launchedOptions.Setup) |
| 202 | + } |
| 203 | + if launchedOptions.Provider != nil { |
| 204 | + t.Fatalf("Provider = %#v, want nil for no-provider fallback", launchedOptions.Provider) |
| 205 | + } |
| 206 | +} |
| 207 | + |
| 208 | +func TestRunNoArgsFailsWhenResolveErrorIsNotProviderRelated(t *testing.T) { |
| 209 | + var stdout bytes.Buffer |
| 210 | + var stderr bytes.Buffer |
| 211 | + cwd := t.TempDir() |
| 212 | + setCLIUserConfigRoot(t) |
| 213 | + |
| 214 | + exitCode := runWithDeps([]string{}, &stdout, &stderr, appDeps{ |
| 215 | + getwd: func() (string, error) { |
| 216 | + return cwd, nil |
| 217 | + }, |
| 218 | + resolveConfig: func(workspaceRoot string, overrides config.Overrides) (config.ResolvedConfig, error) { |
| 219 | + return config.ResolvedConfig{}, fmt.Errorf("invalid config JSON") |
| 220 | + }, |
| 221 | + runTUI: func(ctx context.Context, options tui.Options) int { |
| 222 | + t.Fatal("TUI must not launch on a non-provider resolve error") |
| 223 | + return 0 |
| 224 | + }, |
| 225 | + }) |
| 226 | + |
| 227 | + if exitCode == 0 { |
| 228 | + t.Fatal("exit code = 0, want non-zero for fatal config error") |
| 229 | + } |
| 230 | + if !strings.Contains(stderr.String(), "invalid config JSON") { |
| 231 | + t.Fatalf("stderr = %q, want the underlying config error", stderr.String()) |
| 232 | + } |
| 233 | +} |
| 234 | + |
160 | 235 | func TestRunNoArgsLaunchesTUIWithMCPState(t *testing.T) { |
161 | 236 | var stdout bytes.Buffer |
162 | 237 | var stderr bytes.Buffer |
|
0 commit comments