package config import ( "encoding/json" "os" "path/filepath" "runtime" "testing" "gitgud.io/mike/mpv-manager/pkg/constants" "github.com/stretchr/testify/assert" ) func resetGlobalConfig() { globalConfig = nil globalLoadErr = nil } func TestGetPortableConfigPath(t *testing.T) { tests := []struct { name string mpvDir string want string }{ { name: "absolute path", mpvDir: "/home/user/mpv", want: "/home/user/mpv/portable_config", }, { name: "relative path", mpvDir: "./mpv", want: "mpv/portable_config", }, { name: "windows path", mpvDir: "C:\\Program Files\\mpv", want: "C:\\Program Files\\mpv/portable_config", }, { name: "empty path", mpvDir: "", want: "portable_config", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := GetPortableConfigPath(tt.mpvDir) assert.Equal(t, filepath.FromSlash(tt.want), got) }) } } func TestGetConfigDir(t *testing.T) { t.Run("native home", func(t *testing.T) { home := t.TempDir() isolateConfigHome(t, home) assert.Equal(t, testConfigDir(home), GetConfigDir()) }) t.Run("missing home", func(t *testing.T) { for _, key := range []string{"HOME", "USERPROFILE", "APPDATA", "XDG_CONFIG_HOME"} { t.Setenv(key, "") } assert.Equal(t, ".", GetConfigDir()) }) } func TestLoad(t *testing.T) { isolateConfigHome(t, t.TempDir()) t.Run("load new config", func(t *testing.T) { resetGlobalConfig() config, err := Load() assert.NoError(t, err) assert.NotNil(t, config) assert.False(t, config.AutoUpdate) assert.NotNil(t, config.InstalledApps) }) t.Run("load existing config", func(t *testing.T) { resetGlobalConfig() // Set HOME before creating config to ensure correct path tempDir := t.TempDir() isolateConfigHome(t, tempDir) // Installer config is now stored in MPV config directory configDir := testConfigDir(tempDir) configFile := filepath.Join(configDir, constants.ConfigFileName) err := os.MkdirAll(configDir, 0755) assert.NoError(t, err) testConfig := Config{ LastCheck: "2024-01-01", AutoUpdate: true, InstallPath: getDefaultInstallPath(), InstalledApps: []InstalledApp{ {AppName: "MPV", AppType: "flatpak"}, }, } data, err := json.MarshalIndent(testConfig, "", " ") assert.NoError(t, err) err = os.WriteFile(configFile, data, 0644) assert.NoError(t, err) config, err := Load() assert.NoError(t, err) assert.NotNil(t, config) assert.Equal(t, "2024-01-01", config.LastCheck) assert.True(t, config.AutoUpdate) assert.Equal(t, getDefaultInstallPath(), config.InstallPath) assert.Len(t, config.InstalledApps, 1) }) t.Run("return cached config", func(t *testing.T) { resetGlobalConfig() config1, _ := Load() config2, _ := Load() assert.NotSame(t, config1, config2) config1.InstallPath = "/snapshot-only" assert.NotEqual(t, config1.InstallPath, config2.InstallPath) }) } func TestSave(t *testing.T) { t.Run("save config to file", func(t *testing.T) { resetGlobalConfig() tempDir := t.TempDir() isolateConfigHome(t, tempDir) _, _ = Load() err := Update(func(config *Config) error { config.InstallPath = filepath.Join(tempDir, "custom-mpv") config.AutoUpdate = true return nil }) assert.NoError(t, err) // Installer config is now stored in MPV config directory configFile := filepath.Join(testConfigDir(tempDir), constants.ConfigFileName) assert.FileExists(t, configFile) data, err := os.ReadFile(configFile) assert.NoError(t, err) var loaded Config err = json.Unmarshal(data, &loaded) assert.NoError(t, err) assert.Equal(t, filepath.Join(tempDir, "custom-mpv"), loaded.InstallPath) assert.True(t, loaded.AutoUpdate) }) t.Run("error without loaded config", func(t *testing.T) { resetGlobalConfig() err := Save() assert.Error(t, err) }) } func TestSetInstallPath(t *testing.T) { t.Run("set install path", func(t *testing.T) { resetGlobalConfig() tempDir := t.TempDir() isolateConfigHome(t, tempDir) SetInstallPath(filepath.Join(tempDir, "custom-mpv")) path := GetInstallPath() assert.Equal(t, filepath.Join(tempDir, "custom-mpv"), path) }) t.Run("empty install path", func(t *testing.T) { resetGlobalConfig() tempDir := t.TempDir() isolateConfigHome(t, tempDir) SetInstallPath("") path := GetInstallPath() assert.NotEmpty(t, path) }) } func TestGetInstallPath(t *testing.T) { t.Run("get custom install path", func(t *testing.T) { resetGlobalConfig() tempDir := t.TempDir() isolateConfigHome(t, tempDir) _, _ = Load() assert.NoError(t, SetInstallPath(filepath.Join(tempDir, "custom-mpv"))) path := GetInstallPath() assert.Equal(t, filepath.Join(tempDir, "custom-mpv"), path) }) t.Run("get default install path", func(t *testing.T) { resetGlobalConfig() tempDir := t.TempDir() isolateConfigHome(t, tempDir) path := GetInstallPath() assert.Contains(t, path, tempDir) assert.Contains(t, path, "mpv") }) } func TestSetUOSCVersion(t *testing.T) { resetGlobalConfig() tempDir := t.TempDir() isolateConfigHome(t, tempDir) SetUOSCVersion("4.0.0") version := GetUOSCVersion() assert.Equal(t, "4.0.0", version) // Must persist across reload like its siblings (SetModernZVersion, SetFFmpegVersion) resetGlobalConfig() _, err := Load() assert.NoError(t, err) assert.Equal(t, "4.0.0", GetUOSCVersion()) } func TestGetUOSCVersion(t *testing.T) { isolateConfigHome(t, t.TempDir()) resetGlobalConfig() _, _ = Load() SetUOSCVersion("3.5.0") version := GetUOSCVersion() assert.Equal(t, "3.5.0", version) } func TestAddInstalledApp(t *testing.T) { resetGlobalConfig() tempDir := t.TempDir() isolateConfigHome(t, tempDir) app := InstalledApp{ AppName: "MPV", AppType: "flatpak", InstallMethod: "mpv-flatpak", InstalledDate: "2024-01-01", AppVersion: "0.36.0", } err := AddInstalledApp(app) assert.NoError(t, err) apps := GetInstalledApps() assert.Len(t, apps, 1) assert.Equal(t, "MPV", apps[0].AppName) assert.True(t, IsAppInstalled("MPV")) } func TestRemoveInstalledApp(t *testing.T) { resetGlobalConfig() tempDir := t.TempDir() isolateConfigHome(t, tempDir) app := InstalledApp{AppName: "MPV"} AddInstalledApp(app) err := RemoveInstalledApp("MPV") assert.NoError(t, err) assert.False(t, IsAppInstalled("MPV")) assert.Len(t, GetInstalledApps(), 0) } func TestRemoveInstalledAppByType(t *testing.T) { resetGlobalConfig() tempDir := t.TempDir() isolateConfigHome(t, tempDir) AddInstalledApp(InstalledApp{AppName: "MPV", AppType: "flatpak"}) AddInstalledApp(InstalledApp{AppName: "Celluloid", AppType: "flatpak"}) AddInstalledApp(InstalledApp{AppName: "IINA", AppType: "app"}) err := RemoveInstalledAppByType("flatpak") assert.NoError(t, err) apps := GetInstalledApps() assert.Len(t, apps, 1) assert.Equal(t, "IINA", apps[0].AppName) } func TestGetInstalledApps(t *testing.T) { resetGlobalConfig() tempDir := t.TempDir() isolateConfigHome(t, tempDir) _, _ = Load() assert.NoError(t, AddInstalledApp(InstalledApp{AppName: "MPV", InstallMethod: "mpv-binary", InstallPath: "/mpv"})) assert.NoError(t, AddInstalledApp(InstalledApp{AppName: "IINA", InstallMethod: "iina", InstallPath: "/iina"})) apps := GetInstalledApps() assert.Len(t, apps, 2) } func TestIsAppInstalled(t *testing.T) { resetGlobalConfig() tempDir := t.TempDir() isolateConfigHome(t, tempDir) _, _ = Load() assert.NoError(t, AddInstalledApp(InstalledApp{AppName: "MPV", InstallMethod: "mpv-binary", InstallPath: "/mpv"})) assert.NoError(t, AddInstalledApp(InstalledApp{AppName: "IINA", InstallMethod: "iina", InstallPath: "/iina"})) assert.True(t, IsAppInstalled("MPV")) assert.True(t, IsAppInstalled("IINA")) assert.False(t, IsAppInstalled("VLC")) } func TestAudioLanguagePrefs(t *testing.T) { resetGlobalConfig() tempDir := t.TempDir() isolateConfigHome(t, tempDir) langs := []string{"en", "es"} err := SetAudioLanguagePrefs(langs) assert.NoError(t, err) prefs := GetAudioLanguagePrefs() assert.Equal(t, langs, prefs) } func TestSubtitleLanguagePrefs(t *testing.T) { resetGlobalConfig() tempDir := t.TempDir() isolateConfigHome(t, tempDir) langs := []string{"en", "fr", "de"} err := SetSubtitleLanguagePrefs(langs) assert.NoError(t, err) prefs := GetSubtitleLanguagePrefs() assert.Equal(t, langs, prefs) } func TestManagerInPATH(t *testing.T) { resetGlobalConfig() tempDir := t.TempDir() isolateConfigHome(t, tempDir) err := SetManagerInPATH(true) assert.NoError(t, err) assert.True(t, GetManagerInPATH()) err = SetManagerInPATH(false) assert.NoError(t, err) assert.False(t, GetManagerInPATH()) } func TestManagerBinPath(t *testing.T) { resetGlobalConfig() tempDir := t.TempDir() isolateConfigHome(t, tempDir) err := SetManagerBinPath("/usr/local/bin/mpv-manager") assert.NoError(t, err) assert.Equal(t, "/usr/local/bin/mpv-manager", GetManagerBinPath()) } func TestGetMPVConfigPath(t *testing.T) { resetGlobalConfig() t.Cleanup(resetGlobalConfig) tempDir := t.TempDir() isolateConfigHome(t, tempDir) path := GetMPVConfigPath() assert.Contains(t, path, tempDir) assert.Equal(t, testConfigDir(tempDir), path) assert.Contains(t, path, "mpv") _, _ = Load() assert.NoError(t, Update(func(config *Config) error { config.MPVConfigPath = filepath.Join(tempDir, "custom-mpv-config") return nil })) path = GetMPVConfigPath() if runtime.GOOS == "windows" { assert.Equal(t, testConfigDir(tempDir), path) } else { assert.Equal(t, filepath.Join(tempDir, "custom-mpv-config"), path) } }