2025-08-16 20:20:31 +07:00

336 lines
8.4 KiB
Go

package base_test
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/base"
"github.com/go-playground/validator/v10"
"github.com/gofiber/fiber/v2"
"go.uber.org/zap/zaptest"
)
type testRequestBody struct {
Name string `json:"name" validate:"required"`
Age int `json:"age" validate:"required"`
}
type testRequestBodyNoValidate struct {
Name string `json:"name" validate:"required"`
Age int `json:"age" validate:"required"`
}
type testRequestQuery struct {
Name string `query:"name" validate:"required"`
Age int `query:"age" validate:"required"`
}
type testRequestParams struct {
ID string `params:"id" validate:"required"`
Name string `params:"name" validate:"required"`
}
func (t *testRequestBody) Validate() error {
if t.Age < 18 {
return fmt.Errorf("must be at least 18 years old")
}
return nil
}
func (t *testRequestQuery) Validate() error {
if t.Age < 18 {
return fmt.Errorf("must be at least 18 years old")
}
return nil
}
func (t *testRequestParams) Validate() error {
if t.ID == "invalid" {
return fmt.Errorf("invalid ID")
}
return nil
}
func TestHandler_BodyParserValidator(t *testing.T) {
logger := zaptest.NewLogger(t)
validate := validator.New()
handler := &base.Handler{
Logger: logger,
Validator: validate,
}
app := fiber.New()
app.Post("/test", func(c *fiber.Ctx) error {
var body testRequestBody
return handler.BodyParserValidator(c, &body)
})
app.Post("/test2", func(c *fiber.Ctx) error {
var body testRequestBodyNoValidate
return handler.BodyParserValidator(c, &body)
})
tests := []struct {
description string
path string
payload any
expectedStatus int
}{
{
description: "Valid request body",
path: "/test",
payload: &testRequestBody{Name: "John Doe", Age: 25},
expectedStatus: fiber.StatusOK,
},
{
description: "Invalid request body - missing name",
path: "/test",
payload: &testRequestBody{Age: 25},
expectedStatus: fiber.StatusBadRequest,
},
{
description: "Invalid request body - age too low",
path: "/test",
payload: &testRequestBody{Name: "John Doe", Age: 17},
expectedStatus: fiber.StatusBadRequest,
},
{
description: "Valid request body - no validation",
path: "/test2",
payload: &testRequestBodyNoValidate{Name: "John Doe", Age: 17},
expectedStatus: fiber.StatusOK,
},
{
description: "No request body",
path: "/test",
payload: nil,
expectedStatus: fiber.StatusBadRequest,
},
}
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
var req *http.Request
if test.payload != nil {
bodyBytes, _ := json.Marshal(test.payload)
req = httptest.NewRequest("POST", test.path, bytes.NewReader(bodyBytes))
req.Header.Set("Content-Type", "application/json")
} else {
req = httptest.NewRequest("POST", test.path, nil)
}
resp, err := app.Test(req)
if err != nil {
t.Fatalf("app.Test failed: %v", err)
}
if test.expectedStatus != resp.StatusCode {
t.Errorf("Expected status code %d, got %d", test.expectedStatus, resp.StatusCode)
}
})
}
}
func TestHandler_QueryParserValidator(t *testing.T) {
logger := zaptest.NewLogger(t)
validate := validator.New()
handler := &base.Handler{
Logger: logger,
Validator: validate,
}
app := fiber.New()
app.Get("/test", func(c *fiber.Ctx) error {
var query testRequestQuery
return handler.QueryParserValidator(c, &query)
})
tests := []struct {
description string
path string
expectedStatus int
}{
{
description: "Invalid query parameters - non-integer age",
path: "/test?name=John&age=abc",
expectedStatus: fiber.StatusBadRequest,
},
{
description: "Valid query parameters",
path: "/test?name=John&age=25",
expectedStatus: fiber.StatusOK,
},
{
description: "Invalid query parameters - missing name",
path: "/test?age=25",
expectedStatus: fiber.StatusBadRequest,
},
{
description: "Invalid query parameters - age too low",
path: "/test?name=John&age=17",
expectedStatus: fiber.StatusBadRequest,
},
{
description: "Invalid query parameters - missing age",
path: "/test?name=John",
expectedStatus: fiber.StatusBadRequest,
},
}
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
req := httptest.NewRequest("GET", test.path, nil)
resp, err := app.Test(req)
if err != nil {
t.Fatalf("app.Test failed: %v", err)
}
if test.expectedStatus != resp.StatusCode {
t.Errorf("Expected status code %d, got %d", test.expectedStatus, resp.StatusCode)
}
})
}
}
func TestHandler_ParamsParserValidator(t *testing.T) {
logger := zaptest.NewLogger(t)
validate := validator.New()
handler := &base.Handler{
Logger: logger,
Validator: validate,
}
app := fiber.New()
app.Get("/test/:id/:name", func(c *fiber.Ctx) error {
var params testRequestParams
return handler.ParamsParserValidator(c, &params)
})
tests := []struct {
description string
path string
expectedStatus int
}{
{
description: "Valid path parameters",
path: "/test/123/John",
expectedStatus: fiber.StatusOK,
},
{
description: "Invalid path parameters - missing id",
path: "/test//John",
expectedStatus: fiber.StatusNotFound,
},
{
description: "Invalid path parameters - missing name",
path: "/test/123/",
expectedStatus: fiber.StatusNotFound,
},
{
description: "Invalid path parameters - invalid ID",
path: "/test/invalid/John",
expectedStatus: fiber.StatusBadRequest,
},
}
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
req := httptest.NewRequest("GET", test.path, nil)
resp, err := app.Test(req)
if err != nil {
t.Fatalf("app.Test failed: %v", err)
}
if test.expectedStatus != resp.StatusCode {
t.Errorf("Expected status code %d, got %d", test.expectedStatus, resp.StatusCode)
}
})
}
}
func TestHandler_ValidateStruct(t *testing.T) {
logger := zaptest.NewLogger(t)
validate := validator.New()
// Test with validator
handlerWithValidator := &base.Handler{
Logger: logger,
Validator: validate,
}
// Test without validator
handlerWithoutValidator := &base.Handler{
Logger: logger,
Validator: nil,
}
tests := []struct {
description string
handler *base.Handler
input any
expectedStatus int
}{
{
description: "Valid struct with validator",
handler: handlerWithValidator,
input: &testRequestBody{Name: "John Doe", Age: 25},
expectedStatus: fiber.StatusOK,
},
{
description: "Invalid struct with validator - missing required field",
handler: handlerWithValidator,
input: &testRequestBody{Age: 25},
expectedStatus: fiber.StatusBadRequest,
},
{
description: "Invalid struct with validator - custom validation fails",
handler: handlerWithValidator,
input: &testRequestBody{Name: "John Doe", Age: 17},
expectedStatus: fiber.StatusBadRequest,
},
{
description: "Valid struct without validator",
handler: handlerWithoutValidator,
input: &testRequestBody{Name: "John Doe", Age: 25},
expectedStatus: fiber.StatusOK,
},
{
description: "Invalid struct without validator - custom validation fails",
handler: handlerWithoutValidator,
input: &testRequestBody{Name: "John Doe", Age: 17},
expectedStatus: fiber.StatusBadRequest,
},
{
description: "Valid struct with Validatable interface",
handler: handlerWithValidator,
input: &testRequestQuery{Name: "John", Age: 25},
expectedStatus: fiber.StatusOK,
},
{
description: "Invalid struct with Validatable interface",
handler: handlerWithValidator,
input: &testRequestQuery{Name: "John", Age: 17},
expectedStatus: fiber.StatusBadRequest,
},
}
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
err := test.handler.ValidateStruct(test.input)
if test.expectedStatus == fiber.StatusOK && err != nil {
t.Errorf("Expected no error, got %v", err)
}
if test.expectedStatus == fiber.StatusBadRequest && err == nil {
t.Errorf("Expected error, got nil")
}
})
}
}