Skip to content

Commit 5cca6fb

Browse files
committed
refactor(cli): mcp create validation and parseKVSlice test polish
Move --server-name empty-check inside runCommand closure to match the project convention established in alert.go (validation flows through the same error formatter as all other business-logic errors). Rewrite TestMCPCreateRejectsEmptyServerName to use execCommand + mockClient injection so it survives the guard moving inside runCommand without depending on real config or network. Add TestParseKVSlice table-driven tests covering nil/empty/single/multi/ value-with-equals/empty-value/empty-key/missing-equals cases.
1 parent 9b54252 commit 5cca6fb

3 files changed

Lines changed: 52 additions & 5 deletions

File tree

internal/cli/helpers_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cli
22

33
import (
4+
"reflect"
45
"strings"
56
"testing"
67
)
@@ -125,3 +126,40 @@ func TestOrDash(t *testing.T) {
125126
func TestMemberPersonInfosDisplay(t *testing.T) {
126127
t.Skip("requires injection seam for fake client (Phase 3)")
127128
}
129+
130+
func TestParseKVSlice(t *testing.T) {
131+
cases := []struct {
132+
name string
133+
input []string
134+
want map[string]string
135+
wantErr bool
136+
}{
137+
{"nil input", nil, nil, false},
138+
{"empty input", []string{}, nil, false},
139+
{"single pair", []string{"K=V"}, map[string]string{"K": "V"}, false},
140+
{"multiple pairs", []string{"A=1", "B=2"}, map[string]string{"A": "1", "B": "2"}, false},
141+
// Value contains additional '=' signs — only the first splits key from value.
142+
{"value contains equals", []string{"K=a=b=c"}, map[string]string{"K": "a=b=c"}, false},
143+
{"empty value", []string{"K="}, map[string]string{"K": ""}, false},
144+
// Empty-key is the current behaviour when the entry starts with '='; documented here.
145+
{"empty key", []string{"=V"}, map[string]string{"": "V"}, false},
146+
{"missing equals", []string{"NOEQ"}, nil, true},
147+
}
148+
for _, tc := range cases {
149+
t.Run(tc.name, func(t *testing.T) {
150+
got, err := parseKVSlice(tc.input)
151+
if tc.wantErr {
152+
if err == nil {
153+
t.Fatal("expected error, got nil")
154+
}
155+
return
156+
}
157+
if err != nil {
158+
t.Fatalf("unexpected error: %v", err)
159+
}
160+
if !reflect.DeepEqual(got, tc.want) {
161+
t.Errorf("got %v, want %v", got, tc.want)
162+
}
163+
})
164+
}
165+
}

internal/cli/mcp.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ func newMCPCreateCmd() *cobra.Command {
3636
Use: "create",
3737
Short: "Register an MCP server",
3838
RunE: func(cmd *cobra.Command, args []string) error {
39-
if strings.TrimSpace(serverName) == "" {
40-
return fmt.Errorf("--server-name is required")
41-
}
4239
return runCommand(cmd, args, func(ctx *RunContext) error {
40+
if strings.TrimSpace(serverName) == "" {
41+
return fmt.Errorf("--server-name is required")
42+
}
4343
envMap, err := parseKVSlice(envEntries)
4444
if err != nil {
4545
return fmt.Errorf("invalid --env: %w", err)

internal/cli/mcp_test.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cli
22

33
import (
4+
"strings"
45
"testing"
56
)
67

@@ -19,8 +20,16 @@ func TestMCPCreateFlagSurface(t *testing.T) {
1920
}
2021

2122
func TestMCPCreateRejectsEmptyServerName(t *testing.T) {
22-
cmd := newMCPCreateCmd()
23-
if err := cmd.RunE(cmd, nil); err == nil {
23+
saveAndResetGlobals(t)
24+
// The empty-name guard fires inside runCommand before CreateMCPServer is
25+
// ever called, so a no-op stub is sufficient.
26+
newClientFn = func() (flashdutyClient, error) { return &mockClient{}, nil }
27+
28+
_, err := execCommand("mcp", "create")
29+
if err == nil {
2430
t.Fatal("expected error for empty --server-name, got nil")
2531
}
32+
if !strings.Contains(err.Error(), "--server-name is required") {
33+
t.Fatalf("expected error %q, got %q", "--server-name is required", err.Error())
34+
}
2635
}

0 commit comments

Comments
 (0)