Files

183 lines
4.9 KiB
Go
Raw Permalink Normal View History

package validation
import (
"strconv"
"strings"
"testing"
"time"
)
func TestRuleOptional(t *testing.T) {
// Optional rule should always return nil
result := ruleOptional("field", "", "")
if result != nil {
t.Error("ruleOptional should always return nil")
}
result = ruleOptional("field", "value", "")
if result != nil {
t.Error("ruleOptional should always return nil")
}
}
func TestRuleTrim(t *testing.T) {
// Trim rule is a marker, should always return nil
result := ruleTrim("field", " value ", "")
if result != nil {
t.Error("ruleTrim should always return nil")
}
}
func TestRuleSanitize(t *testing.T) {
// Sanitize rule is a marker, should always return nil
result := ruleSanitize("field", "<script>alert('xss')</script>", "")
if result != nil {
t.Error("ruleSanitize should always return nil")
}
}
func TestRuleMin(t *testing.T) {
tests := []struct {
name string
field string
value string
param string
hasError bool
}{
{"Valid - meets minimum", "msg", "hello", "5", false},
{"Valid - exceeds minimum", "msg", "hello world", "5", false},
{"Invalid - too short", "msg", "hi", "5", true},
{"Invalid - empty", "msg", "", "1", true},
{"Invalid param", "msg", "hello", "invalid", true},
{"UTF-8 aware - valid", "name", "José", "4", false},
{"UTF-8 aware - valid", "name", "日本語", "3", false},
{"UTF-8 aware - invalid", "name", "日", "3", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := ruleMin(tt.field, tt.value, tt.param)
if (result != nil) != tt.hasError {
t.Errorf("ruleMin(%q, %q, %q) error = %v, wantError %v", tt.field, tt.value, tt.param, result != nil, tt.hasError)
}
})
}
}
func TestRuleTiming(t *testing.T) {
now := time.Now().Unix()
tests := []struct {
name string
value string
param string
hasError bool
}{
{"Empty value", "", "2:86400", false},
{"Valid timing", strconv.FormatInt(now-10, 10), "2:86400", false},
{"Too quick", strconv.FormatInt(now-1, 10), "2:86400", true},
{"Too old", strconv.FormatInt(now-100000, 10), "2:86400", true},
{"Invalid param format", strconv.FormatInt(now-10, 10), "invalid", true},
{"Invalid min param", strconv.FormatInt(now-10, 10), "abc:100", true},
{"Invalid max param", strconv.FormatInt(now-10, 10), "2:xyz", true},
{"Invalid timestamp", "not_a_number", "2:86400", true},
{"Future timestamp", strconv.FormatInt(now+1000, 10), "2:86400", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := ruleTiming("timestamp", tt.value, tt.param)
if (result != nil) != tt.hasError {
t.Errorf("ruleTiming(%q, %q) error = %v, wantError %v", tt.value, tt.param, result != nil, tt.hasError)
}
})
}
}
func TestFieldError_Error(t *testing.T) {
t.Run("With param", func(t *testing.T) {
err := FieldError{
Field: "email",
Tag: "max",
Param: "100",
Message: "too long",
}
errStr := err.Error()
if !strings.Contains(errStr, "email") {
t.Error("Error should contain field name")
}
if !strings.Contains(errStr, "max=100") {
t.Error("Error should contain tag=param")
}
})
t.Run("Without param", func(t *testing.T) {
err := FieldError{
Field: "email",
Tag: "required",
Message: "is required",
}
errStr := err.Error()
if !strings.Contains(errStr, "email") {
t.Error("Error should contain field name")
}
if strings.Contains(errStr, "(") {
t.Error("Error without param should not contain parentheses")
}
})
}
func TestValidationErrors_HasErrors(t *testing.T) {
t.Run("No errors", func(t *testing.T) {
var ve ValidationErrors
if ve.HasErrors() {
t.Error("HasErrors should return false for empty errors")
}
})
t.Run("Has errors", func(t *testing.T) {
ve := ValidationErrors{
{Field: "email", Message: "required"},
}
if !ve.HasErrors() {
t.Error("HasErrors should return true when errors exist")
}
})
}
func TestValidationErrors_GetFieldErrors(t *testing.T) {
ve := ValidationErrors{
{Field: "email", Tag: "required", Message: "required"},
{Field: "email", Tag: "email", Message: "invalid format"},
{Field: "name", Tag: "required", Message: "required"},
}
t.Run("Get multiple errors for field", func(t *testing.T) {
errors := ve.GetFieldErrors("email")
if len(errors) != 2 {
t.Errorf("GetFieldErrors(email) returned %d errors, want 2", len(errors))
}
})
t.Run("Get single error for field", func(t *testing.T) {
errors := ve.GetFieldErrors("name")
if len(errors) != 1 {
t.Errorf("GetFieldErrors(name) returned %d errors, want 1", len(errors))
}
})
t.Run("No errors for field", func(t *testing.T) {
errors := ve.GetFieldErrors("nonexistent")
if len(errors) != 0 {
t.Errorf("GetFieldErrors(nonexistent) returned %d errors, want 0", len(errors))
}
})
}
func TestValidationErrors_Error_Empty(t *testing.T) {
var ve ValidationErrors
if ve.Error() != "" {
t.Error("Error() should return empty string for no errors")
}
}