Skip to content

Commit 7cabe13

Browse files
committed
Add command suggestion tests
1 parent c5cb6c4 commit 7cabe13

File tree

2 files changed

+188
-7
lines changed

2 files changed

+188
-7
lines changed

command.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"flag"
77
"fmt"
88
"slices"
9+
"sort"
910
"strings"
1011
)
1112

@@ -291,13 +292,9 @@ func (c *Command) getSuggestions(unknownCmd string) []string {
291292
}
292293
}
293294
// Sort suggestions by score (highest first)
294-
for i := 0; i < len(suggestions)-1; i++ {
295-
for j := i + 1; j < len(suggestions); j++ {
296-
if suggestions[j].score > suggestions[i].score {
297-
suggestions[i], suggestions[j] = suggestions[j], suggestions[i]
298-
}
299-
}
300-
}
295+
sort.Slice(suggestions, func(i, j int) bool {
296+
return suggestions[i].score > suggestions[j].score
297+
})
301298
// Get top 3 suggestions
302299
maxSuggestions := 3
303300
result := make([]string, 0, maxSuggestions)

command_test.go

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package cli
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestCalculateSimilarity(t *testing.T) {
10+
tests := []struct {
11+
name string
12+
a string
13+
b string
14+
expected float64
15+
}{
16+
{
17+
name: "perfect match",
18+
a: "hello",
19+
b: "hello",
20+
expected: 1.0,
21+
},
22+
{
23+
name: "perfect match with different case",
24+
a: "Hello",
25+
b: "hello",
26+
expected: 1.0,
27+
},
28+
{
29+
name: "prefix match",
30+
a: "hel",
31+
b: "hello",
32+
expected: 0.9,
33+
},
34+
{
35+
name: "one character difference",
36+
a: "hello",
37+
b: "hello1",
38+
expected: 0.9, // prefix match case
39+
},
40+
{
41+
name: "completely different strings",
42+
a: "hello",
43+
b: "world",
44+
expected: 0.2, // Based on Levenshtein distance of 4 with max length 5
45+
},
46+
{
47+
name: "empty strings",
48+
a: "",
49+
b: "",
50+
expected: 1.0,
51+
},
52+
{
53+
name: "one empty string",
54+
a: "hello",
55+
b: "",
56+
expected: 0.0,
57+
},
58+
}
59+
60+
for _, tt := range tests {
61+
t.Run(tt.name, func(t *testing.T) {
62+
result := calculateSimilarity(tt.a, tt.b)
63+
assert.InDelta(t, tt.expected, result, 0.001, "similarity mismatch for %q and %q", tt.a, tt.b)
64+
})
65+
}
66+
}
67+
68+
func TestLevenshteinDistance(t *testing.T) {
69+
tests := []struct {
70+
name string
71+
a string
72+
b string
73+
expected int
74+
}{
75+
{
76+
name: "identical strings",
77+
a: "hello",
78+
b: "hello",
79+
expected: 0,
80+
},
81+
{
82+
name: "one character difference",
83+
a: "hello",
84+
b: "hallo",
85+
expected: 1,
86+
},
87+
{
88+
name: "addition",
89+
a: "hello",
90+
b: "hello1",
91+
expected: 1,
92+
},
93+
{
94+
name: "deletion",
95+
a: "hello",
96+
b: "hell",
97+
expected: 1,
98+
},
99+
{
100+
name: "empty first string",
101+
a: "",
102+
b: "hello",
103+
expected: 5,
104+
},
105+
{
106+
name: "empty second string",
107+
a: "hello",
108+
b: "",
109+
expected: 5,
110+
},
111+
{
112+
name: "both empty strings",
113+
a: "",
114+
b: "",
115+
expected: 0,
116+
},
117+
{
118+
name: "completely different strings",
119+
a: "hello",
120+
b: "world",
121+
expected: 4,
122+
},
123+
}
124+
125+
for _, tt := range tests {
126+
t.Run(tt.name, func(t *testing.T) {
127+
result := levenshteinDistance(tt.a, tt.b)
128+
assert.Equal(t, tt.expected, result, "distance mismatch for %q and %q", tt.a, tt.b)
129+
})
130+
}
131+
}
132+
133+
func TestWrapText(t *testing.T) {
134+
tests := []struct {
135+
name string
136+
text string
137+
width int
138+
expected []string
139+
}{
140+
{
141+
name: "simple wrap",
142+
text: "hello world",
143+
width: 5,
144+
expected: []string{"hello", "world"},
145+
},
146+
{
147+
name: "no wrap needed",
148+
text: "hello",
149+
width: 10,
150+
expected: []string{"hello"},
151+
},
152+
{
153+
name: "multiple wraps",
154+
text: "this is a long text that needs wrapping",
155+
width: 10,
156+
expected: []string{"this is a", "long text", "that needs", "wrapping"},
157+
},
158+
{
159+
name: "empty string",
160+
text: "",
161+
width: 10,
162+
expected: nil,
163+
},
164+
{
165+
name: "single word longer than width",
166+
text: "supercalifragilistic",
167+
width: 10,
168+
expected: []string{"supercalifragilistic"},
169+
},
170+
{
171+
name: "multiple spaces",
172+
text: "hello world",
173+
width: 20,
174+
expected: []string{"hello world"},
175+
},
176+
}
177+
178+
for _, tt := range tests {
179+
t.Run(tt.name, func(t *testing.T) {
180+
result := wrapText(tt.text, tt.width)
181+
assert.EqualValues(t, tt.expected, result, "wrapped text mismatch for input %q with width %d", tt.text, tt.width)
182+
})
183+
}
184+
}

0 commit comments

Comments
 (0)