template-monorepo/internal/library/validate/validate_test.go

113 lines
3.0 KiB
Go

package validate
import (
"errors"
"fmt"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
)
// Test struct for validation scenarios
type User struct {
Username string `json:"username" validate:"required,min=4"`
Email string `json:"email" validate:"required,email"`
Bio string `json:"bio" validate:"is-awesome"`
}
// Custom validation function: must be "awesome"
func IsAwesomeValidator(fl validator.FieldLevel) bool {
return fl.Field().String() == "awesome"
}
func TestValidateAll_Success(t *testing.T) {
// A custom option for the "is-awesome" tag
awesomeOption := Option{
ValidatorName: "is-awesome",
ValidatorFunc: IsAwesomeValidator,
}
v, err := NewWithDefaultEN(awesomeOption)
require.NoError(t, err)
user := User{
Username: "tester",
Email: "test@example.com",
Bio: "awesome",
}
err = v.ValidateAll(user)
assert.NoError(t, err)
}
func TestValidateAll_DefaultTranslationFailure(t *testing.T) {
v, err := NewWithDefaultEN()
require.NoError(t, err)
user := struct {
Name string `json:"name" validate:"required"`
Email string `json:"email_address" validate:"email"`
}{
Name: "",
Email: "not-an-email",
}
err = v.ValidateAll(user)
require.Error(t, err)
var validationErrs ValidationErrors
require.True(t, errors.As(err, &validationErrs), "Error should be of type ValidationErrors")
require.Len(t, validationErrs, 2)
// Check errors (order might vary)
errMap := make(map[string]string)
for _, ve := range validationErrs {
errMap[ve.Field] = ve.Message
}
assert.Equal(t, "name is a required field", errMap["name"])
assert.Equal(t, "email_address must be a valid email address", errMap["email_address"])
}
func TestValidateAll_CustomValidationWithTranslation(t *testing.T) {
// A custom option for a "status" validator with translation
statusOption := Option{
ValidatorName: "status",
ValidatorFunc: func(fl validator.FieldLevel) bool {
status := fl.Field().String()
return status == "active" || status == "inactive"
},
// Function to register the translation
RegisterTranslationFunc: func(ut ut.Translator) error {
return ut.Add("status", "{0} must be 'active' or 'inactive'", true)
},
// Function that defines how the translation message is generated
TranslationFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T("status", fe.Field())
return t
},
}
v, err := NewWithDefaultEN(statusOption)
require.NoError(t, err)
payload := struct {
Status string `json:"user_status" validate:"status"`
}{
Status: "pending",
}
err = v.ValidateAll(payload)
require.Error(t, err)
var validationErrs ValidationErrors
require.True(t, errors.As(err, &validationErrs))
require.Len(t, validationErrs, 1)
assert.Equal(t, "user_status", validationErrs[0].Field)
assert.Equal(t, "user_status must be 'active' or 'inactive'", validationErrs[0].Message)
fmt.Println(validationErrs.Error()) // For visual confirmation
}