package engine import ( "image/color" "testing" ) func TestParseHexColorToRGBA(t *testing.T) { tests := []struct { name string input string expected color.RGBA hasError bool }{ // Valid cases {"RGB short form", "#000", color.RGBA{0, 0, 0, 255}, false}, {"RGB short form white", "#fff", color.RGBA{255, 255, 255, 255}, false}, {"RGB short form mixed", "#f0a", color.RGBA{255, 0, 170, 255}, false}, {"RGBA short form", "#f0a8", color.RGBA{255, 0, 170, 136}, false}, {"RRGGBB full form", "#000000", color.RGBA{0, 0, 0, 255}, false}, {"RRGGBB full form white", "#ffffff", color.RGBA{255, 255, 255, 255}, false}, {"RRGGBB full form mixed", "#ff00aa", color.RGBA{255, 0, 170, 255}, false}, {"RRGGBBAA full form", "#ff00aa80", color.RGBA{255, 0, 170, 128}, false}, {"RRGGBBAA full form transparent", "#ff00aa00", color.RGBA{255, 0, 170, 0}, false}, {"RRGGBBAA full form opaque", "#ff00aaff", color.RGBA{255, 0, 170, 255}, false}, // Invalid cases {"Empty string", "", color.RGBA{}, true}, {"No hash prefix", "ffffff", color.RGBA{}, true}, {"Invalid length", "#12", color.RGBA{}, true}, {"Invalid length", "#12345", color.RGBA{}, true}, {"Invalid length", "#1234567", color.RGBA{}, true}, {"Invalid hex character", "#gggggg", color.RGBA{}, true}, {"Invalid hex character short", "#ggg", color.RGBA{}, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result, err := ParseHexColorToRGBA(tt.input) if tt.hasError { if err == nil { t.Errorf("ParseHexColorToRGBA(%q) expected error, got nil", tt.input) } return } if err != nil { t.Errorf("ParseHexColorToRGBA(%q) unexpected error: %v", tt.input, err) return } if result != tt.expected { t.Errorf("ParseHexColorToRGBA(%q) = %+v, expected %+v", tt.input, result, tt.expected) } }) } } func TestValidateHexColor(t *testing.T) { tests := []struct { name string input string hasError bool }{ // Valid cases {"RGB short", "#000", false}, {"RGB short uppercase", "#FFF", false}, {"RGB short mixed case", "#f0A", false}, {"RGBA short", "#f0a8", false}, {"RRGGBB", "#000000", false}, {"RRGGBB uppercase", "#FFFFFF", false}, {"RRGGBB mixed case", "#Ff00Aa", false}, {"RRGGBBAA", "#ff00aa80", false}, {"RRGGBBAA uppercase", "#FF00AA80", false}, // Invalid cases {"Empty string", "", true}, {"No hash", "ffffff", true}, {"Too short", "#12", true}, {"Invalid length", "#12345", true}, {"Too long", "#123456789", true}, {"Invalid character", "#gggggg", true}, {"Invalid character short", "#ggg", true}, {"Space", "#fff fff", true}, {"Special character", "#fff@ff", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := ValidateHexColor(tt.input) if tt.hasError && err == nil { t.Errorf("ValidateHexColor(%q) expected error, got nil", tt.input) } else if !tt.hasError && err != nil { t.Errorf("ValidateHexColor(%q) unexpected error: %v", tt.input, err) } }) } } func TestParseHexColorToEngine(t *testing.T) { tests := []struct { name string input string expected Color hasError bool }{ {"RGB short", "#000", NewColorRGBA(0, 0, 0, 255), false}, {"RGB short white", "#fff", NewColorRGBA(255, 255, 255, 255), false}, {"RRGGBB", "#ff00aa", NewColorRGBA(255, 0, 170, 255), false}, {"RRGGBBAA", "#ff00aa80", NewColorRGBA(255, 0, 170, 128), false}, {"Invalid", "#invalid", Color{}, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result, err := ParseHexColorToEngine(tt.input) if tt.hasError { if err == nil { t.Errorf("ParseHexColorToEngine(%q) expected error, got nil", tt.input) } return } if err != nil { t.Errorf("ParseHexColorToEngine(%q) unexpected error: %v", tt.input, err) return } resultR, resultG, resultB, err1 := result.ToRGB() if err1 != nil { t.Fatalf("result.ToRGB failed: %v", err1) } expectedR, expectedG, expectedB, err2 := tt.expected.ToRGB() if err2 != nil { t.Fatalf("expected.ToRGB failed: %v", err2) } if resultR != expectedR || resultG != expectedG || resultB != expectedB || result.A != tt.expected.A { t.Errorf("ParseHexColorToEngine(%q) = R:%d G:%d B:%d A:%d, expected R:%d G:%d B:%d A:%d", tt.input, resultR, resultG, resultB, result.A, expectedR, expectedG, expectedB, tt.expected.A) } }) } } func TestParseHexColorForRenderer(t *testing.T) { tests := []struct { name string input string opacity float64 expected color.RGBA hasError bool }{ {"RGB with opacity 1.0", "#ff0000", 1.0, color.RGBA{255, 0, 0, 255}, false}, {"RGB with opacity 0.5", "#ff0000", 0.5, color.RGBA{255, 0, 0, 127}, false}, {"RGB with opacity 0.0", "#ff0000", 0.0, color.RGBA{255, 0, 0, 0}, false}, {"RGBA with opacity 1.0", "#ff000080", 1.0, color.RGBA{255, 0, 0, 128}, false}, {"RGBA with opacity 0.5", "#ff000080", 0.5, color.RGBA{255, 0, 0, 64}, false}, {"Invalid color", "#invalid", 1.0, color.RGBA{}, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result, err := ParseHexColorForRenderer(tt.input, tt.opacity) if tt.hasError { if err == nil { t.Errorf("ParseHexColorForRenderer(%q, %f) expected error, got nil", tt.input, tt.opacity) } return } if err != nil { t.Errorf("ParseHexColorForRenderer(%q, %f) unexpected error: %v", tt.input, tt.opacity, err) return } if result != tt.expected { t.Errorf("ParseHexColorForRenderer(%q, %f) = %+v, expected %+v", tt.input, tt.opacity, result, tt.expected) } }) } } func TestHexToByte(t *testing.T) { tests := []struct { name string input string expected uint8 hasError bool }{ {"Zero", "00", 0, false}, {"Max", "ff", 255, false}, {"Max uppercase", "FF", 255, false}, {"Mixed case", "Ff", 255, false}, {"Middle value", "80", 128, false}, {"Small value", "0a", 10, false}, {"Invalid length short", "f", 0, true}, {"Invalid length long", "fff", 0, true}, {"Invalid character", "gg", 0, true}, {"Empty string", "", 0, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result, err := hexToByte(tt.input) if tt.hasError { if err == nil { t.Errorf("hexToByte(%q) expected error, got nil", tt.input) } return } if err != nil { t.Errorf("hexToByte(%q) unexpected error: %v", tt.input, err) return } if result != tt.expected { t.Errorf("hexToByte(%q) = %d, expected %d", tt.input, result, tt.expected) } }) } }