Files
Crussell/backend/internal/validators/email_test.go
T

192 lines
4.6 KiB
Go

//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{
"<script>alert(1)</script>",
"<img src=x onerror=alert(1)>",
"\"><script>alert(1)</script>",
"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")
}
}