Skip to content

Commit c8487cc

Browse files
committed
[handlers] use Validate.Var for slice validation
1 parent 9f8925c commit c8487cc

File tree

3 files changed

+197
-60
lines changed

3 files changed

+197
-60
lines changed

internal/sms-gateway/handlers/base/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func (h *Handler) ParamsParserValidator(c *fiber.Ctx, out any) error {
4343

4444
func (h *Handler) ValidateStruct(out any) error {
4545
if h.Validator != nil {
46-
if err := h.Validator.Struct(out); err != nil {
46+
if err := h.Validator.Var(out, "required,dive"); err != nil {
4747
return fiber.NewError(fiber.StatusBadRequest, err.Error())
4848
}
4949
}

internal/sms-gateway/handlers/base/handler_test.go

Lines changed: 195 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/base"
1212
"github.com/go-playground/validator/v10"
1313
"github.com/gofiber/fiber/v2"
14-
"go.uber.org/zap"
1514
"go.uber.org/zap/zaptest"
1615
)
1716

@@ -25,13 +24,37 @@ type testRequestBodyNoValidate struct {
2524
Age int `json:"age" validate:"required"`
2625
}
2726

27+
type testRequestQuery struct {
28+
Name string `query:"name" validate:"required"`
29+
Age int `query:"age" validate:"required"`
30+
}
31+
32+
type testRequestParams struct {
33+
ID string `params:"id" validate:"required"`
34+
Name string `params:"name" validate:"required"`
35+
}
36+
2837
func (t *testRequestBody) Validate() error {
2938
if t.Age < 18 {
3039
return fmt.Errorf("must be at least 18 years old")
3140
}
3241
return nil
3342
}
3443

44+
func (t *testRequestQuery) Validate() error {
45+
if t.Age < 18 {
46+
return fmt.Errorf("must be at least 18 years old")
47+
}
48+
return nil
49+
}
50+
51+
func (t *testRequestParams) Validate() error {
52+
if t.ID == "invalid" {
53+
return fmt.Errorf("invalid ID")
54+
}
55+
return nil
56+
}
57+
3558
func TestHandler_BodyParserValidator(t *testing.T) {
3659
logger := zaptest.NewLogger(t)
3760
validate := validator.New()
@@ -100,7 +123,10 @@ func TestHandler_BodyParserValidator(t *testing.T) {
100123
req = httptest.NewRequest("POST", test.path, nil)
101124
}
102125

103-
resp, _ := app.Test(req)
126+
resp, err := app.Test(req)
127+
if err != nil {
128+
t.Fatalf("app.Test failed: %v", err)
129+
}
104130
if test.expectedStatus != resp.StatusCode {
105131
t.Errorf("Expected status code %d, got %d", test.expectedStatus, resp.StatusCode)
106132
}
@@ -109,89 +135,200 @@ func TestHandler_BodyParserValidator(t *testing.T) {
109135
}
110136

111137
func TestHandler_QueryParserValidator(t *testing.T) {
112-
type fields struct {
113-
Logger *zap.Logger
114-
Validator *validator.Validate
115-
}
116-
type args struct {
117-
c *fiber.Ctx
118-
out any
138+
logger := zaptest.NewLogger(t)
139+
validate := validator.New()
140+
141+
handler := &base.Handler{
142+
Logger: logger,
143+
Validator: validate,
119144
}
145+
146+
app := fiber.New()
147+
app.Get("/test", func(c *fiber.Ctx) error {
148+
var query testRequestQuery
149+
return handler.QueryParserValidator(c, &query)
150+
})
151+
120152
tests := []struct {
121-
name string
122-
fields fields
123-
args args
124-
wantErr bool
153+
description string
154+
path string
155+
expectedStatus int
125156
}{
126-
// TODO: Add test cases.
157+
{
158+
description: "Invalid query parameters - non-integer age",
159+
path: "/test?name=John&age=abc",
160+
expectedStatus: fiber.StatusBadRequest,
161+
},
162+
{
163+
description: "Valid query parameters",
164+
path: "/test?name=John&age=25",
165+
expectedStatus: fiber.StatusOK,
166+
},
167+
{
168+
description: "Invalid query parameters - missing name",
169+
path: "/test?age=25",
170+
expectedStatus: fiber.StatusBadRequest,
171+
},
172+
{
173+
description: "Invalid query parameters - age too low",
174+
path: "/test?name=John&age=17",
175+
expectedStatus: fiber.StatusBadRequest,
176+
},
177+
{
178+
description: "Invalid query parameters - missing age",
179+
path: "/test?name=John",
180+
expectedStatus: fiber.StatusBadRequest,
181+
},
127182
}
128-
for _, tt := range tests {
129-
t.Run(tt.name, func(t *testing.T) {
130-
h := &base.Handler{
131-
Logger: tt.fields.Logger,
132-
Validator: tt.fields.Validator,
183+
184+
for _, test := range tests {
185+
t.Run(test.description, func(t *testing.T) {
186+
req := httptest.NewRequest("GET", test.path, nil)
187+
188+
resp, err := app.Test(req)
189+
if err != nil {
190+
t.Fatalf("app.Test failed: %v", err)
133191
}
134-
if err := h.QueryParserValidator(tt.args.c, tt.args.out); (err != nil) != tt.wantErr {
135-
t.Errorf("Handler.QueryParserValidator() error = %v, wantErr %v", err, tt.wantErr)
192+
if test.expectedStatus != resp.StatusCode {
193+
t.Errorf("Expected status code %d, got %d", test.expectedStatus, resp.StatusCode)
136194
}
137195
})
138196
}
139197
}
140198

141199
func TestHandler_ParamsParserValidator(t *testing.T) {
142-
type fields struct {
143-
Logger *zap.Logger
144-
Validator *validator.Validate
145-
}
146-
type args struct {
147-
c *fiber.Ctx
148-
out any
200+
logger := zaptest.NewLogger(t)
201+
validate := validator.New()
202+
203+
handler := &base.Handler{
204+
Logger: logger,
205+
Validator: validate,
149206
}
207+
208+
app := fiber.New()
209+
app.Get("/test/:id/:name", func(c *fiber.Ctx) error {
210+
var params testRequestParams
211+
return handler.ParamsParserValidator(c, &params)
212+
})
213+
150214
tests := []struct {
151-
name string
152-
fields fields
153-
args args
154-
wantErr bool
215+
description string
216+
path string
217+
expectedStatus int
155218
}{
156-
// TODO: Add test cases.
219+
{
220+
description: "Valid path parameters",
221+
path: "/test/123/John",
222+
expectedStatus: fiber.StatusOK,
223+
},
224+
{
225+
description: "Invalid path parameters - missing id",
226+
path: "/test//John",
227+
expectedStatus: fiber.StatusNotFound,
228+
},
229+
{
230+
description: "Invalid path parameters - missing name",
231+
path: "/test/123/",
232+
expectedStatus: fiber.StatusNotFound,
233+
},
234+
{
235+
description: "Invalid path parameters - invalid ID",
236+
path: "/test/invalid/John",
237+
expectedStatus: fiber.StatusBadRequest,
238+
},
157239
}
158-
for _, tt := range tests {
159-
t.Run(tt.name, func(t *testing.T) {
160-
h := &base.Handler{
161-
Logger: tt.fields.Logger,
162-
Validator: tt.fields.Validator,
240+
241+
for _, test := range tests {
242+
t.Run(test.description, func(t *testing.T) {
243+
req := httptest.NewRequest("GET", test.path, nil)
244+
245+
resp, err := app.Test(req)
246+
if err != nil {
247+
t.Fatalf("app.Test failed: %v", err)
163248
}
164-
if err := h.ParamsParserValidator(tt.args.c, tt.args.out); (err != nil) != tt.wantErr {
165-
t.Errorf("Handler.ParamsParserValidator() error = %v, wantErr %v", err, tt.wantErr)
249+
if test.expectedStatus != resp.StatusCode {
250+
t.Errorf("Expected status code %d, got %d", test.expectedStatus, resp.StatusCode)
166251
}
167252
})
168253
}
169254
}
170255

171-
func TestHandler_validateStruct(t *testing.T) {
172-
type fields struct {
173-
Logger *zap.Logger
174-
Validator *validator.Validate
256+
func TestHandler_ValidateStruct(t *testing.T) {
257+
logger := zaptest.NewLogger(t)
258+
validate := validator.New()
259+
260+
// Test with validator
261+
handlerWithValidator := &base.Handler{
262+
Logger: logger,
263+
Validator: validate,
175264
}
176-
type args struct {
177-
out any
265+
266+
// Test without validator
267+
handlerWithoutValidator := &base.Handler{
268+
Logger: logger,
269+
Validator: nil,
178270
}
271+
179272
tests := []struct {
180-
name string
181-
fields fields
182-
args args
183-
wantErr bool
273+
description string
274+
handler *base.Handler
275+
input any
276+
expectedStatus int
184277
}{
185-
// TODO: Add test cases.
278+
{
279+
description: "Valid struct with validator",
280+
handler: handlerWithValidator,
281+
input: &testRequestBody{Name: "John Doe", Age: 25},
282+
expectedStatus: fiber.StatusOK,
283+
},
284+
{
285+
description: "Invalid struct with validator - missing required field",
286+
handler: handlerWithValidator,
287+
input: &testRequestBody{Age: 25},
288+
expectedStatus: fiber.StatusBadRequest,
289+
},
290+
{
291+
description: "Invalid struct with validator - custom validation fails",
292+
handler: handlerWithValidator,
293+
input: &testRequestBody{Name: "John Doe", Age: 17},
294+
expectedStatus: fiber.StatusBadRequest,
295+
},
296+
{
297+
description: "Valid struct without validator",
298+
handler: handlerWithoutValidator,
299+
input: &testRequestBody{Name: "John Doe", Age: 25},
300+
expectedStatus: fiber.StatusOK,
301+
},
302+
{
303+
description: "Invalid struct without validator - custom validation fails",
304+
handler: handlerWithoutValidator,
305+
input: &testRequestBody{Name: "John Doe", Age: 17},
306+
expectedStatus: fiber.StatusBadRequest,
307+
},
308+
{
309+
description: "Valid struct with Validatable interface",
310+
handler: handlerWithValidator,
311+
input: &testRequestQuery{Name: "John", Age: 25},
312+
expectedStatus: fiber.StatusOK,
313+
},
314+
{
315+
description: "Invalid struct with Validatable interface",
316+
handler: handlerWithValidator,
317+
input: &testRequestQuery{Name: "John", Age: 17},
318+
expectedStatus: fiber.StatusBadRequest,
319+
},
186320
}
187-
for _, tt := range tests {
188-
t.Run(tt.name, func(t *testing.T) {
189-
h := &base.Handler{
190-
Logger: tt.fields.Logger,
191-
Validator: tt.fields.Validator,
321+
322+
for _, test := range tests {
323+
t.Run(test.description, func(t *testing.T) {
324+
err := test.handler.ValidateStruct(test.input)
325+
326+
if test.expectedStatus == fiber.StatusOK && err != nil {
327+
t.Errorf("Expected no error, got %v", err)
192328
}
193-
if err := h.ValidateStruct(tt.args.out); (err != nil) != tt.wantErr {
194-
t.Errorf("Handler.validateStruct() error = %v, wantErr %v", err, tt.wantErr)
329+
330+
if test.expectedStatus == fiber.StatusBadRequest && err == nil {
331+
t.Errorf("Expected error, got nil")
195332
}
196333
})
197334
}

internal/sms-gateway/handlers/messages/mobile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func (h *MobileController) list(device models.Device, c *fiber.Ctx) error {
8181
//
8282
// Update message state
8383
func (h *MobileController) patch(device models.Device, c *fiber.Ctx) error {
84-
var req smsgateway.MobilePatchMessageRequest
84+
req := smsgateway.MobilePatchMessageRequest{}
8585
if err := h.BodyParserValidator(c, &req); err != nil {
8686
return fiber.NewError(fiber.StatusBadRequest, err.Error())
8787
}

0 commit comments

Comments
 (0)