-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathauto_params_test.go
More file actions
296 lines (242 loc) · 9.61 KB
/
auto_params_test.go
File metadata and controls
296 lines (242 loc) · 9.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
package fiberoapi
import (
"encoding/json"
"testing"
"github.com/gofiber/fiber/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type AutoParamsTestInput struct {
UserID string `path:"userId" validate:"required"`
Name string `query:"name" validate:"required"`
Age int `query:"age" validate:"omitempty,min=0,max=120"`
Active bool `query:"active"`
Score float64 `query:"score"`
Optional string `query:"optional"`
}
type AutoParamsTestOutput struct {
UserID string `json:"userId"`
Name string `json:"name"`
Age int `json:"age"`
Active bool `json:"active"`
Score float64 `json:"score"`
Optional string `json:"optional"`
}
type AutoParamsTestError struct {
StatusCode int `json:"statusCode"`
Message string `json:"message"`
}
func TestAutoGeneratedParameters(t *testing.T) {
app := fiber.New()
oapi := New(app)
// Register an endpoint with auto-generated parameters
handler := func(c *fiber.Ctx, input AutoParamsTestInput) (AutoParamsTestOutput, AutoParamsTestError) {
return AutoParamsTestOutput(input), AutoParamsTestError{}
}
Get(oapi, "/users/:userId", handler, OpenAPIOptions{
OperationID: "getUserWithParams",
Summary: "Get user with auto-generated parameters",
})
// Generate OpenAPI spec
spec := oapi.GenerateOpenAPISpec()
// Convert to JSON for easier inspection
specJSON, err := json.MarshalIndent(spec, "", " ")
require.NoError(t, err)
t.Logf("Generated OpenAPI spec:\n%s", string(specJSON))
// Check that the spec contains paths
paths, ok := spec["paths"].(map[string]interface{})
require.True(t, ok, "Spec should contain paths")
// Check that our endpoint is present
userPath, ok := paths["/users/{userId}"].(map[string]interface{})
require.True(t, ok, "Should contain /users/{userId} path")
// Check GET operation
getOp, ok := userPath["get"].(map[string]interface{})
require.True(t, ok, "Should contain GET operation")
// Check parameters
parameters, ok := getOp["parameters"].([]map[string]interface{})
require.True(t, ok, "Should contain parameters")
// Should have 5 parameters: userId (path), name, age, active, score, optional (all query except userId)
assert.Len(t, parameters, 6, "Should have 6 parameters")
// Check each parameter
paramMap := make(map[string]map[string]interface{})
for _, param := range parameters {
if name, ok := param["name"].(string); ok {
paramMap[name] = param
}
}
// Check userId (path parameter)
userIdParam, exists := paramMap["userId"]
require.True(t, exists, "Should have userId parameter")
assert.Equal(t, "path", userIdParam["in"], "userId should be a path parameter")
assert.Equal(t, true, userIdParam["required"], "userId should be required")
// Check name (required query parameter)
nameParam, exists := paramMap["name"]
require.True(t, exists, "Should have name parameter")
assert.Equal(t, "query", nameParam["in"], "name should be a query parameter")
assert.Equal(t, true, nameParam["required"], "name should be required")
// Check age (optional query parameter)
ageParam, exists := paramMap["age"]
require.True(t, exists, "Should have age parameter")
assert.Equal(t, "query", ageParam["in"], "age should be a query parameter")
assert.Equal(t, false, ageParam["required"], "age should not be required")
// Check active (boolean query parameter)
activeParam, exists := paramMap["active"]
require.True(t, exists, "Should have active parameter")
assert.Equal(t, "query", activeParam["in"], "active should be a query parameter")
assert.Equal(t, false, activeParam["required"], "active should not be required")
// Check schema types
if schema, ok := nameParam["schema"].(map[string]interface{}); ok {
assert.Equal(t, "string", schema["type"], "name should be string type")
}
if schema, ok := ageParam["schema"].(map[string]interface{}); ok {
assert.Equal(t, "integer", schema["type"], "age should be integer type")
}
if schema, ok := activeParam["schema"].(map[string]interface{}); ok {
assert.Equal(t, "boolean", schema["type"], "active should be boolean type")
}
}
func TestMergeWithManualParameters(t *testing.T) {
app := fiber.New()
oapi := New(app)
type MergeTestInput struct {
UserID string `path:"userId" validate:"required"`
Name string `query:"name" validate:"required"`
Filter string `query:"filter"`
}
type MergeTestOutput struct {
UserID string `json:"userId"`
Name string `json:"name"`
Filter string `json:"filter"`
}
type MergeTestError struct {
StatusCode int `json:"statusCode"`
Message string `json:"message"`
}
handler := func(c *fiber.Ctx, input MergeTestInput) (MergeTestOutput, MergeTestError) {
return MergeTestOutput(input), MergeTestError{}
}
// Register with manual parameters that should override auto-generated ones
Get(oapi, "/users/:userId", handler, OpenAPIOptions{
OperationID: "getUserWithMergedParams",
Summary: "Get user with merged parameters",
Parameters: []map[string]interface{}{
{
"name": "name",
"in": "query",
"required": false, // Override the required from struct tag
"description": "Custom description for name parameter",
"schema": map[string]interface{}{
"type": "string",
"pattern": "^[a-zA-Z]+$", // Add custom validation
},
},
{
"name": "customParam",
"in": "query",
"required": false,
"description": "A completely manual parameter",
"schema": map[string]interface{}{
"type": "string",
},
},
},
})
spec := oapi.GenerateOpenAPISpec()
// Check parameters
paths := spec["paths"].(map[string]interface{})
userPath := paths["/users/{userId}"].(map[string]interface{})
getOp := userPath["get"].(map[string]interface{})
parameters := getOp["parameters"].([]map[string]interface{})
// Should have 4 parameters: userId (auto), name (manual override), filter (auto), customParam (manual)
assert.Len(t, parameters, 4, "Should have 4 parameters")
// Check that manual parameter overrides auto-generated one
paramMap := make(map[string]map[string]interface{})
for _, param := range parameters {
if name, ok := param["name"].(string); ok {
paramMap[name] = param
}
}
// Verify manual override
nameParam := paramMap["name"]
assert.Equal(t, false, nameParam["required"], "Manual parameter should override auto-generated required flag")
assert.Equal(t, "Custom description for name parameter", nameParam["description"], "Manual description should be used")
// Verify auto-generated parameters are still present
_, hasUserId := paramMap["userId"]
_, hasFilter := paramMap["filter"]
_, hasCustom := paramMap["customParam"]
assert.True(t, hasUserId, "Auto-generated userId should be present")
assert.True(t, hasFilter, "Auto-generated filter should be present")
assert.True(t, hasCustom, "Manual customParam should be present")
}
func TestNoParametersWhenNoStruct(t *testing.T) {
app := fiber.New()
oapi := New(app)
type SimpleOutput struct {
Message string `json:"message"`
}
type SimpleError struct {
StatusCode int `json:"statusCode"`
Message string `json:"message"`
}
// Register endpoint without input struct
Get(oapi, "/simple", func(c *fiber.Ctx, input struct{}) (SimpleOutput, SimpleError) {
return SimpleOutput{Message: "hello"}, SimpleError{}
}, OpenAPIOptions{
OperationID: "simpleEndpoint",
Summary: "Simple endpoint without parameters",
})
spec := oapi.GenerateOpenAPISpec()
paths := spec["paths"].(map[string]interface{})
simplePath := paths["/simple"].(map[string]interface{})
getOp := simplePath["get"].(map[string]interface{})
// Should not have parameters
_, hasParams := getOp["parameters"]
assert.False(t, hasParams, "Should not have parameters when no input struct")
}
func TestAutoParamsPointerTypesInline(t *testing.T) {
app := fiber.New()
oapi := New(app)
type PointerTestInput struct {
ID string `path:"id" validate:"required"`
OptionalName *string `query:"optionalName"`
RequiredName string `query:"requiredName" validate:"required"`
OmitEmpty string `query:"omitEmpty" validate:"omitempty"`
}
type PointerTestOutput struct {
Message string `json:"message"`
}
type PointerTestError struct {
Code int `json:"code"`
}
Get(oapi, "/pointer/:id", func(c *fiber.Ctx, input PointerTestInput) (PointerTestOutput, PointerTestError) {
return PointerTestOutput{Message: "ok"}, PointerTestError{}
}, OpenAPIOptions{
OperationID: "testPointerTypes",
Summary: "Test pointer types in parameters",
})
spec := oapi.GenerateOpenAPISpec()
paths := spec["paths"].(map[string]interface{})
pointerPath := paths["/pointer/{id}"].(map[string]interface{})
getOp := pointerPath["get"].(map[string]interface{})
parameters := getOp["parameters"].([]map[string]interface{})
// Should have 4 parameters
assert.Len(t, parameters, 4, "Should have 4 parameters")
paramMap := make(map[string]map[string]interface{})
for _, param := range parameters {
if name, ok := param["name"].(string); ok {
paramMap[name] = param
}
}
// Check pointer type is optional and nullable
optionalNameParam := paramMap["optionalName"]
assert.False(t, optionalNameParam["required"].(bool), "Pointer types should be optional by default")
if schema, ok := optionalNameParam["schema"].(map[string]interface{}); ok {
assert.True(t, schema["nullable"].(bool), "Pointer types should be nullable")
}
// Check required field
requiredNameParam := paramMap["requiredName"]
assert.True(t, requiredNameParam["required"].(bool), "Fields with validate:required should be required")
// Check omitempty field
omitEmptyParam := paramMap["omitEmpty"]
assert.False(t, omitEmptyParam["required"].(bool), "Fields with omitempty should be optional")
}