Skip to content

Commit bea9d15

Browse files
authored
fix(goctl): restore API summaries in swagger generation (#5237)
1 parent 3f756a2 commit bea9d15

File tree

2 files changed

+112
-2
lines changed

2 files changed

+112
-2
lines changed

tools/goctl/api/swagger/annotation.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@ func getFirstUsableString(def ...string) string {
2424
}
2525

2626
for _, val := range def {
27-
str, err := strconv.Unquote(val)
28-
if err == nil && len(str) != 0 {
27+
// Try to unquote if it's a quoted string
28+
if str, err := strconv.Unquote(val); err == nil && len(str) != 0 {
2929
return str
3030
}
31+
32+
// Otherwise, use the value as-is if it's not empty
33+
if len(val) != 0 {
34+
return val
35+
}
3136
}
3237

3338
return ""

tools/goctl/api/swagger/annotation_test.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,108 @@ func Test_getListFromInfoOrDefault(t *testing.T) {
8989
assert.Equal(t, []string{"query"}, getListFromInfoOrDefault(unquotedProperties, "tags", []string{"default"}))
9090
assert.Equal(t, []string{"default"}, getListFromInfoOrDefault(unquotedProperties, "empty", []string{"default"}))
9191
}
92+
93+
func Test_getFirstUsableString(t *testing.T) {
94+
t.Run("empty input", func(t *testing.T) {
95+
result := getFirstUsableString()
96+
assert.Equal(t, "", result, "should return empty string for no arguments")
97+
})
98+
99+
t.Run("single plain string", func(t *testing.T) {
100+
result := getFirstUsableString("Check server health status.")
101+
assert.Equal(t, "Check server health status.", result)
102+
})
103+
104+
t.Run("single quoted string", func(t *testing.T) {
105+
// This is how Go would represent a quoted string literal
106+
result := getFirstUsableString(`"Check server health status."`)
107+
assert.Equal(t, "Check server health status.", result, "should unquote quoted strings")
108+
})
109+
110+
t.Run("multiple plain strings", func(t *testing.T) {
111+
result := getFirstUsableString("", "second", "third")
112+
assert.Equal(t, "second", result, "should return first non-empty string")
113+
})
114+
115+
t.Run("handler name fallback", func(t *testing.T) {
116+
// Simulates the real use case: @doc text, handler name
117+
result := getFirstUsableString("", "HealthCheck")
118+
assert.Equal(t, "HealthCheck", result, "should fallback to handler name")
119+
})
120+
121+
t.Run("doc text over handler name", func(t *testing.T) {
122+
// Simulates the real use case with @doc text
123+
result := getFirstUsableString("Check server health status.", "HealthCheck")
124+
assert.Equal(t, "Check server health status.", result, "should use doc text over handler name")
125+
})
126+
127+
t.Run("empty strings before valid", func(t *testing.T) {
128+
result := getFirstUsableString("", "", "valid")
129+
assert.Equal(t, "valid", result, "should skip empty strings")
130+
})
131+
132+
t.Run("all empty strings", func(t *testing.T) {
133+
result := getFirstUsableString("", "", "")
134+
assert.Equal(t, "", result, "should return empty if all are empty")
135+
})
136+
137+
t.Run("quoted then plain", func(t *testing.T) {
138+
result := getFirstUsableString(`"quoted"`, "plain")
139+
assert.Equal(t, "quoted", result, "should unquote first quoted string")
140+
})
141+
142+
t.Run("plain then quoted", func(t *testing.T) {
143+
result := getFirstUsableString("plain", `"quoted"`)
144+
assert.Equal(t, "plain", result, "should use first plain string")
145+
})
146+
147+
t.Run("invalid quoted string", func(t *testing.T) {
148+
// String that looks quoted but isn't valid Go syntax
149+
result := getFirstUsableString(`"incomplete`, "fallback")
150+
assert.Equal(t, `"incomplete`, result, "should use as-is if unquote fails but not empty")
151+
})
152+
153+
t.Run("whitespace only", func(t *testing.T) {
154+
result := getFirstUsableString(" ", "fallback")
155+
assert.Equal(t, " ", result, "should not trim whitespace, return as-is")
156+
})
157+
158+
t.Run("real world API doc scenario", func(t *testing.T) {
159+
// This is the actual bug scenario from issue #5229
160+
atDocText := "Check server health status."
161+
handlerName := "HealthCheck"
162+
163+
result := getFirstUsableString(atDocText, handlerName)
164+
assert.Equal(t, "Check server health status.", result,
165+
"should use @doc text for API summary")
166+
})
167+
168+
t.Run("real world with empty doc", func(t *testing.T) {
169+
// When @doc is empty, should fall back to handler name
170+
atDocText := ""
171+
handlerName := "HealthCheck"
172+
173+
result := getFirstUsableString(atDocText, handlerName)
174+
assert.Equal(t, "HealthCheck", result,
175+
"should fallback to handler name when @doc is empty")
176+
})
177+
178+
t.Run("complex summary with special characters", func(t *testing.T) {
179+
result := getFirstUsableString("Get user by ID: /users/{id}")
180+
assert.Equal(t, "Get user by ID: /users/{id}", result,
181+
"should handle special characters in plain strings")
182+
})
183+
184+
t.Run("multiline string", func(t *testing.T) {
185+
result := getFirstUsableString("Line 1\nLine 2")
186+
assert.Equal(t, "Line 1\nLine 2", result,
187+
"should handle multiline strings")
188+
})
189+
190+
t.Run("unicode characters", func(t *testing.T) {
191+
result := getFirstUsableString("健康检查", "HealthCheck")
192+
assert.Equal(t, "健康检查", result,
193+
"should handle unicode characters")
194+
})
195+
}
196+

0 commit comments

Comments
 (0)