package bootstrap import ( "bytes" "context" "errors" "slices" "strings" "testing" ) func TestRunRoutesSetupHook(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer var got Invocation err := Run(context.Background(), Options{ BinaryName: "my-mcp", Version: "v1.2.3", Args: []string{"setup", "--profile", "prod"}, Stdout: &stdout, Stderr: &stderr, Hooks: Hooks{ Setup: func(_ context.Context, inv Invocation) error { got = inv return nil }, }, }) if err != nil { t.Fatalf("Run error = %v", err) } if got.Command != CommandSetup { t.Fatalf("invocation command = %q, want %q", got.Command, CommandSetup) } wantArgs := []string{"--profile", "prod"} if !slices.Equal(got.Args, wantArgs) { t.Fatalf("invocation args = %v, want %v", got.Args, wantArgs) } } func TestRunReturnsUnknownCommand(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"boom"}, Stdout: &stdout, Stderr: &stderr, }) if !errors.Is(err, ErrUnknownCommand) { t.Fatalf("Run error = %v, want ErrUnknownCommand", err) } } func TestRunReturnsCommandNotConfigured(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"config"}, Stdout: &stdout, Stderr: &stderr, }) if !errors.Is(err, ErrSubcommandRequired) { t.Fatalf("Run error = %v, want ErrSubcommandRequired", err) } if !strings.Contains(err.Error(), "show, test, delete") { t.Fatalf("Run error = %q, want mention of show, test, delete", err) } } func TestRunPrintsVersionByDefault(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer err := Run(context.Background(), Options{ BinaryName: "my-mcp", Version: "v1.2.3", Args: []string{"version"}, Stdout: &stdout, Stderr: &stderr, }) if err != nil { t.Fatalf("Run error = %v", err) } if stdout.String() != "v1.2.3\n" { t.Fatalf("stdout = %q, want %q", stdout.String(), "v1.2.3\n") } } func TestRunVersionHookOverridesDefault(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"version"}, Stdout: &stdout, Stderr: &stderr, Hooks: Hooks{ Version: func(_ context.Context, inv Invocation) error { _, err := inv.Stdout.Write([]byte("custom-version\n")) return err }, }, }) if err != nil { t.Fatalf("Run error = %v", err) } if stdout.String() != "custom-version\n" { t.Fatalf("stdout = %q, want %q", stdout.String(), "custom-version\n") } } func TestRunRequiresVersionWithoutVersionHook(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"version"}, Stdout: &stdout, Stderr: &stderr, }) if !errors.Is(err, ErrVersionRequired) { t.Fatalf("Run error = %v, want ErrVersionRequired", err) } } func TestRunPrintsGlobalHelp(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer err := Run(context.Background(), Options{ BinaryName: "my-mcp", Description: "Binaire MCP de test.", Args: []string{"help"}, Stdout: &stdout, Stderr: &stderr, }) if err != nil { t.Fatalf("Run error = %v", err) } text := stdout.String() for _, snippet := range []string{ "Usage:", "setup", "mcp", "config", "update", "version", } { if !strings.Contains(text, snippet) { t.Fatalf("help output missing %q: %s", snippet, text) } } } func TestRunPrintsGlobalHelpWhenNoArgs(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer err := Run(context.Background(), Options{ BinaryName: "my-mcp", Description: "Binaire MCP de test.", Args: []string{}, Stdout: &stdout, Stderr: &stderr, }) if err != nil { t.Fatalf("Run error = %v", err) } text := stdout.String() for _, snippet := range []string{ "Usage:", "setup", "mcp", "config", "update", "version", } { if !strings.Contains(text, snippet) { t.Fatalf("help output missing %q: %s", snippet, text) } } } func TestRunPrintsCommandHelp(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"help", "update"}, Stdout: &stdout, Stderr: &stderr, }) if err != nil { t.Fatalf("Run error = %v", err) } text := stdout.String() if !strings.Contains(text, "my-mcp update [args]") { t.Fatalf("command help output = %q", text) } if !strings.Contains(text, "auto-update") { t.Fatalf("command help output missing update description: %q", text) } } func TestRunPrintsConfigHelp(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"help", "config"}, Stdout: &stdout, Stderr: &stderr, }) if err != nil { t.Fatalf("Run error = %v", err) } text := stdout.String() for _, snippet := range []string{ "my-mcp config ", "show", "test", } { if !strings.Contains(text, snippet) { t.Fatalf("config help output missing %q: %q", snippet, text) } } } func TestRunPrintsConfigSubcommandHelp(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"help", "config", "show"}, Stdout: &stdout, Stderr: &stderr, }) if err != nil { t.Fatalf("Run error = %v", err) } text := stdout.String() if !strings.Contains(text, "my-mcp config show [args]") { t.Fatalf("config subcommand help output = %q", text) } } func TestRunRoutesConfigShowHook(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer var got Invocation err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"config", "show", "--profile", "prod"}, Stdout: &stdout, Stderr: &stderr, Hooks: Hooks{ ConfigShow: func(_ context.Context, inv Invocation) error { got = inv return nil }, }, }) if err != nil { t.Fatalf("Run error = %v", err) } if got.Command != "config show" { t.Fatalf("invocation command = %q, want %q", got.Command, "config show") } wantArgs := []string{"--profile", "prod"} if !slices.Equal(got.Args, wantArgs) { t.Fatalf("invocation args = %v, want %v", got.Args, wantArgs) } } func TestRunConfigShowReturnsCommandNotConfigured(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"config", "show"}, Stdout: &stdout, Stderr: &stderr, }) if !errors.Is(err, ErrCommandNotConfigured) { t.Fatalf("Run error = %v, want ErrCommandNotConfigured", err) } } func TestRunConfigReturnsUnknownSubcommand(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"config", "sync"}, Stdout: &stdout, Stderr: &stderr, }) if !errors.Is(err, ErrUnknownSubcommand) { t.Fatalf("Run error = %v, want ErrUnknownSubcommand", err) } }