package installer import ( "testing" "gitgud.io/mike/mpv-manager/pkg/config" "gitgud.io/mike/mpv-manager/pkg/constants" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // The version-probe helpers exec read-only system tools (flatpak, pacman, // apt-cache, ...). They must tolerate missing binaries and missing packages // and never fail the test based on what the host happens to have installed. func TestDetectInstalledMPVApps(t *testing.T) { // Loose assertion: detection must not error or panic, whatever the host has. // A nil/empty result is valid on hosts with no mpv installed (e.g. CI). apps := DetectInstalledMPVApps() for _, app := range apps { assert.NotEmpty(t, app.AppName) assert.NotEmpty(t, app.MethodID) } } func TestVersionProbesTolerateMissingTools(t *testing.T) { const bogusPackage = "mpv-manager-definitely-not-installed-pkg" assert.Empty(t, getFlatpakAppVersion("io.mpv.MpvDefintelyMissing")) for _, family := range []string{constants.PMFamilyDebian, constants.PMFamilyRHEL, constants.PMFamilyArch, constants.PMFamilySUSE, "unknown-family"} { version, path := getPackageAppVersion(family, bogusPackage) assert.Empty(t, version) assert.Empty(t, path) } } func TestDetectPackageManagerFamily(t *testing.T) { // The result depends on the host distro; it just has to be a known family // or empty. family := detectPackageManagerFamily() if family != "" { assert.Contains(t, []string{ constants.PMFamilyDebian, constants.PMFamilyRHEL, constants.PMFamilyArch, constants.PMFamilySUSE, }, family) } } func TestSyncInstalledApps(t *testing.T) { isolateConfig(t) detected := []DetectedApp{ {AppName: "MPV", MethodID: constants.MethodMPVFlatpak, Version: "0.39.0", InstallPath: "flatpak run io.mpv.Mpv", InstallType: "flatpak"}, // A distinct path using the same method is a distinct installation. {AppName: "MPV", MethodID: constants.MethodMPVFlatpak, Version: "0.40.0", InstallPath: "other", InstallType: "flatpak"}, } added, removed := SyncInstalledApps(detected) assert.Equal(t, 2, added) assert.Equal(t, 0, removed) apps := config.GetInstalledApps() require.Len(t, apps, 2) versionsByPath := map[string]string{} for _, app := range apps { versionsByPath[app.InstallPath] = app.AppVersion assert.False(t, app.Managed, "externally detected apps are unmanaged") } assert.Equal(t, "0.39.0", versionsByPath["flatpak run io.mpv.Mpv"]) assert.Equal(t, "0.40.0", versionsByPath["other"]) // Syncing the same set again changes nothing. added, removed = SyncInstalledApps(detected) assert.Equal(t, 0, added) assert.Equal(t, 0, removed) // A newer detected version refreshes only the matching identity in place. added, removed = SyncInstalledApps([]DetectedApp{ {AppName: "MPV", MethodID: constants.MethodMPVFlatpak, Version: "0.40.0", InstallPath: "flatpak run io.mpv.Mpv", InstallType: "flatpak"}, }) assert.Equal(t, 0, added) assert.Equal(t, 0, removed) apps = config.GetInstalledApps() require.Len(t, apps, 2) for _, app := range apps { assert.Equal(t, "0.40.0", app.AppVersion) } // Missing or failed probes are not proof of uninstallation. added, removed = SyncInstalledApps(nil) assert.Equal(t, 0, added) assert.Equal(t, 0, removed) require.Len(t, config.GetInstalledApps(), 2) added, removed = SyncInstalledAppObservations([]DetectionObservation{ { State: DetectionUnknown, App: DetectedApp{MethodID: constants.MethodMPVFlatpak}, }, { State: DetectionNotFound, App: DetectedApp{ MethodID: constants.MethodMPVFlatpak, InstallPath: "flatpak run io.mpv.Mpv", }, }, }) assert.Equal(t, 0, added) assert.Equal(t, 1, removed) apps = config.GetInstalledApps() require.Len(t, apps, 1) assert.Equal(t, "other", apps[0].InstallPath) } func TestSyncInstalledAppObservationsFoundWinsAndPathsCanonicalize(t *testing.T) { isolateConfig(t) observations := []DetectionObservation{ {State: DetectionNotFound, App: DetectedApp{MethodID: constants.MethodMPVBinary, InstallPath: `C:\Users\Test\mpv\..\MPV`}}, {State: DetectionFound, App: DetectedApp{AppName: "MPV", MethodID: constants.MethodMPVBinary, Version: "0.40.0", InstallPath: `c:/users/test/mpv`, InstallType: "binary"}}, } added, removed := SyncInstalledAppObservations(observations) assert.Equal(t, 1, added) assert.Equal(t, 0, removed) require.Len(t, config.GetInstalledApps(), 1) } func TestDetectAndSyncApps(t *testing.T) { isolateConfig(t) // Real detection against the host, synced into the sandboxed config. added, removed := DetectAndSyncApps() assert.GreaterOrEqual(t, added, 0) assert.GreaterOrEqual(t, removed, 0) }