summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-16 03:10:55 +0200
committerPaul Buetow <paul@buetow.org>2026-03-16 03:10:55 +0200
commit1fc1611fa99993cab5dc8bf0844183285296e3b2 (patch)
treec5c9b8b5abac5b5d4c0d56ed90b0580184cc4383 /cmd
parent12090f25a3677291863dbb80277bdad3eaec0324 (diff)
Release v0.24.0v0.24.0
Bring unit test coverage from ~75% to 85.1% project-wide. All internal packages now exceed 80% coverage. Refactored cmd entrypoints to extract testable run() functions with injectable seams. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'cmd')
-rw-r--r--cmd/hexai-mcp-server/main.go65
-rw-r--r--cmd/hexai-mcp-server/main_test.go166
-rw-r--r--cmd/hexai-tmux-action/main.go43
-rw-r--r--cmd/hexai-tmux-action/main_test.go63
-rw-r--r--cmd/hexai-tmux-edit/main.go21
-rw-r--r--cmd/hexai-tmux-edit/main_test.go59
-rw-r--r--cmd/hexai/main_test.go111
7 files changed, 496 insertions, 32 deletions
diff --git a/cmd/hexai-mcp-server/main.go b/cmd/hexai-mcp-server/main.go
index 557172f..1f52616 100644
--- a/cmd/hexai-mcp-server/main.go
+++ b/cmd/hexai-mcp-server/main.go
@@ -4,7 +4,7 @@ package main
import (
"flag"
"fmt"
- "log"
+ "io"
"os"
"codeberg.org/snonux/hexai/internal"
@@ -12,6 +12,12 @@ import (
"codeberg.org/snonux/hexai/internal/hexaimcp"
)
+// Seams for testing: override in tests to avoid launching real MCP server.
+var (
+ runMCP = hexaimcp.Run
+ runBackfill = hexaimcp.RunBackfill
+)
+
// printDeprecationWarning outputs a deprecation notice to stderr explaining
// that hexai-mcp-server is experimental and not actively maintained.
func printDeprecationWarning() {
@@ -36,6 +42,17 @@ Use at your own risk.
fmt.Fprintln(os.Stderr, warning)
}
+// mcpOptions holds the parsed command-line flags for the MCP server.
+type mcpOptions struct {
+ logPath string
+ configPath string
+ promptsDir string
+ slashCommandSync bool
+ slashCommandDir string
+ syncAll bool
+ showVersion bool
+}
+
func main() {
printDeprecationWarning()
@@ -49,33 +66,45 @@ func main() {
showVersion := flag.Bool("version", false, "print version and exit")
flag.Parse()
- if *showVersion {
- fmt.Println(internal.Version)
- return
+ opts := mcpOptions{
+ logPath: *logPath,
+ configPath: *configPath,
+ promptsDir: *promptsDir,
+ slashCommandSync: *slashCommandSync,
+ slashCommandDir: *slashCommandDir,
+ syncAll: *syncAll,
+ showVersion: *showVersion,
+ }
+ if err := run(opts, os.Stdin, os.Stdout, os.Stderr); err != nil {
+ fmt.Fprintf(os.Stderr, "error: %v\n", err)
+ os.Exit(1)
}
+}
- // If prompts-dir is specified, set environment variable for RunWithFactory
- if *promptsDir != "" {
- os.Setenv("HEXAI_MCP_PROMPTS_DIR", *promptsDir)
+// run executes the MCP server logic with the given options and I/O streams.
+func run(opts mcpOptions, stdin io.Reader, stdout, stderr io.Writer) error {
+ // Set environment variables for RunWithFactory based on flag values
+ if opts.promptsDir != "" {
+ os.Setenv("HEXAI_MCP_PROMPTS_DIR", opts.promptsDir)
}
- if *slashCommandSync {
+ if opts.slashCommandSync {
os.Setenv("HEXAI_MCP_SLASHCOMMAND_SYNC", "true")
}
- if *slashCommandDir != "" {
- os.Setenv("HEXAI_MCP_SLASHCOMMAND_DIR", *slashCommandDir)
+ if opts.slashCommandDir != "" {
+ os.Setenv("HEXAI_MCP_SLASHCOMMAND_DIR", opts.slashCommandDir)
}
- // Handle backfill operation
- if *syncAll {
- if err := hexaimcp.RunBackfill(*logPath, *configPath); err != nil {
- log.Fatalf("backfill error: %v", err)
- }
- return
+ if opts.showVersion {
+ fmt.Fprintln(stdout, internal.Version)
+ return nil
}
- if err := hexaimcp.Run(*logPath, *configPath, os.Stdin, os.Stdout, os.Stderr); err != nil {
- log.Fatalf("server error: %v", err)
+ // Handle backfill operation
+ if opts.syncAll {
+ return runBackfill(opts.logPath, opts.configPath)
}
+
+ return runMCP(opts.logPath, opts.configPath, stdin, stdout, stderr)
}
// defaultLogPath returns the default MCP log file path in the state directory.
diff --git a/cmd/hexai-mcp-server/main_test.go b/cmd/hexai-mcp-server/main_test.go
new file mode 100644
index 0000000..cf48954
--- /dev/null
+++ b/cmd/hexai-mcp-server/main_test.go
@@ -0,0 +1,166 @@
+package main
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "os"
+ "strings"
+ "testing"
+
+ "codeberg.org/snonux/hexai/internal"
+)
+
+func TestPrintDeprecationWarning(t *testing.T) {
+ r, w, err := os.Pipe()
+ if err != nil {
+ t.Fatalf("failed to create pipe: %v", err)
+ }
+
+ oldStderr := os.Stderr
+ os.Stderr = w
+ defer func() { os.Stderr = oldStderr }()
+
+ printDeprecationWarning()
+
+ if err := w.Close(); err != nil {
+ t.Fatalf("failed to close pipe writer: %v", err)
+ }
+
+ b, err := io.ReadAll(r)
+ if err != nil {
+ t.Fatalf("failed to read pipe: %v", err)
+ }
+
+ output := string(b)
+ for _, want := range []string{"DEPRECATION NOTICE", "EXPERIMENTAL", "NOT ACTIVELY MAINTAINED"} {
+ if !strings.Contains(output, want) {
+ t.Errorf("expected %q in output, got %q", want, output)
+ }
+ }
+}
+
+func TestDefaultLogPath(t *testing.T) {
+ path := defaultLogPath()
+ if path == "" {
+ t.Fatal("expected non-empty log path")
+ }
+ if !strings.HasSuffix(path, "hexai-mcp-server.log") {
+ t.Errorf("expected path to end with hexai-mcp-server.log, got %q", path)
+ }
+}
+
+func TestRun_ShowVersion(t *testing.T) {
+ var stdout bytes.Buffer
+ opts := mcpOptions{showVersion: true}
+ if err := run(opts, nil, &stdout, nil); err != nil {
+ t.Fatalf("run --version: %v", err)
+ }
+ got := strings.TrimSpace(stdout.String())
+ if got != internal.Version {
+ t.Fatalf("expected version %q, got %q", internal.Version, got)
+ }
+}
+
+func TestRun_SetsPromptsDir(t *testing.T) {
+ t.Setenv("HEXAI_MCP_PROMPTS_DIR", "")
+ opts := mcpOptions{showVersion: true, promptsDir: "/tmp/test-prompts"}
+ var stdout bytes.Buffer
+ if err := run(opts, nil, &stdout, nil); err != nil {
+ t.Fatalf("run: %v", err)
+ }
+ if got := os.Getenv("HEXAI_MCP_PROMPTS_DIR"); got != "/tmp/test-prompts" {
+ t.Fatalf("expected HEXAI_MCP_PROMPTS_DIR=/tmp/test-prompts, got %q", got)
+ }
+}
+
+func TestRun_SetsSlashCommandSync(t *testing.T) {
+ t.Setenv("HEXAI_MCP_SLASHCOMMAND_SYNC", "")
+ opts := mcpOptions{showVersion: true, slashCommandSync: true}
+ var stdout bytes.Buffer
+ if err := run(opts, nil, &stdout, nil); err != nil {
+ t.Fatalf("run: %v", err)
+ }
+ if got := os.Getenv("HEXAI_MCP_SLASHCOMMAND_SYNC"); got != "true" {
+ t.Fatalf("expected HEXAI_MCP_SLASHCOMMAND_SYNC=true, got %q", got)
+ }
+}
+
+func TestRun_SetsSlashCommandDir(t *testing.T) {
+ t.Setenv("HEXAI_MCP_SLASHCOMMAND_DIR", "")
+ opts := mcpOptions{showVersion: true, slashCommandDir: "/tmp/test-cmds"}
+ var stdout bytes.Buffer
+ if err := run(opts, nil, &stdout, nil); err != nil {
+ t.Fatalf("run: %v", err)
+ }
+ if got := os.Getenv("HEXAI_MCP_SLASHCOMMAND_DIR"); got != "/tmp/test-cmds" {
+ t.Fatalf("expected HEXAI_MCP_SLASHCOMMAND_DIR=/tmp/test-cmds, got %q", got)
+ }
+}
+
+func TestRun_SyncAll(t *testing.T) {
+ old := runBackfill
+ t.Cleanup(func() { runBackfill = old })
+
+ var gotLog, gotConfig string
+ runBackfill = func(logPath, configPath string) error {
+ gotLog = logPath
+ gotConfig = configPath
+ return nil
+ }
+
+ opts := mcpOptions{syncAll: true, logPath: "/tmp/test.log", configPath: "/tmp/cfg.toml"}
+ if err := run(opts, nil, nil, nil); err != nil {
+ t.Fatalf("run syncAll: %v", err)
+ }
+ if gotLog != "/tmp/test.log" {
+ t.Fatalf("expected logPath=/tmp/test.log, got %q", gotLog)
+ }
+ if gotConfig != "/tmp/cfg.toml" {
+ t.Fatalf("expected configPath=/tmp/cfg.toml, got %q", gotConfig)
+ }
+}
+
+func TestRun_SyncAllError(t *testing.T) {
+ old := runBackfill
+ t.Cleanup(func() { runBackfill = old })
+
+ wantErr := errors.New("backfill failed")
+ runBackfill = func(_, _ string) error { return wantErr }
+
+ opts := mcpOptions{syncAll: true}
+ if err := run(opts, nil, nil, nil); !errors.Is(err, wantErr) {
+ t.Fatalf("expected backfill error, got: %v", err)
+ }
+}
+
+func TestRun_MCPServer(t *testing.T) {
+ old := runMCP
+ t.Cleanup(func() { runMCP = old })
+
+ called := false
+ runMCP = func(logPath, configPath string, stdin io.Reader, stdout, stderr io.Writer) error {
+ called = true
+ return nil
+ }
+
+ opts := mcpOptions{logPath: "/tmp/mcp.log"}
+ if err := run(opts, nil, nil, nil); err != nil {
+ t.Fatalf("run MCP: %v", err)
+ }
+ if !called {
+ t.Fatal("expected runMCP to be called")
+ }
+}
+
+func TestRun_MCPServerError(t *testing.T) {
+ old := runMCP
+ t.Cleanup(func() { runMCP = old })
+
+ wantErr := errors.New("server failed")
+ runMCP = func(_, _ string, _ io.Reader, _, _ io.Writer) error { return wantErr }
+
+ if err := run(mcpOptions{}, nil, nil, nil); !errors.Is(err, wantErr) {
+ t.Fatalf("expected server error, got: %v", err)
+ }
+}
diff --git a/cmd/hexai-tmux-action/main.go b/cmd/hexai-tmux-action/main.go
index 6249de3..715c41f 100644
--- a/cmd/hexai-tmux-action/main.go
+++ b/cmd/hexai-tmux-action/main.go
@@ -4,6 +4,7 @@ import (
"context"
"flag"
"fmt"
+ "io"
"os"
"strings"
@@ -11,6 +12,10 @@ import (
"codeberg.org/snonux/hexai/internal/hexaiaction"
)
+// runCommand is the seam for testing: override in tests to avoid launching
+// the real tmux action.
+var runCommand = hexaiaction.RunCommand
+
func main() {
infile := flag.String("infile", "", "Read input from this file instead of stdin")
outfile := flag.String("outfile", "", "Write output to this file instead of stdout")
@@ -22,16 +27,38 @@ func main() {
tmuxPercent := flag.Int("tmux-percent", 33, "tmux split size percentage (1-100)")
flag.Parse()
- opts := hexaiaction.Options{
- Infile: *infile, Outfile: *outfile,
- UIChild: *uiChild, TmuxTarget: *tmuxTarget, TmuxSplit: *tmuxSplit, TmuxPercent: *tmuxPercent,
- }
- ctx := context.Background()
- if path := strings.TrimSpace(*configPath); path != "" {
- ctx = hexaiaction.WithConfigPath(ctx, path)
+ opts := actionOptions{
+ infile: *infile, outfile: *outfile,
+ uiChild: *uiChild, configPath: *configPath,
+ tmuxTarget: *tmuxTarget, tmuxSplit: *tmuxSplit, tmuxPercent: *tmuxPercent,
}
- if err := hexaiaction.RunCommand(ctx, opts, os.Stdin, os.Stdout, os.Stderr); err != nil {
+ if err := run(opts, os.Stdin, os.Stdout, os.Stderr); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
+
+// actionOptions holds the parsed command-line flags for hexai-tmux-action.
+type actionOptions struct {
+ infile string
+ outfile string
+ uiChild bool
+ configPath string
+ tmuxTarget string
+ tmuxSplit string
+ tmuxPercent int
+}
+
+// run builds the hexaiaction.Options and context, then delegates to runCommand.
+func run(opts actionOptions, stdin io.Reader, stdout, stderr io.Writer) error {
+ haOpts := hexaiaction.Options{
+ Infile: opts.infile, Outfile: opts.outfile,
+ UIChild: opts.uiChild, TmuxTarget: opts.tmuxTarget,
+ TmuxSplit: opts.tmuxSplit, TmuxPercent: opts.tmuxPercent,
+ }
+ ctx := context.Background()
+ if path := strings.TrimSpace(opts.configPath); path != "" {
+ ctx = hexaiaction.WithConfigPath(ctx, path)
+ }
+ return runCommand(ctx, haOpts, stdin, stdout, stderr)
+}
diff --git a/cmd/hexai-tmux-action/main_test.go b/cmd/hexai-tmux-action/main_test.go
new file mode 100644
index 0000000..8abd420
--- /dev/null
+++ b/cmd/hexai-tmux-action/main_test.go
@@ -0,0 +1,63 @@
+package main
+
+import (
+ "context"
+ "errors"
+ "io"
+ "testing"
+
+ "codeberg.org/snonux/hexai/internal/hexaiaction"
+)
+
+func TestRun_DelegatesToRunCommand(t *testing.T) {
+ old := runCommand
+ t.Cleanup(func() { runCommand = old })
+
+ var gotOpts hexaiaction.Options
+ runCommand = func(_ context.Context, opts hexaiaction.Options, _ io.Reader, _, _ io.Writer) error {
+ gotOpts = opts
+ return nil
+ }
+
+ opts := actionOptions{
+ infile: "in.txt", outfile: "out.txt",
+ tmuxSplit: "h", tmuxPercent: 50,
+ }
+ if err := run(opts, nil, nil, nil); err != nil {
+ t.Fatalf("run: %v", err)
+ }
+ if gotOpts.Infile != "in.txt" || gotOpts.Outfile != "out.txt" {
+ t.Fatalf("unexpected opts: %+v", gotOpts)
+ }
+ if gotOpts.TmuxSplit != "h" || gotOpts.TmuxPercent != 50 {
+ t.Fatalf("unexpected tmux opts: %+v", gotOpts)
+ }
+}
+
+func TestRun_WithConfigPath(t *testing.T) {
+ old := runCommand
+ t.Cleanup(func() { runCommand = old })
+
+ runCommand = func(_ context.Context, _ hexaiaction.Options, _ io.Reader, _, _ io.Writer) error {
+ return nil
+ }
+
+ opts := actionOptions{configPath: " /tmp/test.toml ", tmuxSplit: "v", tmuxPercent: 33}
+ if err := run(opts, nil, nil, nil); err != nil {
+ t.Fatalf("run: %v", err)
+ }
+}
+
+func TestRun_Error(t *testing.T) {
+ old := runCommand
+ t.Cleanup(func() { runCommand = old })
+
+ wantErr := errors.New("action failed")
+ runCommand = func(_ context.Context, _ hexaiaction.Options, _ io.Reader, _, _ io.Writer) error {
+ return wantErr
+ }
+
+ if err := run(actionOptions{}, nil, nil, nil); !errors.Is(err, wantErr) {
+ t.Fatalf("expected error, got: %v", err)
+ }
+}
diff --git a/cmd/hexai-tmux-edit/main.go b/cmd/hexai-tmux-edit/main.go
index ea3330b..6d0e75e 100644
--- a/cmd/hexai-tmux-edit/main.go
+++ b/cmd/hexai-tmux-edit/main.go
@@ -21,6 +21,9 @@ import (
"codeberg.org/snonux/hexai/internal/tmuxedit"
)
+// runTmuxEdit is the seam for testing: override in tests to avoid real tmux.
+var runTmuxEdit = tmuxedit.Run
+
func main() {
defaultPath := appconfig.DefaultConfigPath()
configPath := flag.String("config", "", fmt.Sprintf("path to config file (default: %s)", defaultPath))
@@ -28,13 +31,19 @@ func main() {
pane := flag.String("pane", "", "tmux target pane ID (e.g. %%5)")
flag.Parse()
- opts := tmuxedit.Options{
- ConfigPath: strings.TrimSpace(*configPath),
- Agent: strings.TrimSpace(*agent),
- Pane: strings.TrimSpace(*pane),
- }
- if err := tmuxedit.Run(opts); err != nil {
+ opts := buildOptions(*configPath, *agent, *pane)
+ if err := runTmuxEdit(opts); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
+
+// buildOptions constructs tmuxedit.Options from the parsed flag values,
+// trimming whitespace from each field.
+func buildOptions(configPath, agent, pane string) tmuxedit.Options {
+ return tmuxedit.Options{
+ ConfigPath: strings.TrimSpace(configPath),
+ Agent: strings.TrimSpace(agent),
+ Pane: strings.TrimSpace(pane),
+ }
+}
diff --git a/cmd/hexai-tmux-edit/main_test.go b/cmd/hexai-tmux-edit/main_test.go
new file mode 100644
index 0000000..fc2364c
--- /dev/null
+++ b/cmd/hexai-tmux-edit/main_test.go
@@ -0,0 +1,59 @@
+package main
+
+import (
+ "errors"
+ "testing"
+
+ "codeberg.org/snonux/hexai/internal/tmuxedit"
+)
+
+func TestBuildOptions_AllEmpty(t *testing.T) {
+ opts := buildOptions("", "", "")
+ if opts.ConfigPath != "" || opts.Agent != "" || opts.Pane != "" {
+ t.Fatalf("expected all empty, got %+v", opts)
+ }
+}
+
+func TestBuildOptions_TrimsWhitespace(t *testing.T) {
+ opts := buildOptions(" /tmp/cfg.toml ", " claude ", " %5 ")
+ if opts.ConfigPath != "/tmp/cfg.toml" {
+ t.Fatalf("expected trimmed config path, got %q", opts.ConfigPath)
+ }
+ if opts.Agent != "claude" {
+ t.Fatalf("expected trimmed agent, got %q", opts.Agent)
+ }
+ if opts.Pane != "%5" {
+ t.Fatalf("expected trimmed pane, got %q", opts.Pane)
+ }
+}
+
+func TestRunTmuxEdit_Success(t *testing.T) {
+ old := runTmuxEdit
+ t.Cleanup(func() { runTmuxEdit = old })
+
+ var gotOpts tmuxedit.Options
+ runTmuxEdit = func(opts tmuxedit.Options) error {
+ gotOpts = opts
+ return nil
+ }
+
+ opts := buildOptions("/tmp/cfg.toml", "cursor", "%3")
+ if err := runTmuxEdit(opts); err != nil {
+ t.Fatalf("runTmuxEdit: %v", err)
+ }
+ if gotOpts.ConfigPath != "/tmp/cfg.toml" || gotOpts.Agent != "cursor" || gotOpts.Pane != "%3" {
+ t.Fatalf("unexpected opts: %+v", gotOpts)
+ }
+}
+
+func TestRunTmuxEdit_Error(t *testing.T) {
+ old := runTmuxEdit
+ t.Cleanup(func() { runTmuxEdit = old })
+
+ wantErr := errors.New("tmux not found")
+ runTmuxEdit = func(_ tmuxedit.Options) error { return wantErr }
+
+ if err := runTmuxEdit(tmuxedit.Options{}); !errors.Is(err, wantErr) {
+ t.Fatalf("expected error, got: %v", err)
+ }
+}
diff --git a/cmd/hexai/main_test.go b/cmd/hexai/main_test.go
index 531a11f..7c20cc4 100644
--- a/cmd/hexai/main_test.go
+++ b/cmd/hexai/main_test.go
@@ -5,6 +5,8 @@ import (
"os"
"strings"
"testing"
+
+ "codeberg.org/snonux/hexai/internal/appconfig"
)
func TestMain_Version(t *testing.T) {
@@ -25,6 +27,115 @@ func TestMain_Version(t *testing.T) {
}
}
+func TestSplitConfigPath(t *testing.T) {
+ tests := []struct {
+ name string
+ args []string
+ wantPath string
+ wantRest []string
+ }{
+ {
+ name: "no args",
+ args: nil,
+ wantPath: "",
+ wantRest: []string{},
+ },
+ {
+ name: "no config flag",
+ args: []string{"-version", "hello"},
+ wantPath: "",
+ wantRest: []string{"-version", "hello"},
+ },
+ {
+ name: "--config with separate value",
+ args: []string{"--config", "/tmp/cfg.toml", "-version"},
+ wantPath: "/tmp/cfg.toml",
+ wantRest: []string{"-version"},
+ },
+ {
+ name: "-config with separate value",
+ args: []string{"-config", "/tmp/cfg.toml", "extra"},
+ wantPath: "/tmp/cfg.toml",
+ wantRest: []string{"extra"},
+ },
+ {
+ name: "--config= form",
+ args: []string{"--config=/tmp/cfg.toml", "extra"},
+ wantPath: "/tmp/cfg.toml",
+ wantRest: []string{"extra"},
+ },
+ {
+ name: "-config= form",
+ args: []string{"-config=/tmp/cfg.toml", "extra"},
+ wantPath: "/tmp/cfg.toml",
+ wantRest: []string{"extra"},
+ },
+ {
+ name: "--config as last arg without value",
+ args: []string{"extra", "--config"},
+ wantPath: "",
+ wantRest: []string{"extra"},
+ },
+ {
+ name: "-config as last arg without value",
+ args: []string{"-config"},
+ wantPath: "",
+ wantRest: []string{},
+ },
+ {
+ name: "path with whitespace is trimmed",
+ args: []string{"--config", " /tmp/cfg.toml "},
+ wantPath: "/tmp/cfg.toml",
+ wantRest: []string{},
+ },
+ }
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ gotPath, gotRest := splitConfigPath(tc.args)
+ if gotPath != tc.wantPath {
+ t.Errorf("path = %q, want %q", gotPath, tc.wantPath)
+ }
+ if len(gotRest) != len(tc.wantRest) {
+ t.Fatalf("rest len = %d, want %d; got %v", len(gotRest), len(tc.wantRest), gotRest)
+ }
+ for i := range gotRest {
+ if gotRest[i] != tc.wantRest[i] {
+ t.Errorf("rest[%d] = %q, want %q", i, gotRest[i], tc.wantRest[i])
+ }
+ }
+ })
+ }
+}
+
+func TestPickDefaultModel(t *testing.T) {
+ cfg := appconfig.App{
+ OllamaModel: "llama3",
+ AnthropicModel: "claude-sonnet",
+ OpenAIModel: "gpt-4o",
+ }
+ tests := []struct {
+ provider string
+ want string
+ }{
+ {"ollama", "llama3"},
+ {"Ollama", "llama3"},
+ {" OLLAMA ", "llama3"},
+ {"anthropic", "claude-sonnet"},
+ {"Anthropic", "claude-sonnet"},
+ {"openai", "gpt-4o"},
+ {"unknown-provider", "gpt-4o"},
+ {"", "gpt-4o"},
+ }
+ for _, tc := range tests {
+ t.Run(tc.provider, func(t *testing.T) {
+ got := pickDefaultModel(cfg, tc.provider)
+ if got != tc.want {
+ t.Errorf("pickDefaultModel(%q) = %q, want %q", tc.provider, got, tc.want)
+ }
+ })
+ }
+}
+
func TestMain_TPSSimulation(t *testing.T) {
oldArgs := os.Args
defer func() { os.Args = oldArgs }()