using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.IO;
namespace LibationFileManager.Tests;
///
/// The restart offered after a rollback. A process that restarts itself is worth being careful with, so the
/// decision is tested here and only the Process.Start call itself goes untested.
///
[TestClass]
[DoNotParallelize]
public class InstallRelauncherTests
{
private readonly List started = [];
private Func originalStarter = null!;
[TestInitialize]
public void Initialize()
{
originalStarter = InstallRelauncher.StartProcess;
InstallRelauncher.StartProcess = executable =>
{
started.Add(executable);
return true;
};
}
[TestCleanup]
public void Cleanup()
{
InstallRelauncher.StartProcess = originalStarter;
Environment.SetEnvironmentVariable(InstallRelauncher.RelaunchedEnvironmentVariable, null);
StartupLog.ResetForTests();
}
[TestMethod]
public void TryRelaunch_starts_this_same_executable()
{
Assert.IsTrue(InstallRelauncher.TryRelaunch());
Assert.AreEqual(1, started.Count);
Assert.AreEqual(Environment.ProcessPath, started[0]);
}
[TestMethod]
public void A_launcher_that_fails_is_reported_rather_than_thrown()
{
InstallRelauncher.StartProcess = _ => throw new InvalidOperationException("no can do");
Assert.IsFalse(InstallRelauncher.TryRelaunch());
}
[TestMethod]
public void A_launcher_that_declines_is_reported_as_not_started()
{
InstallRelauncher.StartProcess = _ => false;
Assert.IsFalse(InstallRelauncher.TryRelaunch());
}
// A rollback deletes the pending marker first, so it normally cannot repeat. But that delete swallows
// its own failure, and a marker that survives would mean every launch rolls back and offers a restart
// again. The child carries a marker of its own so the chain stops at one.
[TestMethod]
public void A_process_started_by_a_relaunch_knows_it()
{
Assert.IsFalse(InstallRelauncher.WasRelaunched);
Environment.SetEnvironmentVariable(InstallRelauncher.RelaunchedEnvironmentVariable, "1");
Assert.IsTrue(InstallRelauncher.WasRelaunched);
}
[TestMethod]
public void The_restart_is_offered_for_an_install_that_was_fully_restored()
{
Assert.IsTrue(StartupAssemblyBootstrap.ShouldOfferRestart(
Rollback(RollbackConfidence.RestoredToPreviousVersion),
wasRelaunched: false));
}
[TestMethod]
public void The_restart_is_still_offered_for_a_mixed_install_because_it_does_run()
{
Assert.IsTrue(StartupAssemblyBootstrap.ShouldOfferRestart(
Rollback(RollbackConfidence.RestoredButInstallIsMixed),
wasRelaunched: false));
}
[TestMethod]
public void The_restart_is_withheld_when_the_restore_did_not_finish()
{
Assert.IsFalse(StartupAssemblyBootstrap.ShouldOfferRestart(
Rollback(RollbackConfidence.RestoreIncomplete),
wasRelaunched: false));
}
[TestMethod]
public void The_restart_is_withheld_in_a_process_that_a_restart_started()
{
Assert.IsFalse(StartupAssemblyBootstrap.ShouldOfferRestart(
Rollback(RollbackConfidence.RestoredToPreviousVersion),
wasRelaunched: true));
}
[TestMethod]
public void Nothing_is_offered_when_no_rollback_happened()
{
Assert.IsFalse(StartupAssemblyBootstrap.ShouldOfferRestart(
new UpgradeRecoveryResult(false, string.Empty, string.Empty, []),
wasRelaunched: false));
}
private static UpgradeRecoveryResult Rollback(RollbackConfidence confidence)
=> new(true, "title", "body", []) { Confidence = confidence };
}