package web import ( "testing" ) // TestValidateConfigValue tests config value validation func TestValidateConfigValue(t *testing.T) { tests := []struct { name string key string value string wantError bool errorMsg string }{ // Valid hwdec values {"Valid HWA - auto", "hwdec", "auto", false, ""}, {"Valid HWA - auto-safe", "hwdec", "auto-safe", false, ""}, {"Valid HWA - nvdec", "hwdec", "nvdec", false, ""}, {"Valid HWA - nvdec-copy", "hwdec", "nvdec-copy", false, ""}, {"Valid HWA - vaapi", "hwdec", "vaapi", false, ""}, {"Valid HWA - vaapi-copy", "hwdec", "vaapi-copy", false, ""}, {"Valid HWA - vulkan", "hwdec", "vulkan", false, ""}, {"Valid HWA - vulkan-copy", "hwdec", "vulkan-copy", false, ""}, {"Valid HWA - d3d11va", "hwdec", "d3d11va", false, ""}, {"Valid HWA - d3d11va-copy", "hwdec", "d3d11va-copy", false, ""}, {"Valid HWA - videotoolbox", "hwdec", "videotoolbox", false, ""}, {"Valid HWA - videotoolbox-copy", "hwdec", "videotoolbox-copy", false, ""}, {"Valid HWA - drm", "hwdec", "drm", false, ""}, {"Valid HWA - drm-copy", "hwdec", "drm-copy", false, ""}, {"Valid HWA - no", "hwdec", "no", false, ""}, // Invalid hwdec values {"Invalid HWA - invalid method", "hwdec", "invalid", true, "invalid value 'invalid' for key 'hwdec'"}, {"Invalid HWA - typo", "hwdec", "vdau", true, "invalid value 'vdau' for key 'hwdec'"}, // Valid vo values {"Valid VO - gpu", "vo", "gpu", false, ""}, {"Valid VO - vdpau", "vo", "vdpau", false, ""}, {"Valid VO - xv", "vo", "xv", false, ""}, // Invalid vo values {"Invalid VO - special chars", "vo", "gpu$invalid", true, "invalid value"}, // Valid scale values {"Valid scale - bilinear", "scale", "bilinear", false, ""}, {"Valid scale - lanczos", "scale", "lanczos", false, ""}, // Invalid scale values {"Invalid scale - special chars", "scale", "scale$invalid", true, "invalid value"}, // Valid dither values {"Valid dither - no", "dither-depth-convert", "no", false, ""}, {"Valid dither - ordered", "dither-depth-convert", "ordered", false, ""}, {"Valid dither - error-diffusion", "dither-depth-convert", "error-diffusion", false, ""}, {"Valid dither - floyd-steinberg", "dither-depth-convert", "floyd-steinberg", false, ""}, // Invalid dither values {"Invalid dither - invalid", "dither-depth-convert", "invalid", true, "invalid value"}, // Invalid keys {"Invalid key", "invalid_key", "value", true, "invalid config key: invalid_key"}, {"Invalid key - hwdec typo", "hwde", "auto", true, "invalid config key: hwde"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := ValidateConfigValue(tt.key, tt.value) if (err != nil) != tt.wantError { t.Errorf("ValidateConfigValue() error = %v, wantError %v", err, tt.wantError) return } if tt.wantError && err != nil { if !contains(err.Error(), tt.errorMsg) { t.Errorf("ValidateConfigValue() error = %v, expected substring %v", err.Error(), tt.errorMsg) } } }) } } // TestValidateMethodID tests method ID validation func TestValidateMethodID(t *testing.T) { tests := []struct { name string methodID string wantError bool errorMsg string }{ // Valid method IDs {"Valid method - mpv-binary", "mpv-binary", false, ""}, {"Valid method - mpv-binary-v3", "mpv-binary-v3", false, ""}, {"Valid method - mpc-qt", "mpc-qt", false, ""}, {"Valid method - mpv-app", "mpv-app", false, ""}, {"Valid method - mpv-brew", "mpv-brew", false, ""}, {"Valid method - iina", "iina", false, ""}, {"Valid method - mpv-flatpak", "mpv-flatpak", false, ""}, {"Valid method - celluloid-flatpak", "celluloid-flatpak", false, ""}, {"Valid method - mpv-package", "mpv-package", false, ""}, {"Valid method - celluloid-package", "celluloid-package", false, ""}, // Invalid method IDs {"Invalid method - empty", "", true, "invalid method ID"}, {"Invalid method - typo", "mpv-inary", true, "invalid method ID"}, {"Invalid method - case sensitive", "MPV-BINARY", true, "invalid method ID"}, {"Invalid method - special chars", "mpv-binary$", true, "invalid method ID"}, {"Invalid method - random", "random-method", true, "invalid method ID"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := ValidateMethodID(tt.methodID) if (err != nil) != tt.wantError { t.Errorf("ValidateMethodID() error = %v, wantError %v", err, tt.wantError) return } if tt.wantError && err != nil { if !contains(err.Error(), tt.errorMsg) { t.Errorf("ValidateMethodID() error = %v, expected substring %v", err.Error(), tt.errorMsg) } } }) } } // TestValidateAppName tests app name validation func TestValidateAppName(t *testing.T) { tests := []struct { name string appName string wantError bool errorMsg string }{ // Valid app names {"Valid app - MPV", "MPV", false, ""}, {"Valid app - IINA", "IINA", false, ""}, {"Valid app - MPC-QT", "MPC-QT", false, ""}, {"Valid app - Celluloid", "Celluloid", false, ""}, {"Valid app - with spaces", "My Player", false, ""}, {"Valid app - with periods", "MPV.Player", false, ""}, // Invalid app names {"Invalid app - empty", "", true, "app name cannot be empty"}, {"Invalid app - special chars", "MPV$", true, "must contain only letters"}, {"Invalid app - slashes", "MPV/Test", true, "must contain only letters"}, {"Invalid app - too long", "MPVPlayerWithAVeryLongNameThatExceedsTheMaximumAllowedCharacterLimitOfOneHundredCharactersAndShouldBeRejected", true, "app name too long"}, {"Invalid app - unicode", "MPV播放器", true, "must contain only letters"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := ValidateAppName(tt.appName) if (err != nil) != tt.wantError { t.Errorf("ValidateAppName() error = %v, wantError %v", err, tt.wantError) return } if tt.wantError && err != nil { if !contains(err.Error(), tt.errorMsg) { t.Errorf("ValidateAppName() error = %v, expected substring %v", err.Error(), tt.errorMsg) } } }) } } // TestValidateAppType tests app type validation func TestValidateAppType(t *testing.T) { tests := []struct { name string appType string wantError bool errorMsg string }{ // Valid app types {"Valid type - app", "app", false, ""}, {"Valid type - frontend", "frontend", false, ""}, // Legacy types (normalized automatically) {"Legacy type - flatpak", "flatpak", false, ""}, {"Legacy type - package-manager", "package-manager", false, ""}, {"Legacy type - executable", "executable", false, ""}, {"Legacy type - portable", "portable", false, ""}, // Old app names (pre-Feb 2026, normalized automatically) {"Legacy app name - MPV", "MPV", false, ""}, {"Legacy app name - IINA", "IINA", false, ""}, {"Legacy app name - MPC-QT", "MPC-QT", false, ""}, {"Legacy app name - Celluloid", "Celluloid", false, ""}, // Invalid app types {"Invalid type - empty", "", true, "invalid app type"}, {"Invalid type - player", "player", true, "must be 'app' or 'frontend'"}, {"Invalid type - application", "application", true, "must be 'app' or 'frontend'"}, {"Invalid type - random", "random", true, "must be 'app' or 'frontend'"}, {"Invalid type - case sensitive", "App", true, "must be 'app' or 'frontend'"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := ValidateAppType(tt.appType) if (err != nil) != tt.wantError { t.Errorf("ValidateAppType() error = %v, wantError %v", err, tt.wantError) return } if tt.wantError && err != nil { if !contains(err.Error(), tt.errorMsg) { t.Errorf("ValidateAppType() error = %v, expected substring %v", err.Error(), tt.errorMsg) } } }) } } // TestNormalizeAppType tests app type normalization func TestNormalizeAppType(t *testing.T) { tests := []struct { name string input string expected string }{ // Standard types - unchanged {"Standard - app", "app", "app"}, {"Standard - frontend", "frontend", "frontend"}, // Legacy install types - normalize to "app" {"Legacy - flatpak", "flatpak", "app"}, {"Legacy - package-manager", "package-manager", "app"}, {"Legacy - executable", "executable", "app"}, {"Legacy - portable", "portable", "app"}, // Old app names (pre-Feb 2026) {"Old app name - MPV", "MPV", "app"}, {"Old app name - IINA", "IINA", "app"}, {"Old app name - MPC-QT", "MPC-QT", "app"}, {"Old app name - Celluloid", "Celluloid", "frontend"}, // Unknown types - returned as-is {"Unknown - random", "random", "random"}, {"Unknown - empty", "", ""}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := NormalizeAppType(tt.input) if result != tt.expected { t.Errorf("NormalizeAppType(%q) = %q, expected %q", tt.input, result, tt.expected) } }) } } // TestValidateLanguageCode tests language code validation func TestValidateLanguageCode(t *testing.T) { tests := []struct { name string code string wantError bool errorMsg string }{ // Valid language codes {"Valid code - en", "en", false, ""}, {"Valid code - zh", "zh", false, ""}, {"Valid code - es", "es", false, ""}, {"Valid code - en-US", "en-US", false, ""}, {"Valid code - zh-CN", "zh-CN", false, ""}, {"Valid code - en-GB", "en-GB", false, ""}, {"Valid code - empty", "", false, ""}, // Invalid language codes {"Invalid code - single letter", "e", true, "invalid language code"}, {"Invalid code - uppercase", "EN", true, "invalid language code"}, {"Invalid code - three letter", "eng", true, "invalid language code"}, {"Invalid code - lowercase country", "en-us", true, "invalid language code"}, {"Invalid code - special chars", "en_US", true, "invalid language code"}, {"Invalid code - number", "e1", true, "invalid language code"}, {"Invalid code - random", "english", true, "invalid language code"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := ValidateLanguageCode(tt.code) if (err != nil) != tt.wantError { t.Errorf("ValidateLanguageCode() error = %v, wantError %v", err, tt.wantError) return } if tt.wantError && err != nil { if !contains(err.Error(), tt.errorMsg) { t.Errorf("ValidateLanguageCode() error = %v, expected substring %v", err.Error(), tt.errorMsg) } } }) } } // TestValidateHWAValue tests hardware acceleration method validation func TestValidateHWAValue(t *testing.T) { tests := []struct { name string method string wantError bool errorMsg string }{ // Valid HWA methods {"Valid HWA - auto", "auto", false, ""}, {"Valid HWA - auto-safe", "auto-safe", false, ""}, {"Valid HWA - nvdec", "nvdec", false, ""}, {"Valid HWA - nvdec-copy", "nvdec-copy", false, ""}, {"Valid HWA - vaapi", "vaapi", false, ""}, {"Valid HWA - vaapi-copy", "vaapi-copy", false, ""}, {"Valid HWA - vulkan", "vulkan", false, ""}, {"Valid HWA - vulkan-copy", "vulkan-copy", false, ""}, {"Valid HWA - d3d11va", "d3d11va", false, ""}, {"Valid HWA - d3d11va-copy", "d3d11va-copy", false, ""}, {"Valid HWA - videotoolbox", "videotoolbox", false, ""}, {"Valid HWA - videotoolbox-copy", "videotoolbox-copy", false, ""}, {"Valid HWA - drm", "drm", false, ""}, {"Valid HWA - drm-copy", "drm-copy", false, ""}, {"Valid HWA - no", "no", false, ""}, {"Valid HWA - empty", "", false, ""}, // Invalid HWA methods {"Invalid HWA - typo", "vdau", true, "invalid hardware acceleration method"}, {"Invalid HWA - case sensitive", "Auto", true, "invalid hardware acceleration method"}, {"Invalid HWA - partial", "nvde", true, "invalid hardware acceleration method"}, {"Invalid HWA - random", "random", true, "invalid hardware acceleration method"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := ValidateHWAValue(tt.method) if (err != nil) != tt.wantError { t.Errorf("ValidateHWAValue() error = %v, wantError %v", err, tt.wantError) return } if tt.wantError && err != nil { if !contains(err.Error(), tt.errorMsg) { t.Errorf("ValidateHWAValue() error = %v, expected substring %v", err.Error(), tt.errorMsg) } } }) } } // TestValidateInstallMethod tests install method validation with platform compatibility func TestValidateInstallMethod(t *testing.T) { tests := []struct { name string methodID string isWindows bool isDarwin bool isLinux bool wantError bool errorMsg string }{ // Windows-only methods {"MPC-QT on Windows", "mpc-qt", true, false, false, false, ""}, {"MPC-QT on macOS", "mpc-qt", false, true, false, true, "only available on Windows"}, {"MPC-QT on Linux", "mpc-qt", false, false, true, true, "only available on Windows"}, // macOS-only methods {"MPV App on macOS", "mpv-app", false, true, false, false, ""}, {"MPV App on Windows", "mpv-app", true, false, false, true, "only available on macOS"}, {"MPV App on Linux", "mpv-app", false, false, true, true, "only available on macOS"}, {"IINA on macOS", "iina", false, true, false, false, ""}, {"IINA on Windows", "iina", true, false, false, true, "only available on macOS"}, {"IINA on Linux", "iina", false, false, true, true, "only available on macOS"}, // Platform-specific methods {"MPV Binary on Windows", "mpv-binary", true, false, false, false, ""}, {"MPV Binary on Linux", "mpv-binary", false, false, true, false, ""}, {"MPV Binary V3 on Windows", "mpv-binary-v3", true, false, false, false, ""}, {"MPV Binary V3 on Linux", "mpv-binary-v3", false, false, true, false, ""}, {"MPV Binary on macOS", "mpv-binary", false, true, false, true, "not available on macOS"}, {"MPV Binary V3 on macOS", "mpv-binary-v3", false, true, false, true, "not available on macOS"}, // Package manager methods (not available on Windows) {"MPV Brew on macOS", "mpv-brew", false, true, false, false, ""}, {"MPV Brew on Windows", "mpv-brew", true, false, false, true, "not available on Windows"}, {"MPV Flatpak on Linux", "mpv-flatpak", false, false, true, false, ""}, {"MPV Flatpak on Windows", "mpv-flatpak", true, false, false, true, "not available on Windows"}, {"MPV Package on Linux", "mpv-package", false, false, true, false, ""}, {"MPV Package on Windows", "mpv-package", true, false, false, true, "not available on Windows"}, {"Celluloid Flatpak on Linux", "celluloid-flatpak", false, false, true, false, ""}, {"Celluloid Flatpak on Windows", "celluloid-flatpak", true, false, false, true, "not available on Windows"}, {"Celluloid Package on Linux", "celluloid-package", false, false, true, false, ""}, {"Celluloid Package on Windows", "celluloid-package", true, false, false, true, "not available on Windows"}, // Invalid method ID {"Invalid method", "invalid-method", true, false, false, true, "invalid method ID"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := ValidateInstallMethod(tt.methodID, tt.isWindows, tt.isDarwin, tt.isLinux) if (err != nil) != tt.wantError { t.Errorf("ValidateInstallMethod() error = %v, wantError %v", err, tt.wantError) return } if tt.wantError && err != nil { if !contains(err.Error(), tt.errorMsg) { t.Errorf("ValidateInstallMethod() error = %v, expected substring %v", err.Error(), tt.errorMsg) } } }) } } // Helper function to check if string contains substring func contains(s, substr string) bool { return len(s) >= len(substr) && (s == substr || len(s) > len(substr) && findSubstring(s, substr)) } func findSubstring(s, substr string) bool { for i := 0; i <= len(s)-len(substr); i++ { if s[i:i+len(substr)] == substr { return true } } return false }