mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Merge pull request #1656 from GeertvanHorrik/pr/progress-reporting
Add percentage calculation
This commit is contained in:
46
src/Squirrel/ApplyReleasesProgress.cs
Normal file
46
src/Squirrel/ApplyReleasesProgress.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
namespace Squirrel
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
|
||||||
|
internal class ApplyReleasesProgress : Progress<int>
|
||||||
|
{
|
||||||
|
private readonly int _releasesToApply;
|
||||||
|
private int _appliedReleases;
|
||||||
|
private int _currentReleaseProgress;
|
||||||
|
|
||||||
|
public ApplyReleasesProgress(int releasesToApply, Action<int> handler)
|
||||||
|
: base(handler)
|
||||||
|
{
|
||||||
|
_releasesToApply = releasesToApply;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReportReleaseProgress(int progressOfCurrentRelease)
|
||||||
|
{
|
||||||
|
_currentReleaseProgress = progressOfCurrentRelease;
|
||||||
|
|
||||||
|
CalculateProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FinishRelease()
|
||||||
|
{
|
||||||
|
_appliedReleases++;
|
||||||
|
_currentReleaseProgress = 0;
|
||||||
|
|
||||||
|
CalculateProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculateProgress()
|
||||||
|
{
|
||||||
|
// Per release progress
|
||||||
|
var perReleaseProgressRange = 100 / _releasesToApply;
|
||||||
|
|
||||||
|
var appliedReleases = Math.Min(_appliedReleases, _releasesToApply);
|
||||||
|
var basePercentage = appliedReleases * perReleaseProgressRange;
|
||||||
|
|
||||||
|
var currentReleasePercentage = (perReleaseProgressRange / 100d) * _currentReleaseProgress;
|
||||||
|
|
||||||
|
var percentage = basePercentage + currentReleasePercentage;
|
||||||
|
OnReport((int)percentage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -93,6 +93,11 @@ namespace Squirrel
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePackage deltaPackage, string outputFile)
|
public ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePackage deltaPackage, string outputFile)
|
||||||
|
{
|
||||||
|
return ApplyDeltaPackage(basePackage, deltaPackage, outputFile, x => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePackage deltaPackage, string outputFile, Action<int> progress)
|
||||||
{
|
{
|
||||||
Contract.Requires(deltaPackage != null);
|
Contract.Requires(deltaPackage != null);
|
||||||
Contract.Requires(!String.IsNullOrEmpty(outputFile) && !File.Exists(outputFile));
|
Contract.Requires(!String.IsNullOrEmpty(outputFile) && !File.Exists(outputFile));
|
||||||
@@ -108,11 +113,16 @@ namespace Squirrel
|
|||||||
using (var reader = za.ExtractAllEntries()) {
|
using (var reader = za.ExtractAllEntries()) {
|
||||||
reader.WriteAllToDirectory(deltaPath, opts);
|
reader.WriteAllToDirectory(deltaPath, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progress(25);
|
||||||
|
|
||||||
using (var za = ZipArchive.Open(basePackage.InputPackageFile))
|
using (var za = ZipArchive.Open(basePackage.InputPackageFile))
|
||||||
using (var reader = za.ExtractAllEntries()) {
|
using (var reader = za.ExtractAllEntries()) {
|
||||||
reader.WriteAllToDirectory(workingPath, opts);
|
reader.WriteAllToDirectory(workingPath, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progress(50);
|
||||||
|
|
||||||
var pathsVisited = new List<string>();
|
var pathsVisited = new List<string>();
|
||||||
|
|
||||||
var deltaPathRelativePaths = new DirectoryInfo(deltaPath).GetAllFilesRecursively()
|
var deltaPathRelativePaths = new DirectoryInfo(deltaPath).GetAllFilesRecursively()
|
||||||
@@ -130,6 +140,8 @@ namespace Squirrel
|
|||||||
applyDiffToFile(deltaPath, file, workingPath);
|
applyDiffToFile(deltaPath, file, workingPath);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
progress(75);
|
||||||
|
|
||||||
// Delete all of the files that were in the old package but
|
// Delete all of the files that were in the old package but
|
||||||
// not in the new one.
|
// not in the new one.
|
||||||
new DirectoryInfo(workingPath).GetAllFilesRecursively()
|
new DirectoryInfo(workingPath).GetAllFilesRecursively()
|
||||||
@@ -140,6 +152,8 @@ namespace Squirrel
|
|||||||
File.Delete(Path.Combine(workingPath, x));
|
File.Delete(Path.Combine(workingPath, x));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
progress(80);
|
||||||
|
|
||||||
// Update all the files that aren't in 'lib' with the delta
|
// Update all the files that aren't in 'lib' with the delta
|
||||||
// package's versions (i.e. the nuspec file, etc etc).
|
// package's versions (i.e. the nuspec file, etc etc).
|
||||||
deltaPathRelativePaths
|
deltaPathRelativePaths
|
||||||
@@ -156,6 +170,8 @@ namespace Squirrel
|
|||||||
za.AddAllFromDirectory(workingPath);
|
za.AddAllFromDirectory(workingPath);
|
||||||
za.SaveTo(tgt);
|
za.SaveTo(tgt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progress(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ReleasePackage(outputFile);
|
return new ReleasePackage(outputFile);
|
||||||
|
|||||||
@@ -191,13 +191,26 @@ namespace Squirrel
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Task ExtractZipForInstall(string zipFilePath, string outFolder, string rootPackageFolder)
|
public static Task ExtractZipForInstall(string zipFilePath, string outFolder, string rootPackageFolder)
|
||||||
|
{
|
||||||
|
return ExtractZipForInstall(zipFilePath, outFolder, rootPackageFolder, x => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Task ExtractZipForInstall(string zipFilePath, string outFolder, string rootPackageFolder, Action<int> progress)
|
||||||
{
|
{
|
||||||
var re = new Regex(@"lib[\\\/][^\\\/]*[\\\/]", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
|
var re = new Regex(@"lib[\\\/][^\\\/]*[\\\/]", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
return Task.Run(() => {
|
return Task.Run(() => {
|
||||||
using (var za = ZipArchive.Open(zipFilePath))
|
using (var za = ZipArchive.Open(zipFilePath))
|
||||||
using (var reader = za.ExtractAllEntries()) {
|
using (var reader = za.ExtractAllEntries()) {
|
||||||
|
var totalItems = za.Entries.Count;
|
||||||
|
var currentItem = 0;
|
||||||
|
|
||||||
while (reader.MoveToNextEntry()) {
|
while (reader.MoveToNextEntry()) {
|
||||||
|
// Report progress early since we might be need to continue for non-matches
|
||||||
|
currentItem++;
|
||||||
|
var percentage = (currentItem * 100d) / totalItems;
|
||||||
|
progress((int)percentage);
|
||||||
|
|
||||||
var parts = reader.Entry.Key.Split('\\', '/');
|
var parts = reader.Entry.Key.Split('\\', '/');
|
||||||
var decoded = String.Join(Path.DirectorySeparatorChar.ToString(), parts);
|
var decoded = String.Join(Path.DirectorySeparatorChar.ToString(), parts);
|
||||||
|
|
||||||
@@ -234,6 +247,8 @@ namespace Squirrel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progress(100);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,11 @@ namespace Squirrel
|
|||||||
progress = progress ?? (_ => { });
|
progress = progress ?? (_ => { });
|
||||||
|
|
||||||
progress(0);
|
progress(0);
|
||||||
var release = await createFullPackagesFromDeltas(updateInfo.ReleasesToApply, updateInfo.CurrentlyInstalledVersion);
|
|
||||||
progress(10);
|
// Progress range: 00 -> 40
|
||||||
|
var release = await createFullPackagesFromDeltas(updateInfo.ReleasesToApply, updateInfo.CurrentlyInstalledVersion, new ApplyReleasesProgress(updateInfo.ReleasesToApply.Count, x => progress(CalculateProgress(x, 0, 40))));
|
||||||
|
|
||||||
|
progress(40);
|
||||||
|
|
||||||
if (release == null) {
|
if (release == null) {
|
||||||
if (attemptingFullInstall) {
|
if (attemptingFullInstall) {
|
||||||
@@ -45,24 +48,33 @@ namespace Squirrel
|
|||||||
return getDirectoryForRelease(updateInfo.CurrentlyInstalledVersion.Version).FullName;
|
return getDirectoryForRelease(updateInfo.CurrentlyInstalledVersion.Version).FullName;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ret = await this.ErrorIfThrows(() => installPackageToAppDir(updateInfo, release),
|
// Progress range: 40 -> 80
|
||||||
|
var ret = await this.ErrorIfThrows(() => installPackageToAppDir(updateInfo, release, x => progress(CalculateProgress(x, 40, 80))),
|
||||||
"Failed to install package to app dir");
|
"Failed to install package to app dir");
|
||||||
progress(30);
|
|
||||||
|
progress(80);
|
||||||
|
|
||||||
var currentReleases = await this.ErrorIfThrows(() => updateLocalReleasesFile(),
|
var currentReleases = await this.ErrorIfThrows(() => updateLocalReleasesFile(),
|
||||||
"Failed to update local releases file");
|
"Failed to update local releases file");
|
||||||
progress(50);
|
|
||||||
|
progress(85);
|
||||||
|
|
||||||
var newVersion = currentReleases.MaxBy(x => x.Version).First().Version;
|
var newVersion = currentReleases.MaxBy(x => x.Version).First().Version;
|
||||||
executeSelfUpdate(newVersion);
|
executeSelfUpdate(newVersion);
|
||||||
|
|
||||||
|
progress(90);
|
||||||
|
|
||||||
await this.ErrorIfThrows(() => invokePostInstall(newVersion, attemptingFullInstall, false, silentInstall),
|
await this.ErrorIfThrows(() => invokePostInstall(newVersion, attemptingFullInstall, false, silentInstall),
|
||||||
"Failed to invoke post-install");
|
"Failed to invoke post-install");
|
||||||
progress(75);
|
|
||||||
|
progress(95);
|
||||||
|
|
||||||
this.Log().Info("Starting fixPinnedExecutables");
|
this.Log().Info("Starting fixPinnedExecutables");
|
||||||
|
|
||||||
this.ErrorIfThrows(() => fixPinnedExecutables(updateInfo.FutureReleaseEntry.Version));
|
this.ErrorIfThrows(() => fixPinnedExecutables(updateInfo.FutureReleaseEntry.Version));
|
||||||
|
|
||||||
|
progress(96);
|
||||||
|
|
||||||
this.Log().Info("Fixing up tray icons");
|
this.Log().Info("Fixing up tray icons");
|
||||||
|
|
||||||
var trayFixer = new TrayStateChanger();
|
var trayFixer = new TrayStateChanger();
|
||||||
@@ -70,10 +82,12 @@ namespace Squirrel
|
|||||||
var allExes = appDir.GetFiles("*.exe").Select(x => x.Name).ToList();
|
var allExes = appDir.GetFiles("*.exe").Select(x => x.Name).ToList();
|
||||||
|
|
||||||
this.ErrorIfThrows(() => trayFixer.RemoveDeadEntries(allExes, rootAppDirectory, updateInfo.FutureReleaseEntry.Version.ToString()));
|
this.ErrorIfThrows(() => trayFixer.RemoveDeadEntries(allExes, rootAppDirectory, updateInfo.FutureReleaseEntry.Version.ToString()));
|
||||||
progress(80);
|
|
||||||
|
progress(97);
|
||||||
|
|
||||||
unshimOurselves();
|
unshimOurselves();
|
||||||
progress(85);
|
|
||||||
|
progress(98);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var currentVersion = updateInfo.CurrentlyInstalledVersion != null ?
|
var currentVersion = updateInfo.CurrentlyInstalledVersion != null ?
|
||||||
@@ -83,6 +97,7 @@ namespace Squirrel
|
|||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
this.Log().WarnException("Failed to clean dead versions, continuing anyways", ex);
|
this.Log().WarnException("Failed to clean dead versions, continuing anyways", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
progress(100);
|
progress(100);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -280,7 +295,7 @@ namespace Squirrel
|
|||||||
fixPinnedExecutables(zf.Version);
|
fixPinnedExecutables(zf.Version);
|
||||||
}
|
}
|
||||||
|
|
||||||
Task<string> installPackageToAppDir(UpdateInfo updateInfo, ReleaseEntry release)
|
Task<string> installPackageToAppDir(UpdateInfo updateInfo, ReleaseEntry release, Action<int> progressCallback)
|
||||||
{
|
{
|
||||||
return Task.Run(async () => {
|
return Task.Run(async () => {
|
||||||
var target = getDirectoryForRelease(release.Version);
|
var target = getDirectoryForRelease(release.Version);
|
||||||
@@ -297,16 +312,19 @@ namespace Squirrel
|
|||||||
await ReleasePackage.ExtractZipForInstall(
|
await ReleasePackage.ExtractZipForInstall(
|
||||||
Path.Combine(updateInfo.PackageDirectory, release.Filename),
|
Path.Combine(updateInfo.PackageDirectory, release.Filename),
|
||||||
target.FullName,
|
target.FullName,
|
||||||
rootAppDirectory);
|
rootAppDirectory,
|
||||||
|
progressCallback);
|
||||||
|
|
||||||
return target.FullName;
|
return target.FullName;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task<ReleaseEntry> createFullPackagesFromDeltas(IEnumerable<ReleaseEntry> releasesToApply, ReleaseEntry currentVersion)
|
async Task<ReleaseEntry> createFullPackagesFromDeltas(IEnumerable<ReleaseEntry> releasesToApply, ReleaseEntry currentVersion, ApplyReleasesProgress progress)
|
||||||
{
|
{
|
||||||
Contract.Requires(releasesToApply != null);
|
Contract.Requires(releasesToApply != null);
|
||||||
|
|
||||||
|
progress = progress ?? new ApplyReleasesProgress(releasesToApply.Count(), x => { });
|
||||||
|
|
||||||
// If there are no remote releases at all, bail
|
// If there are no remote releases at all, bail
|
||||||
if (!releasesToApply.Any()) {
|
if (!releasesToApply.Any()) {
|
||||||
return null;
|
return null;
|
||||||
@@ -321,6 +339,16 @@ namespace Squirrel
|
|||||||
throw new Exception("Cannot apply combinations of delta and full packages");
|
throw new Exception("Cannot apply combinations of delta and full packages");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Progress calculation is "complex" here. We need to known how many releases, and then give each release a similar amount of
|
||||||
|
// progress. For example, when applying 5 releases:
|
||||||
|
//
|
||||||
|
// release 1: 00 => 20
|
||||||
|
// release 2: 20 => 40
|
||||||
|
// release 3: 40 => 60
|
||||||
|
// release 4: 60 => 80
|
||||||
|
// release 5: 80 => 100
|
||||||
|
//
|
||||||
|
|
||||||
// Smash together our base full package and the nearest delta
|
// Smash together our base full package and the nearest delta
|
||||||
var ret = await Task.Run(() => {
|
var ret = await Task.Run(() => {
|
||||||
var basePkg = new ReleasePackage(Path.Combine(rootAppDirectory, "packages", currentVersion.Filename));
|
var basePkg = new ReleasePackage(Path.Combine(rootAppDirectory, "packages", currentVersion.Filename));
|
||||||
@@ -329,9 +357,12 @@ namespace Squirrel
|
|||||||
var deltaBuilder = new DeltaPackageBuilder(Directory.GetParent(this.rootAppDirectory).FullName);
|
var deltaBuilder = new DeltaPackageBuilder(Directory.GetParent(this.rootAppDirectory).FullName);
|
||||||
|
|
||||||
return deltaBuilder.ApplyDeltaPackage(basePkg, deltaPkg,
|
return deltaBuilder.ApplyDeltaPackage(basePkg, deltaPkg,
|
||||||
Regex.Replace(deltaPkg.InputPackageFile, @"-delta.nupkg$", ".nupkg", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant));
|
Regex.Replace(deltaPkg.InputPackageFile, @"-delta.nupkg$", ".nupkg", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant),
|
||||||
|
x => progress.ReportReleaseProgress(x));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
progress.FinishRelease();
|
||||||
|
|
||||||
if (releasesToApply.Count() == 1) {
|
if (releasesToApply.Count() == 1) {
|
||||||
return ReleaseEntry.GenerateFromFile(ret.InputPackageFile);
|
return ReleaseEntry.GenerateFromFile(ret.InputPackageFile);
|
||||||
}
|
}
|
||||||
@@ -340,7 +371,7 @@ namespace Squirrel
|
|||||||
var entry = ReleaseEntry.GenerateFromFile(fi.OpenRead(), fi.Name);
|
var entry = ReleaseEntry.GenerateFromFile(fi.OpenRead(), fi.Name);
|
||||||
|
|
||||||
// Recursively combine the rest of them
|
// Recursively combine the rest of them
|
||||||
return await createFullPackagesFromDeltas(releasesToApply.Skip(1), entry);
|
return await createFullPackagesFromDeltas(releasesToApply.Skip(1), entry, progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
void executeSelfUpdate(SemanticVersion currentVersion)
|
void executeSelfUpdate(SemanticVersion currentVersion)
|
||||||
|
|||||||
@@ -287,6 +287,27 @@ namespace Squirrel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the total percentage of a specific step that should report within a specific range.
|
||||||
|
/// <para />
|
||||||
|
/// If a step needs to report between 50 -> 75 %, this method should be used as CalculateProgress(percentage, 50, 75).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="percentageOfCurrentStep">The percentage of the current step, a value between 0 and 100.</param>
|
||||||
|
/// <param name="stepStartPercentage">The start percentage of the range the current step represents.</param>
|
||||||
|
/// <param name="stepEndPercentage">The end percentage of the range the current step represents.</param>
|
||||||
|
/// <returns>The calculated percentage that can be reported about the total progress.</returns>
|
||||||
|
internal static int CalculateProgress(int percentageOfCurrentStep, int stepStartPercentage, int stepEndPercentage)
|
||||||
|
{
|
||||||
|
// Ensure we are between 0 and 100
|
||||||
|
percentageOfCurrentStep = Math.Max(Math.Min(percentageOfCurrentStep, 100), 0);
|
||||||
|
|
||||||
|
var range = stepEndPercentage - stepStartPercentage;
|
||||||
|
var singleValue = range / 100d;
|
||||||
|
var totalPercentage = (singleValue * percentageOfCurrentStep) + stepStartPercentage;
|
||||||
|
|
||||||
|
return (int)totalPercentage;
|
||||||
|
}
|
||||||
|
|
||||||
static string getApplicationName()
|
static string getApplicationName()
|
||||||
{
|
{
|
||||||
var fi = new FileInfo(getUpdateExe());
|
var fi = new FileInfo(getUpdateExe());
|
||||||
|
|||||||
38
test/ApplyReleasesProgressTests.cs
Normal file
38
test/ApplyReleasesProgressTests.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Squirrel.Tests
|
||||||
|
{
|
||||||
|
public class ApplyReleasesProgressTests
|
||||||
|
{
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void CalculatesPercentageCorrectly()
|
||||||
|
{
|
||||||
|
// Just 1 complex situation should be enough to cover this
|
||||||
|
|
||||||
|
var percentage = 0;
|
||||||
|
var progress = new ApplyReleasesProgress(5, x => percentage = x);
|
||||||
|
|
||||||
|
// 2 releases already finished
|
||||||
|
progress.FinishRelease();
|
||||||
|
progress.FinishRelease();
|
||||||
|
|
||||||
|
// Report 40 % in current release
|
||||||
|
progress.ReportReleaseProgress(50);
|
||||||
|
|
||||||
|
// Required for callback to be invoked
|
||||||
|
await Task.Delay(50);
|
||||||
|
|
||||||
|
// 20 per release
|
||||||
|
// 10 because we are half-way the 3rd release
|
||||||
|
var expectedProgress = 20 + 20 + 10;
|
||||||
|
|
||||||
|
Assert.Equal(expectedProgress, percentage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -437,7 +437,7 @@ namespace Squirrel.Tests
|
|||||||
var deltaEntry = ReleaseEntry.GenerateFromFile(Path.Combine(tempDir, "theApp", "packages", "Squirrel.Core.1.1.0.0-delta.nupkg"));
|
var deltaEntry = ReleaseEntry.GenerateFromFile(Path.Combine(tempDir, "theApp", "packages", "Squirrel.Core.1.1.0.0-delta.nupkg"));
|
||||||
|
|
||||||
var resultObs = (Task<ReleaseEntry>)fixture.GetType().GetMethod("createFullPackagesFromDeltas", BindingFlags.NonPublic | BindingFlags.Instance)
|
var resultObs = (Task<ReleaseEntry>)fixture.GetType().GetMethod("createFullPackagesFromDeltas", BindingFlags.NonPublic | BindingFlags.Instance)
|
||||||
.Invoke(fixture, new object[] { new[] {deltaEntry}, baseEntry });
|
.Invoke(fixture, new object[] { new[] {deltaEntry}, baseEntry, null });
|
||||||
|
|
||||||
var result = await resultObs;
|
var result = await resultObs;
|
||||||
var zp = new ZipPackage(Path.Combine(tempDir, "theApp", "packages", result.Filename));
|
var zp = new ZipPackage(Path.Combine(tempDir, "theApp", "packages", result.Filename));
|
||||||
|
|||||||
@@ -331,6 +331,22 @@ namespace Squirrel.Tests
|
|||||||
Assert.Equal(expected, fixture.CurrentlyInstalledVersion(input));
|
Assert.Equal(expected, fixture.CurrentlyInstalledVersion(input));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(0, 0, 25, 0)]
|
||||||
|
[InlineData(12, 0, 25, 3)]
|
||||||
|
[InlineData(55, 0, 25, 13)]
|
||||||
|
[InlineData(100, 0, 25, 25)]
|
||||||
|
[InlineData(0, 25, 50, 25)]
|
||||||
|
[InlineData(12, 25, 50, 28)]
|
||||||
|
[InlineData(55, 25, 50, 38)]
|
||||||
|
[InlineData(100, 25, 50, 50)]
|
||||||
|
public void CalculatesPercentageCorrectly(int percentageOfCurrentStep, int stepStartPercentage, int stepEndPercentage, int expectedPercentage)
|
||||||
|
{
|
||||||
|
var percentage = UpdateManager.CalculateProgress(percentageOfCurrentStep, stepStartPercentage, stepEndPercentage);
|
||||||
|
|
||||||
|
Assert.Equal(expectedPercentage, percentage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user