using DodoSSH.Client.Session;
namespace DodoSSH.Client.App.Tests;
///
/// A release channel that answers whatever the test tells it to.
///
///
///
/// records the call instead of making it, and that is the whole reason
/// IUpdateChannel exists as an interface. The real one replaces the running process and never
/// returns, so a test could not observe it at all — and the single most important thing to be able to
/// assert about this feature is a negative: that a downloaded update is never applied unless
/// somebody pressed the button. A counter is what makes that assertion writable.
///
///
/// exists for the same reason in the other direction: without a way to stop a
/// download halfway, the Downloading state would be a state no test could ever catch the view model in.
///
///
internal sealed class FakeUpdateChannel : IUpdateChannel
{
/// What the next check finds. Null means this build is current.
internal AvailableUpdate? Available { get; set; }
/// When set, checking throws it.
internal Exception? CheckFailure { get; set; }
/// When set, downloading throws it.
internal Exception? DownloadFailure { get; set; }
/// When set, a download waits on it before completing.
internal TaskCompletionSource? HoldDownload { get; set; }
/// The percentages a download reports on its way through.
internal IReadOnlyList ProgressSteps { get; set; } = [25, 50, 100];
internal int Checks { get; private set; }
internal int Downloads { get; private set; }
internal int Restarts { get; private set; }
internal AvailableUpdate? RestartedWith { get; private set; }
///
public bool IsSupported { get; set; } = true;
///
public string CurrentVersion { get; set; } = "1.0.0";
///
public Task CheckAsync(CancellationToken cancellationToken)
{
Checks++;
return CheckFailure is { } failure
? Task.FromException(failure)
: Task.FromResult(Available);
}
///
public async Task DownloadAsync(
AvailableUpdate update,
IProgress progress,
CancellationToken cancellationToken)
{
Downloads++;
if (DownloadFailure is { } failure)
{
throw failure;
}
if (HoldDownload is { } gate)
{
await gate.Task.WaitAsync(cancellationToken).ConfigureAwait(false);
}
foreach (var percent in ProgressSteps)
{
cancellationToken.ThrowIfCancellationRequested();
progress.Report(percent);
}
}
///
public void ApplyAndRestart(AvailableUpdate update)
{
Restarts++;
RestartedWith = update;
}
}