package installer import ( "os" "path/filepath" "testing" "gitgud.io/mike/mpv-manager/pkg/constants" "gitgud.io/mike/mpv-manager/pkg/platform" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestPreserveUserSettings(t *testing.T) { t.Run("parses all supported keys", func(t *testing.T) { configPath := filepath.Join(t.TempDir(), "mpv.conf") content := `# comment line alang=ja, en ,de slang=eng hwdec=nvdec vo=gpu-next scale=ewa_lanczossharp dither-depth-convert=no unrelated-key=yes malformed-line-without-equals ` require.NoError(t, os.WriteFile(configPath, []byte(content), 0644)) cr, out := newBufferedRunner() settings, err := PreserveUserSettings(configPath, cr) require.NoError(t, err) assert.Equal(t, []string{"ja", "en", "de"}, settings.AudioLanguages) assert.Equal(t, []string{"eng"}, settings.SubtitleLanguages) assert.Equal(t, "nvdec", settings.HardwareDecoder) assert.Equal(t, "gpu-next", settings.VideoOutput) assert.Equal(t, "ewa_lanczossharp", settings.ScaleFilter) assert.Equal(t, "no", settings.DitherAlgorithm) assert.Contains(t, drainOutput(out), "Preserved 6 user setting(s)") }) t.Run("missing config yields empty settings", func(t *testing.T) { cr, out := newBufferedRunner() settings, err := PreserveUserSettings(filepath.Join(t.TempDir(), "mpv.conf"), cr) require.NoError(t, err) require.NotNil(t, settings) assert.Equal(t, 0, countNonEmptySettings(settings)) assert.Contains(t, drainOutput(out), "No existing mpv.conf found, will use defaults") }) t.Run("nil runner is accepted", func(t *testing.T) { settings, err := PreserveUserSettings(filepath.Join(t.TempDir(), "mpv.conf"), nil) require.NoError(t, err) assert.NotNil(t, settings) }) } func TestApplyUserSettings(t *testing.T) { t.Run("updates existing keys and appends missing ones", func(t *testing.T) { configPath := filepath.Join(t.TempDir(), "mpv.conf") original := "# header comment\nhwdec=auto\nvo=gpu\nkeep-this=yes\n" require.NoError(t, os.WriteFile(configPath, []byte(original), 0644)) settings := &UserSettings{ AudioLanguages: []string{"de", "en"}, SubtitleLanguages: []string{"deu"}, HardwareDecoder: "nvdec", VideoOutput: "gpu-next", ScaleFilter: "spline36", DitherAlgorithm: "yes", } cr, out := newBufferedRunner() require.NoError(t, ApplyUserSettings(configPath, settings, cr)) data, err := os.ReadFile(configPath) require.NoError(t, err) conf := string(data) assert.Contains(t, conf, "# header comment") assert.Contains(t, conf, "keep-this=yes") assert.Contains(t, conf, "hwdec=nvdec") assert.Contains(t, conf, "vo=gpu-next") assert.Contains(t, conf, "alang=de,en") assert.Contains(t, conf, "slang=deu") assert.Contains(t, conf, "scale=spline36") assert.Contains(t, conf, "dither-depth-convert=yes") assert.NotContains(t, conf, "hwdec=auto") outputs := drainOutput(out) assert.Contains(t, outputs, "User settings applied successfully!") }) t.Run("empty settings leave the file content unchanged", func(t *testing.T) { configPath := filepath.Join(t.TempDir(), "mpv.conf") original := "hwdec=vulkan\n" require.NoError(t, os.WriteFile(configPath, []byte(original), 0644)) cr, _ := newBufferedRunner() require.NoError(t, ApplyUserSettings(configPath, &UserSettings{}, cr)) data, err := os.ReadFile(configPath) require.NoError(t, err) assert.Equal(t, original, string(data)) }) t.Run("rejects invalid parameters", func(t *testing.T) { cr, _ := newBufferedRunner() require.Error(t, ApplyUserSettings("whatever", nil, cr)) require.Error(t, ApplyUserSettings("whatever", &UserSettings{}, nil)) }) t.Run("missing config file fails", func(t *testing.T) { cr, _ := newBufferedRunner() err := ApplyUserSettings(filepath.Join(t.TempDir(), "mpv.conf"), &UserSettings{}, cr) require.Error(t, err) assert.Contains(t, err.Error(), "failed to read config file") }) } func TestSetRecommendedHWADecoderIfEmpty(t *testing.T) { nvidia := &platform.GPUInfo{Brand: "nvidia"} recommended := platform.GetRecommendedHWADecoder(platform.Linux, nvidia.Brand, platform.GetGPUBrands(nvidia)...) require.NotEmpty(t, recommended) require.NotEqual(t, "auto", recommended, "test assumes a concrete Linux/Nvidia recommendation") t.Run("replaces the auto fallback", func(t *testing.T) { configPath := filepath.Join(t.TempDir(), "mpv.conf") require.NoError(t, os.WriteFile(configPath, []byte("hwdec=auto # safe fallback\n"), 0644)) cr, out := newBufferedRunner() require.NoError(t, SetRecommendedHWADecoderIfEmpty(configPath, platform.Linux, nvidia, cr)) data, err := os.ReadFile(configPath) require.NoError(t, err) assert.Contains(t, string(data), "hwdec="+recommended) assert.Contains(t, drainOutput(out), "Set recommended hardware decoder: "+recommended) }) t.Run("keeps a custom user value", func(t *testing.T) { configPath := filepath.Join(t.TempDir(), "mpv.conf") require.NoError(t, os.WriteFile(configPath, []byte("hwdec=vulkan\n"), 0644)) cr, _ := newBufferedRunner() require.NoError(t, SetRecommendedHWADecoderIfEmpty(configPath, platform.Linux, nvidia, cr)) data, err := os.ReadFile(configPath) require.NoError(t, err) assert.Equal(t, "hwdec=vulkan\n", string(data)) }) t.Run("adds hwdec when missing", func(t *testing.T) { configPath := filepath.Join(t.TempDir(), "mpv.conf") require.NoError(t, os.WriteFile(configPath, []byte("vo=gpu-next\n"), 0644)) cr, _ := newBufferedRunner() require.NoError(t, SetRecommendedHWADecoderIfEmpty(configPath, platform.Linux, nvidia, cr)) data, err := os.ReadFile(configPath) require.NoError(t, err) assert.Contains(t, string(data), "hwdec="+recommended) }) t.Run("no recommendation leaves the file alone", func(t *testing.T) { configPath := filepath.Join(t.TempDir(), "mpv.conf") original := "hwdec=auto\n" require.NoError(t, os.WriteFile(configPath, []byte(original), 0644)) cr, _ := newBufferedRunner() // nil GPU info yields the "auto" default recommendation: nothing to do. require.NoError(t, SetRecommendedHWADecoderIfEmpty(configPath, platform.Linux, nil, cr)) data, err := os.ReadFile(configPath) require.NoError(t, err) assert.Equal(t, original, string(data)) }) t.Run("unreadable config fails", func(t *testing.T) { cr, _ := newBufferedRunner() err := SetRecommendedHWADecoderIfEmpty(filepath.Join(t.TempDir(), "mpv.conf"), platform.Linux, nvidia, cr) require.Error(t, err) assert.Contains(t, err.Error(), "failed to read config file") }) } func TestInstallMPVConfigWithPlatformDefaults(t *testing.T) { isolateConfig(t) configPath, err := GetMPVConfigPath() require.NoError(t, err) configDir := filepath.Dir(configPath) require.NoError(t, os.MkdirAll(configDir, 0755)) require.NoError(t, os.WriteFile(configPath, []byte("alang=de,en\nhwdec=auto\n"), 0644)) nvidia := &platform.GPUInfo{Brand: "nvidia"} recommended := platform.GetRecommendedHWADecoder(platform.Linux, nvidia.Brand, platform.GetGPUBrands(nvidia)...) inst := NewInstaller(ReleaseInfo{}, "") cr, out := newBufferedRunner() require.NoError(t, InstallMPVConfigWithPlatformDefaults(inst, cr, platform.Linux, nvidia)) data, err := os.ReadFile(configPath) require.NoError(t, err) conf := string(data) // The embedded default config was installed, user languages were preserved, // and the recommended decoder replaced the auto fallback. assert.Contains(t, conf, "profile=high-quality") assert.Contains(t, conf, "alang=de,en") if recommended != "" && recommended != "auto" { assert.Contains(t, conf, "hwdec="+recommended) } // The previous config was backed up into conf_backups. backupDir, err := GetConfigBackupDir() require.NoError(t, err) entries, err := os.ReadDir(backupDir) require.NoError(t, err) assert.NotEmpty(t, entries) outputs := drainOutput(out) assert.Contains(t, outputs, "MPV configuration installed successfully!") } func TestInstallMPVConfigWithOutput_BackupFailureAbortsWithoutChangingLiveConfig(t *testing.T) { isolateConfig(t) configPath, err := GetMPVConfigPath() require.NoError(t, err) configDir := filepath.Dir(configPath) // A regular file where the backup directory should be forces // CreateFullBackup to fail; installation must leave the live file intact. require.NoError(t, os.MkdirAll(configDir, 0755)) require.NoError(t, os.WriteFile(filepath.Join(configDir, constants.ConfigBackupsDir), []byte("blocker"), 0644)) require.NoError(t, os.WriteFile(configPath, []byte("alang=ja\n"), 0644)) inst := NewInstaller(ReleaseInfo{}, "") cr, out := newBufferedRunner() require.Error(t, inst.InstallMPVConfigWithOutput(cr)) assert.NotContains(t, drainOutput(out), "MPV configuration installed successfully!") data, err := os.ReadFile(configPath) require.NoError(t, err) assert.Equal(t, "alang=ja\n", string(data)) }