//go:build test // +build test package validators import ( "testing" ) func TestValidateEmail_Valid(t *testing.T) { valid := []string{ "user@example.com", "user.name+tag@example.co.uk", "a@b.cd", "test@sub.example.org", "123@example.com", } for _, e := range valid { if err := ValidateEmail(e); err != nil { t.Errorf("expected valid email %q, got error: %v", e, err) } } } func TestValidateEmail_Invalid(t *testing.T) { invalid := []string{ "", "not-an-email", "@example.com", "user@", "user@.com", "user@example", "a@b.c", // TLD too short } for _, e := range invalid { if err := ValidateEmail(e); err == nil { t.Errorf("expected invalid email %q to return error", e) } } } func TestValidateEmail_TooLong(t *testing.T) { long := string(make([]byte, 255)) if err := ValidateEmail(long); err == nil { t.Error("expected error for email exceeding 254 chars") } } func TestValidateEmail_WhitespaceTrimmed(t *testing.T) { // ValidateEmail trims whitespace, so leading/trailing spaces are acceptable. if err := ValidateEmail(" user@example.com "); err != nil { t.Errorf("expected valid after trimming whitespace, got: %v", err) } } func TestNormalizeGiftCardCode_StripsNonAlphanumeric(t *testing.T) { result := NormalizeGiftCardCode("abc-123_xyz!@#") if result != "abc123xyz" { t.Errorf("expected abc123xyz, got %s", result) } } func TestNormalizeGiftCardCode_PreservesCase(t *testing.T) { result := NormalizeGiftCardCode("aBcDeF123456") if result != "aBcDeF123456" { t.Errorf("expected aBcDeF123456, got %s", result) } } func TestNormalizeGiftCardCode_Empty(t *testing.T) { result := NormalizeGiftCardCode("") if result != "" { t.Errorf("expected empty string, got %s", result) } } func TestNormalizeGiftCardCode_AlreadyClean(t *testing.T) { result := NormalizeGiftCardCode("ABCDEF123456") if result != "ABCDEF123456" { t.Errorf("expected ABCDEF123456, got %s", result) } } func TestValidateEmail_RejectsSQLInjection(t *testing.T) { payloads := []string{ "' OR '1'='1", "admin'--", "'; DROP TABLE users;--", `" OR 1=1 --`, "' OR '1'='1' --", "1' OR '1'='1", "' UNION SELECT * FROM users --", "admin'/*", } for _, p := range payloads { if err := ValidateEmail(p); err == nil { t.Errorf("expected SQLi payload %q to be rejected", p) } } } func TestValidateEmail_RejectsXSS(t *testing.T) { payloads := []string{ "", "", "\">", "javascript:alert(1)", } for _, p := range payloads { if err := ValidateEmail(p); err == nil { t.Errorf("expected XSS payload %q to be rejected", p) } } } func TestValidateEmail_RejectsCommandInjection(t *testing.T) { payloads := []string{ "; rm -rf /", "| cat /etc/passwd", "`id`", "$(cat /etc/passwd)", } for _, p := range payloads { if err := ValidateEmail(p); err == nil { t.Errorf("expected command injection payload %q to be rejected", p) } } } func TestValidateEmail_RejectsControlChars(t *testing.T) { payloads := []string{ "user@example.com\nX-Injected: header", "user@example.com\r\nX-Injected: header", "user\x00@example.com", "user@ex\tample.com", } for _, p := range payloads { if err := ValidateEmail(p); err == nil { t.Errorf("expected control char payload %q to be rejected", p) } } } func TestValidateEmail_ValidMailsAreSafe(t *testing.T) { // These are perfectly valid emails that happen to contain // characters used in injection attacks — verify they pass. valid := []string{ "safe.sql+select@example.com", "safe.xss+script@example.co.uk", "drop+table@example.org", } for _, e := range valid { if err := ValidateEmail(e); err != nil { t.Errorf("expected safe email %q to be valid, got: %v", e, err) } } } func TestParseCursor_Valid(t *testing.T) { tm, id, err := ParseCursor("2026-06-15T10:30:00Z|abc123def456") if err != nil { t.Fatalf("unexpected error: %v", err) } if tm.Year() != 2026 || tm.Month() != 6 || tm.Day() != 15 { t.Errorf("unexpected time: %v", tm) } if id != "abc123def456" { t.Errorf("expected id 'abc123def456', got %q", id) } } func TestParseCursor_InvalidFormat(t *testing.T) { _, _, err := ParseCursor("not-a-valid-cursor") if err == nil { t.Fatal("expected error for invalid cursor format, got nil") } } func TestParseCursor_InvalidTimestamp(t *testing.T) { _, _, err := ParseCursor("not-a-time|abc123def456") if err == nil { t.Fatal("expected error for invalid timestamp, got nil") } } func TestParseCursor_EmptyCursor(t *testing.T) { _, _, err := ParseCursor("") if err == nil { t.Fatal("expected error for empty cursor, got nil") } }