mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Convert all files to file-scoped name space
This commit is contained in:
@@ -10,115 +10,114 @@ using Squirrel;
|
||||
|
||||
[assembly: AssemblyMetadata("SquirrelAwareVersion", "1")]
|
||||
|
||||
namespace LegacyTestApp
|
||||
namespace LegacyTestApp;
|
||||
|
||||
internal class Program
|
||||
{
|
||||
internal class Program
|
||||
static int Main(string[] args)
|
||||
{
|
||||
static int Main(string[] args)
|
||||
{
|
||||
#if CLOWD
|
||||
SquirrelAwareApp.HandleEvents(
|
||||
onInitialInstall: (v, t) => debugFile("args.txt", String.Join(" ", args)),
|
||||
onAppUpdate: (v, t) => debugFile("args.txt", String.Join(" ", args)),
|
||||
onAppUninstall: (v, t) => debugFile("args.txt", String.Join(" ", args)),
|
||||
onEveryRun: (v, t, f) => debugFile("args.txt", String.Join(" ", args))
|
||||
);
|
||||
SquirrelAwareApp.HandleEvents(
|
||||
onInitialInstall: (v, t) => debugFile("args.txt", String.Join(" ", args)),
|
||||
onAppUpdate: (v, t) => debugFile("args.txt", String.Join(" ", args)),
|
||||
onAppUninstall: (v, t) => debugFile("args.txt", String.Join(" ", args)),
|
||||
onEveryRun: (v, t, f) => debugFile("args.txt", String.Join(" ", args))
|
||||
);
|
||||
#elif VELOPACK
|
||||
VelopackApp.Build()
|
||||
.WithAfterInstallFastCallback(v => debugFile("args.txt", String.Join(" ", args)))
|
||||
.WithBeforeUpdateFastCallback(v => debugFile("args.txt", String.Join(" ", args)))
|
||||
.WithBeforeUninstallFastCallback(v => debugFile("args.txt", String.Join(" ", args)))
|
||||
.WithAfterUpdateFastCallback(v => debugFile("args.txt", String.Join(" ", args)))
|
||||
.Run();
|
||||
VelopackApp.Build()
|
||||
.WithAfterInstallFastCallback(v => debugFile("args.txt", String.Join(" ", args)))
|
||||
.WithBeforeUpdateFastCallback(v => debugFile("args.txt", String.Join(" ", args)))
|
||||
.WithBeforeUninstallFastCallback(v => debugFile("args.txt", String.Join(" ", args)))
|
||||
.WithAfterUpdateFastCallback(v => debugFile("args.txt", String.Join(" ", args)))
|
||||
.Run();
|
||||
#else
|
||||
SquirrelAwareApp.HandleEvents(
|
||||
onInitialInstall: v => debugFile("args.txt", String.Join(" ", args)),
|
||||
onAppUpdate: v => debugFile("args.txt", String.Join(" ", args)),
|
||||
onAppUninstall: v => debugFile("args.txt", String.Join(" ", args)),
|
||||
onFirstRun: () => debugFile("args.txt", String.Join(" ", args))
|
||||
);
|
||||
SquirrelAwareApp.HandleEvents(
|
||||
onInitialInstall: v => debugFile("args.txt", String.Join(" ", args)),
|
||||
onAppUpdate: v => debugFile("args.txt", String.Join(" ", args)),
|
||||
onAppUninstall: v => debugFile("args.txt", String.Join(" ", args)),
|
||||
onFirstRun: () => debugFile("args.txt", String.Join(" ", args))
|
||||
);
|
||||
#endif
|
||||
|
||||
try {
|
||||
try {
|
||||
#if !VELOPACK
|
||||
SquirrelLogger.Register();
|
||||
SquirrelLogger.Register();
|
||||
#endif
|
||||
|
||||
if (args.Length == 1 && args[0] == "version") {
|
||||
if (args.Length == 1 && args[0] == "version") {
|
||||
#if VELOPACK
|
||||
var um = new UpdateManager("n/a", logger: new SquirrelLogger());
|
||||
Console.WriteLine(um.CurrentVersion?.ToString() ?? "unknown_version");
|
||||
var um = new UpdateManager("n/a", logger: new SquirrelLogger());
|
||||
Console.WriteLine(um.CurrentVersion?.ToString() ?? "unknown_version");
|
||||
#else
|
||||
using var um = new UpdateManager("");
|
||||
Console.WriteLine(um.CurrentlyInstalledVersion()?.ToString() ?? "unknown_version");
|
||||
using var um = new UpdateManager("");
|
||||
Console.WriteLine(um.CurrentlyInstalledVersion()?.ToString() ?? "unknown_version");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (args.Length == 2) {
|
||||
if (args[0] == "check") {
|
||||
#if VELOPACK
|
||||
var um = new UpdateManager(args[1]);
|
||||
var info = um.CheckForUpdates();
|
||||
if (info == null || info.TargetFullRelease == null) {
|
||||
Console.WriteLine("no updates");
|
||||
return 0;
|
||||
} else {
|
||||
Console.WriteLine("update: " + info.TargetFullRelease.Version);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
using var um = new UpdateManager(args[1]);
|
||||
var info = um.CheckForUpdate().GetAwaiter().GetResult();
|
||||
if (info == null || info.ReleasesToApply == null || info.FutureReleaseEntry == null || info.ReleasesToApply.Count == 0) {
|
||||
Console.WriteLine("no updates");
|
||||
return 0;
|
||||
} else {
|
||||
Console.WriteLine("update: " + info.FutureReleaseEntry.Version);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (args[0] == "download") {
|
||||
#if VELOPACK
|
||||
var um = new UpdateManager(args[1]);
|
||||
var info = um.CheckForUpdates();
|
||||
if (info == null) return -1;
|
||||
um.DownloadUpdates(info);
|
||||
return 0;
|
||||
#else
|
||||
using var um = new UpdateManager(args[1]);
|
||||
var entry = um.UpdateApp().GetAwaiter().GetResult();
|
||||
return entry == null ? -1 : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (args[0] == "apply") {
|
||||
#if VELOPACK
|
||||
var um = new UpdateManager(args[1]);
|
||||
um.ApplyUpdatesAndRestart();
|
||||
#else
|
||||
UpdateManager.RestartApp();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (args.Length == 2) {
|
||||
if (args[0] == "check") {
|
||||
#if VELOPACK
|
||||
var um = new UpdateManager(args[1]);
|
||||
var info = um.CheckForUpdates();
|
||||
if (info == null || info.TargetFullRelease == null) {
|
||||
Console.WriteLine("no updates");
|
||||
return 0;
|
||||
} else {
|
||||
Console.WriteLine("update: " + info.TargetFullRelease.Version);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
using var um = new UpdateManager(args[1]);
|
||||
var info = um.CheckForUpdate().GetAwaiter().GetResult();
|
||||
if (info == null || info.ReleasesToApply == null || info.FutureReleaseEntry == null || info.ReleasesToApply.Count == 0) {
|
||||
Console.WriteLine("no updates");
|
||||
return 0;
|
||||
} else {
|
||||
Console.WriteLine("update: " + info.FutureReleaseEntry.Version);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (args[0] == "download") {
|
||||
#if VELOPACK
|
||||
var um = new UpdateManager(args[1]);
|
||||
var info = um.CheckForUpdates();
|
||||
if (info == null) return -1;
|
||||
um.DownloadUpdates(info);
|
||||
return 0;
|
||||
#else
|
||||
using var um = new UpdateManager(args[1]);
|
||||
var entry = um.UpdateApp().GetAwaiter().GetResult();
|
||||
return entry == null ? -1 : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (args[0] == "apply") {
|
||||
#if VELOPACK
|
||||
var um = new UpdateManager(args[1]);
|
||||
um.ApplyUpdatesAndRestart();
|
||||
#else
|
||||
UpdateManager.RestartApp();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
Console.WriteLine("exception: " + ex.ToString());
|
||||
if (Debugger.IsAttached) throw;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Console.WriteLine("Unhandled args: " + String.Join(", ", args));
|
||||
} catch (Exception ex) {
|
||||
Console.WriteLine("exception: " + ex.ToString());
|
||||
if (Debugger.IsAttached) throw;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void debugFile(string name, string message)
|
||||
{
|
||||
var path = Path.Combine(AppContext.BaseDirectory, "..", name);
|
||||
File.AppendAllText(path, message + Environment.NewLine);
|
||||
}
|
||||
Console.WriteLine("Unhandled args: " + String.Join(", ", args));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void debugFile(string name, string message)
|
||||
{
|
||||
var path = Path.Combine(AppContext.BaseDirectory, "..", name);
|
||||
File.AppendAllText(path, message + Environment.NewLine);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +1,43 @@
|
||||
using System;
|
||||
|
||||
namespace LegacyTestApp
|
||||
{
|
||||
namespace LegacyTestApp;
|
||||
|
||||
#if VELOPACK
|
||||
using Microsoft.Extensions.Logging;
|
||||
class SquirrelLogger : ILogger
|
||||
using Microsoft.Extensions.Logging;
|
||||
class SquirrelLogger : ILogger
|
||||
{
|
||||
public IDisposable BeginScope<TState>(TState state) where TState : notnull
|
||||
{
|
||||
public IDisposable BeginScope<TState>(TState state) where TState : notnull
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||
{
|
||||
Console.WriteLine(formatter(state, exception));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
#else
|
||||
class SquirrelLogger : Squirrel.SimpleSplat.ILogger
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel)
|
||||
{
|
||||
protected SquirrelLogger()
|
||||
{
|
||||
}
|
||||
|
||||
public Squirrel.SimpleSplat.LogLevel Level { get; set; }
|
||||
|
||||
public static void Register()
|
||||
{
|
||||
Squirrel.SimpleSplat.SquirrelLocator.CurrentMutable.Register(() => new SquirrelLogger(), typeof(Squirrel.SimpleSplat.ILogger));
|
||||
}
|
||||
|
||||
public void Write(string message, Squirrel.SimpleSplat.LogLevel logLevel)
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||
{
|
||||
Console.WriteLine(formatter(state, exception));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
class SquirrelLogger : Squirrel.SimpleSplat.ILogger
|
||||
{
|
||||
protected SquirrelLogger()
|
||||
{
|
||||
}
|
||||
|
||||
public Squirrel.SimpleSplat.LogLevel Level { get; set; }
|
||||
|
||||
public static void Register()
|
||||
{
|
||||
Squirrel.SimpleSplat.SquirrelLocator.CurrentMutable.Register(() => new SquirrelLogger(), typeof(Squirrel.SimpleSplat.ILogger));
|
||||
}
|
||||
|
||||
public void Write(string message, Squirrel.SimpleSplat.LogLevel logLevel)
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -7,102 +7,101 @@ using Velopack.Packaging.Exceptions;
|
||||
using Velopack.Packaging.Windows;
|
||||
using Velopack.Packaging.Windows.Commands;
|
||||
|
||||
namespace Velopack.Packaging.Tests
|
||||
namespace Velopack.Packaging.Tests;
|
||||
|
||||
public class DotnetUtilTests
|
||||
{
|
||||
public class DotnetUtilTests
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public DotnetUtilTests(ITestOutputHelper output)
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
_output = output;
|
||||
}
|
||||
|
||||
public DotnetUtilTests(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
[SkippableFact]
|
||||
public void NonDotnetBinaryPasses()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<DotnetUtilTests>();
|
||||
Assert.Null(DotnetUtil.VerifyVelopackApp(PathHelper.GetRustAsset("testapp.exe"), logger));
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void NonDotnetBinaryPasses()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<DotnetUtilTests>();
|
||||
Assert.Null(DotnetUtil.VerifyVelopackApp(PathHelper.GetRustAsset("testapp.exe"), logger));
|
||||
}
|
||||
[SkippableFact]
|
||||
public void PublishSingleFilePasses()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<DotnetUtilTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var dir);
|
||||
var sample = PathHelper.GetAvaloniaSample();
|
||||
Exe.InvokeAndThrowIfNonZero(
|
||||
"dotnet",
|
||||
new string[] { "publish", "--no-self-contained", "-r", "win-x64", "-o", dir,
|
||||
"-p:UseLocalVelopack=true", "-p:PublishSingleFile=true" },
|
||||
sample);
|
||||
|
||||
[SkippableFact]
|
||||
public void PublishSingleFilePasses()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<DotnetUtilTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var dir);
|
||||
var sample = PathHelper.GetAvaloniaSample();
|
||||
Exe.InvokeAndThrowIfNonZero(
|
||||
"dotnet",
|
||||
new string[] { "publish", "--no-self-contained", "-r", "win-x64", "-o", dir,
|
||||
"-p:UseLocalVelopack=true", "-p:PublishSingleFile=true" },
|
||||
sample);
|
||||
var path = Path.Combine(dir, "AvaloniaCrossPlat.exe");
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, DotnetUtil.VerifyVelopackApp(path, logger));
|
||||
|
||||
var path = Path.Combine(dir, "AvaloniaCrossPlat.exe");
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, DotnetUtil.VerifyVelopackApp(path, logger));
|
||||
var newPath = Path.Combine(dir, "AvaloniaCrossPlat-asd2.exe");
|
||||
File.Move(path, newPath);
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, DotnetUtil.VerifyVelopackApp(newPath, logger));
|
||||
}
|
||||
|
||||
var newPath = Path.Combine(dir, "AvaloniaCrossPlat-asd2.exe");
|
||||
File.Move(path, newPath);
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, DotnetUtil.VerifyVelopackApp(newPath, logger));
|
||||
}
|
||||
[SkippableFact]
|
||||
public void PublishDotnet6Passes()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<DotnetUtilTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var dir);
|
||||
var sample = PathHelper.GetAvaloniaSample();
|
||||
Exe.InvokeAndThrowIfNonZero(
|
||||
"dotnet",
|
||||
new string[] { "publish", "--no-self-contained", "-r", "win-x64", "-o", dir,
|
||||
"-p:UseLocalVelopack=true" },
|
||||
sample);
|
||||
|
||||
[SkippableFact]
|
||||
public void PublishDotnet6Passes()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<DotnetUtilTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var dir);
|
||||
var sample = PathHelper.GetAvaloniaSample();
|
||||
Exe.InvokeAndThrowIfNonZero(
|
||||
"dotnet",
|
||||
new string[] { "publish", "--no-self-contained", "-r", "win-x64", "-o", dir,
|
||||
"-p:UseLocalVelopack=true" },
|
||||
sample);
|
||||
var path = Path.Combine(dir, "AvaloniaCrossPlat.exe");
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, DotnetUtil.VerifyVelopackApp(path, logger));
|
||||
|
||||
var path = Path.Combine(dir, "AvaloniaCrossPlat.exe");
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, DotnetUtil.VerifyVelopackApp(path, logger));
|
||||
var newPath = Path.Combine(dir, "AvaloniaCrossPlat-asd2.exe");
|
||||
File.Move(path, newPath);
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, DotnetUtil.VerifyVelopackApp(newPath, logger));
|
||||
}
|
||||
|
||||
var newPath = Path.Combine(dir, "AvaloniaCrossPlat-asd2.exe");
|
||||
File.Move(path, newPath);
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, DotnetUtil.VerifyVelopackApp(newPath, logger));
|
||||
}
|
||||
[SkippableFact]
|
||||
public void PublishNet48Passes()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<DotnetUtilTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var dir);
|
||||
var sample = PathHelper.GetWpfSample();
|
||||
Exe.InvokeAndThrowIfNonZero(
|
||||
"dotnet",
|
||||
new string[] { "publish", "-o", dir },
|
||||
sample);
|
||||
|
||||
[SkippableFact]
|
||||
public void PublishNet48Passes()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<DotnetUtilTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var dir);
|
||||
var sample = PathHelper.GetWpfSample();
|
||||
Exe.InvokeAndThrowIfNonZero(
|
||||
"dotnet",
|
||||
new string[] { "publish", "-o", dir },
|
||||
sample);
|
||||
var path = Path.Combine(dir, "VeloWpfSample.exe");
|
||||
Assert.NotNull(DotnetUtil.VerifyVelopackApp(path, logger));
|
||||
|
||||
var path = Path.Combine(dir, "VeloWpfSample.exe");
|
||||
Assert.NotNull(DotnetUtil.VerifyVelopackApp(path, logger));
|
||||
var newPath = Path.Combine(dir, "VeloWpfSample-asd2.exe");
|
||||
File.Move(path, newPath);
|
||||
Assert.NotNull(DotnetUtil.VerifyVelopackApp(newPath, logger));
|
||||
}
|
||||
|
||||
var newPath = Path.Combine(dir, "VeloWpfSample-asd2.exe");
|
||||
File.Move(path, newPath);
|
||||
Assert.NotNull(DotnetUtil.VerifyVelopackApp(newPath, logger));
|
||||
}
|
||||
[SkippableFact]
|
||||
public void UnawareDotnetAppFails()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<DotnetUtilTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var dir);
|
||||
var sample = PathHelper.GetTestRootPath("TestApp");
|
||||
Exe.InvokeAndThrowIfNonZero(
|
||||
"dotnet",
|
||||
new string[] { "publish", "--no-self-contained", "-r", "win-x64", "-o", dir,
|
||||
"-p:NoVelopackApp=true" },
|
||||
sample);
|
||||
|
||||
[SkippableFact]
|
||||
public void UnawareDotnetAppFails()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<DotnetUtilTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var dir);
|
||||
var sample = PathHelper.GetTestRootPath("TestApp");
|
||||
Exe.InvokeAndThrowIfNonZero(
|
||||
"dotnet",
|
||||
new string[] { "publish", "--no-self-contained", "-r", "win-x64", "-o", dir,
|
||||
"-p:NoVelopackApp=true" },
|
||||
sample);
|
||||
|
||||
var path = Path.Combine(dir, "TestApp.exe");
|
||||
Assert.Throws<UserInfoException>(() => DotnetUtil.VerifyVelopackApp(path, logger));
|
||||
}
|
||||
var path = Path.Combine(dir, "TestApp.exe");
|
||||
Assert.Throws<UserInfoException>(() => DotnetUtil.VerifyVelopackApp(path, logger));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,232 +6,231 @@ using Velopack.Sources;
|
||||
using Octokit;
|
||||
using Velopack.Packaging.Exceptions;
|
||||
|
||||
namespace Velopack.Packaging.Tests
|
||||
namespace Velopack.Packaging.Tests;
|
||||
|
||||
public class GithubDeploymentTests
|
||||
{
|
||||
public class GithubDeploymentTests
|
||||
public readonly static string GITHUB_TOKEN = Environment.GetEnvironmentVariable("VELOPACK_GITHUB_TEST_TOKEN");
|
||||
public readonly static string GITHUB_REPOURL = "https://github.com/caesay/VelopackGithubUpdateTest";
|
||||
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public GithubDeploymentTests(ITestOutputHelper output)
|
||||
{
|
||||
public readonly static string GITHUB_TOKEN = Environment.GetEnvironmentVariable("VELOPACK_GITHUB_TEST_TOKEN");
|
||||
public readonly static string GITHUB_REPOURL = "https://github.com/caesay/VelopackGithubUpdateTest";
|
||||
_output = output;
|
||||
}
|
||||
|
||||
private readonly ITestOutputHelper _output;
|
||||
[SkippableFact]
|
||||
public void WillRefuseToUploadMultipleWithoutMergeArg()
|
||||
{
|
||||
Skip.If(String.IsNullOrWhiteSpace(GITHUB_TOKEN), "VELOPACK_GITHUB_TEST_TOKEN is not set.");
|
||||
using var logger = _output.BuildLoggerFor<GithubDeploymentTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var releaseDir);
|
||||
using var _2 = Utility.GetTempDirectory(out var releaseDir2);
|
||||
using var ghvar = GitHubReleaseTest.Create("nomerge", logger);
|
||||
var id = "GithubUpdateTest";
|
||||
TestApp.PackTestApp(id, $"0.0.1-{ghvar.UniqueSuffix}", "t1", releaseDir, logger);
|
||||
|
||||
public GithubDeploymentTests(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
var gh = new GitHubRepository(logger);
|
||||
var options = new GitHubUploadOptions {
|
||||
ReleaseName = ghvar.ReleaseName,
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
RepoUrl = GITHUB_REPOURL,
|
||||
Token = GITHUB_TOKEN,
|
||||
Prerelease = false,
|
||||
Publish = true,
|
||||
};
|
||||
|
||||
[SkippableFact]
|
||||
public void WillRefuseToUploadMultipleWithoutMergeArg()
|
||||
{
|
||||
Skip.If(String.IsNullOrWhiteSpace(GITHUB_TOKEN), "VELOPACK_GITHUB_TEST_TOKEN is not set.");
|
||||
using var logger = _output.BuildLoggerFor<GithubDeploymentTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var releaseDir);
|
||||
using var _2 = Utility.GetTempDirectory(out var releaseDir2);
|
||||
using var ghvar = GitHubReleaseTest.Create("nomerge", logger);
|
||||
var id = "GithubUpdateTest";
|
||||
TestApp.PackTestApp(id, $"0.0.1-{ghvar.UniqueSuffix}", "t1", releaseDir, logger);
|
||||
gh.UploadMissingAssetsAsync(options).GetAwaiterResult();
|
||||
|
||||
var gh = new GitHubRepository(logger);
|
||||
var options = new GitHubUploadOptions {
|
||||
ReleaseName = ghvar.ReleaseName,
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
RepoUrl = GITHUB_REPOURL,
|
||||
Token = GITHUB_TOKEN,
|
||||
Prerelease = false,
|
||||
Publish = true,
|
||||
};
|
||||
TestApp.PackTestApp(id, $"0.0.2-{ghvar.UniqueSuffix}", "t1", releaseDir2, logger);
|
||||
options.ReleaseDir = new DirectoryInfo(releaseDir2);
|
||||
|
||||
gh.UploadMissingAssetsAsync(options).GetAwaiterResult();
|
||||
Assert.ThrowsAny<UserInfoException>(() => gh.UploadMissingAssetsAsync(options).GetAwaiterResult());
|
||||
}
|
||||
|
||||
TestApp.PackTestApp(id, $"0.0.2-{ghvar.UniqueSuffix}", "t1", releaseDir2, logger);
|
||||
options.ReleaseDir = new DirectoryInfo(releaseDir2);
|
||||
[SkippableFact]
|
||||
public void WillNotMergeMixmatchedTag()
|
||||
{
|
||||
Skip.If(String.IsNullOrWhiteSpace(GITHUB_TOKEN), "VELOPACK_GITHUB_TEST_TOKEN is not set.");
|
||||
using var logger = _output.BuildLoggerFor<GithubDeploymentTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var releaseDir);
|
||||
using var _2 = Utility.GetTempDirectory(out var releaseDir2);
|
||||
using var ghvar = GitHubReleaseTest.Create("mixmatched", logger);
|
||||
var id = "GithubUpdateTest";
|
||||
TestApp.PackTestApp(id, $"0.0.1-{ghvar.UniqueSuffix}", "t1", releaseDir, logger);
|
||||
|
||||
Assert.ThrowsAny<UserInfoException>(() => gh.UploadMissingAssetsAsync(options).GetAwaiterResult());
|
||||
}
|
||||
var gh = new GitHubRepository(logger);
|
||||
var options = new GitHubUploadOptions {
|
||||
ReleaseName = ghvar.ReleaseName,
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
RepoUrl = GITHUB_REPOURL,
|
||||
Token = GITHUB_TOKEN,
|
||||
Prerelease = false,
|
||||
Publish = true,
|
||||
Merge = true,
|
||||
};
|
||||
|
||||
[SkippableFact]
|
||||
public void WillNotMergeMixmatchedTag()
|
||||
{
|
||||
Skip.If(String.IsNullOrWhiteSpace(GITHUB_TOKEN), "VELOPACK_GITHUB_TEST_TOKEN is not set.");
|
||||
using var logger = _output.BuildLoggerFor<GithubDeploymentTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var releaseDir);
|
||||
using var _2 = Utility.GetTempDirectory(out var releaseDir2);
|
||||
using var ghvar = GitHubReleaseTest.Create("mixmatched", logger);
|
||||
var id = "GithubUpdateTest";
|
||||
TestApp.PackTestApp(id, $"0.0.1-{ghvar.UniqueSuffix}", "t1", releaseDir, logger);
|
||||
gh.UploadMissingAssetsAsync(options).GetAwaiterResult();
|
||||
|
||||
var gh = new GitHubRepository(logger);
|
||||
var options = new GitHubUploadOptions {
|
||||
ReleaseName = ghvar.ReleaseName,
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
RepoUrl = GITHUB_REPOURL,
|
||||
Token = GITHUB_TOKEN,
|
||||
Prerelease = false,
|
||||
Publish = true,
|
||||
Merge = true,
|
||||
};
|
||||
TestApp.PackTestApp(id, $"0.0.2-{ghvar.UniqueSuffix}", "t1", releaseDir2, logger);
|
||||
options.ReleaseDir = new DirectoryInfo(releaseDir2);
|
||||
|
||||
gh.UploadMissingAssetsAsync(options).GetAwaiterResult();
|
||||
Assert.ThrowsAny<UserInfoException>(() => gh.UploadMissingAssetsAsync(options).GetAwaiterResult());
|
||||
}
|
||||
|
||||
TestApp.PackTestApp(id, $"0.0.2-{ghvar.UniqueSuffix}", "t1", releaseDir2, logger);
|
||||
options.ReleaseDir = new DirectoryInfo(releaseDir2);
|
||||
[SkippableFact]
|
||||
public void WillMergeGithubReleases()
|
||||
{
|
||||
Skip.If(String.IsNullOrWhiteSpace(GITHUB_TOKEN), "VELOPACK_GITHUB_TEST_TOKEN is not set.");
|
||||
using var logger = _output.BuildLoggerFor<GithubDeploymentTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var releaseDir);
|
||||
using var _2 = Utility.GetTempDirectory(out var releaseDir2);
|
||||
using var ghvar = GitHubReleaseTest.Create("yesmerge", logger);
|
||||
var id = "GithubUpdateTest";
|
||||
TestApp.PackTestApp(id, $"0.0.1-{ghvar.UniqueSuffix}", "t1", releaseDir, logger);
|
||||
|
||||
Assert.ThrowsAny<UserInfoException>(() => gh.UploadMissingAssetsAsync(options).GetAwaiterResult());
|
||||
}
|
||||
var gh = new GitHubRepository(logger);
|
||||
var options = new GitHubUploadOptions {
|
||||
ReleaseName = ghvar.ReleaseName,
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
RepoUrl = GITHUB_REPOURL,
|
||||
Token = GITHUB_TOKEN,
|
||||
TagName = $"0.0.1-{ghvar.UniqueSuffix}",
|
||||
Prerelease = false,
|
||||
Publish = true,
|
||||
Merge = true,
|
||||
};
|
||||
|
||||
[SkippableFact]
|
||||
public void WillMergeGithubReleases()
|
||||
{
|
||||
Skip.If(String.IsNullOrWhiteSpace(GITHUB_TOKEN), "VELOPACK_GITHUB_TEST_TOKEN is not set.");
|
||||
using var logger = _output.BuildLoggerFor<GithubDeploymentTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var releaseDir);
|
||||
using var _2 = Utility.GetTempDirectory(out var releaseDir2);
|
||||
using var ghvar = GitHubReleaseTest.Create("yesmerge", logger);
|
||||
var id = "GithubUpdateTest";
|
||||
TestApp.PackTestApp(id, $"0.0.1-{ghvar.UniqueSuffix}", "t1", releaseDir, logger);
|
||||
gh.UploadMissingAssetsAsync(options).GetAwaiterResult();
|
||||
|
||||
var gh = new GitHubRepository(logger);
|
||||
var options = new GitHubUploadOptions {
|
||||
ReleaseName = ghvar.ReleaseName,
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
RepoUrl = GITHUB_REPOURL,
|
||||
Token = GITHUB_TOKEN,
|
||||
TagName = $"0.0.1-{ghvar.UniqueSuffix}",
|
||||
Prerelease = false,
|
||||
Publish = true,
|
||||
Merge = true,
|
||||
};
|
||||
TestApp.PackTestApp(id, $"0.0.1-{ghvar.UniqueSuffix}", "t1", releaseDir2, logger, channel: "experimental");
|
||||
options.ReleaseDir = new DirectoryInfo(releaseDir2);
|
||||
options.Channel = "experimental";
|
||||
|
||||
gh.UploadMissingAssetsAsync(options).GetAwaiterResult();
|
||||
gh.UploadMissingAssetsAsync(options).GetAwaiterResult();
|
||||
}
|
||||
|
||||
TestApp.PackTestApp(id, $"0.0.1-{ghvar.UniqueSuffix}", "t1", releaseDir2, logger, channel: "experimental");
|
||||
options.ReleaseDir = new DirectoryInfo(releaseDir2);
|
||||
options.Channel = "experimental";
|
||||
[SkippableFact]
|
||||
public void CanDeployAndUpdateFromGithub()
|
||||
{
|
||||
Skip.If(String.IsNullOrWhiteSpace(GITHUB_TOKEN), "VELOPACK_GITHUB_TEST_TOKEN is not set.");
|
||||
using var logger = _output.BuildLoggerFor<GithubDeploymentTests>();
|
||||
var id = "GithubUpdateTest";
|
||||
using var _1 = Utility.GetTempDirectory(out var releaseDir);
|
||||
var (repoOwner, repoName) = GitHubRepository.GetOwnerAndRepo(GITHUB_REPOURL);
|
||||
using var ghvar = GitHubReleaseTest.Create("integration", logger);
|
||||
var releaseName = ghvar.ReleaseName;
|
||||
var uniqueSuffix = ghvar.UniqueSuffix;
|
||||
var client = ghvar.Client;
|
||||
|
||||
gh.UploadMissingAssetsAsync(options).GetAwaiterResult();
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void CanDeployAndUpdateFromGithub()
|
||||
{
|
||||
Skip.If(String.IsNullOrWhiteSpace(GITHUB_TOKEN), "VELOPACK_GITHUB_TEST_TOKEN is not set.");
|
||||
using var logger = _output.BuildLoggerFor<GithubDeploymentTests>();
|
||||
var id = "GithubUpdateTest";
|
||||
using var _1 = Utility.GetTempDirectory(out var releaseDir);
|
||||
var (repoOwner, repoName) = GitHubRepository.GetOwnerAndRepo(GITHUB_REPOURL);
|
||||
using var ghvar = GitHubReleaseTest.Create("integration", logger);
|
||||
var releaseName = ghvar.ReleaseName;
|
||||
var uniqueSuffix = ghvar.UniqueSuffix;
|
||||
var client = ghvar.Client;
|
||||
|
||||
// create releases
|
||||
var notesPath = Path.Combine(releaseDir, "NOTES");
|
||||
var notesContent = $"""
|
||||
// create releases
|
||||
var notesPath = Path.Combine(releaseDir, "NOTES");
|
||||
var notesContent = $"""
|
||||
# Release {releaseName}
|
||||
This is just a _test_!
|
||||
""";
|
||||
File.WriteAllText(notesPath, notesContent);
|
||||
File.WriteAllText(notesPath, notesContent);
|
||||
|
||||
if (String.IsNullOrEmpty(GITHUB_TOKEN))
|
||||
throw new Exception("VELOPACK_GITHUB_TEST_TOKEN is not set.");
|
||||
if (String.IsNullOrEmpty(GITHUB_TOKEN))
|
||||
throw new Exception("VELOPACK_GITHUB_TEST_TOKEN is not set.");
|
||||
|
||||
var newVer = $"{VelopackRuntimeInfo.VelopackNugetVersion}";
|
||||
TestApp.PackTestApp(id, $"0.0.1", "t1", releaseDir, logger, notesPath, channel: uniqueSuffix);
|
||||
TestApp.PackTestApp(id, newVer, "t2", releaseDir, logger, notesPath, channel: uniqueSuffix);
|
||||
var newVer = $"{VelopackRuntimeInfo.VelopackNugetVersion}";
|
||||
TestApp.PackTestApp(id, $"0.0.1", "t1", releaseDir, logger, notesPath, channel: uniqueSuffix);
|
||||
TestApp.PackTestApp(id, newVer, "t2", releaseDir, logger, notesPath, channel: uniqueSuffix);
|
||||
|
||||
// deploy
|
||||
var gh = new GitHubRepository(logger);
|
||||
var options = new GitHubUploadOptions {
|
||||
ReleaseName = releaseName,
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
RepoUrl = GITHUB_REPOURL,
|
||||
Token = GITHUB_TOKEN,
|
||||
Prerelease = false,
|
||||
Publish = true,
|
||||
Channel = uniqueSuffix,
|
||||
};
|
||||
gh.UploadMissingAssetsAsync(options).GetAwaiterResult();
|
||||
// deploy
|
||||
var gh = new GitHubRepository(logger);
|
||||
var options = new GitHubUploadOptions {
|
||||
ReleaseName = releaseName,
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
RepoUrl = GITHUB_REPOURL,
|
||||
Token = GITHUB_TOKEN,
|
||||
Prerelease = false,
|
||||
Publish = true,
|
||||
Channel = uniqueSuffix,
|
||||
};
|
||||
gh.UploadMissingAssetsAsync(options).GetAwaiterResult();
|
||||
|
||||
// check
|
||||
var newRelease = client.Repository.Release.GetAll(repoOwner, repoName).GetAwaiterResult().Single(s => s.Name == releaseName);
|
||||
Assert.False(newRelease.Draft);
|
||||
Assert.Equal(notesContent.Trim().ReplaceLineEndings("\n"), newRelease.Body.Trim());
|
||||
// check
|
||||
var newRelease = client.Repository.Release.GetAll(repoOwner, repoName).GetAwaiterResult().Single(s => s.Name == releaseName);
|
||||
Assert.False(newRelease.Draft);
|
||||
Assert.Equal(notesContent.Trim().ReplaceLineEndings("\n"), newRelease.Body.Trim());
|
||||
|
||||
// update
|
||||
var source = new GithubSource(GITHUB_REPOURL, GITHUB_TOKEN, false);
|
||||
var releases = source.GetReleaseFeed(channel: uniqueSuffix, logger: logger).GetAwaiterResult();
|
||||
// update
|
||||
var source = new GithubSource(GITHUB_REPOURL, GITHUB_TOKEN, false);
|
||||
var releases = source.GetReleaseFeed(channel: uniqueSuffix, logger: logger).GetAwaiterResult();
|
||||
|
||||
var ghrel = releases.Assets.Select(r => (GithubSource.GitBaseAsset) r).ToArray();
|
||||
foreach (var g in ghrel) {
|
||||
logger.Info($"Found asset: ({g.Release.Name}) {g.FileName}");
|
||||
}
|
||||
|
||||
var assetsInThisRelease = ghrel.Where(r => r.Release.Name == releaseName).ToArray();
|
||||
|
||||
Assert.Equal(2, assetsInThisRelease.Length);
|
||||
foreach (var r in assetsInThisRelease) {
|
||||
Assert.Equal(releaseName, r.Release.Name);
|
||||
Assert.Equal(id, r.PackageId);
|
||||
Assert.Equal(newVer, r.Version.ToNormalizedString());
|
||||
}
|
||||
|
||||
using var _2 = Utility.GetTempDirectory(out var releaseDirNew);
|
||||
gh.DownloadLatestFullPackageAsync(new GitHubDownloadOptions {
|
||||
Token = GITHUB_TOKEN,
|
||||
RepoUrl = GITHUB_REPOURL,
|
||||
ReleaseDir = new DirectoryInfo(releaseDirNew),
|
||||
Channel = uniqueSuffix,
|
||||
}).GetAwaiterResult();
|
||||
|
||||
var filename = $"{id}-{newVer}-{uniqueSuffix}-full.nupkg";
|
||||
Assert.True(File.Exists(Path.Combine(releaseDirNew, filename)));
|
||||
var ghrel = releases.Assets.Select(r => (GithubSource.GitBaseAsset) r).ToArray();
|
||||
foreach (var g in ghrel) {
|
||||
logger.Info($"Found asset: ({g.Release.Name}) {g.FileName}");
|
||||
}
|
||||
|
||||
private class GitHubReleaseTest : IDisposable
|
||||
{
|
||||
public string ReleaseName { get; }
|
||||
public string UniqueSuffix { get; }
|
||||
public GitHubClient Client { get; }
|
||||
public ILogger Logger { get; }
|
||||
var assetsInThisRelease = ghrel.Where(r => r.Release.Name == releaseName).ToArray();
|
||||
|
||||
public GitHubReleaseTest(string releaseName, string uniqueSuffix, GitHubClient client, ILogger logger)
|
||||
{
|
||||
ReleaseName = releaseName;
|
||||
UniqueSuffix = uniqueSuffix;
|
||||
Client = client;
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
public static GitHubReleaseTest Create(string method, ILogger logger)
|
||||
{
|
||||
var ci = !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("CI"));
|
||||
var uniqueSuffix = (ci ? "ci-" : "local-") + VelopackRuntimeInfo.SystemOs.GetOsShortName();
|
||||
var releaseName = $"{VelopackRuntimeInfo.VelopackNugetVersion}-{uniqueSuffix}-{method}";
|
||||
var (repoOwner, repoName) = GitHubRepository.GetOwnerAndRepo(GITHUB_REPOURL);
|
||||
|
||||
// delete release if already exists
|
||||
var client = new GitHubClient(new ProductHeaderValue("Velopack")) {
|
||||
Credentials = new Credentials(GITHUB_TOKEN)
|
||||
};
|
||||
var existingRelease = client.Repository.Release.GetAll(repoOwner, repoName).GetAwaiterResult().SingleOrDefault(s => s.Name == releaseName);
|
||||
if (existingRelease != null) {
|
||||
client.Repository.Release.Delete(repoOwner, repoName, existingRelease.Id).GetAwaiterResult();
|
||||
logger.Info("Deleted existing release: " + releaseName);
|
||||
}
|
||||
return new GitHubReleaseTest(releaseName, uniqueSuffix, client, logger);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var (repoOwner, repoName) = GitHubRepository.GetOwnerAndRepo(GITHUB_REPOURL);
|
||||
var finalRelease = Client.Repository.Release.GetAll(repoOwner, repoName).GetAwaiterResult().SingleOrDefault(s => s.Name == ReleaseName);
|
||||
if (finalRelease != null) {
|
||||
Client.Repository.Release.Delete(repoOwner, repoName, finalRelease.Id).GetAwaiterResult();
|
||||
Logger.Info($"Deleted final release '{ReleaseName}'");
|
||||
}
|
||||
}
|
||||
Assert.Equal(2, assetsInThisRelease.Length);
|
||||
foreach (var r in assetsInThisRelease) {
|
||||
Assert.Equal(releaseName, r.Release.Name);
|
||||
Assert.Equal(id, r.PackageId);
|
||||
Assert.Equal(newVer, r.Version.ToNormalizedString());
|
||||
}
|
||||
|
||||
using var _2 = Utility.GetTempDirectory(out var releaseDirNew);
|
||||
gh.DownloadLatestFullPackageAsync(new GitHubDownloadOptions {
|
||||
Token = GITHUB_TOKEN,
|
||||
RepoUrl = GITHUB_REPOURL,
|
||||
ReleaseDir = new DirectoryInfo(releaseDirNew),
|
||||
Channel = uniqueSuffix,
|
||||
}).GetAwaiterResult();
|
||||
|
||||
var filename = $"{id}-{newVer}-{uniqueSuffix}-full.nupkg";
|
||||
Assert.True(File.Exists(Path.Combine(releaseDirNew, filename)));
|
||||
}
|
||||
|
||||
private class GitHubReleaseTest : IDisposable
|
||||
{
|
||||
public string ReleaseName { get; }
|
||||
public string UniqueSuffix { get; }
|
||||
public GitHubClient Client { get; }
|
||||
public ILogger Logger { get; }
|
||||
|
||||
public GitHubReleaseTest(string releaseName, string uniqueSuffix, GitHubClient client, ILogger logger)
|
||||
{
|
||||
ReleaseName = releaseName;
|
||||
UniqueSuffix = uniqueSuffix;
|
||||
Client = client;
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
public static GitHubReleaseTest Create(string method, ILogger logger)
|
||||
{
|
||||
var ci = !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("CI"));
|
||||
var uniqueSuffix = (ci ? "ci-" : "local-") + VelopackRuntimeInfo.SystemOs.GetOsShortName();
|
||||
var releaseName = $"{VelopackRuntimeInfo.VelopackNugetVersion}-{uniqueSuffix}-{method}";
|
||||
var (repoOwner, repoName) = GitHubRepository.GetOwnerAndRepo(GITHUB_REPOURL);
|
||||
|
||||
// delete release if already exists
|
||||
var client = new GitHubClient(new ProductHeaderValue("Velopack")) {
|
||||
Credentials = new Credentials(GITHUB_TOKEN)
|
||||
};
|
||||
var existingRelease = client.Repository.Release.GetAll(repoOwner, repoName).GetAwaiterResult().SingleOrDefault(s => s.Name == releaseName);
|
||||
if (existingRelease != null) {
|
||||
client.Repository.Release.Delete(repoOwner, repoName, existingRelease.Id).GetAwaiterResult();
|
||||
logger.Info("Deleted existing release: " + releaseName);
|
||||
}
|
||||
return new GitHubReleaseTest(releaseName, uniqueSuffix, client, logger);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var (repoOwner, repoName) = GitHubRepository.GetOwnerAndRepo(GITHUB_REPOURL);
|
||||
var finalRelease = Client.Repository.Release.GetAll(repoOwner, repoName).GetAwaiterResult().SingleOrDefault(s => s.Name == ReleaseName);
|
||||
if (finalRelease != null) {
|
||||
Client.Repository.Release.Delete(repoOwner, repoName, finalRelease.Id).GetAwaiterResult();
|
||||
Logger.Info($"Deleted final release '{ReleaseName}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
|
||||
[assembly: TestFramework("Velopack.Packaging.Tests.TestsInit", "Velopack.Packaging.Tests")]
|
||||
|
||||
namespace Velopack.Packaging.Tests
|
||||
namespace Velopack.Packaging.Tests;
|
||||
|
||||
public class TestsInit : XunitTestFramework
|
||||
{
|
||||
public class TestsInit : XunitTestFramework
|
||||
public TestsInit(IMessageSink messageSink)
|
||||
: base(messageSink)
|
||||
{
|
||||
public TestsInit(IMessageSink messageSink)
|
||||
: base(messageSink)
|
||||
{
|
||||
HelperFile.AddSearchPath(PathHelper.GetRustBuildOutputDir());
|
||||
HelperFile.AddSearchPath(PathHelper.GetVendorLibDir());
|
||||
}
|
||||
HelperFile.AddSearchPath(PathHelper.GetRustBuildOutputDir());
|
||||
HelperFile.AddSearchPath(PathHelper.GetVendorLibDir());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,80 +8,79 @@ using Velopack.Deployment;
|
||||
using Velopack.Packaging.Exceptions;
|
||||
using Velopack.Sources;
|
||||
|
||||
namespace Velopack.Packaging.Tests
|
||||
namespace Velopack.Packaging.Tests;
|
||||
|
||||
public class S3DeploymentTests
|
||||
{
|
||||
public class S3DeploymentTests
|
||||
public readonly static string B2_KEYID = "0035016844a4188000000000a";
|
||||
public readonly static string B2_SECRET = Environment.GetEnvironmentVariable("VELOPACK_B2_TEST_TOKEN");
|
||||
public readonly static string B2_BUCKET = "velopack-testing";
|
||||
public readonly static string B2_ENDPOINT = "s3.eu-central-003.backblazeb2.com";
|
||||
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public S3DeploymentTests(ITestOutputHelper output)
|
||||
{
|
||||
public readonly static string B2_KEYID = "0035016844a4188000000000a";
|
||||
public readonly static string B2_SECRET = Environment.GetEnvironmentVariable("VELOPACK_B2_TEST_TOKEN");
|
||||
public readonly static string B2_BUCKET = "velopack-testing";
|
||||
public readonly static string B2_ENDPOINT = "s3.eu-central-003.backblazeb2.com";
|
||||
_output = output;
|
||||
}
|
||||
|
||||
private readonly ITestOutputHelper _output;
|
||||
[SkippableFact]
|
||||
public void CanDeployToBackBlazeB2()
|
||||
{
|
||||
Skip.If(String.IsNullOrWhiteSpace(B2_SECRET), "VELOPACK_B2_TEST_TOKEN is not set.");
|
||||
using var logger = _output.BuildLoggerFor<S3DeploymentTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var releaseDir);
|
||||
|
||||
public S3DeploymentTests(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
string channel = String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("CI"))
|
||||
? VelopackRuntimeInfo.SystemOs.GetOsShortName()
|
||||
: "ci-" + VelopackRuntimeInfo.SystemOs.GetOsShortName();
|
||||
|
||||
[SkippableFact]
|
||||
public void CanDeployToBackBlazeB2()
|
||||
{
|
||||
Skip.If(String.IsNullOrWhiteSpace(B2_SECRET), "VELOPACK_B2_TEST_TOKEN is not set.");
|
||||
using var logger = _output.BuildLoggerFor<S3DeploymentTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var releaseDir);
|
||||
|
||||
string channel = String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("CI"))
|
||||
? VelopackRuntimeInfo.SystemOs.GetOsShortName()
|
||||
: "ci-" + VelopackRuntimeInfo.SystemOs.GetOsShortName();
|
||||
|
||||
// get latest version, and increment patch by one
|
||||
var updateUrl = $"https://{B2_BUCKET}.{B2_ENDPOINT}/";
|
||||
var source = new SimpleWebSource(updateUrl);
|
||||
VelopackAssetFeed feed = new VelopackAssetFeed();
|
||||
try {
|
||||
feed = source.GetReleaseFeed(logger, channel).GetAwaiterResult();
|
||||
} catch (Exception ex) {
|
||||
logger.Warn(ex, "Failed to fetch release feed.");
|
||||
}
|
||||
var latest = feed.Assets.Where(a => a.Version != null && a.Type == VelopackAssetType.Full)
|
||||
.OrderByDescending(a => a.Version)
|
||||
.FirstOrDefault();
|
||||
var newVer = latest != null ? new SemanticVersion(1, 0, latest.Version.Patch + 1) : new SemanticVersion(1, 0, 0);
|
||||
|
||||
// create repo
|
||||
var repo = new S3Repository(logger);
|
||||
var options = new S3UploadOptions {
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
Bucket = B2_BUCKET,
|
||||
Channel = channel,
|
||||
Endpoint = "https://" + B2_ENDPOINT,
|
||||
KeyId = B2_KEYID,
|
||||
Secret = B2_SECRET,
|
||||
KeepMaxReleases = 4,
|
||||
};
|
||||
|
||||
// download latest version and create delta
|
||||
repo.DownloadLatestFullPackageAsync(options).GetAwaiterResult();
|
||||
var id = "B2TestApp";
|
||||
TestApp.PackTestApp(id, newVer.ToFullString(), $"b2-{DateTime.UtcNow.ToLongDateString()}", releaseDir, logger, channel: channel);
|
||||
if (latest != null) {
|
||||
// check delta was created
|
||||
Assert.True(Directory.EnumerateFiles(releaseDir, "*-delta.nupkg").Any(), "No delta package was created.");
|
||||
}
|
||||
|
||||
// upload new files
|
||||
repo.UploadMissingAssetsAsync(options).GetAwaiterResult();
|
||||
|
||||
// verify that new version has been uploaded
|
||||
// get latest version, and increment patch by one
|
||||
var updateUrl = $"https://{B2_BUCKET}.{B2_ENDPOINT}/";
|
||||
var source = new SimpleWebSource(updateUrl);
|
||||
VelopackAssetFeed feed = new VelopackAssetFeed();
|
||||
try {
|
||||
feed = source.GetReleaseFeed(logger, channel).GetAwaiterResult();
|
||||
latest = feed.Assets.Where(a => a.Version != null && a.Type == VelopackAssetType.Full)
|
||||
.OrderByDescending(a => a.Version)
|
||||
.FirstOrDefault();
|
||||
|
||||
Assert.True(latest != null, "No latest version found.");
|
||||
Assert.Equal(newVer, latest.Version);
|
||||
Assert.True(feed.Assets.Count(x => x.Type == VelopackAssetType.Full) <= options.KeepMaxReleases, "Too many releases were kept.");
|
||||
} catch (Exception ex) {
|
||||
logger.Warn(ex, "Failed to fetch release feed.");
|
||||
}
|
||||
var latest = feed.Assets.Where(a => a.Version != null && a.Type == VelopackAssetType.Full)
|
||||
.OrderByDescending(a => a.Version)
|
||||
.FirstOrDefault();
|
||||
var newVer = latest != null ? new SemanticVersion(1, 0, latest.Version.Patch + 1) : new SemanticVersion(1, 0, 0);
|
||||
|
||||
// create repo
|
||||
var repo = new S3Repository(logger);
|
||||
var options = new S3UploadOptions {
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
Bucket = B2_BUCKET,
|
||||
Channel = channel,
|
||||
Endpoint = "https://" + B2_ENDPOINT,
|
||||
KeyId = B2_KEYID,
|
||||
Secret = B2_SECRET,
|
||||
KeepMaxReleases = 4,
|
||||
};
|
||||
|
||||
// download latest version and create delta
|
||||
repo.DownloadLatestFullPackageAsync(options).GetAwaiterResult();
|
||||
var id = "B2TestApp";
|
||||
TestApp.PackTestApp(id, newVer.ToFullString(), $"b2-{DateTime.UtcNow.ToLongDateString()}", releaseDir, logger, channel: channel);
|
||||
if (latest != null) {
|
||||
// check delta was created
|
||||
Assert.True(Directory.EnumerateFiles(releaseDir, "*-delta.nupkg").Any(), "No delta package was created.");
|
||||
}
|
||||
|
||||
// upload new files
|
||||
repo.UploadMissingAssetsAsync(options).GetAwaiterResult();
|
||||
|
||||
// verify that new version has been uploaded
|
||||
feed = source.GetReleaseFeed(logger, channel).GetAwaiterResult();
|
||||
latest = feed.Assets.Where(a => a.Version != null && a.Type == VelopackAssetType.Full)
|
||||
.OrderByDescending(a => a.Version)
|
||||
.FirstOrDefault();
|
||||
|
||||
Assert.True(latest != null, "No latest version found.");
|
||||
Assert.Equal(newVer, latest.Version);
|
||||
Assert.True(feed.Assets.Count(x => x.Type == VelopackAssetType.Full) <= options.KeepMaxReleases, "Too many releases were kept.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,83 +8,82 @@ using Velopack.Packaging.Unix.Commands;
|
||||
using Velopack.Packaging.Windows.Commands;
|
||||
using Velopack.Vpk.Logging;
|
||||
|
||||
namespace Velopack.Packaging.Tests
|
||||
namespace Velopack.Packaging.Tests;
|
||||
|
||||
public static class TestApp
|
||||
{
|
||||
public static class TestApp
|
||||
public static void PackTestApp(string id, string version, string testString, string releaseDir, ILogger logger,
|
||||
string releaseNotes = null, string channel = null)
|
||||
{
|
||||
public static void PackTestApp(string id, string version, string testString, string releaseDir, ILogger logger,
|
||||
string releaseNotes = null, string channel = null)
|
||||
{
|
||||
var projDir = PathHelper.GetTestRootPath("TestApp");
|
||||
var testStringFile = Path.Combine(projDir, "Const.cs");
|
||||
var oldText = File.ReadAllText(testStringFile);
|
||||
var projDir = PathHelper.GetTestRootPath("TestApp");
|
||||
var testStringFile = Path.Combine(projDir, "Const.cs");
|
||||
var oldText = File.ReadAllText(testStringFile);
|
||||
|
||||
try {
|
||||
File.WriteAllText(testStringFile, $"class Const {{ public const string TEST_STRING = \"{testString}\"; }}");
|
||||
try {
|
||||
File.WriteAllText(testStringFile, $"class Const {{ public const string TEST_STRING = \"{testString}\"; }}");
|
||||
|
||||
var args = new string[] { "publish", "--no-self-contained", "-c", "Release", "-r", VelopackRuntimeInfo.SystemRid, "-o", "publish" };
|
||||
var args = new string[] { "publish", "--no-self-contained", "-c", "Release", "-r", VelopackRuntimeInfo.SystemRid, "-o", "publish" };
|
||||
|
||||
var psi = new ProcessStartInfo("dotnet");
|
||||
psi.WorkingDirectory = projDir;
|
||||
psi.AppendArgumentListSafe(args, out var debug);
|
||||
var psi = new ProcessStartInfo("dotnet");
|
||||
psi.WorkingDirectory = projDir;
|
||||
psi.AppendArgumentListSafe(args, out var debug);
|
||||
|
||||
logger.Info($"TEST: Running {psi.FileName} {debug}");
|
||||
logger.Info($"TEST: Running {psi.FileName} {debug}");
|
||||
|
||||
using var p = Process.Start(psi);
|
||||
p.WaitForExit();
|
||||
using var p = Process.Start(psi);
|
||||
p.WaitForExit();
|
||||
|
||||
if (p.ExitCode != 0)
|
||||
throw new Exception($"dotnet publish failed with exit code {p.ExitCode}");
|
||||
if (p.ExitCode != 0)
|
||||
throw new Exception($"dotnet publish failed with exit code {p.ExitCode}");
|
||||
|
||||
var console = new BasicConsole(logger, new DefaultPromptValueFactory(false));
|
||||
var console = new BasicConsole(logger, new DefaultPromptValueFactory(false));
|
||||
|
||||
if (VelopackRuntimeInfo.IsWindows) {
|
||||
var options = new WindowsPackOptions {
|
||||
EntryExecutableName = "TestApp.exe",
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
PackId = id,
|
||||
TargetRuntime = RID.Parse(VelopackRuntimeInfo.SystemOs.GetOsShortName()),
|
||||
PackVersion = version,
|
||||
PackDirectory = Path.Combine(projDir, "publish"),
|
||||
ReleaseNotes = releaseNotes,
|
||||
Channel = channel,
|
||||
};
|
||||
var runner = new WindowsPackCommandRunner(logger, console);
|
||||
runner.Run(options).GetAwaiterResult();
|
||||
} else if (VelopackRuntimeInfo.IsOSX) {
|
||||
var options = new OsxPackOptions {
|
||||
EntryExecutableName = "TestApp",
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
PackId = id,
|
||||
Icon = Path.Combine(PathHelper.GetProjectDir(), "examples", "AvaloniaCrossPlat", "Velopack.icns"),
|
||||
TargetRuntime = RID.Parse(VelopackRuntimeInfo.SystemOs.GetOsShortName()),
|
||||
PackVersion = version,
|
||||
PackDirectory = Path.Combine(projDir, "publish"),
|
||||
ReleaseNotes = releaseNotes,
|
||||
Channel = channel,
|
||||
};
|
||||
var runner = new OsxPackCommandRunner(logger, console);
|
||||
runner.Run(options).GetAwaiterResult();
|
||||
} else if (VelopackRuntimeInfo.IsLinux) {
|
||||
var options = new LinuxPackOptions {
|
||||
EntryExecutableName = "TestApp",
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
PackId = id,
|
||||
Icon = Path.Combine(PathHelper.GetProjectDir(), "examples", "AvaloniaCrossPlat", "Velopack.png"),
|
||||
TargetRuntime = RID.Parse(VelopackRuntimeInfo.SystemOs.GetOsShortName()),
|
||||
PackVersion = version,
|
||||
PackDirectory = Path.Combine(projDir, "publish"),
|
||||
ReleaseNotes = releaseNotes,
|
||||
Channel = channel,
|
||||
};
|
||||
var runner = new LinuxPackCommandRunner(logger, console);
|
||||
runner.Run(options).GetAwaiterResult();
|
||||
} else {
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
} finally {
|
||||
File.WriteAllText(testStringFile, oldText);
|
||||
if (VelopackRuntimeInfo.IsWindows) {
|
||||
var options = new WindowsPackOptions {
|
||||
EntryExecutableName = "TestApp.exe",
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
PackId = id,
|
||||
TargetRuntime = RID.Parse(VelopackRuntimeInfo.SystemOs.GetOsShortName()),
|
||||
PackVersion = version,
|
||||
PackDirectory = Path.Combine(projDir, "publish"),
|
||||
ReleaseNotes = releaseNotes,
|
||||
Channel = channel,
|
||||
};
|
||||
var runner = new WindowsPackCommandRunner(logger, console);
|
||||
runner.Run(options).GetAwaiterResult();
|
||||
} else if (VelopackRuntimeInfo.IsOSX) {
|
||||
var options = new OsxPackOptions {
|
||||
EntryExecutableName = "TestApp",
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
PackId = id,
|
||||
Icon = Path.Combine(PathHelper.GetProjectDir(), "examples", "AvaloniaCrossPlat", "Velopack.icns"),
|
||||
TargetRuntime = RID.Parse(VelopackRuntimeInfo.SystemOs.GetOsShortName()),
|
||||
PackVersion = version,
|
||||
PackDirectory = Path.Combine(projDir, "publish"),
|
||||
ReleaseNotes = releaseNotes,
|
||||
Channel = channel,
|
||||
};
|
||||
var runner = new OsxPackCommandRunner(logger, console);
|
||||
runner.Run(options).GetAwaiterResult();
|
||||
} else if (VelopackRuntimeInfo.IsLinux) {
|
||||
var options = new LinuxPackOptions {
|
||||
EntryExecutableName = "TestApp",
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
PackId = id,
|
||||
Icon = Path.Combine(PathHelper.GetProjectDir(), "examples", "AvaloniaCrossPlat", "Velopack.png"),
|
||||
TargetRuntime = RID.Parse(VelopackRuntimeInfo.SystemOs.GetOsShortName()),
|
||||
PackVersion = version,
|
||||
PackDirectory = Path.Combine(projDir, "publish"),
|
||||
ReleaseNotes = releaseNotes,
|
||||
Channel = channel,
|
||||
};
|
||||
var runner = new LinuxPackCommandRunner(logger, console);
|
||||
runner.Run(options).GetAwaiterResult();
|
||||
} else {
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
} finally {
|
||||
File.WriteAllText(testStringFile, oldText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,278 +2,277 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Velopack.Tests.OldSquirrel
|
||||
namespace Velopack.Tests.OldSquirrel;
|
||||
|
||||
[DataContract]
|
||||
public class ReleaseEntry
|
||||
{
|
||||
[DataContract]
|
||||
public class ReleaseEntry
|
||||
[DataMember] public string SHA1 { get; protected set; }
|
||||
[DataMember] public string BaseUrl { get; protected set; }
|
||||
[DataMember] public string Filename { get; protected set; }
|
||||
[DataMember] public string Query { get; protected set; }
|
||||
[DataMember] public long Filesize { get; protected set; }
|
||||
[DataMember] public bool IsDelta { get; protected set; }
|
||||
[DataMember] public float? StagingPercentage { get; protected set; }
|
||||
|
||||
protected ReleaseEntry(string sha1, string filename, long filesize, bool isDelta, string baseUrl = null, string query = null, float? stagingPercentage = null)
|
||||
{
|
||||
[DataMember] public string SHA1 { get; protected set; }
|
||||
[DataMember] public string BaseUrl { get; protected set; }
|
||||
[DataMember] public string Filename { get; protected set; }
|
||||
[DataMember] public string Query { get; protected set; }
|
||||
[DataMember] public long Filesize { get; protected set; }
|
||||
[DataMember] public bool IsDelta { get; protected set; }
|
||||
[DataMember] public float? StagingPercentage { get; protected set; }
|
||||
Contract.Requires(sha1 != null && sha1.Length == 40);
|
||||
Contract.Requires(filename != null);
|
||||
Contract.Requires(filename.Contains(Path.DirectorySeparatorChar) == false);
|
||||
Contract.Requires(filesize > 0);
|
||||
|
||||
protected ReleaseEntry(string sha1, string filename, long filesize, bool isDelta, string baseUrl = null, string query = null, float? stagingPercentage = null)
|
||||
{
|
||||
Contract.Requires(sha1 != null && sha1.Length == 40);
|
||||
Contract.Requires(filename != null);
|
||||
Contract.Requires(filename.Contains(Path.DirectorySeparatorChar) == false);
|
||||
Contract.Requires(filesize > 0);
|
||||
|
||||
SHA1 = sha1; BaseUrl = baseUrl; Filename = filename; Query = query; Filesize = filesize; IsDelta = isDelta; StagingPercentage = stagingPercentage;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string EntryAsString {
|
||||
get {
|
||||
if (StagingPercentage != null) {
|
||||
return String.Format("{0} {1}{2} {3} # {4}", SHA1, BaseUrl, Filename, Filesize, stagingPercentageAsString(StagingPercentage.Value));
|
||||
} else {
|
||||
return String.Format("{0} {1}{2} {3}", SHA1, BaseUrl, Filename, Filesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public SemanticVersion Version { get { return Filename.ToSemanticVersion(); } }
|
||||
|
||||
static readonly Regex packageNameRegex = new Regex(@"^([\w-]+)-\d+\..+\.nupkg$");
|
||||
[IgnoreDataMember]
|
||||
public string PackageName {
|
||||
get {
|
||||
var match = packageNameRegex.Match(Filename);
|
||||
return match.Success ?
|
||||
match.Groups[1].Value :
|
||||
Filename.Substring(0, Filename.IndexOfAny(new[] { '-', '.' }));
|
||||
}
|
||||
}
|
||||
|
||||
//public string GetReleaseNotes(string packageDirectory)
|
||||
//{
|
||||
// var zp = new ZipPackage(Path.Combine(packageDirectory, Filename));
|
||||
// var t = zp.Id;
|
||||
|
||||
// if (String.IsNullOrWhiteSpace(zp.ReleaseNotes)) {
|
||||
// throw new Exception(String.Format("Invalid 'ReleaseNotes' value in nuspec file at '{0}'", Path.Combine(packageDirectory, Filename)));
|
||||
// }
|
||||
|
||||
// return zp.ReleaseNotes;
|
||||
//}
|
||||
|
||||
//public Uri GetIconUrl(string packageDirectory)
|
||||
//{
|
||||
// var zp = new ZipPackage(Path.Combine(packageDirectory, Filename));
|
||||
// return zp.IconUrl;
|
||||
//}
|
||||
|
||||
static readonly Regex entryRegex = new Regex(@"^([0-9a-fA-F]{40})\s+(\S+)\s+(\d+)[\r]*$");
|
||||
static readonly Regex commentRegex = new Regex(@"\s*#.*$");
|
||||
static readonly Regex stagingRegex = new Regex(@"#\s+(\d{1,3})%$");
|
||||
public static ReleaseEntry ParseReleaseEntry(string entry)
|
||||
{
|
||||
Contract.Requires(entry != null);
|
||||
|
||||
float? stagingPercentage = null;
|
||||
var m = stagingRegex.Match(entry);
|
||||
if (m != null && m.Success) {
|
||||
stagingPercentage = Single.Parse(m.Groups[1].Value) / 100.0f;
|
||||
}
|
||||
|
||||
entry = commentRegex.Replace(entry, "");
|
||||
if (String.IsNullOrWhiteSpace(entry)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
m = entryRegex.Match(entry);
|
||||
if (!m.Success) {
|
||||
throw new Exception("Invalid release entry: " + entry);
|
||||
}
|
||||
|
||||
if (m.Groups.Count != 4) {
|
||||
throw new Exception("Invalid release entry: " + entry);
|
||||
}
|
||||
|
||||
string filename = m.Groups[2].Value;
|
||||
|
||||
// Split the base URL and the filename if an URI is provided,
|
||||
// throws if a path is provided
|
||||
string baseUrl = null;
|
||||
string query = null;
|
||||
|
||||
if (Utility.IsHttpUrl(filename)) {
|
||||
var uri = new Uri(filename);
|
||||
var path = uri.LocalPath;
|
||||
var authority = uri.GetLeftPart(UriPartial.Authority);
|
||||
|
||||
if (String.IsNullOrEmpty(path) || String.IsNullOrEmpty(authority)) {
|
||||
throw new Exception("Invalid URL");
|
||||
}
|
||||
|
||||
var indexOfLastPathSeparator = path.LastIndexOf("/") + 1;
|
||||
baseUrl = authority + path.Substring(0, indexOfLastPathSeparator);
|
||||
filename = path.Substring(indexOfLastPathSeparator);
|
||||
|
||||
if (!String.IsNullOrEmpty(uri.Query)) {
|
||||
query = uri.Query;
|
||||
}
|
||||
}
|
||||
|
||||
if (filename.IndexOfAny(Path.GetInvalidFileNameChars()) > -1) {
|
||||
throw new Exception("Filename can either be an absolute HTTP[s] URL, *or* a file name");
|
||||
}
|
||||
|
||||
long size = Int64.Parse(m.Groups[3].Value);
|
||||
bool isDelta = filenameIsDeltaFile(filename);
|
||||
|
||||
return new ReleaseEntry(m.Groups[1].Value, filename, size, isDelta, baseUrl, query, stagingPercentage);
|
||||
}
|
||||
|
||||
public bool IsStagingMatch(Guid? userId)
|
||||
{
|
||||
// A "Staging match" is when a user falls into the affirmative
|
||||
// bucket - i.e. if the staging is at 10%, this user is the one out
|
||||
// of ten case.
|
||||
if (!StagingPercentage.HasValue) return true;
|
||||
if (!userId.HasValue) return false;
|
||||
|
||||
uint val = BitConverter.ToUInt32(userId.Value.ToByteArray(), 12);
|
||||
|
||||
double percentage = ((double) val / (double) UInt32.MaxValue);
|
||||
return percentage < StagingPercentage.Value;
|
||||
}
|
||||
|
||||
public static IEnumerable<ReleaseEntry> ParseReleaseFile(string fileContents)
|
||||
{
|
||||
if (String.IsNullOrEmpty(fileContents)) {
|
||||
return new ReleaseEntry[0];
|
||||
}
|
||||
|
||||
//fileContents = Utility.RemoveByteOrderMarkerIfPresent(fileContents);
|
||||
|
||||
var ret = fileContents.Split('\n')
|
||||
.Where(x => !String.IsNullOrWhiteSpace(x))
|
||||
.Select(ParseReleaseEntry)
|
||||
.Where(x => x != null)
|
||||
.ToArray();
|
||||
|
||||
return ret.Any(x => x == null) ? null : ret;
|
||||
}
|
||||
|
||||
public static IEnumerable<ReleaseEntry> ParseReleaseFileAndApplyStaging(string fileContents, Guid? userToken)
|
||||
{
|
||||
if (String.IsNullOrEmpty(fileContents)) {
|
||||
return new ReleaseEntry[0];
|
||||
}
|
||||
|
||||
//fileContents = Utility.RemoveByteOrderMarkerIfPresent(fileContents);
|
||||
|
||||
var ret = fileContents.Split('\n')
|
||||
.Where(x => !String.IsNullOrWhiteSpace(x))
|
||||
.Select(ParseReleaseEntry)
|
||||
.Where(x => x != null && x.IsStagingMatch(userToken))
|
||||
.ToArray();
|
||||
|
||||
return ret.Any(x => x == null) ? null : ret;
|
||||
}
|
||||
|
||||
|
||||
//public static void WriteReleaseFile(IEnumerable<ReleaseEntry> releaseEntries, Stream stream)
|
||||
//{
|
||||
// Contract.Requires(releaseEntries != null && releaseEntries.Any());
|
||||
// Contract.Requires(stream != null);
|
||||
|
||||
// using (var sw = new StreamWriter(stream, Encoding.UTF8)) {
|
||||
// sw.Write(String.Join("\n", releaseEntries
|
||||
// .OrderBy(x => x.Version)
|
||||
// .ThenByDescending(x => x.IsDelta)
|
||||
// .Select(x => x.EntryAsString)));
|
||||
// }
|
||||
//}
|
||||
|
||||
//public static void WriteReleaseFile(IEnumerable<ReleaseEntry> releaseEntries, string path)
|
||||
//{
|
||||
// Contract.Requires(releaseEntries != null && releaseEntries.Any());
|
||||
// Contract.Requires(!String.IsNullOrEmpty(path));
|
||||
|
||||
// using (var f = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None)) {
|
||||
// WriteReleaseFile(releaseEntries, f);
|
||||
// }
|
||||
//}
|
||||
|
||||
//public static ReleaseEntry GenerateFromFile(Stream file, string filename, string baseUrl = null)
|
||||
//{
|
||||
// Contract.Requires(file != null && file.CanRead);
|
||||
// Contract.Requires(!String.IsNullOrEmpty(filename));
|
||||
|
||||
// var hash = Utility.CalculateStreamSHA1(file);
|
||||
// return new ReleaseEntry(hash, filename, file.Length, filenameIsDeltaFile(filename), baseUrl);
|
||||
//}
|
||||
|
||||
//public static ReleaseEntry GenerateFromFile(string path, string baseUrl = null)
|
||||
//{
|
||||
// using (var inf = File.OpenRead(path)) {
|
||||
// return GenerateFromFile(inf, Path.GetFileName(path), baseUrl);
|
||||
// }
|
||||
//}
|
||||
|
||||
//public static List<ReleaseEntry> BuildReleasesFile(string releasePackagesDir)
|
||||
//{
|
||||
// var packagesDir = new DirectoryInfo(releasePackagesDir);
|
||||
|
||||
// // Generate release entries for all of the local packages
|
||||
// var entriesQueue = new ConcurrentQueue<ReleaseEntry>();
|
||||
// Parallel.ForEach(packagesDir.GetFiles("*.nupkg"), x => {
|
||||
// using (var file = x.OpenRead()) {
|
||||
// entriesQueue.Enqueue(GenerateFromFile(file, x.Name));
|
||||
// }
|
||||
// });
|
||||
|
||||
// // Write the new RELEASES file to a temp file then move it into
|
||||
// // place
|
||||
// var entries = entriesQueue.ToList();
|
||||
// var tempFile = default(string);
|
||||
// Utility.WithTempFile(out tempFile, releasePackagesDir);
|
||||
|
||||
// try {
|
||||
// using (var of = File.OpenWrite(tempFile)) {
|
||||
// if (entries.Count > 0) WriteReleaseFile(entries, of);
|
||||
// }
|
||||
|
||||
// var target = Path.Combine(packagesDir.FullName, "RELEASES");
|
||||
// if (File.Exists(target)) {
|
||||
// File.Delete(target);
|
||||
// }
|
||||
|
||||
// File.Move(tempFile, target);
|
||||
// } finally {
|
||||
// if (File.Exists(tempFile)) Utility.DeleteFileHarder(tempFile, true);
|
||||
// }
|
||||
|
||||
// return entries;
|
||||
//}
|
||||
|
||||
static string stagingPercentageAsString(float percentage)
|
||||
{
|
||||
return String.Format("{0:F0}%", percentage * 100.0);
|
||||
}
|
||||
|
||||
static bool filenameIsDeltaFile(string filename)
|
||||
{
|
||||
return filename.EndsWith("-delta.nupkg", StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
//public static ReleasePackage GetPreviousRelease(IEnumerable<ReleaseEntry> releaseEntries, IReleasePackage package, string targetDir)
|
||||
//{
|
||||
// if (releaseEntries == null || !releaseEntries.Any()) return null;
|
||||
|
||||
// return releaseEntries
|
||||
// .Where(x => x.IsDelta == false)
|
||||
// .Where(x => x.Version < package.ToSemanticVersion())
|
||||
// .OrderByDescending(x => x.Version)
|
||||
// .Select(x => new ReleasePackage(Path.Combine(targetDir, x.Filename), true))
|
||||
// .FirstOrDefault();
|
||||
//}
|
||||
SHA1 = sha1; BaseUrl = baseUrl; Filename = filename; Query = query; Filesize = filesize; IsDelta = isDelta; StagingPercentage = stagingPercentage;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string EntryAsString {
|
||||
get {
|
||||
if (StagingPercentage != null) {
|
||||
return String.Format("{0} {1}{2} {3} # {4}", SHA1, BaseUrl, Filename, Filesize, stagingPercentageAsString(StagingPercentage.Value));
|
||||
} else {
|
||||
return String.Format("{0} {1}{2} {3}", SHA1, BaseUrl, Filename, Filesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public SemanticVersion Version { get { return Filename.ToSemanticVersion(); } }
|
||||
|
||||
static readonly Regex packageNameRegex = new Regex(@"^([\w-]+)-\d+\..+\.nupkg$");
|
||||
[IgnoreDataMember]
|
||||
public string PackageName {
|
||||
get {
|
||||
var match = packageNameRegex.Match(Filename);
|
||||
return match.Success ?
|
||||
match.Groups[1].Value :
|
||||
Filename.Substring(0, Filename.IndexOfAny(new[] { '-', '.' }));
|
||||
}
|
||||
}
|
||||
|
||||
//public string GetReleaseNotes(string packageDirectory)
|
||||
//{
|
||||
// var zp = new ZipPackage(Path.Combine(packageDirectory, Filename));
|
||||
// var t = zp.Id;
|
||||
|
||||
// if (String.IsNullOrWhiteSpace(zp.ReleaseNotes)) {
|
||||
// throw new Exception(String.Format("Invalid 'ReleaseNotes' value in nuspec file at '{0}'", Path.Combine(packageDirectory, Filename)));
|
||||
// }
|
||||
|
||||
// return zp.ReleaseNotes;
|
||||
//}
|
||||
|
||||
//public Uri GetIconUrl(string packageDirectory)
|
||||
//{
|
||||
// var zp = new ZipPackage(Path.Combine(packageDirectory, Filename));
|
||||
// return zp.IconUrl;
|
||||
//}
|
||||
|
||||
static readonly Regex entryRegex = new Regex(@"^([0-9a-fA-F]{40})\s+(\S+)\s+(\d+)[\r]*$");
|
||||
static readonly Regex commentRegex = new Regex(@"\s*#.*$");
|
||||
static readonly Regex stagingRegex = new Regex(@"#\s+(\d{1,3})%$");
|
||||
public static ReleaseEntry ParseReleaseEntry(string entry)
|
||||
{
|
||||
Contract.Requires(entry != null);
|
||||
|
||||
float? stagingPercentage = null;
|
||||
var m = stagingRegex.Match(entry);
|
||||
if (m != null && m.Success) {
|
||||
stagingPercentage = Single.Parse(m.Groups[1].Value) / 100.0f;
|
||||
}
|
||||
|
||||
entry = commentRegex.Replace(entry, "");
|
||||
if (String.IsNullOrWhiteSpace(entry)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
m = entryRegex.Match(entry);
|
||||
if (!m.Success) {
|
||||
throw new Exception("Invalid release entry: " + entry);
|
||||
}
|
||||
|
||||
if (m.Groups.Count != 4) {
|
||||
throw new Exception("Invalid release entry: " + entry);
|
||||
}
|
||||
|
||||
string filename = m.Groups[2].Value;
|
||||
|
||||
// Split the base URL and the filename if an URI is provided,
|
||||
// throws if a path is provided
|
||||
string baseUrl = null;
|
||||
string query = null;
|
||||
|
||||
if (Utility.IsHttpUrl(filename)) {
|
||||
var uri = new Uri(filename);
|
||||
var path = uri.LocalPath;
|
||||
var authority = uri.GetLeftPart(UriPartial.Authority);
|
||||
|
||||
if (String.IsNullOrEmpty(path) || String.IsNullOrEmpty(authority)) {
|
||||
throw new Exception("Invalid URL");
|
||||
}
|
||||
|
||||
var indexOfLastPathSeparator = path.LastIndexOf("/") + 1;
|
||||
baseUrl = authority + path.Substring(0, indexOfLastPathSeparator);
|
||||
filename = path.Substring(indexOfLastPathSeparator);
|
||||
|
||||
if (!String.IsNullOrEmpty(uri.Query)) {
|
||||
query = uri.Query;
|
||||
}
|
||||
}
|
||||
|
||||
if (filename.IndexOfAny(Path.GetInvalidFileNameChars()) > -1) {
|
||||
throw new Exception("Filename can either be an absolute HTTP[s] URL, *or* a file name");
|
||||
}
|
||||
|
||||
long size = Int64.Parse(m.Groups[3].Value);
|
||||
bool isDelta = filenameIsDeltaFile(filename);
|
||||
|
||||
return new ReleaseEntry(m.Groups[1].Value, filename, size, isDelta, baseUrl, query, stagingPercentage);
|
||||
}
|
||||
|
||||
public bool IsStagingMatch(Guid? userId)
|
||||
{
|
||||
// A "Staging match" is when a user falls into the affirmative
|
||||
// bucket - i.e. if the staging is at 10%, this user is the one out
|
||||
// of ten case.
|
||||
if (!StagingPercentage.HasValue) return true;
|
||||
if (!userId.HasValue) return false;
|
||||
|
||||
uint val = BitConverter.ToUInt32(userId.Value.ToByteArray(), 12);
|
||||
|
||||
double percentage = ((double) val / (double) UInt32.MaxValue);
|
||||
return percentage < StagingPercentage.Value;
|
||||
}
|
||||
|
||||
public static IEnumerable<ReleaseEntry> ParseReleaseFile(string fileContents)
|
||||
{
|
||||
if (String.IsNullOrEmpty(fileContents)) {
|
||||
return new ReleaseEntry[0];
|
||||
}
|
||||
|
||||
//fileContents = Utility.RemoveByteOrderMarkerIfPresent(fileContents);
|
||||
|
||||
var ret = fileContents.Split('\n')
|
||||
.Where(x => !String.IsNullOrWhiteSpace(x))
|
||||
.Select(ParseReleaseEntry)
|
||||
.Where(x => x != null)
|
||||
.ToArray();
|
||||
|
||||
return ret.Any(x => x == null) ? null : ret;
|
||||
}
|
||||
|
||||
public static IEnumerable<ReleaseEntry> ParseReleaseFileAndApplyStaging(string fileContents, Guid? userToken)
|
||||
{
|
||||
if (String.IsNullOrEmpty(fileContents)) {
|
||||
return new ReleaseEntry[0];
|
||||
}
|
||||
|
||||
//fileContents = Utility.RemoveByteOrderMarkerIfPresent(fileContents);
|
||||
|
||||
var ret = fileContents.Split('\n')
|
||||
.Where(x => !String.IsNullOrWhiteSpace(x))
|
||||
.Select(ParseReleaseEntry)
|
||||
.Where(x => x != null && x.IsStagingMatch(userToken))
|
||||
.ToArray();
|
||||
|
||||
return ret.Any(x => x == null) ? null : ret;
|
||||
}
|
||||
|
||||
|
||||
//public static void WriteReleaseFile(IEnumerable<ReleaseEntry> releaseEntries, Stream stream)
|
||||
//{
|
||||
// Contract.Requires(releaseEntries != null && releaseEntries.Any());
|
||||
// Contract.Requires(stream != null);
|
||||
|
||||
// using (var sw = new StreamWriter(stream, Encoding.UTF8)) {
|
||||
// sw.Write(String.Join("\n", releaseEntries
|
||||
// .OrderBy(x => x.Version)
|
||||
// .ThenByDescending(x => x.IsDelta)
|
||||
// .Select(x => x.EntryAsString)));
|
||||
// }
|
||||
//}
|
||||
|
||||
//public static void WriteReleaseFile(IEnumerable<ReleaseEntry> releaseEntries, string path)
|
||||
//{
|
||||
// Contract.Requires(releaseEntries != null && releaseEntries.Any());
|
||||
// Contract.Requires(!String.IsNullOrEmpty(path));
|
||||
|
||||
// using (var f = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None)) {
|
||||
// WriteReleaseFile(releaseEntries, f);
|
||||
// }
|
||||
//}
|
||||
|
||||
//public static ReleaseEntry GenerateFromFile(Stream file, string filename, string baseUrl = null)
|
||||
//{
|
||||
// Contract.Requires(file != null && file.CanRead);
|
||||
// Contract.Requires(!String.IsNullOrEmpty(filename));
|
||||
|
||||
// var hash = Utility.CalculateStreamSHA1(file);
|
||||
// return new ReleaseEntry(hash, filename, file.Length, filenameIsDeltaFile(filename), baseUrl);
|
||||
//}
|
||||
|
||||
//public static ReleaseEntry GenerateFromFile(string path, string baseUrl = null)
|
||||
//{
|
||||
// using (var inf = File.OpenRead(path)) {
|
||||
// return GenerateFromFile(inf, Path.GetFileName(path), baseUrl);
|
||||
// }
|
||||
//}
|
||||
|
||||
//public static List<ReleaseEntry> BuildReleasesFile(string releasePackagesDir)
|
||||
//{
|
||||
// var packagesDir = new DirectoryInfo(releasePackagesDir);
|
||||
|
||||
// // Generate release entries for all of the local packages
|
||||
// var entriesQueue = new ConcurrentQueue<ReleaseEntry>();
|
||||
// Parallel.ForEach(packagesDir.GetFiles("*.nupkg"), x => {
|
||||
// using (var file = x.OpenRead()) {
|
||||
// entriesQueue.Enqueue(GenerateFromFile(file, x.Name));
|
||||
// }
|
||||
// });
|
||||
|
||||
// // Write the new RELEASES file to a temp file then move it into
|
||||
// // place
|
||||
// var entries = entriesQueue.ToList();
|
||||
// var tempFile = default(string);
|
||||
// Utility.WithTempFile(out tempFile, releasePackagesDir);
|
||||
|
||||
// try {
|
||||
// using (var of = File.OpenWrite(tempFile)) {
|
||||
// if (entries.Count > 0) WriteReleaseFile(entries, of);
|
||||
// }
|
||||
|
||||
// var target = Path.Combine(packagesDir.FullName, "RELEASES");
|
||||
// if (File.Exists(target)) {
|
||||
// File.Delete(target);
|
||||
// }
|
||||
|
||||
// File.Move(tempFile, target);
|
||||
// } finally {
|
||||
// if (File.Exists(tempFile)) Utility.DeleteFileHarder(tempFile, true);
|
||||
// }
|
||||
|
||||
// return entries;
|
||||
//}
|
||||
|
||||
static string stagingPercentageAsString(float percentage)
|
||||
{
|
||||
return String.Format("{0:F0}%", percentage * 100.0);
|
||||
}
|
||||
|
||||
static bool filenameIsDeltaFile(string filename)
|
||||
{
|
||||
return filename.EndsWith("-delta.nupkg", StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
//public static ReleasePackage GetPreviousRelease(IEnumerable<ReleaseEntry> releaseEntries, IReleasePackage package, string targetDir)
|
||||
//{
|
||||
// if (releaseEntries == null || !releaseEntries.Any()) return null;
|
||||
|
||||
// return releaseEntries
|
||||
// .Where(x => x.IsDelta == false)
|
||||
// .Where(x => x.Version < package.ToSemanticVersion())
|
||||
// .OrderByDescending(x => x.Version)
|
||||
// .Select(x => new ReleasePackage(Path.Combine(targetDir, x.Filename), true))
|
||||
// .FirstOrDefault();
|
||||
//}
|
||||
}
|
||||
@@ -1,22 +1,21 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Velopack.Tests.OldSquirrel
|
||||
namespace Velopack.Tests.OldSquirrel;
|
||||
|
||||
public static class VersionExtensions
|
||||
{
|
||||
public static class VersionExtensions
|
||||
static readonly Regex _suffixRegex = new Regex(@"(-full|-delta)?\.nupkg$", RegexOptions.Compiled);
|
||||
static readonly Regex _versionRegex = new Regex(@"\d+(\.\d+){0,3}(-[A-Za-z][0-9A-Za-z-]*)?$", RegexOptions.Compiled);
|
||||
|
||||
//public static SemanticVersion ToSemanticVersion(this IReleasePackage package)
|
||||
//{
|
||||
// return package.InputPackageFile.ToSemanticVersion();
|
||||
//}
|
||||
|
||||
public static SemanticVersion ToSemanticVersion(this string fileName)
|
||||
{
|
||||
static readonly Regex _suffixRegex = new Regex(@"(-full|-delta)?\.nupkg$", RegexOptions.Compiled);
|
||||
static readonly Regex _versionRegex = new Regex(@"\d+(\.\d+){0,3}(-[A-Za-z][0-9A-Za-z-]*)?$", RegexOptions.Compiled);
|
||||
|
||||
//public static SemanticVersion ToSemanticVersion(this IReleasePackage package)
|
||||
//{
|
||||
// return package.InputPackageFile.ToSemanticVersion();
|
||||
//}
|
||||
|
||||
public static SemanticVersion ToSemanticVersion(this string fileName)
|
||||
{
|
||||
var name = _suffixRegex.Replace(fileName, "");
|
||||
var version = _versionRegex.Match(name).Value;
|
||||
return new SemanticVersion(version);
|
||||
}
|
||||
var name = _suffixRegex.Replace(fileName, "");
|
||||
var version = _versionRegex.Match(name).Value;
|
||||
return new SemanticVersion(version);
|
||||
}
|
||||
}
|
||||
@@ -1,302 +1,301 @@
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Velopack.Tests.OldSquirrel
|
||||
namespace Velopack.Tests.OldSquirrel;
|
||||
|
||||
/// <summary>
|
||||
/// A hybrid implementation of SemVer that supports semantic versioning as described at http://semver.org while not strictly enforcing it to
|
||||
/// allow older 4-digit versioning schemes to continue working.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed class SemanticVersion : IComparable, IComparable<SemanticVersion>, IEquatable<SemanticVersion>
|
||||
{
|
||||
/// <summary>
|
||||
/// A hybrid implementation of SemVer that supports semantic versioning as described at http://semver.org while not strictly enforcing it to
|
||||
/// allow older 4-digit versioning schemes to continue working.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed class SemanticVersion : IComparable, IComparable<SemanticVersion>, IEquatable<SemanticVersion>
|
||||
private const RegexOptions _flags = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture;
|
||||
private static readonly Regex _semanticVersionRegex = new Regex(@"^(?<Version>\d+(\s*\.\s*\d+){0,3})(?<Release>-[a-z][0-9a-z-]*)?$", _flags);
|
||||
private static readonly Regex _strictSemanticVersionRegex = new Regex(@"^(?<Version>\d+(\.\d+){2})(?<Release>-[a-z][0-9a-z-]*)?$", _flags);
|
||||
private static readonly Regex _preReleaseVersionRegex = new Regex(@"(?<PreReleaseString>[a-z]+)(?<PreReleaseNumber>[0-9]+)$", _flags);
|
||||
private readonly string _originalString;
|
||||
|
||||
public SemanticVersion(string version)
|
||||
: this(Parse(version))
|
||||
{
|
||||
private const RegexOptions _flags = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture;
|
||||
private static readonly Regex _semanticVersionRegex = new Regex(@"^(?<Version>\d+(\s*\.\s*\d+){0,3})(?<Release>-[a-z][0-9a-z-]*)?$", _flags);
|
||||
private static readonly Regex _strictSemanticVersionRegex = new Regex(@"^(?<Version>\d+(\.\d+){2})(?<Release>-[a-z][0-9a-z-]*)?$", _flags);
|
||||
private static readonly Regex _preReleaseVersionRegex = new Regex(@"(?<PreReleaseString>[a-z]+)(?<PreReleaseNumber>[0-9]+)$", _flags);
|
||||
private readonly string _originalString;
|
||||
// The constructor normalizes the version string so that it we do not need to normalize it every time we need to operate on it.
|
||||
// The original string represents the original form in which the version is represented to be used when printing.
|
||||
_originalString = version;
|
||||
}
|
||||
|
||||
public SemanticVersion(string version)
|
||||
: this(Parse(version))
|
||||
{
|
||||
// The constructor normalizes the version string so that it we do not need to normalize it every time we need to operate on it.
|
||||
// The original string represents the original form in which the version is represented to be used when printing.
|
||||
_originalString = version;
|
||||
public SemanticVersion(int major, int minor, int build, int revision)
|
||||
: this(new Version(major, minor, build, revision))
|
||||
{
|
||||
}
|
||||
|
||||
public SemanticVersion(int major, int minor, int build, string specialVersion)
|
||||
: this(new Version(major, minor, build), specialVersion)
|
||||
{
|
||||
}
|
||||
|
||||
public SemanticVersion(Version version)
|
||||
: this(version, String.Empty)
|
||||
{
|
||||
}
|
||||
|
||||
public SemanticVersion(Version version, string specialVersion)
|
||||
: this(version, specialVersion, null)
|
||||
{
|
||||
}
|
||||
|
||||
private SemanticVersion(Version version, string specialVersion, string originalString)
|
||||
{
|
||||
if (version == null) {
|
||||
throw new ArgumentNullException("version");
|
||||
}
|
||||
Version = NormalizeVersionValue(version);
|
||||
SpecialVersion = specialVersion ?? String.Empty;
|
||||
_originalString = String.IsNullOrEmpty(originalString) ? version.ToString() + (!String.IsNullOrEmpty(specialVersion) ? '-' + specialVersion : null) : originalString;
|
||||
}
|
||||
|
||||
public SemanticVersion(int major, int minor, int build, int revision)
|
||||
: this(new Version(major, minor, build, revision))
|
||||
{
|
||||
}
|
||||
internal SemanticVersion(SemanticVersion semVer)
|
||||
{
|
||||
_originalString = semVer.ToString();
|
||||
Version = semVer.Version;
|
||||
SpecialVersion = semVer.SpecialVersion;
|
||||
}
|
||||
|
||||
public SemanticVersion(int major, int minor, int build, string specialVersion)
|
||||
: this(new Version(major, minor, build), specialVersion)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the normalized version portion.
|
||||
/// </summary>
|
||||
public Version Version {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public SemanticVersion(Version version)
|
||||
: this(version, String.Empty)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the optional special version.
|
||||
/// </summary>
|
||||
public string SpecialVersion {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public SemanticVersion(Version version, string specialVersion)
|
||||
: this(version, specialVersion, null)
|
||||
{
|
||||
}
|
||||
public string[] GetOriginalVersionComponents()
|
||||
{
|
||||
if (!String.IsNullOrEmpty(_originalString)) {
|
||||
string original;
|
||||
|
||||
private SemanticVersion(Version version, string specialVersion, string originalString)
|
||||
{
|
||||
if (version == null) {
|
||||
throw new ArgumentNullException("version");
|
||||
}
|
||||
Version = NormalizeVersionValue(version);
|
||||
SpecialVersion = specialVersion ?? String.Empty;
|
||||
_originalString = String.IsNullOrEmpty(originalString) ? version.ToString() + (!String.IsNullOrEmpty(specialVersion) ? '-' + specialVersion : null) : originalString;
|
||||
}
|
||||
|
||||
internal SemanticVersion(SemanticVersion semVer)
|
||||
{
|
||||
_originalString = semVer.ToString();
|
||||
Version = semVer.Version;
|
||||
SpecialVersion = semVer.SpecialVersion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the normalized version portion.
|
||||
/// </summary>
|
||||
public Version Version {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the optional special version.
|
||||
/// </summary>
|
||||
public string SpecialVersion {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public string[] GetOriginalVersionComponents()
|
||||
{
|
||||
if (!String.IsNullOrEmpty(_originalString)) {
|
||||
string original;
|
||||
|
||||
// search the start of the SpecialVersion part, if any
|
||||
int dashIndex = _originalString.IndexOf('-');
|
||||
if (dashIndex != -1) {
|
||||
// remove the SpecialVersion part
|
||||
original = _originalString.Substring(0, dashIndex);
|
||||
} else {
|
||||
original = _originalString;
|
||||
}
|
||||
|
||||
return SplitAndPadVersionString(original);
|
||||
// search the start of the SpecialVersion part, if any
|
||||
int dashIndex = _originalString.IndexOf('-');
|
||||
if (dashIndex != -1) {
|
||||
// remove the SpecialVersion part
|
||||
original = _originalString.Substring(0, dashIndex);
|
||||
} else {
|
||||
return SplitAndPadVersionString(Version.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static string[] SplitAndPadVersionString(string version)
|
||||
{
|
||||
string[] a = version.Split('.');
|
||||
if (a.Length == 4) {
|
||||
return a;
|
||||
} else {
|
||||
// if 'a' has less than 4 elements, we pad the '0' at the end
|
||||
// to make it 4.
|
||||
var b = new string[4] { "0", "0", "0", "0" };
|
||||
Array.Copy(a, 0, b, 0, a.Length);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a version string using loose semantic versioning rules that allows 2-4 version components followed by an optional special version.
|
||||
/// </summary>
|
||||
public static SemanticVersion Parse(string version)
|
||||
{
|
||||
if (String.IsNullOrEmpty(version)) {
|
||||
throw new ArgumentException("Argument_Cannot_Be_Null_Or_Empty", "version");
|
||||
original = _originalString;
|
||||
}
|
||||
|
||||
SemanticVersion semVer;
|
||||
if (!TryParse(version, out semVer)) {
|
||||
throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "InvalidVersionString", version), "version");
|
||||
}
|
||||
return semVer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a version string using loose semantic versioning rules that allows 2-4 version components followed by an optional special version.
|
||||
/// </summary>
|
||||
public static bool TryParse(string version, out SemanticVersion value)
|
||||
{
|
||||
return TryParseInternal(version, _semanticVersionRegex, out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a version string using strict semantic versioning rules that allows exactly 3 components and an optional special version.
|
||||
/// </summary>
|
||||
public static bool TryParseStrict(string version, out SemanticVersion value)
|
||||
{
|
||||
return TryParseInternal(version, _strictSemanticVersionRegex, out value);
|
||||
}
|
||||
|
||||
private static bool TryParseInternal(string version, Regex regex, out SemanticVersion semVer)
|
||||
{
|
||||
semVer = null;
|
||||
if (String.IsNullOrEmpty(version)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var match = regex.Match(version.Trim());
|
||||
Version versionValue;
|
||||
if (!match.Success || !Version.TryParse(match.Groups["Version"].Value, out versionValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
semVer = new SemanticVersion(NormalizeVersionValue(versionValue), match.Groups["Release"].Value.TrimStart('-'), version.Replace(" ", ""));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to parse the version token as a SemanticVersion.
|
||||
/// </summary>
|
||||
/// <returns>An instance of SemanticVersion if it parses correctly, null otherwise.</returns>
|
||||
public static SemanticVersion ParseOptionalVersion(string version)
|
||||
{
|
||||
SemanticVersion semVer;
|
||||
TryParse(version, out semVer);
|
||||
return semVer;
|
||||
}
|
||||
|
||||
private static Version NormalizeVersionValue(Version version)
|
||||
{
|
||||
return new Version(version.Major,
|
||||
version.Minor,
|
||||
Math.Max(version.Build, 0),
|
||||
Math.Max(version.Revision, 0));
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (Object.ReferenceEquals(obj, null)) {
|
||||
return 1;
|
||||
}
|
||||
SemanticVersion other = obj as SemanticVersion;
|
||||
if (other == null) {
|
||||
throw new ArgumentException("TypeMustBeASemanticVersion", "obj");
|
||||
}
|
||||
return CompareTo(other);
|
||||
}
|
||||
|
||||
public int CompareTo(SemanticVersion other)
|
||||
{
|
||||
if (Object.ReferenceEquals(other, null)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int result = Version.CompareTo(other.Version);
|
||||
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool empty = String.IsNullOrEmpty(SpecialVersion);
|
||||
bool otherEmpty = String.IsNullOrEmpty(other.SpecialVersion);
|
||||
if (empty && otherEmpty) {
|
||||
return 0;
|
||||
} else if (empty) {
|
||||
return 1;
|
||||
} else if (otherEmpty) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If both versions have a prerelease section with the same prefix
|
||||
// and end with digits, compare based on the digits' numeric order
|
||||
var match = _preReleaseVersionRegex.Match(SpecialVersion.Trim());
|
||||
var otherMatch = _preReleaseVersionRegex.Match(other.SpecialVersion.Trim());
|
||||
if (match.Success && otherMatch.Success &&
|
||||
string.Equals(
|
||||
match.Groups["PreReleaseString"].Value,
|
||||
otherMatch.Groups["PreReleaseString"].Value,
|
||||
StringComparison.OrdinalIgnoreCase)) {
|
||||
int delta =
|
||||
int.Parse(match.Groups["PreReleaseNumber"].Value) -
|
||||
int.Parse(otherMatch.Groups["PreReleaseNumber"].Value);
|
||||
|
||||
return delta != 0 ? delta / Math.Abs(delta) : 0;
|
||||
}
|
||||
|
||||
return StringComparer.OrdinalIgnoreCase.Compare(SpecialVersion, other.SpecialVersion);
|
||||
}
|
||||
|
||||
public static bool operator ==(SemanticVersion version1, SemanticVersion version2)
|
||||
{
|
||||
if (Object.ReferenceEquals(version1, null)) {
|
||||
return Object.ReferenceEquals(version2, null);
|
||||
}
|
||||
return version1.Equals(version2);
|
||||
}
|
||||
|
||||
public static bool operator !=(SemanticVersion version1, SemanticVersion version2)
|
||||
{
|
||||
return !(version1 == version2);
|
||||
}
|
||||
|
||||
public static bool operator <(SemanticVersion version1, SemanticVersion version2)
|
||||
{
|
||||
if (version1 == null) {
|
||||
throw new ArgumentNullException("version1");
|
||||
}
|
||||
return version1.CompareTo(version2) < 0;
|
||||
}
|
||||
|
||||
public static bool operator <=(SemanticVersion version1, SemanticVersion version2)
|
||||
{
|
||||
return (version1 == version2) || (version1 < version2);
|
||||
}
|
||||
|
||||
public static bool operator >(SemanticVersion version1, SemanticVersion version2)
|
||||
{
|
||||
if (version1 == null) {
|
||||
throw new ArgumentNullException("version1");
|
||||
}
|
||||
return version2 < version1;
|
||||
}
|
||||
|
||||
public static bool operator >=(SemanticVersion version1, SemanticVersion version2)
|
||||
{
|
||||
return (version1 == version2) || (version1 > version2);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _originalString;
|
||||
}
|
||||
|
||||
public bool Equals(SemanticVersion other)
|
||||
{
|
||||
return !Object.ReferenceEquals(null, other) &&
|
||||
Version.Equals(other.Version) &&
|
||||
SpecialVersion.Equals(other.SpecialVersion, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
SemanticVersion semVer = obj as SemanticVersion;
|
||||
return !Object.ReferenceEquals(null, semVer) && Equals(semVer);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hashCode = Version.GetHashCode();
|
||||
if (SpecialVersion != null) {
|
||||
hashCode = hashCode * 4567 + SpecialVersion.GetHashCode();
|
||||
}
|
||||
|
||||
return hashCode;
|
||||
return SplitAndPadVersionString(original);
|
||||
} else {
|
||||
return SplitAndPadVersionString(Version.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static string[] SplitAndPadVersionString(string version)
|
||||
{
|
||||
string[] a = version.Split('.');
|
||||
if (a.Length == 4) {
|
||||
return a;
|
||||
} else {
|
||||
// if 'a' has less than 4 elements, we pad the '0' at the end
|
||||
// to make it 4.
|
||||
var b = new string[4] { "0", "0", "0", "0" };
|
||||
Array.Copy(a, 0, b, 0, a.Length);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a version string using loose semantic versioning rules that allows 2-4 version components followed by an optional special version.
|
||||
/// </summary>
|
||||
public static SemanticVersion Parse(string version)
|
||||
{
|
||||
if (String.IsNullOrEmpty(version)) {
|
||||
throw new ArgumentException("Argument_Cannot_Be_Null_Or_Empty", "version");
|
||||
}
|
||||
|
||||
SemanticVersion semVer;
|
||||
if (!TryParse(version, out semVer)) {
|
||||
throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "InvalidVersionString", version), "version");
|
||||
}
|
||||
return semVer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a version string using loose semantic versioning rules that allows 2-4 version components followed by an optional special version.
|
||||
/// </summary>
|
||||
public static bool TryParse(string version, out SemanticVersion value)
|
||||
{
|
||||
return TryParseInternal(version, _semanticVersionRegex, out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a version string using strict semantic versioning rules that allows exactly 3 components and an optional special version.
|
||||
/// </summary>
|
||||
public static bool TryParseStrict(string version, out SemanticVersion value)
|
||||
{
|
||||
return TryParseInternal(version, _strictSemanticVersionRegex, out value);
|
||||
}
|
||||
|
||||
private static bool TryParseInternal(string version, Regex regex, out SemanticVersion semVer)
|
||||
{
|
||||
semVer = null;
|
||||
if (String.IsNullOrEmpty(version)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var match = regex.Match(version.Trim());
|
||||
Version versionValue;
|
||||
if (!match.Success || !Version.TryParse(match.Groups["Version"].Value, out versionValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
semVer = new SemanticVersion(NormalizeVersionValue(versionValue), match.Groups["Release"].Value.TrimStart('-'), version.Replace(" ", ""));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to parse the version token as a SemanticVersion.
|
||||
/// </summary>
|
||||
/// <returns>An instance of SemanticVersion if it parses correctly, null otherwise.</returns>
|
||||
public static SemanticVersion ParseOptionalVersion(string version)
|
||||
{
|
||||
SemanticVersion semVer;
|
||||
TryParse(version, out semVer);
|
||||
return semVer;
|
||||
}
|
||||
|
||||
private static Version NormalizeVersionValue(Version version)
|
||||
{
|
||||
return new Version(version.Major,
|
||||
version.Minor,
|
||||
Math.Max(version.Build, 0),
|
||||
Math.Max(version.Revision, 0));
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (Object.ReferenceEquals(obj, null)) {
|
||||
return 1;
|
||||
}
|
||||
SemanticVersion other = obj as SemanticVersion;
|
||||
if (other == null) {
|
||||
throw new ArgumentException("TypeMustBeASemanticVersion", "obj");
|
||||
}
|
||||
return CompareTo(other);
|
||||
}
|
||||
|
||||
public int CompareTo(SemanticVersion other)
|
||||
{
|
||||
if (Object.ReferenceEquals(other, null)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int result = Version.CompareTo(other.Version);
|
||||
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool empty = String.IsNullOrEmpty(SpecialVersion);
|
||||
bool otherEmpty = String.IsNullOrEmpty(other.SpecialVersion);
|
||||
if (empty && otherEmpty) {
|
||||
return 0;
|
||||
} else if (empty) {
|
||||
return 1;
|
||||
} else if (otherEmpty) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If both versions have a prerelease section with the same prefix
|
||||
// and end with digits, compare based on the digits' numeric order
|
||||
var match = _preReleaseVersionRegex.Match(SpecialVersion.Trim());
|
||||
var otherMatch = _preReleaseVersionRegex.Match(other.SpecialVersion.Trim());
|
||||
if (match.Success && otherMatch.Success &&
|
||||
string.Equals(
|
||||
match.Groups["PreReleaseString"].Value,
|
||||
otherMatch.Groups["PreReleaseString"].Value,
|
||||
StringComparison.OrdinalIgnoreCase)) {
|
||||
int delta =
|
||||
int.Parse(match.Groups["PreReleaseNumber"].Value) -
|
||||
int.Parse(otherMatch.Groups["PreReleaseNumber"].Value);
|
||||
|
||||
return delta != 0 ? delta / Math.Abs(delta) : 0;
|
||||
}
|
||||
|
||||
return StringComparer.OrdinalIgnoreCase.Compare(SpecialVersion, other.SpecialVersion);
|
||||
}
|
||||
|
||||
public static bool operator ==(SemanticVersion version1, SemanticVersion version2)
|
||||
{
|
||||
if (Object.ReferenceEquals(version1, null)) {
|
||||
return Object.ReferenceEquals(version2, null);
|
||||
}
|
||||
return version1.Equals(version2);
|
||||
}
|
||||
|
||||
public static bool operator !=(SemanticVersion version1, SemanticVersion version2)
|
||||
{
|
||||
return !(version1 == version2);
|
||||
}
|
||||
|
||||
public static bool operator <(SemanticVersion version1, SemanticVersion version2)
|
||||
{
|
||||
if (version1 == null) {
|
||||
throw new ArgumentNullException("version1");
|
||||
}
|
||||
return version1.CompareTo(version2) < 0;
|
||||
}
|
||||
|
||||
public static bool operator <=(SemanticVersion version1, SemanticVersion version2)
|
||||
{
|
||||
return (version1 == version2) || (version1 < version2);
|
||||
}
|
||||
|
||||
public static bool operator >(SemanticVersion version1, SemanticVersion version2)
|
||||
{
|
||||
if (version1 == null) {
|
||||
throw new ArgumentNullException("version1");
|
||||
}
|
||||
return version2 < version1;
|
||||
}
|
||||
|
||||
public static bool operator >=(SemanticVersion version1, SemanticVersion version2)
|
||||
{
|
||||
return (version1 == version2) || (version1 > version2);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _originalString;
|
||||
}
|
||||
|
||||
public bool Equals(SemanticVersion other)
|
||||
{
|
||||
return !Object.ReferenceEquals(null, other) &&
|
||||
Version.Equals(other.Version) &&
|
||||
SpecialVersion.Equals(other.SpecialVersion, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
SemanticVersion semVer = obj as SemanticVersion;
|
||||
return !Object.ReferenceEquals(null, semVer) && Equals(semVer);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hashCode = Version.GetHashCode();
|
||||
if (SpecialVersion != null) {
|
||||
hashCode = hashCode * 4567 + SpecialVersion.GetHashCode();
|
||||
}
|
||||
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,14 @@
|
||||
namespace Velopack.Tests.OldSquirrel
|
||||
{
|
||||
internal static class Utility
|
||||
{
|
||||
public static bool IsHttpUrl(string urlOrPath)
|
||||
{
|
||||
var uri = default(Uri);
|
||||
if (!Uri.TryCreate(urlOrPath, UriKind.Absolute, out uri)) {
|
||||
return false;
|
||||
}
|
||||
namespace Velopack.Tests.OldSquirrel;
|
||||
|
||||
return uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps;
|
||||
internal static class Utility
|
||||
{
|
||||
public static bool IsHttpUrl(string urlOrPath)
|
||||
{
|
||||
var uri = default(Uri);
|
||||
if (!Uri.TryCreate(urlOrPath, UriKind.Absolute, out uri)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,506 +4,505 @@ using NuGet.Versioning;
|
||||
using OldReleaseEntry = Velopack.Tests.OldSquirrel.ReleaseEntry;
|
||||
using OldSemanticVersion = Velopack.Tests.OldSquirrel.SemanticVersion;
|
||||
|
||||
namespace Velopack.Tests
|
||||
namespace Velopack.Tests;
|
||||
|
||||
public class ReleaseEntryTests
|
||||
{
|
||||
public class ReleaseEntryTests
|
||||
[Theory]
|
||||
[InlineData(@"MyCoolApp-1.0-full.nupkg", "MyCoolApp", "1.0", "")]
|
||||
[InlineData(@"MyCoolApp-1.0.0-full.nupkg", "MyCoolApp", "1.0.0", "")]
|
||||
[InlineData(@"MyCoolApp-1.0.0-delta.nupkg", "MyCoolApp", "1.0.0", "")]
|
||||
[InlineData(@"MyCoolApp-1.0.0-win-x64-full.nupkg", "MyCoolApp", "1.0.0", "win-x64")]
|
||||
[InlineData(@"MyCoolApp-123.456.789-win-x64-full.nupkg", "MyCoolApp", "123.456.789", "win-x64")]
|
||||
[InlineData(@"MyCoolApp-123.456.789-hello-win-x64-full.nupkg", "MyCoolApp", "123.456.789", "hello-win-x64")]
|
||||
public void NewEntryCanRoundTripToOldSquirrel(string fileName, string id, string version, string metadata)
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(@"MyCoolApp-1.0-full.nupkg", "MyCoolApp", "1.0", "")]
|
||||
[InlineData(@"MyCoolApp-1.0.0-full.nupkg", "MyCoolApp", "1.0.0", "")]
|
||||
[InlineData(@"MyCoolApp-1.0.0-delta.nupkg", "MyCoolApp", "1.0.0", "")]
|
||||
[InlineData(@"MyCoolApp-1.0.0-win-x64-full.nupkg", "MyCoolApp", "1.0.0", "win-x64")]
|
||||
[InlineData(@"MyCoolApp-123.456.789-win-x64-full.nupkg", "MyCoolApp", "123.456.789", "win-x64")]
|
||||
[InlineData(@"MyCoolApp-123.456.789-hello-win-x64-full.nupkg", "MyCoolApp", "123.456.789", "hello-win-x64")]
|
||||
public void NewEntryCanRoundTripToOldSquirrel(string fileName, string id, string version, string metadata)
|
||||
{
|
||||
var size = 80396;
|
||||
var sha = "14db31d2647c6d2284882a2e101924a9c409ee67";
|
||||
var re = new ReleaseEntry(sha, fileName, size, null, null, null);
|
||||
StringBuilder file = new StringBuilder();
|
||||
file.AppendLine(re.EntryAsString);
|
||||
var size = 80396;
|
||||
var sha = "14db31d2647c6d2284882a2e101924a9c409ee67";
|
||||
var re = new ReleaseEntry(sha, fileName, size, null, null, null);
|
||||
StringBuilder file = new StringBuilder();
|
||||
file.AppendLine(re.EntryAsString);
|
||||
|
||||
var parsed = OldReleaseEntry.ParseReleaseFile(file.ToString());
|
||||
Assert.True(parsed.Count() == 1);
|
||||
var parsed = OldReleaseEntry.ParseReleaseFile(file.ToString());
|
||||
Assert.True(parsed.Count() == 1);
|
||||
|
||||
var oldEntry = parsed.First();
|
||||
var oldEntry = parsed.First();
|
||||
|
||||
Assert.Equal(fileName, oldEntry.Filename);
|
||||
Assert.Equal(id, oldEntry.PackageName);
|
||||
Assert.Equal(size, oldEntry.Filesize);
|
||||
Assert.Equal(sha, oldEntry.SHA1);
|
||||
Assert.Null(oldEntry.BaseUrl);
|
||||
Assert.Null(oldEntry.Query);
|
||||
Assert.True(oldEntry.Version.Version == OldSemanticVersion.Parse(version).Version);
|
||||
Assert.Equal(oldEntry.Version.SpecialVersion, metadata);
|
||||
Assert.Equal(fileName, oldEntry.Filename);
|
||||
Assert.Equal(id, oldEntry.PackageName);
|
||||
Assert.Equal(size, oldEntry.Filesize);
|
||||
Assert.Equal(sha, oldEntry.SHA1);
|
||||
Assert.Null(oldEntry.BaseUrl);
|
||||
Assert.Null(oldEntry.Query);
|
||||
Assert.True(oldEntry.Version.Version == OldSemanticVersion.Parse(version).Version);
|
||||
Assert.Equal(oldEntry.Version.SpecialVersion, metadata);
|
||||
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"94689fede03fed7ab59c24337673a27837f0c3ec MyCoolApp-1.0.nupkg 1004502", "MyCoolApp-1.0.nupkg", 1004502, null, null)]
|
||||
[InlineData(@"3a2eadd15dd984e4559f2b4d790ec8badaeb6a39 MyCoolApp-1.1.nupkg 1040561", "MyCoolApp-1.1.nupkg", 1040561, null, null)]
|
||||
[InlineData(@"14db31d2647c6d2284882a2e101924a9c409ee67 MyCoolApp-1.1.nupkg.delta 80396", "MyCoolApp-1.1.nupkg.delta", 80396, null, null)]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 http://test.org/Folder/MyCoolApp-1.2.nupkg 2569", "MyCoolApp-1.2.nupkg", 2569, "http://test.org/Folder/", null)]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 http://test.org/Folder/MyCoolApp-1.2.nupkg?query=param 2569", "MyCoolApp-1.2.nupkg", 2569, "http://test.org/Folder/", "?query=param")]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 https://www.test.org/Folder/MyCoolApp-1.2-delta.nupkg 1231953", "MyCoolApp-1.2-delta.nupkg", 1231953, "https://www.test.org/Folder/", null)]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 https://www.test.org/Folder/MyCoolApp-1.2-delta.nupkg?query=param 1231953", "MyCoolApp-1.2-delta.nupkg", 1231953, "https://www.test.org/Folder/", "?query=param")]
|
||||
public void ParseValidReleaseEntryLines(string releaseEntry, string fileName, long fileSize, string baseUrl, string query)
|
||||
{
|
||||
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
|
||||
Assert.Equal(fileName, fixture.OriginalFilename);
|
||||
Assert.Equal(fileSize, fixture.Filesize);
|
||||
Assert.Equal(baseUrl, fixture.BaseUrl);
|
||||
Assert.Equal(query, fixture.Query);
|
||||
|
||||
var old = OldReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
Assert.Equal(fileName, old.Filename);
|
||||
Assert.Equal(fileSize, old.Filesize);
|
||||
Assert.Equal(baseUrl, old.BaseUrl);
|
||||
Assert.Equal(query, old.Query);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"94689fede03fed7ab59c24337673a27837f0c3ec My.Cool.App-1.0-full.nupkg 1004502", "My.Cool.App")]
|
||||
[InlineData(@"94689fede03fed7ab59c24337673a27837f0c3ec My.Cool.App-1.1.nupkg 1004502", "My.Cool.App")]
|
||||
[InlineData(@"94689fede03fed7ab59c24337673a27837f0c3ec http://test.org/Folder/My.Cool.App-1.2.nupkg?query=param 1231953", "My.Cool.App")]
|
||||
public void ParseValidReleaseEntryLinesWithDots(string releaseEntry, string packageName)
|
||||
{
|
||||
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
Assert.Equal(packageName, fixture.PackageId);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"94689fede03fed7ab59c24337673a27837f0c3ec My-Cool-App-1.0-full.nupkg 1004502", "My-Cool-App")]
|
||||
[InlineData(@"94689fede03fed7ab59c24337673a27837f0c3ec My.Cool-App-1.1.nupkg 1004502", "My.Cool-App")]
|
||||
[InlineData(@"94689fede03fed7ab59c24337673a27837f0c3ec http://test.org/Folder/My.Cool-App-1.2.nupkg?query=param 1231953", "My.Cool-App")]
|
||||
public void ParseValidReleaseEntryLinesWithDashes(string releaseEntry, string packageName)
|
||||
{
|
||||
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
Assert.Equal(packageName, fixture.PackageId);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 file:/C/Folder/MyCoolApp-0.0.nupkg 0")]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 C:\Folder\MyCoolApp-0.0.nupkg 0")]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 ..\OtherFolder\MyCoolApp-0.0.nupkg 0")]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 ../OtherFolder/MyCoolApp-0.0.nupkg 0")]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 \\Somewhere\NetworkShare\MyCoolApp-0.0.nupkg.delta 0")]
|
||||
public void ParseThrowsWhenInvalidReleaseEntryLines(string releaseEntry)
|
||||
{
|
||||
Assert.Throws<Exception>(() => ReleaseEntry.ParseReleaseEntry(releaseEntry));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 file.nupkg 0")]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 http://path/file.nupkg 0")]
|
||||
public void EntryAsStringMatchesParsedInput(string releaseEntry)
|
||||
{
|
||||
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
Assert.Equal(releaseEntry, fixture.EntryAsString);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Squirrel.Core.1.0.0.0.nupkg", 4457, "75255cfd229a1ed1447abe1104f5635e69975d30")]
|
||||
[InlineData("Squirrel.Core.1.1.0.0.nupkg", 15830, "9baf1dbacb09940086c8c62d9a9dbe69fe1f7593")]
|
||||
public void GenerateFromFileTest(string name, long size, string sha1)
|
||||
{
|
||||
var path = PathHelper.GetFixture(name);
|
||||
|
||||
using (var f = File.OpenRead(path)) {
|
||||
var fixture = ReleaseEntry.GenerateFromFile(f, "dontcare");
|
||||
Assert.Equal(size, fixture.Filesize);
|
||||
Assert.Equal(sha1, fixture.SHA1.ToLowerInvariant());
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.nupkg 123", 1, 2, 0, 0, "", false)]
|
||||
[InlineData("1000000000000000000000000000000000000000 MyCoolApp-1.2-full.nupkg 123", 1, 2, 0, 0, "", false)]
|
||||
[InlineData("2000000000000000000000000000000000000000 MyCoolApp-1.2-delta.nupkg 123", 1, 2, 0, 0, "", true)]
|
||||
[InlineData("3000000000000000000000000000000000000000 MyCoolApp-1.2-beta1.nupkg 123", 1, 2, 0, 0, "beta1", false)]
|
||||
[InlineData("4000000000000000000000000000000000000000 MyCoolApp-1.2-beta1-full.nupkg 123", 1, 2, 0, 0, "beta1", false)]
|
||||
[InlineData("5000000000000000000000000000000000000000 MyCoolApp-1.2-beta1-delta.nupkg 123", 1, 2, 0, 0, "beta1", true)]
|
||||
[InlineData("6000000000000000000000000000000000000000 MyCoolApp-1.2.3.nupkg 123", 1, 2, 3, 0, "", false)]
|
||||
[InlineData("7000000000000000000000000000000000000000 MyCoolApp-1.2.3-full.nupkg 123", 1, 2, 3, 0, "", false)]
|
||||
[InlineData("8000000000000000000000000000000000000000 MyCoolApp-1.2.3-delta.nupkg 123", 1, 2, 3, 0, "", true)]
|
||||
[InlineData("9000000000000000000000000000000000000000 MyCoolApp-1.2.3-beta1.nupkg 123", 1, 2, 3, 0, "beta1", false)]
|
||||
[InlineData("0100000000000000000000000000000000000000 MyCoolApp-1.2.3-beta1-full.nupkg 123", 1, 2, 3, 0, "beta1", false)]
|
||||
[InlineData("0200000000000000000000000000000000000000 MyCoolApp-1.2.3-beta1-delta.nupkg 123", 1, 2, 3, 0, "beta1", true)]
|
||||
[InlineData("0300000000000000000000000000000000000000 MyCoolApp-1.2.3.4.nupkg 123", 1, 2, 3, 4, "", false)]
|
||||
[InlineData("0400000000000000000000000000000000000000 MyCoolApp-1.2.3.4-full.nupkg 123", 1, 2, 3, 4, "", false)]
|
||||
[InlineData("0500000000000000000000000000000000000000 MyCoolApp-1.2.3.4-delta.nupkg 123", 1, 2, 3, 4, "", true)]
|
||||
[InlineData("0600000000000000000000000000000000000000 MyCoolApp-1.2.3.4-beta1.nupkg 123", 1, 2, 3, 4, "beta1", false)]
|
||||
[InlineData("0700000000000000000000000000000000000000 MyCoolApp-1.2.3.4-beta1-full.nupkg 123", 1, 2, 3, 4, "beta1", false)]
|
||||
[InlineData("0800000000000000000000000000000000000000 MyCoolApp-1.2.3.4-beta1-delta.nupkg 123", 1, 2, 3, 4, "beta1", true)]
|
||||
|
||||
public void ParseVersionTest(string releaseEntry, int major, int minor, int patch, int revision, string prerelease, bool isDelta)
|
||||
{
|
||||
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
|
||||
Assert.Equal(new NuGetVersion(major, minor, patch, revision, prerelease, null), fixture.Version);
|
||||
Assert.Equal(isDelta, fixture.IsDelta);
|
||||
|
||||
var old = OldReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
Assert.Equal(new NuGetVersion(major, minor, patch, revision, prerelease, null), new NuGetVersion(old.Version.ToString()));
|
||||
Assert.Equal(isDelta, old.IsDelta);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCool-App-1.2.nupkg 123", "MyCool-App")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCool_App-1.2-full.nupkg 123", "MyCool_App")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2-delta.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2-beta1.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2-beta1-full.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2-beta1-delta.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCool-App-1.2.3.nupkg 123", "MyCool-App")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCool_App-1.2.3-full.nupkg 123", "MyCool_App")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.3-delta.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.3-beta1.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.3-beta1-full.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.3-beta1-delta.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCool-App-1.2.3.4.nupkg 123", "MyCool-App")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCool_App-1.2.3.4-full.nupkg 123", "MyCool_App")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.3.4-delta.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.3.4-beta1.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.3.4-beta1-full.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCool-App-1.2.3.4-beta1-delta.nupkg 123", "MyCool-App")]
|
||||
public void CheckPackageName(string releaseEntry, string expected)
|
||||
{
|
||||
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
Assert.Equal(expected, fixture.PackageId);
|
||||
|
||||
var old = OldReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
Assert.Equal(expected, old.PackageName);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.nupkg 123 # 10%", 1, 2, 0, 0, "", "", false, 0.1f)]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2-full.nupkg 123 # 90%", 1, 2, 0, 0, "", "", false, 0.9f)]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2-delta.nupkg 123", 1, 2, 0, 0, "", "", true, null)]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2-delta.nupkg 123 # 5%", 1, 2, 0, 0, "", "", true, 0.05f)]
|
||||
public void ParseStagingPercentageTest(string releaseEntry, int major, int minor, int patch, int revision, string prerelease, string rid, bool isDelta, float? stagingPercentage)
|
||||
{
|
||||
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
|
||||
Assert.Equal(new NuGetVersion(major, minor, patch, revision, prerelease, null), fixture.Version);
|
||||
Assert.Equal(isDelta, fixture.IsDelta);
|
||||
|
||||
if (stagingPercentage.HasValue) {
|
||||
Assert.True(Math.Abs(fixture.StagingPercentage.Value - stagingPercentage.Value) < 0.001);
|
||||
} else {
|
||||
Assert.Null(fixture.StagingPercentage);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"94689fede03fed7ab59c24337673a27837f0c3ec MyCoolApp-1.0.nupkg 1004502", "MyCoolApp-1.0.nupkg", 1004502, null, null)]
|
||||
[InlineData(@"3a2eadd15dd984e4559f2b4d790ec8badaeb6a39 MyCoolApp-1.1.nupkg 1040561", "MyCoolApp-1.1.nupkg", 1040561, null, null)]
|
||||
[InlineData(@"14db31d2647c6d2284882a2e101924a9c409ee67 MyCoolApp-1.1.nupkg.delta 80396", "MyCoolApp-1.1.nupkg.delta", 80396, null, null)]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 http://test.org/Folder/MyCoolApp-1.2.nupkg 2569", "MyCoolApp-1.2.nupkg", 2569, "http://test.org/Folder/", null)]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 http://test.org/Folder/MyCoolApp-1.2.nupkg?query=param 2569", "MyCoolApp-1.2.nupkg", 2569, "http://test.org/Folder/", "?query=param")]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 https://www.test.org/Folder/MyCoolApp-1.2-delta.nupkg 1231953", "MyCoolApp-1.2-delta.nupkg", 1231953, "https://www.test.org/Folder/", null)]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 https://www.test.org/Folder/MyCoolApp-1.2-delta.nupkg?query=param 1231953", "MyCoolApp-1.2-delta.nupkg", 1231953, "https://www.test.org/Folder/", "?query=param")]
|
||||
public void ParseValidReleaseEntryLines(string releaseEntry, string fileName, long fileSize, string baseUrl, string query)
|
||||
{
|
||||
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
var old = OldReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
var legacyPre = !String.IsNullOrEmpty(prerelease) && !String.IsNullOrEmpty(rid) ? $"{prerelease}-{rid}" : String.IsNullOrEmpty(prerelease) ? rid : prerelease;
|
||||
Assert.Equal(new NuGetVersion(major, minor, patch, revision, legacyPre, null), new NuGetVersion(old.Version.ToString()));
|
||||
Assert.Equal(isDelta, old.IsDelta);
|
||||
|
||||
Assert.Equal(fileName, fixture.OriginalFilename);
|
||||
Assert.Equal(fileSize, fixture.Filesize);
|
||||
Assert.Equal(baseUrl, fixture.BaseUrl);
|
||||
Assert.Equal(query, fixture.Query);
|
||||
|
||||
var old = OldReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
Assert.Equal(fileName, old.Filename);
|
||||
Assert.Equal(fileSize, old.Filesize);
|
||||
Assert.Equal(baseUrl, old.BaseUrl);
|
||||
Assert.Equal(query, old.Query);
|
||||
if (stagingPercentage.HasValue) {
|
||||
Assert.True(Math.Abs(old.StagingPercentage.Value - stagingPercentage.Value) < 0.001);
|
||||
} else {
|
||||
Assert.Null(old.StagingPercentage);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"94689fede03fed7ab59c24337673a27837f0c3ec My.Cool.App-1.0-full.nupkg 1004502", "My.Cool.App")]
|
||||
[InlineData(@"94689fede03fed7ab59c24337673a27837f0c3ec My.Cool.App-1.1.nupkg 1004502", "My.Cool.App")]
|
||||
[InlineData(@"94689fede03fed7ab59c24337673a27837f0c3ec http://test.org/Folder/My.Cool.App-1.2.nupkg?query=param 1231953", "My.Cool.App")]
|
||||
public void ParseValidReleaseEntryLinesWithDots(string releaseEntry, string packageName)
|
||||
{
|
||||
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
Assert.Equal(packageName, fixture.PackageId);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"94689fede03fed7ab59c24337673a27837f0c3ec My-Cool-App-1.0-full.nupkg 1004502", "My-Cool-App")]
|
||||
[InlineData(@"94689fede03fed7ab59c24337673a27837f0c3ec My.Cool-App-1.1.nupkg 1004502", "My.Cool-App")]
|
||||
[InlineData(@"94689fede03fed7ab59c24337673a27837f0c3ec http://test.org/Folder/My.Cool-App-1.2.nupkg?query=param 1231953", "My.Cool-App")]
|
||||
public void ParseValidReleaseEntryLinesWithDashes(string releaseEntry, string packageName)
|
||||
{
|
||||
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
Assert.Equal(packageName, fixture.PackageId);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 file:/C/Folder/MyCoolApp-0.0.nupkg 0")]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 C:\Folder\MyCoolApp-0.0.nupkg 0")]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 ..\OtherFolder\MyCoolApp-0.0.nupkg 0")]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 ../OtherFolder/MyCoolApp-0.0.nupkg 0")]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 \\Somewhere\NetworkShare\MyCoolApp-0.0.nupkg.delta 0")]
|
||||
public void ParseThrowsWhenInvalidReleaseEntryLines(string releaseEntry)
|
||||
{
|
||||
Assert.Throws<Exception>(() => ReleaseEntry.ParseReleaseEntry(releaseEntry));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 file.nupkg 0")]
|
||||
[InlineData(@"0000000000000000000000000000000000000000 http://path/file.nupkg 0")]
|
||||
public void EntryAsStringMatchesParsedInput(string releaseEntry)
|
||||
{
|
||||
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
Assert.Equal(releaseEntry, fixture.EntryAsString);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Squirrel.Core.1.0.0.0.nupkg", 4457, "75255cfd229a1ed1447abe1104f5635e69975d30")]
|
||||
[InlineData("Squirrel.Core.1.1.0.0.nupkg", 15830, "9baf1dbacb09940086c8c62d9a9dbe69fe1f7593")]
|
||||
public void GenerateFromFileTest(string name, long size, string sha1)
|
||||
{
|
||||
var path = PathHelper.GetFixture(name);
|
||||
|
||||
using (var f = File.OpenRead(path)) {
|
||||
var fixture = ReleaseEntry.GenerateFromFile(f, "dontcare");
|
||||
Assert.Equal(size, fixture.Filesize);
|
||||
Assert.Equal(sha1, fixture.SHA1.ToLowerInvariant());
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.nupkg 123", 1, 2, 0, 0, "", false)]
|
||||
[InlineData("1000000000000000000000000000000000000000 MyCoolApp-1.2-full.nupkg 123", 1, 2, 0, 0, "", false)]
|
||||
[InlineData("2000000000000000000000000000000000000000 MyCoolApp-1.2-delta.nupkg 123", 1, 2, 0, 0, "", true)]
|
||||
[InlineData("3000000000000000000000000000000000000000 MyCoolApp-1.2-beta1.nupkg 123", 1, 2, 0, 0, "beta1", false)]
|
||||
[InlineData("4000000000000000000000000000000000000000 MyCoolApp-1.2-beta1-full.nupkg 123", 1, 2, 0, 0, "beta1", false)]
|
||||
[InlineData("5000000000000000000000000000000000000000 MyCoolApp-1.2-beta1-delta.nupkg 123", 1, 2, 0, 0, "beta1", true)]
|
||||
[InlineData("6000000000000000000000000000000000000000 MyCoolApp-1.2.3.nupkg 123", 1, 2, 3, 0, "", false)]
|
||||
[InlineData("7000000000000000000000000000000000000000 MyCoolApp-1.2.3-full.nupkg 123", 1, 2, 3, 0, "", false)]
|
||||
[InlineData("8000000000000000000000000000000000000000 MyCoolApp-1.2.3-delta.nupkg 123", 1, 2, 3, 0, "", true)]
|
||||
[InlineData("9000000000000000000000000000000000000000 MyCoolApp-1.2.3-beta1.nupkg 123", 1, 2, 3, 0, "beta1", false)]
|
||||
[InlineData("0100000000000000000000000000000000000000 MyCoolApp-1.2.3-beta1-full.nupkg 123", 1, 2, 3, 0, "beta1", false)]
|
||||
[InlineData("0200000000000000000000000000000000000000 MyCoolApp-1.2.3-beta1-delta.nupkg 123", 1, 2, 3, 0, "beta1", true)]
|
||||
[InlineData("0300000000000000000000000000000000000000 MyCoolApp-1.2.3.4.nupkg 123", 1, 2, 3, 4, "", false)]
|
||||
[InlineData("0400000000000000000000000000000000000000 MyCoolApp-1.2.3.4-full.nupkg 123", 1, 2, 3, 4, "", false)]
|
||||
[InlineData("0500000000000000000000000000000000000000 MyCoolApp-1.2.3.4-delta.nupkg 123", 1, 2, 3, 4, "", true)]
|
||||
[InlineData("0600000000000000000000000000000000000000 MyCoolApp-1.2.3.4-beta1.nupkg 123", 1, 2, 3, 4, "beta1", false)]
|
||||
[InlineData("0700000000000000000000000000000000000000 MyCoolApp-1.2.3.4-beta1-full.nupkg 123", 1, 2, 3, 4, "beta1", false)]
|
||||
[InlineData("0800000000000000000000000000000000000000 MyCoolApp-1.2.3.4-beta1-delta.nupkg 123", 1, 2, 3, 4, "beta1", true)]
|
||||
|
||||
public void ParseVersionTest(string releaseEntry, int major, int minor, int patch, int revision, string prerelease, bool isDelta)
|
||||
{
|
||||
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
|
||||
Assert.Equal(new NuGetVersion(major, minor, patch, revision, prerelease, null), fixture.Version);
|
||||
Assert.Equal(isDelta, fixture.IsDelta);
|
||||
|
||||
var old = OldReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
Assert.Equal(new NuGetVersion(major, minor, patch, revision, prerelease, null), new NuGetVersion(old.Version.ToString()));
|
||||
Assert.Equal(isDelta, old.IsDelta);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCool-App-1.2.nupkg 123", "MyCool-App")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCool_App-1.2-full.nupkg 123", "MyCool_App")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2-delta.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2-beta1.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2-beta1-full.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2-beta1-delta.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCool-App-1.2.3.nupkg 123", "MyCool-App")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCool_App-1.2.3-full.nupkg 123", "MyCool_App")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.3-delta.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.3-beta1.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.3-beta1-full.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.3-beta1-delta.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCool-App-1.2.3.4.nupkg 123", "MyCool-App")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCool_App-1.2.3.4-full.nupkg 123", "MyCool_App")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.3.4-delta.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.3.4-beta1.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.3.4-beta1-full.nupkg 123", "MyCoolApp")]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCool-App-1.2.3.4-beta1-delta.nupkg 123", "MyCool-App")]
|
||||
public void CheckPackageName(string releaseEntry, string expected)
|
||||
{
|
||||
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
Assert.Equal(expected, fixture.PackageId);
|
||||
|
||||
var old = OldReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
Assert.Equal(expected, old.PackageName);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2.nupkg 123 # 10%", 1, 2, 0, 0, "", "", false, 0.1f)]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2-full.nupkg 123 # 90%", 1, 2, 0, 0, "", "", false, 0.9f)]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2-delta.nupkg 123", 1, 2, 0, 0, "", "", true, null)]
|
||||
[InlineData("0000000000000000000000000000000000000000 MyCoolApp-1.2-delta.nupkg 123 # 5%", 1, 2, 0, 0, "", "", true, 0.05f)]
|
||||
public void ParseStagingPercentageTest(string releaseEntry, int major, int minor, int patch, int revision, string prerelease, string rid, bool isDelta, float? stagingPercentage)
|
||||
{
|
||||
var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
|
||||
Assert.Equal(new NuGetVersion(major, minor, patch, revision, prerelease, null), fixture.Version);
|
||||
Assert.Equal(isDelta, fixture.IsDelta);
|
||||
|
||||
if (stagingPercentage.HasValue) {
|
||||
Assert.True(Math.Abs(fixture.StagingPercentage.Value - stagingPercentage.Value) < 0.001);
|
||||
} else {
|
||||
Assert.Null(fixture.StagingPercentage);
|
||||
}
|
||||
|
||||
var old = OldReleaseEntry.ParseReleaseEntry(releaseEntry);
|
||||
var legacyPre = !String.IsNullOrEmpty(prerelease) && !String.IsNullOrEmpty(rid) ? $"{prerelease}-{rid}" : String.IsNullOrEmpty(prerelease) ? rid : prerelease;
|
||||
Assert.Equal(new NuGetVersion(major, minor, patch, revision, legacyPre, null), new NuGetVersion(old.Version.ToString()));
|
||||
Assert.Equal(isDelta, old.IsDelta);
|
||||
|
||||
if (stagingPercentage.HasValue) {
|
||||
Assert.True(Math.Abs(old.StagingPercentage.Value - stagingPercentage.Value) < 0.001);
|
||||
} else {
|
||||
Assert.Null(old.StagingPercentage);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanParseGeneratedReleaseEntryAsString()
|
||||
{
|
||||
var path = PathHelper.GetFixture("Squirrel.Core.1.1.0.0.nupkg");
|
||||
var entryAsString = ReleaseEntry.GenerateFromFile(path).EntryAsString;
|
||||
ReleaseEntry.ParseReleaseEntry(entryAsString);
|
||||
}
|
||||
|
||||
//[Fact]
|
||||
//public void GetLatestReleaseWithNullCollectionReturnsNull()
|
||||
//{
|
||||
// Assert.Null(ReleasePackageBuilder.GetPreviousRelease(
|
||||
// null, null, null, null));
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public void GetLatestReleaseWithEmptyCollectionReturnsNull()
|
||||
//{
|
||||
// Assert.Null(ReleasePackageBuilder.GetPreviousRelease(
|
||||
// Enumerable.Empty<ReleaseEntry>(), null, null, null));
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public void WhenCurrentReleaseMatchesLastReleaseReturnNull()
|
||||
//{
|
||||
// var package = new ReleasePackageBuilder("Espera-1.7.6-beta.nupkg");
|
||||
|
||||
// var releaseEntries = new[] {
|
||||
// ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.6-beta.nupkg"))
|
||||
// };
|
||||
// Assert.Null(ReleasePackageBuilder.GetPreviousRelease(
|
||||
// releaseEntries, package, @"C:\temp\somefolder", null));
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public void WhenMultipleReleaseMatchesReturnEarlierResult()
|
||||
//{
|
||||
// var expected = SemanticVersion.Parse("1.7.5-beta");
|
||||
// var package = new ReleasePackageBuilder("Espera-1.7.6-beta.nupkg");
|
||||
|
||||
// var releaseEntries = new[] {
|
||||
// ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.6-beta.nupkg")),
|
||||
// ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.5-beta.nupkg"))
|
||||
// };
|
||||
|
||||
// var actual = ReleasePackageBuilder.GetPreviousRelease(
|
||||
// releaseEntries,
|
||||
// package,
|
||||
// @"C:\temp\", null);
|
||||
|
||||
// Assert.Equal(expected, actual.Version);
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public void WhenMultipleReleasesFoundReturnPreviousVersion()
|
||||
//{
|
||||
// var expected = SemanticVersion.Parse("1.7.6-beta");
|
||||
// var input = new ReleasePackageBuilder("Espera-1.7.7-beta.nupkg");
|
||||
|
||||
// var releaseEntries = new[] {
|
||||
// ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.6-beta.nupkg")),
|
||||
// ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.5-beta.nupkg"))
|
||||
// };
|
||||
|
||||
// var actual = ReleasePackageBuilder.GetPreviousRelease(
|
||||
// releaseEntries,
|
||||
// input,
|
||||
// @"C:\temp\", null);
|
||||
|
||||
// Assert.Equal(expected, actual.Version);
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public void WhenMultipleReleasesFoundInOtherOrderReturnPreviousVersion()
|
||||
//{
|
||||
// var expected = SemanticVersion.Parse("1.7.6-beta");
|
||||
// var input = new ReleasePackageBuilder("Espera-1.7.7-beta.nupkg");
|
||||
|
||||
// var releaseEntries = new[] {
|
||||
// ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.5-beta.nupkg")),
|
||||
// ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.6-beta.nupkg"))
|
||||
// };
|
||||
|
||||
// var actual = ReleasePackageBuilder.GetPreviousRelease(
|
||||
// releaseEntries,
|
||||
// input,
|
||||
// @"C:\temp\", null);
|
||||
|
||||
// Assert.Equal(expected, actual.Version);
|
||||
//}
|
||||
|
||||
[Fact]
|
||||
public void WhenReleasesAreOutOfOrderSortByVersion()
|
||||
{
|
||||
var path = Path.GetTempFileName();
|
||||
var firstVersion = SemanticVersion.Parse("1.0.0");
|
||||
var secondVersion = SemanticVersion.Parse("1.1.0");
|
||||
var thirdVersion = SemanticVersion.Parse("1.2.0");
|
||||
|
||||
var releaseEntries = new[] {
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-delta.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-delta.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.0.0-full.nupkg"))
|
||||
};
|
||||
|
||||
ReleaseEntry.WriteReleaseFile(releaseEntries, path);
|
||||
|
||||
var releases = ReleaseEntry.ParseReleaseFile(File.ReadAllText(path)).ToArray();
|
||||
|
||||
Assert.Equal(firstVersion, releases[0].Version);
|
||||
Assert.Equal(secondVersion, releases[1].Version);
|
||||
Assert.Equal(true, releases[1].IsDelta);
|
||||
Assert.Equal(secondVersion, releases[2].Version);
|
||||
Assert.Equal(false, releases[2].IsDelta);
|
||||
Assert.Equal(thirdVersion, releases[3].Version);
|
||||
Assert.Equal(true, releases[3].IsDelta);
|
||||
Assert.Equal(thirdVersion, releases[4].Version);
|
||||
Assert.Equal(false, releases[4].IsDelta);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WhenPreReleasesAreOutOfOrderSortByNumericSuffixSemVer2()
|
||||
{
|
||||
var path = Path.GetTempFileName();
|
||||
var firstVersion = SemanticVersion.Parse("1.1.9-beta.105");
|
||||
var secondVersion = SemanticVersion.Parse("1.2.0-beta.9");
|
||||
var thirdVersion = SemanticVersion.Parse("1.2.0-beta.10");
|
||||
var fourthVersion = SemanticVersion.Parse("1.2.0-beta.100");
|
||||
|
||||
var releaseEntries = new[] {
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-beta.1-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-beta.9-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-beta.100-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.9-beta.105-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-beta.10-full.nupkg"))
|
||||
};
|
||||
|
||||
ReleaseEntry.WriteReleaseFile(releaseEntries, path);
|
||||
|
||||
var releases = ReleaseEntry.ParseReleaseFile(File.ReadAllText(path)).ToArray();
|
||||
|
||||
Assert.Equal(firstVersion, releases[0].Version);
|
||||
Assert.Equal(secondVersion, releases[2].Version);
|
||||
Assert.Equal(thirdVersion, releases[3].Version);
|
||||
Assert.Equal(fourthVersion, releases[4].Version);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StagingUsersGetBetaSoftware()
|
||||
{
|
||||
// NB: We're kind of using a hack here, in that we know that the
|
||||
// last 4 bytes are used as the percentage, and the percentage
|
||||
// effectively measures, "How close are you to zero". Guid.Empty
|
||||
// is v close to zero, because it is zero.
|
||||
var path = Path.GetTempFileName();
|
||||
var ourGuid = Guid.Empty;
|
||||
|
||||
var releaseEntries = new[] {
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-full.nupkg", 0.1f)),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.0.0-full.nupkg"))
|
||||
};
|
||||
|
||||
ReleaseEntry.WriteReleaseFile(releaseEntries, path);
|
||||
|
||||
var releases = ReleaseEntry.ParseReleaseFileAndApplyStaging(File.ReadAllText(path), ourGuid).ToArray();
|
||||
Assert.Equal(3, releases.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BorkedUsersGetProductionSoftware()
|
||||
{
|
||||
var path = Path.GetTempFileName();
|
||||
var ourGuid = default(Guid?);
|
||||
|
||||
var releaseEntries = new[] {
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-full.nupkg", 0.1f)),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.0.0-full.nupkg"))
|
||||
};
|
||||
|
||||
ReleaseEntry.WriteReleaseFile(releaseEntries, path);
|
||||
|
||||
var releases = ReleaseEntry.ParseReleaseFileAndApplyStaging(File.ReadAllText(path), ourGuid).ToArray();
|
||||
Assert.Equal(2, releases.Length);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("{22b29e6f-bd2e-43d2-85ca-ffffffffffff}")]
|
||||
[InlineData("{22b29e6f-bd2e-43d2-85ca-888888888888}")]
|
||||
[InlineData("{22b29e6f-bd2e-43d2-85ca-444444444444}")]
|
||||
public void UnluckyUsersGetProductionSoftware(string inputGuid)
|
||||
{
|
||||
var path = Path.GetTempFileName();
|
||||
var ourGuid = Guid.ParseExact(inputGuid, "B");
|
||||
|
||||
var releaseEntries = new[] {
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-full.nupkg", 0.1f)),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.0.0-full.nupkg"))
|
||||
};
|
||||
|
||||
ReleaseEntry.WriteReleaseFile(releaseEntries, path);
|
||||
|
||||
var releases = ReleaseEntry.ParseReleaseFileAndApplyStaging(File.ReadAllText(path), ourGuid).ToArray();
|
||||
Assert.Equal(2, releases.Length);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("{22b29e6f-bd2e-43d2-85ca-333333333333}")]
|
||||
[InlineData("{22b29e6f-bd2e-43d2-85ca-111111111111}")]
|
||||
[InlineData("{22b29e6f-bd2e-43d2-85ca-000000000000}")]
|
||||
public void LuckyUsersGetBetaSoftware(string inputGuid)
|
||||
{
|
||||
var path = Path.GetTempFileName();
|
||||
var ourGuid = Guid.ParseExact(inputGuid, "B");
|
||||
|
||||
var releaseEntries = new[] {
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-full.nupkg", 0.25f)),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.0.0-full.nupkg"))
|
||||
};
|
||||
|
||||
ReleaseEntry.WriteReleaseFile(releaseEntries, path);
|
||||
|
||||
var releases = ReleaseEntry.ParseReleaseFileAndApplyStaging(File.ReadAllText(path), ourGuid).ToArray();
|
||||
Assert.Equal(3, releases.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseReleaseFileShouldReturnNothingForBlankFiles()
|
||||
{
|
||||
Assert.True(ReleaseEntry.ParseReleaseFile("").Count() == 0);
|
||||
Assert.True(ReleaseEntry.ParseReleaseFile(null).Count() == 0);
|
||||
}
|
||||
|
||||
// [Fact]
|
||||
// public void FindCurrentVersionWithExactRidMatch()
|
||||
// {
|
||||
// string _ridReleaseEntries = """
|
||||
//0000000000000000000000000000000000000000 MyApp-1.3-win-x86.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-win-x64.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-win-x86.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-osx-x86.nupkg 123
|
||||
//""";
|
||||
|
||||
// var entries = ReleaseEntry.ParseReleaseFile(_ridReleaseEntries);
|
||||
|
||||
// var e = Utility.FindLatestFullVersion(entries, RID.Parse("win-x86"));
|
||||
// Assert.Equal("MyApp-1.4-win-x86.nupkg", e.OriginalFilename);
|
||||
// }
|
||||
|
||||
// [Fact]
|
||||
// public void FindCurrentVersionWithExactRidMatchNotLatest()
|
||||
// {
|
||||
// string _ridReleaseEntries = """
|
||||
//0000000000000000000000000000000000000000 MyApp-1.3-win-x86.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-win-x64.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-win.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-osx-x86.nupkg 123
|
||||
//""";
|
||||
|
||||
// var entries = ReleaseEntry.ParseReleaseFile(_ridReleaseEntries);
|
||||
|
||||
// var e = Utility.FindLatestFullVersion(entries, RID.Parse("win-x86"));
|
||||
// Assert.Equal("MyApp-1.3-win.nupkg", e.OriginalFilename);
|
||||
// }
|
||||
|
||||
// [Fact]
|
||||
// public void FindCurrentVersionWithExactRidMatchOnlyArchitecture()
|
||||
// {
|
||||
// string _ridReleaseEntries = """
|
||||
//0000000000000000000000000000000000000000 MyApp-1.3-win-x86.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-win-x64.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-win.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-osx-x86.nupkg 123
|
||||
//""";
|
||||
|
||||
// var entries = ReleaseEntry.ParseReleaseFile(_ridReleaseEntries);
|
||||
|
||||
// var e = Utility.FindLatestFullVersion(entries, RID.Parse("win-x86"));
|
||||
// Assert.Equal("MyApp-1.3-win.nupkg", e.OriginalFilename);
|
||||
// }
|
||||
|
||||
static string MockReleaseEntry(string name, float? percentage = null)
|
||||
{
|
||||
if (percentage.HasValue) {
|
||||
var ret = String.Format("94689fede03fed7ab59c24337673a27837f0c3ec {0} 1004502 # {1:F0}%", name, percentage * 100.0f);
|
||||
return ret;
|
||||
} else {
|
||||
return String.Format("94689fede03fed7ab59c24337673a27837f0c3ec {0} 1004502", name);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanParseGeneratedReleaseEntryAsString()
|
||||
{
|
||||
var path = PathHelper.GetFixture("Squirrel.Core.1.1.0.0.nupkg");
|
||||
var entryAsString = ReleaseEntry.GenerateFromFile(path).EntryAsString;
|
||||
ReleaseEntry.ParseReleaseEntry(entryAsString);
|
||||
}
|
||||
|
||||
//[Fact]
|
||||
//public void GetLatestReleaseWithNullCollectionReturnsNull()
|
||||
//{
|
||||
// Assert.Null(ReleasePackageBuilder.GetPreviousRelease(
|
||||
// null, null, null, null));
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public void GetLatestReleaseWithEmptyCollectionReturnsNull()
|
||||
//{
|
||||
// Assert.Null(ReleasePackageBuilder.GetPreviousRelease(
|
||||
// Enumerable.Empty<ReleaseEntry>(), null, null, null));
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public void WhenCurrentReleaseMatchesLastReleaseReturnNull()
|
||||
//{
|
||||
// var package = new ReleasePackageBuilder("Espera-1.7.6-beta.nupkg");
|
||||
|
||||
// var releaseEntries = new[] {
|
||||
// ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.6-beta.nupkg"))
|
||||
// };
|
||||
// Assert.Null(ReleasePackageBuilder.GetPreviousRelease(
|
||||
// releaseEntries, package, @"C:\temp\somefolder", null));
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public void WhenMultipleReleaseMatchesReturnEarlierResult()
|
||||
//{
|
||||
// var expected = SemanticVersion.Parse("1.7.5-beta");
|
||||
// var package = new ReleasePackageBuilder("Espera-1.7.6-beta.nupkg");
|
||||
|
||||
// var releaseEntries = new[] {
|
||||
// ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.6-beta.nupkg")),
|
||||
// ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.5-beta.nupkg"))
|
||||
// };
|
||||
|
||||
// var actual = ReleasePackageBuilder.GetPreviousRelease(
|
||||
// releaseEntries,
|
||||
// package,
|
||||
// @"C:\temp\", null);
|
||||
|
||||
// Assert.Equal(expected, actual.Version);
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public void WhenMultipleReleasesFoundReturnPreviousVersion()
|
||||
//{
|
||||
// var expected = SemanticVersion.Parse("1.7.6-beta");
|
||||
// var input = new ReleasePackageBuilder("Espera-1.7.7-beta.nupkg");
|
||||
|
||||
// var releaseEntries = new[] {
|
||||
// ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.6-beta.nupkg")),
|
||||
// ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.5-beta.nupkg"))
|
||||
// };
|
||||
|
||||
// var actual = ReleasePackageBuilder.GetPreviousRelease(
|
||||
// releaseEntries,
|
||||
// input,
|
||||
// @"C:\temp\", null);
|
||||
|
||||
// Assert.Equal(expected, actual.Version);
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public void WhenMultipleReleasesFoundInOtherOrderReturnPreviousVersion()
|
||||
//{
|
||||
// var expected = SemanticVersion.Parse("1.7.6-beta");
|
||||
// var input = new ReleasePackageBuilder("Espera-1.7.7-beta.nupkg");
|
||||
|
||||
// var releaseEntries = new[] {
|
||||
// ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.5-beta.nupkg")),
|
||||
// ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.6-beta.nupkg"))
|
||||
// };
|
||||
|
||||
// var actual = ReleasePackageBuilder.GetPreviousRelease(
|
||||
// releaseEntries,
|
||||
// input,
|
||||
// @"C:\temp\", null);
|
||||
|
||||
// Assert.Equal(expected, actual.Version);
|
||||
//}
|
||||
|
||||
[Fact]
|
||||
public void WhenReleasesAreOutOfOrderSortByVersion()
|
||||
{
|
||||
var path = Path.GetTempFileName();
|
||||
var firstVersion = SemanticVersion.Parse("1.0.0");
|
||||
var secondVersion = SemanticVersion.Parse("1.1.0");
|
||||
var thirdVersion = SemanticVersion.Parse("1.2.0");
|
||||
|
||||
var releaseEntries = new[] {
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-delta.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-delta.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.0.0-full.nupkg"))
|
||||
};
|
||||
|
||||
ReleaseEntry.WriteReleaseFile(releaseEntries, path);
|
||||
|
||||
var releases = ReleaseEntry.ParseReleaseFile(File.ReadAllText(path)).ToArray();
|
||||
|
||||
Assert.Equal(firstVersion, releases[0].Version);
|
||||
Assert.Equal(secondVersion, releases[1].Version);
|
||||
Assert.Equal(true, releases[1].IsDelta);
|
||||
Assert.Equal(secondVersion, releases[2].Version);
|
||||
Assert.Equal(false, releases[2].IsDelta);
|
||||
Assert.Equal(thirdVersion, releases[3].Version);
|
||||
Assert.Equal(true, releases[3].IsDelta);
|
||||
Assert.Equal(thirdVersion, releases[4].Version);
|
||||
Assert.Equal(false, releases[4].IsDelta);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WhenPreReleasesAreOutOfOrderSortByNumericSuffixSemVer2()
|
||||
{
|
||||
var path = Path.GetTempFileName();
|
||||
var firstVersion = SemanticVersion.Parse("1.1.9-beta.105");
|
||||
var secondVersion = SemanticVersion.Parse("1.2.0-beta.9");
|
||||
var thirdVersion = SemanticVersion.Parse("1.2.0-beta.10");
|
||||
var fourthVersion = SemanticVersion.Parse("1.2.0-beta.100");
|
||||
|
||||
var releaseEntries = new[] {
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-beta.1-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-beta.9-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-beta.100-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.9-beta.105-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-beta.10-full.nupkg"))
|
||||
};
|
||||
|
||||
ReleaseEntry.WriteReleaseFile(releaseEntries, path);
|
||||
|
||||
var releases = ReleaseEntry.ParseReleaseFile(File.ReadAllText(path)).ToArray();
|
||||
|
||||
Assert.Equal(firstVersion, releases[0].Version);
|
||||
Assert.Equal(secondVersion, releases[2].Version);
|
||||
Assert.Equal(thirdVersion, releases[3].Version);
|
||||
Assert.Equal(fourthVersion, releases[4].Version);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StagingUsersGetBetaSoftware()
|
||||
{
|
||||
// NB: We're kind of using a hack here, in that we know that the
|
||||
// last 4 bytes are used as the percentage, and the percentage
|
||||
// effectively measures, "How close are you to zero". Guid.Empty
|
||||
// is v close to zero, because it is zero.
|
||||
var path = Path.GetTempFileName();
|
||||
var ourGuid = Guid.Empty;
|
||||
|
||||
var releaseEntries = new[] {
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-full.nupkg", 0.1f)),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.0.0-full.nupkg"))
|
||||
};
|
||||
|
||||
ReleaseEntry.WriteReleaseFile(releaseEntries, path);
|
||||
|
||||
var releases = ReleaseEntry.ParseReleaseFileAndApplyStaging(File.ReadAllText(path), ourGuid).ToArray();
|
||||
Assert.Equal(3, releases.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BorkedUsersGetProductionSoftware()
|
||||
{
|
||||
var path = Path.GetTempFileName();
|
||||
var ourGuid = default(Guid?);
|
||||
|
||||
var releaseEntries = new[] {
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-full.nupkg", 0.1f)),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.0.0-full.nupkg"))
|
||||
};
|
||||
|
||||
ReleaseEntry.WriteReleaseFile(releaseEntries, path);
|
||||
|
||||
var releases = ReleaseEntry.ParseReleaseFileAndApplyStaging(File.ReadAllText(path), ourGuid).ToArray();
|
||||
Assert.Equal(2, releases.Length);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("{22b29e6f-bd2e-43d2-85ca-ffffffffffff}")]
|
||||
[InlineData("{22b29e6f-bd2e-43d2-85ca-888888888888}")]
|
||||
[InlineData("{22b29e6f-bd2e-43d2-85ca-444444444444}")]
|
||||
public void UnluckyUsersGetProductionSoftware(string inputGuid)
|
||||
{
|
||||
var path = Path.GetTempFileName();
|
||||
var ourGuid = Guid.ParseExact(inputGuid, "B");
|
||||
|
||||
var releaseEntries = new[] {
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-full.nupkg", 0.1f)),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.0.0-full.nupkg"))
|
||||
};
|
||||
|
||||
ReleaseEntry.WriteReleaseFile(releaseEntries, path);
|
||||
|
||||
var releases = ReleaseEntry.ParseReleaseFileAndApplyStaging(File.ReadAllText(path), ourGuid).ToArray();
|
||||
Assert.Equal(2, releases.Length);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("{22b29e6f-bd2e-43d2-85ca-333333333333}")]
|
||||
[InlineData("{22b29e6f-bd2e-43d2-85ca-111111111111}")]
|
||||
[InlineData("{22b29e6f-bd2e-43d2-85ca-000000000000}")]
|
||||
public void LuckyUsersGetBetaSoftware(string inputGuid)
|
||||
{
|
||||
var path = Path.GetTempFileName();
|
||||
var ourGuid = Guid.ParseExact(inputGuid, "B");
|
||||
|
||||
var releaseEntries = new[] {
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-full.nupkg", 0.25f)),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-full.nupkg")),
|
||||
ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.0.0-full.nupkg"))
|
||||
};
|
||||
|
||||
ReleaseEntry.WriteReleaseFile(releaseEntries, path);
|
||||
|
||||
var releases = ReleaseEntry.ParseReleaseFileAndApplyStaging(File.ReadAllText(path), ourGuid).ToArray();
|
||||
Assert.Equal(3, releases.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseReleaseFileShouldReturnNothingForBlankFiles()
|
||||
{
|
||||
Assert.True(ReleaseEntry.ParseReleaseFile("").Count() == 0);
|
||||
Assert.True(ReleaseEntry.ParseReleaseFile(null).Count() == 0);
|
||||
}
|
||||
|
||||
// [Fact]
|
||||
// public void FindCurrentVersionWithExactRidMatch()
|
||||
// {
|
||||
// string _ridReleaseEntries = """
|
||||
//0000000000000000000000000000000000000000 MyApp-1.3-win-x86.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-win-x64.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-win-x86.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-osx-x86.nupkg 123
|
||||
//""";
|
||||
|
||||
// var entries = ReleaseEntry.ParseReleaseFile(_ridReleaseEntries);
|
||||
|
||||
// var e = Utility.FindLatestFullVersion(entries, RID.Parse("win-x86"));
|
||||
// Assert.Equal("MyApp-1.4-win-x86.nupkg", e.OriginalFilename);
|
||||
// }
|
||||
|
||||
// [Fact]
|
||||
// public void FindCurrentVersionWithExactRidMatchNotLatest()
|
||||
// {
|
||||
// string _ridReleaseEntries = """
|
||||
//0000000000000000000000000000000000000000 MyApp-1.3-win-x86.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-win-x64.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-win.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-osx-x86.nupkg 123
|
||||
//""";
|
||||
|
||||
// var entries = ReleaseEntry.ParseReleaseFile(_ridReleaseEntries);
|
||||
|
||||
// var e = Utility.FindLatestFullVersion(entries, RID.Parse("win-x86"));
|
||||
// Assert.Equal("MyApp-1.3-win.nupkg", e.OriginalFilename);
|
||||
// }
|
||||
|
||||
// [Fact]
|
||||
// public void FindCurrentVersionWithExactRidMatchOnlyArchitecture()
|
||||
// {
|
||||
// string _ridReleaseEntries = """
|
||||
//0000000000000000000000000000000000000000 MyApp-1.3-win-x86.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-win-x64.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-win.nupkg 123
|
||||
//0000000000000000000000000000000000000000 MyApp-1.4-osx-x86.nupkg 123
|
||||
//""";
|
||||
|
||||
// var entries = ReleaseEntry.ParseReleaseFile(_ridReleaseEntries);
|
||||
|
||||
// var e = Utility.FindLatestFullVersion(entries, RID.Parse("win-x86"));
|
||||
// Assert.Equal("MyApp-1.3-win.nupkg", e.OriginalFilename);
|
||||
// }
|
||||
|
||||
static string MockReleaseEntry(string name, float? percentage = null)
|
||||
{
|
||||
if (percentage.HasValue) {
|
||||
var ret = String.Format("94689fede03fed7ab59c24337673a27837f0c3ec {0} 1004502 # {1:F0}%", name, percentage * 100.0f);
|
||||
return ret;
|
||||
} else {
|
||||
return String.Format("94689fede03fed7ab59c24337673a27837f0c3ec {0} 1004502", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,40 +6,39 @@ using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Velopack.Tests
|
||||
{
|
||||
public class RuntimeInfoTests
|
||||
{
|
||||
[Fact]
|
||||
public void NugetVersionAgreesWithNbgv()
|
||||
{
|
||||
var args = new List<string> { "get-version", "-v", "NuGetPackageVersion" };
|
||||
var psi = new ProcessStartInfo("nbgv");
|
||||
psi.AppendArgumentListSafe(args, out var _);
|
||||
var current = psi.Output(10_000);
|
||||
Assert.Equal(current, VelopackRuntimeInfo.VelopackNugetVersion.ToString());
|
||||
}
|
||||
namespace Velopack.Tests;
|
||||
|
||||
[Fact]
|
||||
public void PlatformIsCorrect()
|
||||
{
|
||||
public class RuntimeInfoTests
|
||||
{
|
||||
[Fact]
|
||||
public void NugetVersionAgreesWithNbgv()
|
||||
{
|
||||
var args = new List<string> { "get-version", "-v", "NuGetPackageVersion" };
|
||||
var psi = new ProcessStartInfo("nbgv");
|
||||
psi.AppendArgumentListSafe(args, out var _);
|
||||
var current = psi.Output(10_000);
|
||||
Assert.Equal(current, VelopackRuntimeInfo.VelopackNugetVersion.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PlatformIsCorrect()
|
||||
{
|
||||
#if NETFRAMEWORK
|
||||
Assert.True(VelopackRuntimeInfo.IsWindows);
|
||||
Assert.Equal(RuntimeOs.Windows, VelopackRuntimeInfo.SystemOs);
|
||||
#else
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
|
||||
Assert.True(VelopackRuntimeInfo.IsWindows);
|
||||
Assert.Equal(RuntimeOs.Windows, VelopackRuntimeInfo.SystemOs);
|
||||
#else
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
|
||||
Assert.True(VelopackRuntimeInfo.IsWindows);
|
||||
Assert.Equal(RuntimeOs.Windows, VelopackRuntimeInfo.SystemOs);
|
||||
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
|
||||
Assert.True(VelopackRuntimeInfo.IsLinux);
|
||||
Assert.Equal(RuntimeOs.Linux, VelopackRuntimeInfo.SystemOs);
|
||||
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
|
||||
Assert.True(VelopackRuntimeInfo.IsOSX);
|
||||
Assert.Equal(RuntimeOs.OSX, VelopackRuntimeInfo.SystemOs);
|
||||
} else {
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
#endif
|
||||
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
|
||||
Assert.True(VelopackRuntimeInfo.IsLinux);
|
||||
Assert.Equal(RuntimeOs.Linux, VelopackRuntimeInfo.SystemOs);
|
||||
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
|
||||
Assert.True(VelopackRuntimeInfo.IsOSX);
|
||||
Assert.Equal(RuntimeOs.OSX, VelopackRuntimeInfo.SystemOs);
|
||||
} else {
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,107 +2,106 @@
|
||||
using System.Net.Http;
|
||||
using Velopack.Windows;
|
||||
|
||||
namespace Velopack.Tests
|
||||
namespace Velopack.Tests;
|
||||
|
||||
public class RuntimeTests
|
||||
{
|
||||
public class RuntimeTests
|
||||
[Theory]
|
||||
[InlineData("net6", "net6-x64-desktop")]
|
||||
[InlineData("net6.0", "net6-x64-desktop")]
|
||||
[InlineData("net6-x64", "net6-x64-desktop")]
|
||||
[InlineData("net6-x86", "net6-x86-desktop")]
|
||||
[InlineData("net3.1", "netcoreapp3.1-x64-desktop")]
|
||||
[InlineData("netcoreapp3.1", "netcoreapp3.1-x64-desktop")]
|
||||
[InlineData("net3.1-x86", "netcoreapp3.1-x86-desktop")]
|
||||
[InlineData("net6.0.2", "net6.0.2-x64-desktop")]
|
||||
[InlineData("net6.0.2-x86", "net6.0.2-x86-desktop")]
|
||||
[InlineData("net6.0.1-x86", "net6.0.1-x86-desktop")]
|
||||
[InlineData("net6.0.0", "net6-x64-desktop")]
|
||||
[InlineData("net6.0-x64-desktop", "net6-x64-desktop")]
|
||||
[InlineData("net7.0-x64-runtime", "net7-x64-runtime")]
|
||||
[InlineData("net7.0-x64-asp", "net7-x64-asp")]
|
||||
[InlineData("net7.0-desktop", "net7-x64-desktop")]
|
||||
[InlineData("net7.0-runtime", "net7-x64-runtime")]
|
||||
public void DotnetParsesValidVersions(string input, string expected)
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("net6", "net6-x64-desktop")]
|
||||
[InlineData("net6.0", "net6-x64-desktop")]
|
||||
[InlineData("net6-x64", "net6-x64-desktop")]
|
||||
[InlineData("net6-x86", "net6-x86-desktop")]
|
||||
[InlineData("net3.1", "netcoreapp3.1-x64-desktop")]
|
||||
[InlineData("netcoreapp3.1", "netcoreapp3.1-x64-desktop")]
|
||||
[InlineData("net3.1-x86", "netcoreapp3.1-x86-desktop")]
|
||||
[InlineData("net6.0.2", "net6.0.2-x64-desktop")]
|
||||
[InlineData("net6.0.2-x86", "net6.0.2-x86-desktop")]
|
||||
[InlineData("net6.0.1-x86", "net6.0.1-x86-desktop")]
|
||||
[InlineData("net6.0.0", "net6-x64-desktop")]
|
||||
[InlineData("net6.0-x64-desktop", "net6-x64-desktop")]
|
||||
[InlineData("net7.0-x64-runtime", "net7-x64-runtime")]
|
||||
[InlineData("net7.0-x64-asp", "net7-x64-asp")]
|
||||
[InlineData("net7.0-desktop", "net7-x64-desktop")]
|
||||
[InlineData("net7.0-runtime", "net7-x64-runtime")]
|
||||
public void DotnetParsesValidVersions(string input, string expected)
|
||||
{
|
||||
var p = Runtimes.DotnetInfo.Parse(input);
|
||||
Assert.Equal(expected, p.Id);
|
||||
}
|
||||
var p = Runtimes.DotnetInfo.Parse(input);
|
||||
Assert.Equal(expected, p.Id);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("net3.2")]
|
||||
[InlineData("net4.9")]
|
||||
[InlineData("net6.0.0.4")]
|
||||
[InlineData("net7.0-x64-base")]
|
||||
[InlineData("net6-basd")]
|
||||
[InlineData("net6-x64-aakaka")]
|
||||
public void DotnetParseThrowsInvalidVersion(string input)
|
||||
{
|
||||
Assert.ThrowsAny<Exception>(() => Runtimes.DotnetInfo.Parse(input));
|
||||
}
|
||||
[Theory]
|
||||
[InlineData("net3.2")]
|
||||
[InlineData("net4.9")]
|
||||
[InlineData("net6.0.0.4")]
|
||||
[InlineData("net7.0-x64-base")]
|
||||
[InlineData("net6-basd")]
|
||||
[InlineData("net6-x64-aakaka")]
|
||||
public void DotnetParseThrowsInvalidVersion(string input)
|
||||
{
|
||||
Assert.ThrowsAny<Exception>(() => Runtimes.DotnetInfo.Parse(input));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("net6", true)]
|
||||
[InlineData("net20.0", true)]
|
||||
[InlineData("net5.0.14-x86", true)]
|
||||
[InlineData("netcoreapp3.1-x86", true)]
|
||||
[InlineData("net48", true)]
|
||||
[InlineData("netcoreapp4.8", false)]
|
||||
[InlineData("net4.8", false)]
|
||||
[InlineData("net2.5", false)]
|
||||
[InlineData("vcredist110-x64", true)]
|
||||
[InlineData("vcredist110-x86", true)]
|
||||
[InlineData("vcredist110", true)]
|
||||
[InlineData("vcredist143", true)]
|
||||
[InlineData("asd", false)]
|
||||
[InlineData("", false)]
|
||||
[InlineData(null, false)]
|
||||
[InlineData("net6-x64", true)]
|
||||
[InlineData("net6-x64-runtime", true)]
|
||||
[InlineData("net6-x64-desktop", true)]
|
||||
public void GetRuntimeTests(string input, bool expected)
|
||||
{
|
||||
var dn = Runtimes.GetRuntimeByName(input);
|
||||
Assert.Equal(expected, dn != null);
|
||||
}
|
||||
[Theory]
|
||||
[InlineData("net6", true)]
|
||||
[InlineData("net20.0", true)]
|
||||
[InlineData("net5.0.14-x86", true)]
|
||||
[InlineData("netcoreapp3.1-x86", true)]
|
||||
[InlineData("net48", true)]
|
||||
[InlineData("netcoreapp4.8", false)]
|
||||
[InlineData("net4.8", false)]
|
||||
[InlineData("net2.5", false)]
|
||||
[InlineData("vcredist110-x64", true)]
|
||||
[InlineData("vcredist110-x86", true)]
|
||||
[InlineData("vcredist110", true)]
|
||||
[InlineData("vcredist143", true)]
|
||||
[InlineData("asd", false)]
|
||||
[InlineData("", false)]
|
||||
[InlineData(null, false)]
|
||||
[InlineData("net6-x64", true)]
|
||||
[InlineData("net6-x64-runtime", true)]
|
||||
[InlineData("net6-x64-desktop", true)]
|
||||
public void GetRuntimeTests(string input, bool expected)
|
||||
{
|
||||
var dn = Runtimes.GetRuntimeByName(input);
|
||||
Assert.Equal(expected, dn != null);
|
||||
}
|
||||
|
||||
[Theory(Skip = "Only run when needed")]
|
||||
[InlineData("3.1", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.WindowsDesktop)]
|
||||
[InlineData("3.1", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.Runtime)]
|
||||
[InlineData("3.1", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.AspNetCore)]
|
||||
[InlineData("3.1", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.WindowsDesktop)]
|
||||
[InlineData("3.1", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.Runtime)]
|
||||
[InlineData("3.1", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.AspNetCore)]
|
||||
[InlineData("5.0", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.WindowsDesktop)]
|
||||
[InlineData("5.0", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.Runtime)]
|
||||
[InlineData("5.0", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.AspNetCore)]
|
||||
[InlineData("5.0", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.WindowsDesktop)]
|
||||
[InlineData("5.0", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.Runtime)]
|
||||
[InlineData("5.0", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.AspNetCore)]
|
||||
[InlineData("7.0", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.WindowsDesktop)]
|
||||
[InlineData("7.0", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.Runtime)]
|
||||
[InlineData("7.0", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.AspNetCore)]
|
||||
[InlineData("7.0", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.WindowsDesktop)]
|
||||
[InlineData("7.0", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.Runtime)]
|
||||
[InlineData("7.0", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.AspNetCore)]
|
||||
public async Task MicrosoftReturnsValidDotnetDownload(string minversion, RuntimeCpu architecture, Runtimes.DotnetRuntimeType runtimeType)
|
||||
{
|
||||
var dni = new Runtimes.DotnetInfo(minversion, architecture, runtimeType);
|
||||
var url = await dni.GetDownloadUrl();
|
||||
[Theory(Skip = "Only run when needed")]
|
||||
[InlineData("3.1", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.WindowsDesktop)]
|
||||
[InlineData("3.1", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.Runtime)]
|
||||
[InlineData("3.1", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.AspNetCore)]
|
||||
[InlineData("3.1", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.WindowsDesktop)]
|
||||
[InlineData("3.1", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.Runtime)]
|
||||
[InlineData("3.1", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.AspNetCore)]
|
||||
[InlineData("5.0", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.WindowsDesktop)]
|
||||
[InlineData("5.0", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.Runtime)]
|
||||
[InlineData("5.0", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.AspNetCore)]
|
||||
[InlineData("5.0", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.WindowsDesktop)]
|
||||
[InlineData("5.0", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.Runtime)]
|
||||
[InlineData("5.0", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.AspNetCore)]
|
||||
[InlineData("7.0", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.WindowsDesktop)]
|
||||
[InlineData("7.0", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.Runtime)]
|
||||
[InlineData("7.0", RuntimeCpu.x86, Runtimes.DotnetRuntimeType.AspNetCore)]
|
||||
[InlineData("7.0", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.WindowsDesktop)]
|
||||
[InlineData("7.0", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.Runtime)]
|
||||
[InlineData("7.0", RuntimeCpu.x64, Runtimes.DotnetRuntimeType.AspNetCore)]
|
||||
public async Task MicrosoftReturnsValidDotnetDownload(string minversion, RuntimeCpu architecture, Runtimes.DotnetRuntimeType runtimeType)
|
||||
{
|
||||
var dni = new Runtimes.DotnetInfo(minversion, architecture, runtimeType);
|
||||
var url = await dni.GetDownloadUrl();
|
||||
|
||||
Assert.Contains(minversion, url, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains(architecture.ToString(), url, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains(minversion, url, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains(architecture.ToString(), url, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (runtimeType == Runtimes.DotnetRuntimeType.Runtime)
|
||||
Assert.Matches(@"/dotnet-runtime-\d", url);
|
||||
else if (runtimeType == Runtimes.DotnetRuntimeType.AspNetCore)
|
||||
Assert.Matches(@"/aspnetcore-runtime-\d", url);
|
||||
else if (runtimeType == Runtimes.DotnetRuntimeType.WindowsDesktop)
|
||||
Assert.Matches(@"/windowsdesktop-runtime-\d", url);
|
||||
if (runtimeType == Runtimes.DotnetRuntimeType.Runtime)
|
||||
Assert.Matches(@"/dotnet-runtime-\d", url);
|
||||
else if (runtimeType == Runtimes.DotnetRuntimeType.AspNetCore)
|
||||
Assert.Matches(@"/aspnetcore-runtime-\d", url);
|
||||
else if (runtimeType == Runtimes.DotnetRuntimeType.WindowsDesktop)
|
||||
Assert.Matches(@"/windowsdesktop-runtime-\d", url);
|
||||
|
||||
using var hc = new HttpClient();
|
||||
var result = await hc.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
|
||||
result.EnsureSuccessStatusCode();
|
||||
}
|
||||
using var hc = new HttpClient();
|
||||
var result = await hc.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
|
||||
result.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
@@ -8,56 +8,55 @@ using System.Threading.Tasks;
|
||||
using Velopack.Locators;
|
||||
using Velopack.Windows;
|
||||
|
||||
namespace Velopack.Tests
|
||||
namespace Velopack.Tests;
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class ShortcutTests
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class ShortcutTests
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public ShortcutTests(ITestOutputHelper output)
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
_output = output;
|
||||
}
|
||||
|
||||
public ShortcutTests(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
[SkippableFact]
|
||||
public void CanCreateAndRemoveShortcuts()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<ShortcutTests>();
|
||||
string exeName = "NotSquirrelAwareApp.exe";
|
||||
|
||||
[SkippableFact]
|
||||
public void CanCreateAndRemoveShortcuts()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<ShortcutTests>();
|
||||
string exeName = "NotSquirrelAwareApp.exe";
|
||||
using var _1 = Utility.GetTempDirectory(out var rootDir);
|
||||
var packages = Directory.CreateDirectory(Path.Combine(rootDir, "packages"));
|
||||
var current = Directory.CreateDirectory(Path.Combine(rootDir, "current"));
|
||||
|
||||
using var _1 = Utility.GetTempDirectory(out var rootDir);
|
||||
var packages = Directory.CreateDirectory(Path.Combine(rootDir, "packages"));
|
||||
var current = Directory.CreateDirectory(Path.Combine(rootDir, "current"));
|
||||
PathHelper.CopyFixtureTo("AvaloniaCrossPlat-1.0.15-win-full.nupkg", packages.FullName);
|
||||
PathHelper.CopyFixtureTo(exeName, current.FullName);
|
||||
|
||||
PathHelper.CopyFixtureTo("AvaloniaCrossPlat-1.0.15-win-full.nupkg", packages.FullName);
|
||||
PathHelper.CopyFixtureTo(exeName, current.FullName);
|
||||
var locator = new TestVelopackLocator("AvaloniaCrossPlat", "1.0.0", packages.FullName, current.FullName, rootDir, null, null, logger);
|
||||
var sh = new Shortcuts(logger, locator);
|
||||
var flag = ShortcutLocation.StartMenuRoot | ShortcutLocation.Desktop;
|
||||
sh.DeleteShortcuts(exeName, flag);
|
||||
sh.CreateShortcut(exeName, flag, false, "");
|
||||
var shortcuts = sh.FindShortcuts(exeName, flag);
|
||||
Assert.Equal(2, shortcuts.Keys.Count);
|
||||
|
||||
var locator = new TestVelopackLocator("AvaloniaCrossPlat", "1.0.0", packages.FullName, current.FullName, rootDir, null, null, logger);
|
||||
var sh = new Shortcuts(logger, locator);
|
||||
var flag = ShortcutLocation.StartMenuRoot | ShortcutLocation.Desktop;
|
||||
sh.DeleteShortcuts(exeName, flag);
|
||||
sh.CreateShortcut(exeName, flag, false, "");
|
||||
var shortcuts = sh.FindShortcuts(exeName, flag);
|
||||
Assert.Equal(2, shortcuts.Keys.Count);
|
||||
var startDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Programs");
|
||||
var desktopDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop));
|
||||
var lnkName = "SquirrelAwareApp.lnk";
|
||||
|
||||
var startDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Programs");
|
||||
var desktopDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop));
|
||||
var lnkName = "SquirrelAwareApp.lnk";
|
||||
var start = shortcuts[ShortcutLocation.StartMenuRoot];
|
||||
var desktop = shortcuts[ShortcutLocation.Desktop];
|
||||
|
||||
var start = shortcuts[ShortcutLocation.StartMenuRoot];
|
||||
var desktop = shortcuts[ShortcutLocation.Desktop];
|
||||
var target = Path.Combine(current.FullName, exeName);
|
||||
Assert.Equal(Path.Combine(startDir, lnkName), start.ShortCutFile);
|
||||
Assert.Equal(target, start.Target);
|
||||
Assert.Equal(Path.Combine(desktopDir, lnkName), desktop.ShortCutFile);
|
||||
Assert.Equal(target, desktop.Target);
|
||||
|
||||
var target = Path.Combine(current.FullName, exeName);
|
||||
Assert.Equal(Path.Combine(startDir, lnkName), start.ShortCutFile);
|
||||
Assert.Equal(target, start.Target);
|
||||
Assert.Equal(Path.Combine(desktopDir, lnkName), desktop.ShortCutFile);
|
||||
Assert.Equal(target, desktop.Target);
|
||||
|
||||
sh.DeleteShortcuts(exeName, flag);
|
||||
var after = sh.FindShortcuts(exeName, flag);
|
||||
Assert.Equal(0, after.Keys.Count);
|
||||
}
|
||||
sh.DeleteShortcuts(exeName, flag);
|
||||
var after = sh.FindShortcuts(exeName, flag);
|
||||
Assert.Equal(0, after.Keys.Count);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,136 +16,135 @@ using SimpleJsonNameAttribute = System.Text.Json.Serialization.JsonPropertyNameA
|
||||
using SimpleJsonNameAttribute = Velopack.Json.JsonPropertyNameAttribute;
|
||||
#endif
|
||||
|
||||
namespace Velopack.Tests
|
||||
namespace Velopack.Tests;
|
||||
|
||||
public class SimpleJsonTests
|
||||
{
|
||||
public class SimpleJsonTests
|
||||
public static readonly JsonSerializerOptions Options = new JsonSerializerOptions {
|
||||
AllowTrailingCommas = true,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip,
|
||||
PropertyNameCaseInsensitive = true,
|
||||
Converters = { new JsonStringEnumConverter(), new SemanticVersionConverter() },
|
||||
};
|
||||
|
||||
internal class SemanticVersionConverter : JsonConverter<SemanticVersion>
|
||||
{
|
||||
public static readonly JsonSerializerOptions Options = new JsonSerializerOptions {
|
||||
AllowTrailingCommas = true,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip,
|
||||
PropertyNameCaseInsensitive = true,
|
||||
Converters = { new JsonStringEnumConverter(), new SemanticVersionConverter() },
|
||||
};
|
||||
|
||||
internal class SemanticVersionConverter : JsonConverter<SemanticVersion>
|
||||
public override SemanticVersion Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
public override SemanticVersion Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
return SemanticVersion.Parse(reader.GetString());
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, SemanticVersion value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(value.ToFullString());
|
||||
}
|
||||
return SemanticVersion.Parse(reader.GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JsonPropertyNameAttribueWrks()
|
||||
public override void Write(Utf8JsonWriter writer, SemanticVersion value, JsonSerializerOptions options)
|
||||
{
|
||||
var obj = new TestGithubReleaseAsset {
|
||||
UrlSomething = "https://ho",
|
||||
BrowserDownloadUrl = "https://browser",
|
||||
ContentType = "via",
|
||||
};
|
||||
var json = JsonSerializer.Serialize(obj, Options);
|
||||
var dez = SimpleJson.DeserializeObject<GithubReleaseAsset>(json);
|
||||
Assert.Equal(obj.UrlSomething, dez.Url);
|
||||
Assert.Equal(obj.BrowserDownloadUrl, dez.BrowserDownloadUrl);
|
||||
Assert.Equal(obj.ContentType, dez.ContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JsonCanRoundTripComplexTypes()
|
||||
{
|
||||
var obj = new TestClass1 {
|
||||
NameAsd = "hello",
|
||||
UpcomingRelease = true,
|
||||
ReleasedAt = DateTime.UtcNow,
|
||||
Version = SemanticVersion.Parse("1.2.3-hello.23+metadata"),
|
||||
AssetType = VelopackAssetType.Delta,
|
||||
Greetings = new List<string> { "hi", "there" },
|
||||
};
|
||||
var json = JsonSerializer.Serialize(obj, Options);
|
||||
|
||||
Assert.Contains("\"Delta\"", json);
|
||||
|
||||
var dez = SimpleJson.DeserializeObject<TestClass2>(json);
|
||||
Assert.Equal(obj.NameAsd, dez.nameAsd);
|
||||
Assert.Equal(obj.UpcomingRelease, dez.upcomingRelease);
|
||||
Assert.Equal(obj.ReleasedAt, dez.releasedAt);
|
||||
Assert.Equal(obj.Version, dez.version);
|
||||
Assert.Equal(obj.AssetType, dez.assetType);
|
||||
Assert.Equal(obj.Greetings, dez.greetings);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JsonCanParseReleasesJson()
|
||||
{
|
||||
var json = File.ReadAllText(PathHelper.GetFixture("testfeed.json"));
|
||||
var feed = SimpleJson.DeserializeObject<VelopackAssetFeed>(json);
|
||||
Assert.Equal(21, feed.Assets.Length);
|
||||
Assert.True(feed.Assets.First().Version == new SemanticVersion(1, 0, 11));
|
||||
}
|
||||
|
||||
public class TestGithubReleaseAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// The asset URL for this release asset. Requests to this URL will use API
|
||||
/// quota and return JSON unless the 'Accept' header is "application/octet-stream".
|
||||
/// </summary>
|
||||
[JsonPropertyName("url")]
|
||||
public string UrlSomething { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The browser URL for this release asset. This does not use API quota,
|
||||
/// however this URL only works for public repositories. If downloading
|
||||
/// assets from a private repository, the <see cref="Url"/> property must
|
||||
/// be used with an appropriate access token.
|
||||
/// </summary>
|
||||
[JsonPropertyName("browser_download_url")]
|
||||
public string BrowserDownloadUrl { get; set; }
|
||||
|
||||
/// <summary> The mime type of this release asset (as detected by GitHub). </summary>
|
||||
[JsonPropertyName("content_type")]
|
||||
public string ContentType { get; set; }
|
||||
}
|
||||
|
||||
|
||||
internal class TestClass1
|
||||
{
|
||||
public string NameAsd { get; set; }
|
||||
|
||||
[JsonPropertyName("upcoming_release888")]
|
||||
public bool UpcomingRelease { get; set; }
|
||||
|
||||
[JsonPropertyName("released_at")]
|
||||
public DateTime ReleasedAt { get; set; }
|
||||
|
||||
public SemanticVersion Version { get; set; }
|
||||
|
||||
[JsonPropertyName("t")]
|
||||
public VelopackAssetType AssetType { get; set; }
|
||||
|
||||
public List<string> Greetings { get; set; }
|
||||
}
|
||||
|
||||
internal class TestClass2
|
||||
{
|
||||
public string nameAsd { get; set; }
|
||||
|
||||
[SimpleJsonName("upcoming_release888")]
|
||||
public bool upcomingRelease { get; set; }
|
||||
|
||||
[SimpleJsonName("released_at")]
|
||||
public DateTime releasedAt { get; set; }
|
||||
|
||||
public SemanticVersion version { get; set; }
|
||||
|
||||
[SimpleJsonName("t")]
|
||||
public VelopackAssetType assetType { get; set; }
|
||||
|
||||
public List<string> greetings { get; set; }
|
||||
writer.WriteStringValue(value.ToFullString());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JsonPropertyNameAttribueWrks()
|
||||
{
|
||||
var obj = new TestGithubReleaseAsset {
|
||||
UrlSomething = "https://ho",
|
||||
BrowserDownloadUrl = "https://browser",
|
||||
ContentType = "via",
|
||||
};
|
||||
var json = JsonSerializer.Serialize(obj, Options);
|
||||
var dez = SimpleJson.DeserializeObject<GithubReleaseAsset>(json);
|
||||
Assert.Equal(obj.UrlSomething, dez.Url);
|
||||
Assert.Equal(obj.BrowserDownloadUrl, dez.BrowserDownloadUrl);
|
||||
Assert.Equal(obj.ContentType, dez.ContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JsonCanRoundTripComplexTypes()
|
||||
{
|
||||
var obj = new TestClass1 {
|
||||
NameAsd = "hello",
|
||||
UpcomingRelease = true,
|
||||
ReleasedAt = DateTime.UtcNow,
|
||||
Version = SemanticVersion.Parse("1.2.3-hello.23+metadata"),
|
||||
AssetType = VelopackAssetType.Delta,
|
||||
Greetings = new List<string> { "hi", "there" },
|
||||
};
|
||||
var json = JsonSerializer.Serialize(obj, Options);
|
||||
|
||||
Assert.Contains("\"Delta\"", json);
|
||||
|
||||
var dez = SimpleJson.DeserializeObject<TestClass2>(json);
|
||||
Assert.Equal(obj.NameAsd, dez.nameAsd);
|
||||
Assert.Equal(obj.UpcomingRelease, dez.upcomingRelease);
|
||||
Assert.Equal(obj.ReleasedAt, dez.releasedAt);
|
||||
Assert.Equal(obj.Version, dez.version);
|
||||
Assert.Equal(obj.AssetType, dez.assetType);
|
||||
Assert.Equal(obj.Greetings, dez.greetings);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JsonCanParseReleasesJson()
|
||||
{
|
||||
var json = File.ReadAllText(PathHelper.GetFixture("testfeed.json"));
|
||||
var feed = SimpleJson.DeserializeObject<VelopackAssetFeed>(json);
|
||||
Assert.Equal(21, feed.Assets.Length);
|
||||
Assert.True(feed.Assets.First().Version == new SemanticVersion(1, 0, 11));
|
||||
}
|
||||
|
||||
public class TestGithubReleaseAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// The asset URL for this release asset. Requests to this URL will use API
|
||||
/// quota and return JSON unless the 'Accept' header is "application/octet-stream".
|
||||
/// </summary>
|
||||
[JsonPropertyName("url")]
|
||||
public string UrlSomething { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The browser URL for this release asset. This does not use API quota,
|
||||
/// however this URL only works for public repositories. If downloading
|
||||
/// assets from a private repository, the <see cref="Url"/> property must
|
||||
/// be used with an appropriate access token.
|
||||
/// </summary>
|
||||
[JsonPropertyName("browser_download_url")]
|
||||
public string BrowserDownloadUrl { get; set; }
|
||||
|
||||
/// <summary> The mime type of this release asset (as detected by GitHub). </summary>
|
||||
[JsonPropertyName("content_type")]
|
||||
public string ContentType { get; set; }
|
||||
}
|
||||
|
||||
|
||||
internal class TestClass1
|
||||
{
|
||||
public string NameAsd { get; set; }
|
||||
|
||||
[JsonPropertyName("upcoming_release888")]
|
||||
public bool UpcomingRelease { get; set; }
|
||||
|
||||
[JsonPropertyName("released_at")]
|
||||
public DateTime ReleasedAt { get; set; }
|
||||
|
||||
public SemanticVersion Version { get; set; }
|
||||
|
||||
[JsonPropertyName("t")]
|
||||
public VelopackAssetType AssetType { get; set; }
|
||||
|
||||
public List<string> Greetings { get; set; }
|
||||
}
|
||||
|
||||
internal class TestClass2
|
||||
{
|
||||
public string nameAsd { get; set; }
|
||||
|
||||
[SimpleJsonName("upcoming_release888")]
|
||||
public bool upcomingRelease { get; set; }
|
||||
|
||||
[SimpleJsonName("released_at")]
|
||||
public DateTime releasedAt { get; set; }
|
||||
|
||||
public SemanticVersion version { get; set; }
|
||||
|
||||
[SimpleJsonName("t")]
|
||||
public VelopackAssetType assetType { get; set; }
|
||||
|
||||
public List<string> greetings { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,147 +1,146 @@
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Velopack.Tests.TestHelpers
|
||||
namespace Velopack.Tests.TestHelpers;
|
||||
|
||||
public static class AssertExtensions
|
||||
{
|
||||
public static class AssertExtensions
|
||||
public static void ShouldBeAboutEqualTo(this DateTimeOffset expected, DateTimeOffset current)
|
||||
{
|
||||
public static void ShouldBeAboutEqualTo(this DateTimeOffset expected, DateTimeOffset current)
|
||||
{
|
||||
Assert.Equal(expected.Date, current.Date);
|
||||
Assert.Equal(expected.Offset, current.Offset);
|
||||
Assert.Equal(expected.Hour, current.Hour);
|
||||
Assert.Equal(expected.Minute, current.Minute);
|
||||
Assert.Equal(expected.Second, current.Second);
|
||||
}
|
||||
|
||||
public static void ShouldBeFalse(this bool currentObject)
|
||||
{
|
||||
Assert.False(currentObject);
|
||||
}
|
||||
|
||||
public static void ShouldBeNull(this object currentObject)
|
||||
{
|
||||
Assert.Null(currentObject);
|
||||
}
|
||||
|
||||
public static void ShouldBeEmpty(this IEnumerable items)
|
||||
{
|
||||
Assert.Empty(items);
|
||||
}
|
||||
|
||||
public static void ShouldNotBeEmpty(this IEnumerable items)
|
||||
{
|
||||
Assert.NotEmpty(items);
|
||||
}
|
||||
|
||||
public static void ShouldBeTrue(this bool currentObject)
|
||||
{
|
||||
Assert.True(currentObject);
|
||||
}
|
||||
|
||||
public static void ShouldEqual(this object compareFrom, object compareTo)
|
||||
{
|
||||
Assert.Equal(compareTo, compareFrom);
|
||||
}
|
||||
|
||||
public static void ShouldEqual<T>(this T compareFrom, T compareTo)
|
||||
{
|
||||
Assert.Equal(compareTo, compareFrom);
|
||||
}
|
||||
|
||||
public static void ShouldBeSameAs<T>(this T actual, T expected)
|
||||
{
|
||||
Assert.Same(expected, actual);
|
||||
}
|
||||
|
||||
public static void ShouldNotBeSameAs<T>(this T actual, T expected)
|
||||
{
|
||||
Assert.NotSame(expected, actual);
|
||||
}
|
||||
|
||||
public static void ShouldBeAssignableFrom<T>(this object instance) where T : class
|
||||
{
|
||||
Assert.IsAssignableFrom<T>(instance);
|
||||
}
|
||||
|
||||
public static void ShouldBeType(this object instance, Type type)
|
||||
{
|
||||
Assert.IsType(type, instance);
|
||||
}
|
||||
|
||||
public static void ShouldBeType<T>(this object instance)
|
||||
{
|
||||
Assert.IsType<T>(instance);
|
||||
}
|
||||
|
||||
public static void ShouldNotBeType<T>(this object instance)
|
||||
{
|
||||
Assert.IsNotType<T>(instance);
|
||||
}
|
||||
|
||||
public static void ShouldContain(this string current, string expectedSubstring, StringComparison comparison)
|
||||
{
|
||||
Assert.Contains(expectedSubstring, current, comparison);
|
||||
}
|
||||
|
||||
public static void ShouldStartWith(this string current, string expectedSubstring, StringComparison comparison)
|
||||
{
|
||||
Assert.True(current.StartsWith(expectedSubstring, comparison));
|
||||
}
|
||||
|
||||
public static void ShouldNotBeNull(this object currentObject)
|
||||
{
|
||||
Assert.NotNull(currentObject);
|
||||
}
|
||||
|
||||
public static void ShouldNotBeNullNorEmpty(this string value)
|
||||
{
|
||||
Assert.NotNull(value);
|
||||
Assert.NotEmpty(value);
|
||||
}
|
||||
|
||||
public static void ShouldNotEqual(this object compareFrom, object compareTo)
|
||||
{
|
||||
Assert.NotEqual(compareTo, compareFrom);
|
||||
}
|
||||
|
||||
public static void ShouldBeGreaterThan<T>(this T current, T other) where T : IComparable
|
||||
{
|
||||
Assert.True(current.CompareTo(other) > 0, current + " is not greater than " + other);
|
||||
}
|
||||
|
||||
public static void ShouldBeLessThan<T>(this T current, T other) where T : IComparable
|
||||
{
|
||||
Assert.True(current.CompareTo(other) < 0, current + " is not less than " + other);
|
||||
}
|
||||
|
||||
static string ToSafeString(this char c)
|
||||
{
|
||||
if (Char.IsControl(c) || Char.IsWhiteSpace(c)) {
|
||||
switch (c) {
|
||||
case '\r':
|
||||
return @"\r";
|
||||
case '\n':
|
||||
return @"\n";
|
||||
case '\t':
|
||||
return @"\t";
|
||||
case '\a':
|
||||
return @"\a";
|
||||
case '\v':
|
||||
return @"\v";
|
||||
case '\f':
|
||||
return @"\f";
|
||||
default:
|
||||
return String.Format("\\u{0:X};", (int) c);
|
||||
}
|
||||
}
|
||||
return c.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
Assert.Equal(expected.Date, current.Date);
|
||||
Assert.Equal(expected.Offset, current.Offset);
|
||||
Assert.Equal(expected.Hour, current.Hour);
|
||||
Assert.Equal(expected.Minute, current.Minute);
|
||||
Assert.Equal(expected.Second, current.Second);
|
||||
}
|
||||
|
||||
public enum DiffStyle
|
||||
public static void ShouldBeFalse(this bool currentObject)
|
||||
{
|
||||
Full,
|
||||
Minimal
|
||||
Assert.False(currentObject);
|
||||
}
|
||||
|
||||
public static void ShouldBeNull(this object currentObject)
|
||||
{
|
||||
Assert.Null(currentObject);
|
||||
}
|
||||
|
||||
public static void ShouldBeEmpty(this IEnumerable items)
|
||||
{
|
||||
Assert.Empty(items);
|
||||
}
|
||||
|
||||
public static void ShouldNotBeEmpty(this IEnumerable items)
|
||||
{
|
||||
Assert.NotEmpty(items);
|
||||
}
|
||||
|
||||
public static void ShouldBeTrue(this bool currentObject)
|
||||
{
|
||||
Assert.True(currentObject);
|
||||
}
|
||||
|
||||
public static void ShouldEqual(this object compareFrom, object compareTo)
|
||||
{
|
||||
Assert.Equal(compareTo, compareFrom);
|
||||
}
|
||||
|
||||
public static void ShouldEqual<T>(this T compareFrom, T compareTo)
|
||||
{
|
||||
Assert.Equal(compareTo, compareFrom);
|
||||
}
|
||||
|
||||
public static void ShouldBeSameAs<T>(this T actual, T expected)
|
||||
{
|
||||
Assert.Same(expected, actual);
|
||||
}
|
||||
|
||||
public static void ShouldNotBeSameAs<T>(this T actual, T expected)
|
||||
{
|
||||
Assert.NotSame(expected, actual);
|
||||
}
|
||||
|
||||
public static void ShouldBeAssignableFrom<T>(this object instance) where T : class
|
||||
{
|
||||
Assert.IsAssignableFrom<T>(instance);
|
||||
}
|
||||
|
||||
public static void ShouldBeType(this object instance, Type type)
|
||||
{
|
||||
Assert.IsType(type, instance);
|
||||
}
|
||||
|
||||
public static void ShouldBeType<T>(this object instance)
|
||||
{
|
||||
Assert.IsType<T>(instance);
|
||||
}
|
||||
|
||||
public static void ShouldNotBeType<T>(this object instance)
|
||||
{
|
||||
Assert.IsNotType<T>(instance);
|
||||
}
|
||||
|
||||
public static void ShouldContain(this string current, string expectedSubstring, StringComparison comparison)
|
||||
{
|
||||
Assert.Contains(expectedSubstring, current, comparison);
|
||||
}
|
||||
|
||||
public static void ShouldStartWith(this string current, string expectedSubstring, StringComparison comparison)
|
||||
{
|
||||
Assert.True(current.StartsWith(expectedSubstring, comparison));
|
||||
}
|
||||
|
||||
public static void ShouldNotBeNull(this object currentObject)
|
||||
{
|
||||
Assert.NotNull(currentObject);
|
||||
}
|
||||
|
||||
public static void ShouldNotBeNullNorEmpty(this string value)
|
||||
{
|
||||
Assert.NotNull(value);
|
||||
Assert.NotEmpty(value);
|
||||
}
|
||||
|
||||
public static void ShouldNotEqual(this object compareFrom, object compareTo)
|
||||
{
|
||||
Assert.NotEqual(compareTo, compareFrom);
|
||||
}
|
||||
|
||||
public static void ShouldBeGreaterThan<T>(this T current, T other) where T : IComparable
|
||||
{
|
||||
Assert.True(current.CompareTo(other) > 0, current + " is not greater than " + other);
|
||||
}
|
||||
|
||||
public static void ShouldBeLessThan<T>(this T current, T other) where T : IComparable
|
||||
{
|
||||
Assert.True(current.CompareTo(other) < 0, current + " is not less than " + other);
|
||||
}
|
||||
|
||||
static string ToSafeString(this char c)
|
||||
{
|
||||
if (Char.IsControl(c) || Char.IsWhiteSpace(c)) {
|
||||
switch (c) {
|
||||
case '\r':
|
||||
return @"\r";
|
||||
case '\n':
|
||||
return @"\n";
|
||||
case '\t':
|
||||
return @"\t";
|
||||
case '\a':
|
||||
return @"\a";
|
||||
case '\v':
|
||||
return @"\v";
|
||||
case '\f':
|
||||
return @"\f";
|
||||
default:
|
||||
return String.Format("\\u{0:X};", (int) c);
|
||||
}
|
||||
}
|
||||
return c.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public enum DiffStyle
|
||||
{
|
||||
Full,
|
||||
Minimal
|
||||
}
|
||||
|
||||
@@ -6,133 +6,132 @@ using System.Reflection;
|
||||
|
||||
// Lovingly stolen from http://exposedobject.codeplex.com/
|
||||
|
||||
namespace Velopack.Tests.TestHelpers
|
||||
namespace Velopack.Tests.TestHelpers;
|
||||
|
||||
public class ExposedClass : DynamicObject
|
||||
{
|
||||
public class ExposedClass : DynamicObject
|
||||
private Type m_type;
|
||||
private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_staticMethods;
|
||||
private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_genStaticMethods;
|
||||
|
||||
private ExposedClass(Type type)
|
||||
{
|
||||
private Type m_type;
|
||||
private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_staticMethods;
|
||||
private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_genStaticMethods;
|
||||
m_type = type;
|
||||
|
||||
private ExposedClass(Type type)
|
||||
m_staticMethods =
|
||||
m_type
|
||||
.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
|
||||
.Where(m => !m.IsGenericMethod)
|
||||
.GroupBy(m => m.Name)
|
||||
.ToDictionary(
|
||||
p => p.Key,
|
||||
p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));
|
||||
|
||||
m_genStaticMethods =
|
||||
m_type
|
||||
.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
|
||||
.Where(m => m.IsGenericMethod)
|
||||
.GroupBy(m => m.Name)
|
||||
.ToDictionary(
|
||||
p => p.Key,
|
||||
p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));
|
||||
}
|
||||
|
||||
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
|
||||
{
|
||||
// Get type args of the call
|
||||
Type[] typeArgs = ExposedObjectHelper.GetTypeArgs(binder);
|
||||
if (typeArgs != null && typeArgs.Length == 0) typeArgs = null;
|
||||
|
||||
//
|
||||
// Try to call a non-generic instance method
|
||||
//
|
||||
if (typeArgs == null
|
||||
&& m_staticMethods.ContainsKey(binder.Name)
|
||||
&& m_staticMethods[binder.Name].ContainsKey(args.Length)
|
||||
&& ExposedObjectHelper.InvokeBestMethod(args, null, m_staticMethods[binder.Name][args.Length], out result))
|
||||
{
|
||||
m_type = type;
|
||||
|
||||
m_staticMethods =
|
||||
m_type
|
||||
.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
|
||||
.Where(m => !m.IsGenericMethod)
|
||||
.GroupBy(m => m.Name)
|
||||
.ToDictionary(
|
||||
p => p.Key,
|
||||
p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));
|
||||
|
||||
m_genStaticMethods =
|
||||
m_type
|
||||
.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
|
||||
.Where(m => m.IsGenericMethod)
|
||||
.GroupBy(m => m.Name)
|
||||
.ToDictionary(
|
||||
p => p.Key,
|
||||
p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
|
||||
//
|
||||
// Try to call a generic instance method
|
||||
//
|
||||
if (m_staticMethods.ContainsKey(binder.Name)
|
||||
&& m_staticMethods[binder.Name].ContainsKey(args.Length))
|
||||
{
|
||||
// Get type args of the call
|
||||
Type[] typeArgs = ExposedObjectHelper.GetTypeArgs(binder);
|
||||
if (typeArgs != null && typeArgs.Length == 0) typeArgs = null;
|
||||
List<MethodInfo> methods = new List<MethodInfo>();
|
||||
|
||||
//
|
||||
// Try to call a non-generic instance method
|
||||
//
|
||||
if (typeArgs == null
|
||||
&& m_staticMethods.ContainsKey(binder.Name)
|
||||
&& m_staticMethods[binder.Name].ContainsKey(args.Length)
|
||||
&& ExposedObjectHelper.InvokeBestMethod(args, null, m_staticMethods[binder.Name][args.Length], out result))
|
||||
foreach (var method in m_genStaticMethods[binder.Name][args.Length])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Try to call a generic instance method
|
||||
//
|
||||
if (m_staticMethods.ContainsKey(binder.Name)
|
||||
&& m_staticMethods[binder.Name].ContainsKey(args.Length))
|
||||
{
|
||||
List<MethodInfo> methods = new List<MethodInfo>();
|
||||
|
||||
foreach (var method in m_genStaticMethods[binder.Name][args.Length])
|
||||
if (method.GetGenericArguments().Length == typeArgs.Length)
|
||||
{
|
||||
if (method.GetGenericArguments().Length == typeArgs.Length)
|
||||
{
|
||||
methods.Add(method.MakeGenericMethod(typeArgs));
|
||||
}
|
||||
}
|
||||
|
||||
if (ExposedObjectHelper.InvokeBestMethod(args, null, methods, out result))
|
||||
{
|
||||
return true;
|
||||
methods.Add(method.MakeGenericMethod(typeArgs));
|
||||
}
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
if (ExposedObjectHelper.InvokeBestMethod(args, null, methods, out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool TrySetMember(SetMemberBinder binder, object value)
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
public override bool TrySetMember(SetMemberBinder binder, object value)
|
||||
{
|
||||
var propertyInfo = m_type.GetProperty(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
if (propertyInfo != null)
|
||||
{
|
||||
var propertyInfo = m_type.GetProperty(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
if (propertyInfo != null)
|
||||
{
|
||||
propertyInfo.SetValue(null, value, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
var fieldInfo = m_type.GetField(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
if (fieldInfo != null)
|
||||
{
|
||||
fieldInfo.SetValue(null, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
propertyInfo.SetValue(null, value, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
var fieldInfo = m_type.GetField(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
if (fieldInfo != null)
|
||||
{
|
||||
var propertyInfo = m_type.GetProperty(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
if (propertyInfo != null)
|
||||
{
|
||||
result = propertyInfo.GetValue(null, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
var fieldInfo = m_type.GetField(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
if (fieldInfo != null)
|
||||
{
|
||||
result = fieldInfo.GetValue(null);
|
||||
return true;
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
fieldInfo.SetValue(null, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static dynamic From(Type type)
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
var propertyInfo = m_type.GetProperty(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
if (propertyInfo != null)
|
||||
{
|
||||
return new ExposedClass(type);
|
||||
result = propertyInfo.GetValue(null, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
var fieldInfo = m_type.GetField(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
if (fieldInfo != null)
|
||||
{
|
||||
result = fieldInfo.GetValue(null);
|
||||
return true;
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static dynamic From(Type type)
|
||||
{
|
||||
return new ExposedClass(type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,164 +7,162 @@ using System.Reflection;
|
||||
|
||||
// Lovingly stolen from http://exposedobject.codeplex.com/
|
||||
|
||||
namespace Velopack.Tests.TestHelpers
|
||||
namespace Velopack.Tests.TestHelpers;
|
||||
|
||||
public class ExposedObject : DynamicObject
|
||||
{
|
||||
public class ExposedObject : DynamicObject
|
||||
private object m_object;
|
||||
private Type m_type;
|
||||
private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_instanceMethods;
|
||||
private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_genInstanceMethods;
|
||||
|
||||
private ExposedObject(object obj)
|
||||
{
|
||||
private object m_object;
|
||||
private Type m_type;
|
||||
private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_instanceMethods;
|
||||
private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_genInstanceMethods;
|
||||
m_object = obj;
|
||||
m_type = obj.GetType();
|
||||
|
||||
private ExposedObject(object obj)
|
||||
{
|
||||
m_object = obj;
|
||||
m_type = obj.GetType();
|
||||
m_instanceMethods =
|
||||
m_type
|
||||
.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(m => !m.IsGenericMethod)
|
||||
.GroupBy(m => m.Name)
|
||||
.ToDictionary(
|
||||
p => p.Key,
|
||||
p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));
|
||||
|
||||
m_instanceMethods =
|
||||
m_type
|
||||
.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(m => !m.IsGenericMethod)
|
||||
.GroupBy(m => m.Name)
|
||||
.ToDictionary(
|
||||
p => p.Key,
|
||||
p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));
|
||||
|
||||
m_genInstanceMethods =
|
||||
m_type
|
||||
.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(m => m.IsGenericMethod)
|
||||
.GroupBy(m => m.Name)
|
||||
.ToDictionary(
|
||||
p => p.Key,
|
||||
p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));
|
||||
}
|
||||
|
||||
public object Object { get { return m_object; } }
|
||||
|
||||
public static dynamic New<T>()
|
||||
{
|
||||
return New(typeof(T));
|
||||
}
|
||||
|
||||
public static dynamic New(Type type)
|
||||
{
|
||||
return new ExposedObject(Activator.CreateInstance(type));
|
||||
}
|
||||
|
||||
public static dynamic From(object obj)
|
||||
{
|
||||
return new ExposedObject(obj);
|
||||
}
|
||||
|
||||
public static T Cast<T>(ExposedObject t)
|
||||
{
|
||||
return (T)t.m_object;
|
||||
}
|
||||
|
||||
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
|
||||
{
|
||||
// Get type args of the call
|
||||
Type[] typeArgs = ExposedObjectHelper.GetTypeArgs(binder);
|
||||
if (typeArgs != null && typeArgs.Length == 0) typeArgs = null;
|
||||
|
||||
//
|
||||
// Try to call a non-generic instance method
|
||||
//
|
||||
if (typeArgs == null
|
||||
&& m_instanceMethods.ContainsKey(binder.Name)
|
||||
&& m_instanceMethods[binder.Name].ContainsKey(args.Length)
|
||||
&& ExposedObjectHelper.InvokeBestMethod(args, m_object, m_instanceMethods[binder.Name][args.Length], out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Try to call a generic instance method
|
||||
//
|
||||
if (m_instanceMethods.ContainsKey(binder.Name)
|
||||
&& m_instanceMethods[binder.Name].ContainsKey(args.Length))
|
||||
{
|
||||
List<MethodInfo> methods = new List<MethodInfo>();
|
||||
|
||||
if (m_genInstanceMethods.ContainsKey(binder.Name) &&
|
||||
m_genInstanceMethods[binder.Name].ContainsKey(args.Length))
|
||||
{
|
||||
foreach (var method in m_genInstanceMethods[binder.Name][args.Length])
|
||||
{
|
||||
if (method.GetGenericArguments().Length == typeArgs.Length)
|
||||
{
|
||||
methods.Add(method.MakeGenericMethod(typeArgs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ExposedObjectHelper.InvokeBestMethod(args, m_object, methods, out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TrySetMember(SetMemberBinder binder, object value)
|
||||
{
|
||||
var propertyInfo = m_type.GetProperty(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
if (propertyInfo != null)
|
||||
{
|
||||
propertyInfo.SetValue(m_object, value, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
var fieldInfo = m_type.GetField(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
if (fieldInfo != null)
|
||||
{
|
||||
fieldInfo.SetValue(m_object, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
var propertyInfo = m_object.GetType().GetProperty(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
if (propertyInfo != null)
|
||||
{
|
||||
result = propertyInfo.GetValue(m_object, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
var fieldInfo = m_object.GetType().GetField(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
if (fieldInfo != null)
|
||||
{
|
||||
result = fieldInfo.GetValue(m_object);
|
||||
return true;
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TryConvert(ConvertBinder binder, out object result)
|
||||
{
|
||||
result = m_object;
|
||||
return true;
|
||||
}
|
||||
m_genInstanceMethods =
|
||||
m_type
|
||||
.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(m => m.IsGenericMethod)
|
||||
.GroupBy(m => m.Name)
|
||||
.ToDictionary(
|
||||
p => p.Key,
|
||||
p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));
|
||||
}
|
||||
|
||||
public object Object { get { return m_object; } }
|
||||
|
||||
public static dynamic New<T>()
|
||||
{
|
||||
return New(typeof(T));
|
||||
}
|
||||
|
||||
public static dynamic New(Type type)
|
||||
{
|
||||
return new ExposedObject(Activator.CreateInstance(type));
|
||||
}
|
||||
|
||||
public static dynamic From(object obj)
|
||||
{
|
||||
return new ExposedObject(obj);
|
||||
}
|
||||
|
||||
public static T Cast<T>(ExposedObject t)
|
||||
{
|
||||
return (T)t.m_object;
|
||||
}
|
||||
|
||||
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
|
||||
{
|
||||
// Get type args of the call
|
||||
Type[] typeArgs = ExposedObjectHelper.GetTypeArgs(binder);
|
||||
if (typeArgs != null && typeArgs.Length == 0) typeArgs = null;
|
||||
|
||||
//
|
||||
// Try to call a non-generic instance method
|
||||
//
|
||||
if (typeArgs == null
|
||||
&& m_instanceMethods.ContainsKey(binder.Name)
|
||||
&& m_instanceMethods[binder.Name].ContainsKey(args.Length)
|
||||
&& ExposedObjectHelper.InvokeBestMethod(args, m_object, m_instanceMethods[binder.Name][args.Length], out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Try to call a generic instance method
|
||||
//
|
||||
if (m_instanceMethods.ContainsKey(binder.Name)
|
||||
&& m_instanceMethods[binder.Name].ContainsKey(args.Length))
|
||||
{
|
||||
List<MethodInfo> methods = new List<MethodInfo>();
|
||||
|
||||
if (m_genInstanceMethods.ContainsKey(binder.Name) &&
|
||||
m_genInstanceMethods[binder.Name].ContainsKey(args.Length))
|
||||
{
|
||||
foreach (var method in m_genInstanceMethods[binder.Name][args.Length])
|
||||
{
|
||||
if (method.GetGenericArguments().Length == typeArgs.Length)
|
||||
{
|
||||
methods.Add(method.MakeGenericMethod(typeArgs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ExposedObjectHelper.InvokeBestMethod(args, m_object, methods, out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TrySetMember(SetMemberBinder binder, object value)
|
||||
{
|
||||
var propertyInfo = m_type.GetProperty(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
if (propertyInfo != null)
|
||||
{
|
||||
propertyInfo.SetValue(m_object, value, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
var fieldInfo = m_type.GetField(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
if (fieldInfo != null)
|
||||
{
|
||||
fieldInfo.SetValue(m_object, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
var propertyInfo = m_object.GetType().GetProperty(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
if (propertyInfo != null)
|
||||
{
|
||||
result = propertyInfo.GetValue(m_object, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
var fieldInfo = m_object.GetType().GetField(
|
||||
binder.Name,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
if (fieldInfo != null)
|
||||
{
|
||||
result = fieldInfo.GetValue(m_object);
|
||||
return true;
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TryConvert(ConvertBinder binder, out object result)
|
||||
{
|
||||
result = m_object;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,89 +6,88 @@ using System.Dynamic;
|
||||
|
||||
// Lovingly stolen from http://exposedobject.codeplex.com/
|
||||
|
||||
namespace Velopack.Tests.TestHelpers
|
||||
namespace Velopack.Tests.TestHelpers;
|
||||
|
||||
internal class ExposedObjectHelper
|
||||
{
|
||||
internal class ExposedObjectHelper
|
||||
private static Type s_csharpInvokePropertyType =
|
||||
typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)
|
||||
.Assembly
|
||||
.GetType("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");
|
||||
|
||||
internal static bool InvokeBestMethod(object[] args, object target, List<MethodInfo> instanceMethods, out object result)
|
||||
{
|
||||
private static Type s_csharpInvokePropertyType =
|
||||
typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)
|
||||
.Assembly
|
||||
.GetType("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");
|
||||
|
||||
internal static bool InvokeBestMethod(object[] args, object target, List<MethodInfo> instanceMethods, out object result)
|
||||
if (instanceMethods.Count == 1)
|
||||
{
|
||||
if (instanceMethods.Count == 1)
|
||||
// Just one matching instance method - call it
|
||||
if (TryInvoke(instanceMethods[0], target, args, out result))
|
||||
{
|
||||
// Just one matching instance method - call it
|
||||
if (TryInvoke(instanceMethods[0], target, args, out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (instanceMethods.Count > 1)
|
||||
{
|
||||
// Find a method with best matching parameters
|
||||
MethodInfo best = null;
|
||||
Type[] bestParams = null;
|
||||
Type[] actualParams = args.Select(p => p == null ? typeof(object) : p.GetType()).ToArray();
|
||||
|
||||
Func<Type[], Type[], bool> isAssignableFrom = (a, b) =>
|
||||
{
|
||||
for (int i = 0; i < a.Length; i++)
|
||||
{
|
||||
if (!a[i].IsAssignableFrom(b[i])) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
foreach (var method in instanceMethods.Where(m => m.GetParameters().Length == args.Length))
|
||||
{
|
||||
Type[] mParams = method.GetParameters().Select(x => x.ParameterType).ToArray();
|
||||
if (isAssignableFrom(mParams, actualParams))
|
||||
{
|
||||
if (best == null || isAssignableFrom(bestParams, mParams))
|
||||
{
|
||||
best = method;
|
||||
bestParams = mParams;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best != null && TryInvoke(best, target, args, out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool TryInvoke(MethodInfo methodInfo, object target, object[] args, out object result)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = methodInfo.Invoke(target, args);
|
||||
return true;
|
||||
}
|
||||
catch (TargetInvocationException) { }
|
||||
catch (TargetParameterCountException) { }
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
internal static Type[] GetTypeArgs(InvokeMemberBinder binder)
|
||||
else if (instanceMethods.Count > 1)
|
||||
{
|
||||
if (s_csharpInvokePropertyType.IsInstanceOfType(binder))
|
||||
// Find a method with best matching parameters
|
||||
MethodInfo best = null;
|
||||
Type[] bestParams = null;
|
||||
Type[] actualParams = args.Select(p => p == null ? typeof(object) : p.GetType()).ToArray();
|
||||
|
||||
Func<Type[], Type[], bool> isAssignableFrom = (a, b) =>
|
||||
{
|
||||
PropertyInfo typeArgsProperty = s_csharpInvokePropertyType.GetProperty("TypeArguments");
|
||||
return ((IEnumerable<Type>)typeArgsProperty.GetValue(binder, null)).ToArray();
|
||||
for (int i = 0; i < a.Length; i++)
|
||||
{
|
||||
if (!a[i].IsAssignableFrom(b[i])) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
foreach (var method in instanceMethods.Where(m => m.GetParameters().Length == args.Length))
|
||||
{
|
||||
Type[] mParams = method.GetParameters().Select(x => x.ParameterType).ToArray();
|
||||
if (isAssignableFrom(mParams, actualParams))
|
||||
{
|
||||
if (best == null || isAssignableFrom(bestParams, mParams))
|
||||
{
|
||||
best = method;
|
||||
bestParams = mParams;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best != null && TryInvoke(best, target, args, out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool TryInvoke(MethodInfo methodInfo, object target, object[] args, out object result)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = methodInfo.Invoke(target, args);
|
||||
return true;
|
||||
}
|
||||
catch (TargetInvocationException) { }
|
||||
catch (TargetParameterCountException) { }
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
internal static Type[] GetTypeArgs(InvokeMemberBinder binder)
|
||||
{
|
||||
if (s_csharpInvokePropertyType.IsInstanceOfType(binder))
|
||||
{
|
||||
PropertyInfo typeArgsProperty = s_csharpInvokePropertyType.GetProperty("TypeArguments");
|
||||
return ((IEnumerable<Type>)typeArgsProperty.GetValue(binder, null)).ToArray();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,39 +1,38 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Velopack.Tests
|
||||
namespace Velopack.Tests;
|
||||
|
||||
public class FakeDownloader : Sources.IFileDownloader
|
||||
{
|
||||
public class FakeDownloader : Sources.IFileDownloader
|
||||
public string LastUrl { get; private set; }
|
||||
public string LastLocalFile { get; private set; }
|
||||
public string LastAuthHeader { get; private set; }
|
||||
public string LastAcceptHeader { get; private set; }
|
||||
public byte[] MockedResponseBytes { get; set; } = new byte[0];
|
||||
public bool WriteMockLocalFile { get; set; } = false;
|
||||
|
||||
public Task<byte[]> DownloadBytes(string url, string auth, string acc)
|
||||
{
|
||||
public string LastUrl { get; private set; }
|
||||
public string LastLocalFile { get; private set; }
|
||||
public string LastAuthHeader { get; private set; }
|
||||
public string LastAcceptHeader { get; private set; }
|
||||
public byte[] MockedResponseBytes { get; set; } = new byte[0];
|
||||
public bool WriteMockLocalFile { get; set; } = false;
|
||||
LastUrl = url;
|
||||
LastAuthHeader = auth;
|
||||
LastAcceptHeader = acc;
|
||||
return Task.FromResult(MockedResponseBytes);
|
||||
}
|
||||
|
||||
public Task<byte[]> DownloadBytes(string url, string auth, string acc)
|
||||
{
|
||||
LastUrl = url;
|
||||
LastAuthHeader = auth;
|
||||
LastAcceptHeader = acc;
|
||||
return Task.FromResult(MockedResponseBytes);
|
||||
}
|
||||
public async Task DownloadFile(string url, string targetFile, Action<int> progress, string auth, string acc, CancellationToken token)
|
||||
{
|
||||
LastLocalFile = targetFile;
|
||||
var resp = await DownloadBytes(url, auth, acc);
|
||||
progress?.Invoke(25);
|
||||
progress?.Invoke(50);
|
||||
progress?.Invoke(75);
|
||||
progress?.Invoke(100);
|
||||
if (WriteMockLocalFile)
|
||||
File.WriteAllBytes(targetFile, resp);
|
||||
}
|
||||
|
||||
public async Task DownloadFile(string url, string targetFile, Action<int> progress, string auth, string acc, CancellationToken token)
|
||||
{
|
||||
LastLocalFile = targetFile;
|
||||
var resp = await DownloadBytes(url, auth, acc);
|
||||
progress?.Invoke(25);
|
||||
progress?.Invoke(50);
|
||||
progress?.Invoke(75);
|
||||
progress?.Invoke(100);
|
||||
if (WriteMockLocalFile)
|
||||
File.WriteAllBytes(targetFile, resp);
|
||||
}
|
||||
|
||||
public async Task<string> DownloadString(string url, string auth, string acc)
|
||||
{
|
||||
return Encoding.UTF8.GetString(await DownloadBytes(url, auth, acc));
|
||||
}
|
||||
public async Task<string> DownloadString(string url, string auth, string acc)
|
||||
{
|
||||
return Encoding.UTF8.GetString(await DownloadBytes(url, auth, acc));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,111 +4,110 @@ using System.Text;
|
||||
using System.Text.Json;
|
||||
using Velopack.Sources;
|
||||
|
||||
namespace Velopack.Tests.TestHelpers
|
||||
namespace Velopack.Tests.TestHelpers;
|
||||
|
||||
internal class FakeFixtureRepository : Sources.IFileDownloader
|
||||
{
|
||||
internal class FakeFixtureRepository : Sources.IFileDownloader
|
||||
private readonly string _pkgId;
|
||||
private readonly IEnumerable<ReleaseEntry> _releases;
|
||||
private readonly VelopackAssetFeed _releasesNew;
|
||||
private readonly string _releasesName;
|
||||
private readonly string _releasesNameNew;
|
||||
|
||||
public FakeFixtureRepository(string pkgId, bool mockLatestFullVer, string channel = null)
|
||||
{
|
||||
private readonly string _pkgId;
|
||||
private readonly IEnumerable<ReleaseEntry> _releases;
|
||||
private readonly VelopackAssetFeed _releasesNew;
|
||||
private readonly string _releasesName;
|
||||
private readonly string _releasesNameNew;
|
||||
_releasesName = Utility.GetReleasesFileName(channel);
|
||||
_releasesNameNew = Utility.GetVeloReleaseIndexName(channel);
|
||||
_pkgId = pkgId;
|
||||
var releases = ReleaseEntry.BuildReleasesFile(PathHelper.GetFixturesDir(), false)
|
||||
.Where(r => r.OriginalFilename.StartsWith(_pkgId))
|
||||
.ToList();
|
||||
|
||||
public FakeFixtureRepository(string pkgId, bool mockLatestFullVer, string channel = null)
|
||||
{
|
||||
_releasesName = Utility.GetReleasesFileName(channel);
|
||||
_releasesNameNew = Utility.GetVeloReleaseIndexName(channel);
|
||||
_pkgId = pkgId;
|
||||
var releases = ReleaseEntry.BuildReleasesFile(PathHelper.GetFixturesDir(), false)
|
||||
.Where(r => r.OriginalFilename.StartsWith(_pkgId))
|
||||
.ToList();
|
||||
var releasesNew = new SimpleFileSource(new DirectoryInfo(PathHelper.GetFixturesDir()))
|
||||
.GetReleaseFeed(NullLogger.Instance, null).GetAwaiterResult().Assets
|
||||
.Where(r => r.FileName.StartsWith(_pkgId))
|
||||
.ToList();
|
||||
|
||||
var releasesNew = new SimpleFileSource(new DirectoryInfo(PathHelper.GetFixturesDir()))
|
||||
.GetReleaseFeed(NullLogger.Instance, null).GetAwaiterResult().Assets
|
||||
.Where(r => r.FileName.StartsWith(_pkgId))
|
||||
.ToList();
|
||||
if (mockLatestFullVer) {
|
||||
var minFullVer = releases.Where(r => !r.IsDelta).OrderBy(r => r.Version).First();
|
||||
var maxfullVer = releases.Where(r => !r.IsDelta).OrderByDescending(r => r.Version).First();
|
||||
var maxDeltaVer = releases.Where(r => r.IsDelta).OrderByDescending(r => r.Version).First();
|
||||
|
||||
if (mockLatestFullVer) {
|
||||
var minFullVer = releases.Where(r => !r.IsDelta).OrderBy(r => r.Version).First();
|
||||
var maxfullVer = releases.Where(r => !r.IsDelta).OrderByDescending(r => r.Version).First();
|
||||
var maxDeltaVer = releases.Where(r => r.IsDelta).OrderByDescending(r => r.Version).First();
|
||||
// our fixtures don't have a full package for the latest version, we expect the tests to generate this file
|
||||
if (maxfullVer.Version < maxDeltaVer.Version) {
|
||||
var name = new ReleaseEntryName(maxfullVer.PackageId, maxDeltaVer.Version, false);
|
||||
releases.Add(new ReleaseEntry("0000000000000000000000000000000000000000", name.ToFileName(), maxfullVer.Filesize));
|
||||
|
||||
// our fixtures don't have a full package for the latest version, we expect the tests to generate this file
|
||||
if (maxfullVer.Version < maxDeltaVer.Version) {
|
||||
var name = new ReleaseEntryName(maxfullVer.PackageId, maxDeltaVer.Version, false);
|
||||
releases.Add(new ReleaseEntry("0000000000000000000000000000000000000000", name.ToFileName(), maxfullVer.Filesize));
|
||||
|
||||
releasesNew.Add(new VelopackAsset {
|
||||
PackageId = maxfullVer.PackageId,
|
||||
Version = maxDeltaVer.Version,
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"{maxfullVer.PackageId}-{maxDeltaVer.Version}-full.nupkg",
|
||||
Size = maxfullVer.Filesize,
|
||||
});
|
||||
}
|
||||
releasesNew.Add(new VelopackAsset {
|
||||
PackageId = maxfullVer.PackageId,
|
||||
Version = maxDeltaVer.Version,
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"{maxfullVer.PackageId}-{maxDeltaVer.Version}-full.nupkg",
|
||||
Size = maxfullVer.Filesize,
|
||||
});
|
||||
}
|
||||
|
||||
_releasesNew = new VelopackAssetFeed {
|
||||
Assets = releasesNew.ToArray(),
|
||||
};
|
||||
_releases = releases;
|
||||
}
|
||||
|
||||
public Task<byte[]> DownloadBytes(string url, string authorization = null, string accept = null)
|
||||
{
|
||||
if (url.Contains($"/{_releasesName}?")) {
|
||||
MemoryStream ms = new MemoryStream();
|
||||
ReleaseEntry.WriteReleaseFile(_releases, ms);
|
||||
return Task.FromResult(ms.ToArray());
|
||||
}
|
||||
_releasesNew = new VelopackAssetFeed {
|
||||
Assets = releasesNew.ToArray(),
|
||||
};
|
||||
_releases = releases;
|
||||
}
|
||||
|
||||
if (url.Contains($"/{_releasesNameNew}?")) {
|
||||
var json = JsonSerializer.Serialize(_releasesNew, SimpleJsonTests.Options);
|
||||
return Task.FromResult(Encoding.UTF8.GetBytes(json));
|
||||
}
|
||||
|
||||
var rel = _releases.FirstOrDefault(r => url.EndsWith(r.OriginalFilename));
|
||||
if (rel == null)
|
||||
throw new Exception("Fake release not found: " + url);
|
||||
|
||||
var filePath = PathHelper.GetFixture(rel.OriginalFilename);
|
||||
if (!File.Exists(filePath)) {
|
||||
throw new NotSupportedException("FakeFixtureRepository doesn't have: " + rel.OriginalFilename);
|
||||
}
|
||||
|
||||
return Task.FromResult(File.ReadAllBytes(filePath));
|
||||
public Task<byte[]> DownloadBytes(string url, string authorization = null, string accept = null)
|
||||
{
|
||||
if (url.Contains($"/{_releasesName}?")) {
|
||||
MemoryStream ms = new MemoryStream();
|
||||
ReleaseEntry.WriteReleaseFile(_releases, ms);
|
||||
return Task.FromResult(ms.ToArray());
|
||||
}
|
||||
|
||||
public Task DownloadFile(string url, string targetFile, Action<int> progress, string authorization = null, string accept = null, CancellationToken token = default)
|
||||
{
|
||||
var rel = _releases.FirstOrDefault(r => url.EndsWith(r.OriginalFilename));
|
||||
var filePath = PathHelper.GetFixture(rel.OriginalFilename);
|
||||
if (!File.Exists(filePath)) {
|
||||
throw new NotSupportedException("FakeFixtureRepository doesn't have: " + rel.OriginalFilename);
|
||||
}
|
||||
|
||||
File.Copy(filePath, targetFile);
|
||||
progress(25);
|
||||
progress(50);
|
||||
progress(75);
|
||||
progress(100);
|
||||
return Task.CompletedTask;
|
||||
if (url.Contains($"/{_releasesNameNew}?")) {
|
||||
var json = JsonSerializer.Serialize(_releasesNew, SimpleJsonTests.Options);
|
||||
return Task.FromResult(Encoding.UTF8.GetBytes(json));
|
||||
}
|
||||
|
||||
public Task<string> DownloadString(string url, string authorization = null, string accept = null)
|
||||
{
|
||||
if (url.Contains($"/{_releasesName}?")) {
|
||||
MemoryStream ms = new MemoryStream();
|
||||
ReleaseEntry.WriteReleaseFile(_releases, ms);
|
||||
return Task.FromResult(Encoding.UTF8.GetString(ms.ToArray()));
|
||||
}
|
||||
var rel = _releases.FirstOrDefault(r => url.EndsWith(r.OriginalFilename));
|
||||
if (rel == null)
|
||||
throw new Exception("Fake release not found: " + url);
|
||||
|
||||
if (url.Contains($"/{_releasesNameNew}?")) {
|
||||
var json = JsonSerializer.Serialize(_releasesNew, SimpleJsonTests.Options);
|
||||
return Task.FromResult(json);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("FakeFixtureRepository doesn't have: " + url);
|
||||
var filePath = PathHelper.GetFixture(rel.OriginalFilename);
|
||||
if (!File.Exists(filePath)) {
|
||||
throw new NotSupportedException("FakeFixtureRepository doesn't have: " + rel.OriginalFilename);
|
||||
}
|
||||
|
||||
return Task.FromResult(File.ReadAllBytes(filePath));
|
||||
}
|
||||
|
||||
public Task DownloadFile(string url, string targetFile, Action<int> progress, string authorization = null, string accept = null, CancellationToken token = default)
|
||||
{
|
||||
var rel = _releases.FirstOrDefault(r => url.EndsWith(r.OriginalFilename));
|
||||
var filePath = PathHelper.GetFixture(rel.OriginalFilename);
|
||||
if (!File.Exists(filePath)) {
|
||||
throw new NotSupportedException("FakeFixtureRepository doesn't have: " + rel.OriginalFilename);
|
||||
}
|
||||
|
||||
File.Copy(filePath, targetFile);
|
||||
progress(25);
|
||||
progress(50);
|
||||
progress(75);
|
||||
progress(100);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<string> DownloadString(string url, string authorization = null, string accept = null)
|
||||
{
|
||||
if (url.Contains($"/{_releasesName}?")) {
|
||||
MemoryStream ms = new MemoryStream();
|
||||
ReleaseEntry.WriteReleaseFile(_releases, ms);
|
||||
return Task.FromResult(Encoding.UTF8.GetString(ms.ToArray()));
|
||||
}
|
||||
|
||||
if (url.Contains($"/{_releasesNameNew}?")) {
|
||||
var json = JsonSerializer.Serialize(_releasesNew, SimpleJsonTests.Options);
|
||||
return Task.FromResult(json);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("FakeFixtureRepository doesn't have: " + url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,92 +1,91 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace Velopack.Tests
|
||||
namespace Velopack.Tests;
|
||||
|
||||
public sealed class StaticHttpServer : IDisposable
|
||||
{
|
||||
public sealed class StaticHttpServer : IDisposable
|
||||
public int Port { get; private set; }
|
||||
public string RootPath { get; private set; }
|
||||
|
||||
IDisposable inner;
|
||||
|
||||
public StaticHttpServer(int port, string rootPath)
|
||||
{
|
||||
public int Port { get; private set; }
|
||||
public string RootPath { get; private set; }
|
||||
Port = port; RootPath = rootPath;
|
||||
}
|
||||
|
||||
IDisposable inner;
|
||||
|
||||
public StaticHttpServer(int port, string rootPath)
|
||||
{
|
||||
Port = port; RootPath = rootPath;
|
||||
public IDisposable Start()
|
||||
{
|
||||
if (inner != null) {
|
||||
throw new InvalidOperationException("Already started!");
|
||||
}
|
||||
|
||||
public IDisposable Start()
|
||||
{
|
||||
if (inner != null) {
|
||||
throw new InvalidOperationException("Already started!");
|
||||
}
|
||||
var server = new HttpListener();
|
||||
server.Prefixes.Add(String.Format("http://+:{0}/", Port));
|
||||
server.Start();
|
||||
|
||||
var server = new HttpListener();
|
||||
server.Prefixes.Add(String.Format("http://+:{0}/", Port));
|
||||
server.Start();
|
||||
bool shouldStop = false;
|
||||
var listener = Task.Run(async () => {
|
||||
while (!shouldStop) {
|
||||
var ctx = await server.GetContextAsync();
|
||||
|
||||
bool shouldStop = false;
|
||||
var listener = Task.Run(async () => {
|
||||
while (!shouldStop) {
|
||||
var ctx = await server.GetContextAsync();
|
||||
|
||||
if (ctx.Request.HttpMethod != "GET") {
|
||||
closeResponseWith(ctx, 400, "GETs only");
|
||||
return;
|
||||
}
|
||||
|
||||
var target = Path.Combine(RootPath, ctx.Request.Url.AbsolutePath.Replace('/', Path.DirectorySeparatorChar).Substring(1));
|
||||
var fi = new FileInfo(target);
|
||||
|
||||
if (!fi.FullName.StartsWith(RootPath)) {
|
||||
closeResponseWith(ctx, 401, "Not authorized");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fi.Exists) {
|
||||
closeResponseWith(ctx, 404, "Not found");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
using (var input = File.OpenRead(target)) {
|
||||
ctx.Response.StatusCode = 200;
|
||||
input.CopyTo(ctx.Response.OutputStream);
|
||||
ctx.Response.Close();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
closeResponseWith(ctx, 500, ex.ToString());
|
||||
}
|
||||
if (ctx.Request.HttpMethod != "GET") {
|
||||
closeResponseWith(ctx, 400, "GETs only");
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
var ret = Disposable.Create(() => {
|
||||
shouldStop = true;
|
||||
server.Stop();
|
||||
listener.Wait(2000);
|
||||
var target = Path.Combine(RootPath, ctx.Request.Url.AbsolutePath.Replace('/', Path.DirectorySeparatorChar).Substring(1));
|
||||
var fi = new FileInfo(target);
|
||||
|
||||
inner = null;
|
||||
});
|
||||
if (!fi.FullName.StartsWith(RootPath)) {
|
||||
closeResponseWith(ctx, 401, "Not authorized");
|
||||
return;
|
||||
}
|
||||
|
||||
inner = ret;
|
||||
return ret;
|
||||
}
|
||||
if (!fi.Exists) {
|
||||
closeResponseWith(ctx, 404, "Not found");
|
||||
return;
|
||||
}
|
||||
|
||||
static void closeResponseWith(HttpListenerContext ctx, int statusCode, string message)
|
||||
{
|
||||
ctx.Response.StatusCode = statusCode;
|
||||
using (var sw = new StreamWriter(ctx.Response.OutputStream, Encoding.UTF8)) {
|
||||
sw.WriteLine(message);
|
||||
try {
|
||||
using (var input = File.OpenRead(target)) {
|
||||
ctx.Response.StatusCode = 200;
|
||||
input.CopyTo(ctx.Response.OutputStream);
|
||||
ctx.Response.Close();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
closeResponseWith(ctx, 500, ex.ToString());
|
||||
}
|
||||
}
|
||||
ctx.Response.Close();
|
||||
}
|
||||
});
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var toDispose = Interlocked.Exchange(ref inner, null);
|
||||
if (toDispose != null) {
|
||||
toDispose.Dispose();
|
||||
}
|
||||
var ret = Disposable.Create(() => {
|
||||
shouldStop = true;
|
||||
server.Stop();
|
||||
listener.Wait(2000);
|
||||
|
||||
inner = null;
|
||||
});
|
||||
|
||||
inner = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void closeResponseWith(HttpListenerContext ctx, int statusCode, string message)
|
||||
{
|
||||
ctx.Response.StatusCode = statusCode;
|
||||
using (var sw = new StreamWriter(ctx.Response.OutputStream, Encoding.UTF8)) {
|
||||
sw.WriteLine(message);
|
||||
}
|
||||
ctx.Response.Close();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var toDispose = Interlocked.Exchange(ref inner, null);
|
||||
if (toDispose != null) {
|
||||
toDispose.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,378 +7,377 @@ using Velopack.Locators;
|
||||
using Velopack.Sources;
|
||||
using Velopack.Tests.TestHelpers;
|
||||
|
||||
namespace Velopack.Tests
|
||||
namespace Velopack.Tests;
|
||||
|
||||
public class UpdateManagerTests
|
||||
{
|
||||
public class UpdateManagerTests
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public UpdateManagerTests(ITestOutputHelper output)
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
_output = output;
|
||||
}
|
||||
|
||||
public UpdateManagerTests(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
private FakeDownloader GetMockDownloaderNoDelta()
|
||||
{
|
||||
var feed = new VelopackAssetFeed() {
|
||||
Assets = new VelopackAsset[] {
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 1, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-1.1.0.nupkg",
|
||||
SHA1 = "3a2eadd15dd984e4559f2b4d790ec8badaeb6a39",
|
||||
Size = 1040561,
|
||||
},
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 0, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-1.0.0.nupkg",
|
||||
SHA1 = "94689fede03fed7ab59c24337673a27837f0c3ec",
|
||||
Size = 1004502,
|
||||
},
|
||||
}
|
||||
};
|
||||
var json = JsonSerializer.Serialize(feed, SimpleJsonTests.Options);
|
||||
return new FakeDownloader() { MockedResponseBytes = Encoding.UTF8.GetBytes(json) };
|
||||
}
|
||||
|
||||
private FakeDownloader GetMockDownloaderNoDelta()
|
||||
{
|
||||
var feed = new VelopackAssetFeed() {
|
||||
Assets = new VelopackAsset[] {
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 1, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-1.1.0.nupkg",
|
||||
SHA1 = "3a2eadd15dd984e4559f2b4d790ec8badaeb6a39",
|
||||
Size = 1040561,
|
||||
},
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 0, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-1.0.0.nupkg",
|
||||
SHA1 = "94689fede03fed7ab59c24337673a27837f0c3ec",
|
||||
Size = 1004502,
|
||||
},
|
||||
}
|
||||
};
|
||||
var json = JsonSerializer.Serialize(feed, SimpleJsonTests.Options);
|
||||
return new FakeDownloader() { MockedResponseBytes = Encoding.UTF8.GetBytes(json) };
|
||||
}
|
||||
private FakeDownloader GetMockDownloaderWith2Delta()
|
||||
{
|
||||
var feed = new VelopackAssetFeed {
|
||||
Assets = new VelopackAsset[] {
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 1, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-1.1.0.nupkg",
|
||||
SHA1 = "3a2eadd15dd984e4559f2b4d790ec8badaeb6a39",
|
||||
Size = 1040561,
|
||||
},
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 0, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-1.0.0.nupkg",
|
||||
SHA1 = "94689fede03fed7ab59c24337673a27837f0c3ec",
|
||||
Size = 1004502,
|
||||
},
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 1, 0),
|
||||
Type = VelopackAssetType.Delta,
|
||||
FileName = $"MyCoolApp-1.1.0-delta.nupkg",
|
||||
SHA1 = "14db31d2647c6d2284882a2e101924a9c409ee67",
|
||||
Size = 80396,
|
||||
},
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 0, 0),
|
||||
Type = VelopackAssetType.Delta,
|
||||
FileName = $"MyCoolApp-1.0.0-delta.nupkg",
|
||||
SHA1 = "14db31d2647c6d2284882a2e101924a9c409ee67",
|
||||
Size = 80396,
|
||||
},
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 2, 0),
|
||||
Type = VelopackAssetType.Delta,
|
||||
FileName = $"MyCoolApp-1.2.0-delta.nupkg",
|
||||
SHA1 = "14db31d2647c6d2284882a2e101924a9c409ee67",
|
||||
Size = 80396,
|
||||
},
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 2, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-1.2.0.nupkg",
|
||||
SHA1 = "3a2eadd15dd984e4559f2b4d790ec8badaeb6a39",
|
||||
Size = 1040561,
|
||||
},
|
||||
}
|
||||
};
|
||||
var json = JsonSerializer.Serialize(feed, SimpleJsonTests.Options);
|
||||
return new FakeDownloader() { MockedResponseBytes = Encoding.UTF8.GetBytes(json) };
|
||||
}
|
||||
|
||||
private FakeDownloader GetMockDownloaderWith2Delta()
|
||||
{
|
||||
var feed = new VelopackAssetFeed {
|
||||
Assets = new VelopackAsset[] {
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 1, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-1.1.0.nupkg",
|
||||
SHA1 = "3a2eadd15dd984e4559f2b4d790ec8badaeb6a39",
|
||||
Size = 1040561,
|
||||
},
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 0, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-1.0.0.nupkg",
|
||||
SHA1 = "94689fede03fed7ab59c24337673a27837f0c3ec",
|
||||
Size = 1004502,
|
||||
},
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 1, 0),
|
||||
Type = VelopackAssetType.Delta,
|
||||
FileName = $"MyCoolApp-1.1.0-delta.nupkg",
|
||||
SHA1 = "14db31d2647c6d2284882a2e101924a9c409ee67",
|
||||
Size = 80396,
|
||||
},
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 0, 0),
|
||||
Type = VelopackAssetType.Delta,
|
||||
FileName = $"MyCoolApp-1.0.0-delta.nupkg",
|
||||
SHA1 = "14db31d2647c6d2284882a2e101924a9c409ee67",
|
||||
Size = 80396,
|
||||
},
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 2, 0),
|
||||
Type = VelopackAssetType.Delta,
|
||||
FileName = $"MyCoolApp-1.2.0-delta.nupkg",
|
||||
SHA1 = "14db31d2647c6d2284882a2e101924a9c409ee67",
|
||||
Size = 80396,
|
||||
},
|
||||
new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 2, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-1.2.0.nupkg",
|
||||
SHA1 = "3a2eadd15dd984e4559f2b4d790ec8badaeb6a39",
|
||||
Size = 1040561,
|
||||
},
|
||||
}
|
||||
};
|
||||
var json = JsonSerializer.Serialize(feed, SimpleJsonTests.Options);
|
||||
return new FakeDownloader() { MockedResponseBytes = Encoding.UTF8.GetBytes(json) };
|
||||
}
|
||||
[Fact]
|
||||
public void CheckFromLocal()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderNoDelta();
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.NotNull(info);
|
||||
Assert.True(new SemanticVersion(1, 1, 0) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
Assert.False(info.IsDowngrade);
|
||||
Assert.StartsWith($"http://any.com/releases.{VelopackRuntimeInfo.SystemOs.GetOsShortName()}.json?", dl.LastUrl);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckFromLocal()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderNoDelta();
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.NotNull(info);
|
||||
Assert.True(new SemanticVersion(1, 1, 0) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
Assert.False(info.IsDowngrade);
|
||||
Assert.StartsWith($"http://any.com/releases.{VelopackRuntimeInfo.SystemOs.GetOsShortName()}.json?", dl.LastUrl);
|
||||
}
|
||||
[Fact]
|
||||
public void CheckFromLocalWithChannel()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderNoDelta();
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
|
||||
var opt = new UpdateOptions { ExplicitChannel = "experimental" };
|
||||
var um = new UpdateManager(source, opt, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.NotNull(info);
|
||||
Assert.True(new SemanticVersion(1, 1, 0) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
Assert.False(info.IsDowngrade);
|
||||
Assert.StartsWith("http://any.com/releases.experimental.json?", dl.LastUrl);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckFromLocalWithChannel()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderNoDelta();
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
|
||||
var opt = new UpdateOptions { ExplicitChannel = "experimental" };
|
||||
var um = new UpdateManager(source, opt, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.NotNull(info);
|
||||
Assert.True(new SemanticVersion(1, 1, 0) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
Assert.False(info.IsDowngrade);
|
||||
Assert.StartsWith("http://any.com/releases.experimental.json?", dl.LastUrl);
|
||||
}
|
||||
[Fact]
|
||||
public void CheckForSameAsInstalledVersion()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderWith2Delta();
|
||||
var myVer = new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 2, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-1.2.0.nupkg",
|
||||
SHA1 = "3a2eadd15dd984e4559f2b4d790ec8badaeb6a39",
|
||||
Size = 1040561,
|
||||
};
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.2.0", tempPath, null, null, null, logger: logger, localPackage: myVer, channel: "stable");
|
||||
|
||||
[Fact]
|
||||
public void CheckForSameAsInstalledVersion()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderWith2Delta();
|
||||
var myVer = new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 2, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-1.2.0.nupkg",
|
||||
SHA1 = "3a2eadd15dd984e4559f2b4d790ec8badaeb6a39",
|
||||
Size = 1040561,
|
||||
};
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.2.0", tempPath, null, null, null, logger: logger, localPackage: myVer, channel: "stable");
|
||||
// checking for same version should return null
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.Null(info);
|
||||
Assert.StartsWith("http://any.com/releases.stable.json?", dl.LastUrl);
|
||||
|
||||
// checking for same version should return null
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.Null(info);
|
||||
Assert.StartsWith("http://any.com/releases.stable.json?", dl.LastUrl);
|
||||
// checking for same version WITHOUT explicit channel should return null
|
||||
var opt = new UpdateOptions { AllowVersionDowngrade = true };
|
||||
um = new UpdateManager(source, opt, logger, locator);
|
||||
Assert.Null(info);
|
||||
Assert.StartsWith("http://any.com/releases.stable.json?", dl.LastUrl);
|
||||
|
||||
// checking for same version WITHOUT explicit channel should return null
|
||||
var opt = new UpdateOptions { AllowVersionDowngrade = true };
|
||||
um = new UpdateManager(source, opt, logger, locator);
|
||||
Assert.Null(info);
|
||||
Assert.StartsWith("http://any.com/releases.stable.json?", dl.LastUrl);
|
||||
// checking for same version with explicit channel & downgrade allowed should return version
|
||||
opt = new UpdateOptions { ExplicitChannel = "experimental", AllowVersionDowngrade = true };
|
||||
um = new UpdateManager(source, opt, logger, locator);
|
||||
info = um.CheckForUpdates();
|
||||
Assert.True(info.IsDowngrade);
|
||||
Assert.NotNull(info);
|
||||
Assert.True(new SemanticVersion(1, 2, 0) == info.TargetFullRelease.Version);
|
||||
Assert.StartsWith("http://any.com/releases.experimental.json?", dl.LastUrl);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
}
|
||||
|
||||
// checking for same version with explicit channel & downgrade allowed should return version
|
||||
opt = new UpdateOptions { ExplicitChannel = "experimental", AllowVersionDowngrade = true };
|
||||
um = new UpdateManager(source, opt, logger, locator);
|
||||
info = um.CheckForUpdates();
|
||||
Assert.True(info.IsDowngrade);
|
||||
Assert.NotNull(info);
|
||||
Assert.True(new SemanticVersion(1, 2, 0) == info.TargetFullRelease.Version);
|
||||
Assert.StartsWith("http://any.com/releases.experimental.json?", dl.LastUrl);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
}
|
||||
[Fact]
|
||||
public void CheckForLowerThanInstalledVersion()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderWith2Delta();
|
||||
var myVer = new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(2, 0, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-2.0.0.nupkg",
|
||||
SHA1 = "3a2eadd15dd984e4559f2b4d790ec8badaeb6a39",
|
||||
Size = 1040561,
|
||||
};
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "2.0.0", tempPath, null, null, null, logger: logger, localPackage: myVer, channel: "stable");
|
||||
|
||||
[Fact]
|
||||
public void CheckForLowerThanInstalledVersion()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderWith2Delta();
|
||||
var myVer = new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(2, 0, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-2.0.0.nupkg",
|
||||
SHA1 = "3a2eadd15dd984e4559f2b4d790ec8badaeb6a39",
|
||||
Size = 1040561,
|
||||
};
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "2.0.0", tempPath, null, null, null, logger: logger, localPackage: myVer, channel: "stable");
|
||||
// checking for lower version should return null
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.Null(info);
|
||||
Assert.StartsWith("http://any.com/releases.stable.json?", dl.LastUrl);
|
||||
|
||||
// checking for lower version should return null
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.Null(info);
|
||||
Assert.StartsWith("http://any.com/releases.stable.json?", dl.LastUrl);
|
||||
// checking for lower version with downgrade allowed should return lower version
|
||||
var opt = new UpdateOptions { AllowVersionDowngrade = true };
|
||||
um = new UpdateManager(source, opt, logger, locator);
|
||||
info = um.CheckForUpdates();
|
||||
Assert.True(info.IsDowngrade);
|
||||
Assert.NotNull(info);
|
||||
Assert.True(new SemanticVersion(1, 2, 0) == info.TargetFullRelease.Version);
|
||||
Assert.StartsWith("http://any.com/releases.stable.json?", dl.LastUrl);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
}
|
||||
|
||||
// checking for lower version with downgrade allowed should return lower version
|
||||
var opt = new UpdateOptions { AllowVersionDowngrade = true };
|
||||
um = new UpdateManager(source, opt, logger, locator);
|
||||
info = um.CheckForUpdates();
|
||||
Assert.True(info.IsDowngrade);
|
||||
Assert.NotNull(info);
|
||||
Assert.True(new SemanticVersion(1, 2, 0) == info.TargetFullRelease.Version);
|
||||
Assert.StartsWith("http://any.com/releases.stable.json?", dl.LastUrl);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
}
|
||||
[Fact]
|
||||
public void CheckFromLocalWithDelta()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderWith2Delta();
|
||||
var myVer = new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 0, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-1.0.0.nupkg",
|
||||
SHA1 = "94689fede03fed7ab59c24337673a27837f0c3ec",
|
||||
Size = 1004502,
|
||||
};
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
|
||||
[Fact]
|
||||
public void CheckFromLocalWithDelta()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderWith2Delta();
|
||||
var myVer = new VelopackAsset() {
|
||||
PackageId = "MyCoolApp",
|
||||
Version = new SemanticVersion(1, 0, 0),
|
||||
Type = VelopackAssetType.Full,
|
||||
FileName = $"MyCoolApp-1.0.0.nupkg",
|
||||
SHA1 = "94689fede03fed7ab59c24337673a27837f0c3ec",
|
||||
Size = 1004502,
|
||||
};
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, null, null, null, logger: logger, localPackage: myVer);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.False(info.IsDowngrade);
|
||||
Assert.NotNull(info);
|
||||
Assert.True(new SemanticVersion(1, 2, 0) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(2, info.DeltasToTarget.Count());
|
||||
}
|
||||
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, null, null, null, logger: logger, localPackage: myVer);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.False(info.IsDowngrade);
|
||||
Assert.NotNull(info);
|
||||
Assert.True(new SemanticVersion(1, 2, 0) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(2, info.DeltasToTarget.Count());
|
||||
}
|
||||
[Fact]
|
||||
public void NoDeltaIfNoBasePackage()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderWith2Delta();
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger: logger);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.NotNull(info);
|
||||
Assert.False(info.IsDowngrade);
|
||||
Assert.True(new SemanticVersion(1, 2, 0) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoDeltaIfNoBasePackage()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderWith2Delta();
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger: logger);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.NotNull(info);
|
||||
Assert.False(info.IsDowngrade);
|
||||
Assert.True(new SemanticVersion(1, 2, 0) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
}
|
||||
[Fact]
|
||||
public void CheckFromLocalWithDeltaNoLocalPackage()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderWith2Delta();
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger: logger);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.NotNull(info);
|
||||
Assert.False(info.IsDowngrade);
|
||||
Assert.True(new SemanticVersion(1, 2, 0) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckFromLocalWithDeltaNoLocalPackage()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderWith2Delta();
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger: logger);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.NotNull(info);
|
||||
Assert.False(info.IsDowngrade);
|
||||
Assert.True(new SemanticVersion(1, 2, 0) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
}
|
||||
[Fact(Skip = "Consumes API Quota")]
|
||||
public void CheckGithub()
|
||||
{
|
||||
// https://github.com/caesay/SquirrelCustomLauncherTestApp
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
|
||||
var source = new GithubSource("https://github.com/caesay/SquirrelCustomLauncherTestApp", null, false);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.NotNull(info);
|
||||
Assert.True(new SemanticVersion(1, 0, 1) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
}
|
||||
|
||||
[Fact(Skip = "Consumes API Quota")]
|
||||
public void CheckGithub()
|
||||
{
|
||||
// https://github.com/caesay/SquirrelCustomLauncherTestApp
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
|
||||
var source = new GithubSource("https://github.com/caesay/SquirrelCustomLauncherTestApp", null, false);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.NotNull(info);
|
||||
Assert.True(new SemanticVersion(1, 0, 1) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
}
|
||||
[Fact(Skip = "Consumes API Quota")]
|
||||
public void CheckGithubWithNonExistingChannel()
|
||||
{
|
||||
// https://github.com/caesay/SquirrelCustomLauncherTestApp
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
|
||||
var source = new GithubSource("https://github.com/caesay/SquirrelCustomLauncherTestApp", null, false);
|
||||
var opt = new UpdateOptions { ExplicitChannel = "hello" };
|
||||
var um = new UpdateManager(source, opt, logger, locator);
|
||||
Assert.Throws<ArgumentException>(() => um.CheckForUpdates());
|
||||
}
|
||||
|
||||
[Fact(Skip = "Consumes API Quota")]
|
||||
public void CheckGithubWithNonExistingChannel()
|
||||
{
|
||||
// https://github.com/caesay/SquirrelCustomLauncherTestApp
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
|
||||
var source = new GithubSource("https://github.com/caesay/SquirrelCustomLauncherTestApp", null, false);
|
||||
var opt = new UpdateOptions { ExplicitChannel = "hello" };
|
||||
var um = new UpdateManager(source, opt, logger, locator);
|
||||
Assert.Throws<ArgumentException>(() => um.CheckForUpdates());
|
||||
}
|
||||
[Fact]
|
||||
public void NoUpdatesIfCurrentEqualsRemoteVersion()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderNoDelta();
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.1.0", tempPath, logger);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.Null(info);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoUpdatesIfCurrentEqualsRemoteVersion()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderNoDelta();
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.1.0", tempPath, logger);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.Null(info);
|
||||
}
|
||||
[Fact]
|
||||
public void NoUpdatesIfCurrentGreaterThanRemoteVersion()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderNoDelta();
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.2.0", tempPath, logger);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.Null(info);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoUpdatesIfCurrentGreaterThanRemoteVersion()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var tempPath);
|
||||
var dl = GetMockDownloaderNoDelta();
|
||||
var source = new SimpleWebSource("http://any.com", dl);
|
||||
var locator = new TestVelopackLocator("MyCoolApp", "1.2.0", tempPath, logger);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.Null(info);
|
||||
}
|
||||
[Theory]
|
||||
[InlineData("Clowd", "3.4.287")]
|
||||
[InlineData("slack", "1.1.8")]
|
||||
public void DownloadsLatestFullVersion(string id, string version)
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var packagesDir);
|
||||
var repo = new FakeFixtureRepository(id, false);
|
||||
var source = new SimpleWebSource("http://any.com", repo);
|
||||
var locator = new TestVelopackLocator(id, "1.0.0", packagesDir, logger);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
|
||||
[Theory]
|
||||
[InlineData("Clowd", "3.4.287")]
|
||||
[InlineData("slack", "1.1.8")]
|
||||
public void DownloadsLatestFullVersion(string id, string version)
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var packagesDir);
|
||||
var repo = new FakeFixtureRepository(id, false);
|
||||
var source = new SimpleWebSource("http://any.com", repo);
|
||||
var locator = new TestVelopackLocator(id, "1.0.0", packagesDir, logger);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.NotNull(info);
|
||||
Assert.True(SemanticVersion.Parse(version) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
|
||||
var info = um.CheckForUpdates();
|
||||
Assert.NotNull(info);
|
||||
Assert.True(SemanticVersion.Parse(version) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||
um.DownloadUpdates(info);
|
||||
|
||||
um.DownloadUpdates(info);
|
||||
var target = Path.Combine(packagesDir, $"{id}-{version}-full.nupkg");
|
||||
Assert.True(File.Exists(target));
|
||||
um.VerifyPackageChecksum(info.TargetFullRelease);
|
||||
}
|
||||
|
||||
var target = Path.Combine(packagesDir, $"{id}-{version}-full.nupkg");
|
||||
Assert.True(File.Exists(target));
|
||||
um.VerifyPackageChecksum(info.TargetFullRelease);
|
||||
}
|
||||
[SkippableTheory]
|
||||
[InlineData("Clowd", "3.4.287", "3.4.292")]
|
||||
//[InlineData("slack", "1.1.8", "1.2.2")]
|
||||
public async Task DownloadsDeltasAndCreatesFullVersion(string id, string fromVersion, string toVersion)
|
||||
{
|
||||
Skip.If(VelopackRuntimeInfo.IsLinux);
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var packagesDir);
|
||||
var repo = new FakeFixtureRepository(id, true);
|
||||
var source = new SimpleWebSource("http://any.com", repo);
|
||||
|
||||
[SkippableTheory]
|
||||
[InlineData("Clowd", "3.4.287", "3.4.292")]
|
||||
//[InlineData("slack", "1.1.8", "1.2.2")]
|
||||
public async Task DownloadsDeltasAndCreatesFullVersion(string id, string fromVersion, string toVersion)
|
||||
{
|
||||
Skip.If(VelopackRuntimeInfo.IsLinux);
|
||||
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
|
||||
using var _1 = Utility.GetTempDirectory(out var packagesDir);
|
||||
var repo = new FakeFixtureRepository(id, true);
|
||||
var source = new SimpleWebSource("http://any.com", repo);
|
||||
var feed = await source.GetReleaseFeed(logger, VelopackRuntimeInfo.SystemOs.GetOsShortName());
|
||||
var basePkg = feed.Assets
|
||||
.Where(x => x.Type == VelopackAssetType.Full)
|
||||
.Single(x => x.Version == SemanticVersion.Parse(fromVersion));
|
||||
var basePkgFixturePath = PathHelper.GetFixture(basePkg.FileName);
|
||||
var basePkgPath = Path.Combine(packagesDir, basePkg.FileName);
|
||||
File.Copy(basePkgFixturePath, basePkgPath);
|
||||
|
||||
var feed = await source.GetReleaseFeed(logger, VelopackRuntimeInfo.SystemOs.GetOsShortName());
|
||||
var basePkg = feed.Assets
|
||||
.Where(x => x.Type == VelopackAssetType.Full)
|
||||
.Single(x => x.Version == SemanticVersion.Parse(fromVersion));
|
||||
var basePkgFixturePath = PathHelper.GetFixture(basePkg.FileName);
|
||||
var basePkgPath = Path.Combine(packagesDir, basePkg.FileName);
|
||||
File.Copy(basePkgFixturePath, basePkgPath);
|
||||
var updateExe = PathHelper.CopyUpdateTo(packagesDir);
|
||||
var locator = new TestVelopackLocator(id, fromVersion,
|
||||
packagesDir, null, null, updateExe, null, logger);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
|
||||
var updateExe = PathHelper.CopyUpdateTo(packagesDir);
|
||||
var locator = new TestVelopackLocator(id, fromVersion,
|
||||
packagesDir, null, null, updateExe, null, logger);
|
||||
var um = new UpdateManager(source, null, logger, locator);
|
||||
var info = await um.CheckForUpdatesAsync();
|
||||
Assert.NotNull(info);
|
||||
Assert.True(SemanticVersion.Parse(toVersion) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(3, info.DeltasToTarget.Count());
|
||||
Assert.NotNull(info.BaseRelease);
|
||||
|
||||
var info = await um.CheckForUpdatesAsync();
|
||||
Assert.NotNull(info);
|
||||
Assert.True(SemanticVersion.Parse(toVersion) == info.TargetFullRelease.Version);
|
||||
Assert.Equal(3, info.DeltasToTarget.Count());
|
||||
Assert.NotNull(info.BaseRelease);
|
||||
|
||||
await um.DownloadUpdatesAsync(info);
|
||||
var target = Path.Combine(packagesDir, $"{id}-{toVersion}-full.nupkg");
|
||||
Assert.True(File.Exists(target));
|
||||
}
|
||||
await um.DownloadUpdatesAsync(info);
|
||||
var target = Path.Combine(packagesDir, $"{id}-{toVersion}-full.nupkg");
|
||||
Assert.True(File.Exists(target));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,235 +4,234 @@ using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Velopack.Windows;
|
||||
|
||||
namespace Velopack.Tests
|
||||
namespace Velopack.Tests;
|
||||
|
||||
public class UtilityTests
|
||||
{
|
||||
public class UtilityTests
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public UtilityTests(ITestOutputHelper output)
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public UtilityTests(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
|
||||
[SkippableTheory]
|
||||
[InlineData("file.txt", "file.txt")]
|
||||
[InlineData("file", "file")]
|
||||
[InlineData("/file", "\\file")]
|
||||
[InlineData("/file/", "\\file")]
|
||||
[InlineData("one\\two\\..\\file", "one\\file")]
|
||||
[InlineData("C:/AnApp/file/", "C:\\AnApp\\file")]
|
||||
public void PathIsNormalized(string input, string expected)
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
var exp = Path.GetFullPath(expected);
|
||||
var normal = Utility.NormalizePath(input);
|
||||
Assert.Equal(exp, normal);
|
||||
}
|
||||
|
||||
[SkippableTheory]
|
||||
[InlineData("C:\\AnApp", "C:\\AnApp\\file.exe", true)]
|
||||
[InlineData("C:\\AnApp\\", "C:\\AnApp\\file.exe", true)]
|
||||
[InlineData("C:\\AnApp", "C:\\AnApp\\sub\\dir\\file.exe", true)]
|
||||
[InlineData("C:\\AnApp\\", "C:\\AnApp\\sub\\dir\\file.exe", true)]
|
||||
[InlineData("C:\\AnAppTwo", "C:\\AnApp\\file.exe", false)]
|
||||
[InlineData("C:\\AnAppTwo\\", "C:\\AnApp\\file.exe", false)]
|
||||
[InlineData("C:\\AnAppTwo", "C:\\AnApp\\sub\\dir\\file.exe", false)]
|
||||
[InlineData("C:\\AnAppTwo\\", "C:\\AnApp\\sub\\dir\\file.exe", false)]
|
||||
[InlineData("AnAppThree", "AnAppThree\\file.exe", true)]
|
||||
public void FileIsInDirectory(string directory, string file, bool isIn)
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
var fileInDir = Utility.IsFileInDirectory(file, directory);
|
||||
Assert.Equal(isIn, fileInDir);
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
[SupportedOSPlatform("windows")]
|
||||
public void SetAppIdOnShortcutTest()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
var sl = new ShellLink() {
|
||||
Target = @"C:\Windows\Notepad.exe",
|
||||
Description = "It's Notepad",
|
||||
};
|
||||
|
||||
sl.SetAppUserModelId("org.anaïsbetts.test");
|
||||
var path = Path.GetFullPath(@".\test.lnk");
|
||||
sl.Save(path);
|
||||
|
||||
Console.WriteLine("Saved to " + path);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveByteOrderMarkerIfPresent()
|
||||
{
|
||||
var utf32Be = new byte[] { 0x00, 0x00, 0xFE, 0xFF };
|
||||
var utf32Le = new byte[] { 0xFF, 0xFE, 0x00, 0x00 };
|
||||
var utf16Be = new byte[] { 0xFE, 0xFF };
|
||||
var utf16Le = new byte[] { 0xFF, 0xFE };
|
||||
var utf8 = new byte[] { 0xEF, 0xBB, 0xBF };
|
||||
|
||||
var utf32BeHelloWorld = combine(utf32Be, Encoding.UTF8.GetBytes("hello world"));
|
||||
var utf32LeHelloWorld = combine(utf32Le, Encoding.UTF8.GetBytes("hello world"));
|
||||
var utf16BeHelloWorld = combine(utf16Be, Encoding.UTF8.GetBytes("hello world"));
|
||||
var utf16LeHelloWorld = combine(utf16Le, Encoding.UTF8.GetBytes("hello world"));
|
||||
var utf8HelloWorld = combine(utf8, Encoding.UTF8.GetBytes("hello world"));
|
||||
|
||||
var asciiMultipleChars = Encoding.ASCII.GetBytes("hello world");
|
||||
var asciiSingleChar = Encoding.ASCII.GetBytes("A");
|
||||
|
||||
var emptyString = string.Empty;
|
||||
string nullString = null;
|
||||
byte[] nullByteArray = { };
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(emptyString));
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(nullString));
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(nullByteArray));
|
||||
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf32Be));
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf32Le));
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf16Be));
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf16Le));
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf8));
|
||||
|
||||
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(utf32BeHelloWorld));
|
||||
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(utf32LeHelloWorld));
|
||||
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(utf16BeHelloWorld));
|
||||
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(utf16LeHelloWorld));
|
||||
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(utf8HelloWorld));
|
||||
|
||||
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(asciiMultipleChars));
|
||||
Assert.Equal("A", Utility.RemoveByteOrderMarkerIfPresent(asciiSingleChar));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShaCheckShouldBeCaseInsensitive()
|
||||
{
|
||||
var sha1FromExternalTool = "75255cfd229a1ed1447abe1104f5635e69975d30";
|
||||
var inputPackage = PathHelper.GetFixture("Squirrel.Core.1.0.0.0.nupkg");
|
||||
var stream = File.OpenRead(inputPackage);
|
||||
var sha1 = Utility.CalculateStreamSHA1(stream);
|
||||
|
||||
Assert.NotEqual(sha1FromExternalTool, sha1);
|
||||
Assert.Equal(sha1FromExternalTool, sha1, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanDeleteDeepRecursiveDirectoryStructure()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UtilityTests>();
|
||||
string tempDir;
|
||||
using (Utility.GetTempDirectory(out tempDir)) {
|
||||
for (var i = 0; i < 50; i++) {
|
||||
var directory = Path.Combine(tempDir, newId());
|
||||
CreateSampleDirectory(directory);
|
||||
}
|
||||
|
||||
var files = Directory.GetFiles(tempDir, "*", SearchOption.AllDirectories);
|
||||
|
||||
var count = files.Count();
|
||||
|
||||
logger.Info($"Created {count} files under directory {tempDir}");
|
||||
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
Utility.DeleteFileOrDirectoryHard(tempDir);
|
||||
sw.Stop();
|
||||
logger.Info($"Delete took {sw.ElapsedMilliseconds}ms");
|
||||
|
||||
Assert.False(Directory.Exists(tempDir));
|
||||
}
|
||||
}
|
||||
|
||||
//[Fact]
|
||||
//public void CreateFakePackageSmokeTest()
|
||||
//{
|
||||
// string path;
|
||||
// using (Utility.GetTempDirectory(out path)) {
|
||||
// var output = IntegrationTestHelper.CreateFakeInstalledApp("0.3.0", path);
|
||||
// Assert.True(File.Exists(output));
|
||||
// }
|
||||
//}
|
||||
|
||||
[Theory]
|
||||
[InlineData("foo.dll", true)]
|
||||
[InlineData("foo.DlL", true)]
|
||||
[InlineData("C:\\Foo\\Bar\\foo.Exe", true)]
|
||||
[InlineData("Test.png", false)]
|
||||
[InlineData(".rels", false)]
|
||||
public void FileIsLikelyPEImageTest(string input, bool result)
|
||||
{
|
||||
Assert.Equal(result, Utility.FileIsLikelyPEImage(input));
|
||||
}
|
||||
|
||||
[Fact(Skip = "Only really need to run this test after changes to FileDownloader")]
|
||||
public async Task DownloaderReportsProgress()
|
||||
{
|
||||
// this probably should use a local http server instead.
|
||||
const string testUrl = "http://speedtest.tele2.net/1MB.zip";
|
||||
|
||||
var dl = Utility.CreateDefaultDownloader();
|
||||
|
||||
List<int> prog = new List<int>();
|
||||
using (Utility.GetTempFileName(out var tempPath))
|
||||
await dl.DownloadFile(testUrl, tempPath, prog.Add);
|
||||
|
||||
Assert.True(prog.Count > 10);
|
||||
Assert.Equal(100, prog.Last());
|
||||
Assert.True(prog[1] != 0);
|
||||
}
|
||||
|
||||
static void CreateSampleDirectory(string directory)
|
||||
{
|
||||
Random prng = new Random();
|
||||
while (true) {
|
||||
Directory.CreateDirectory(directory);
|
||||
|
||||
for (var j = 0; j < 100; j++) {
|
||||
var file = Path.Combine(directory, newId());
|
||||
if (file.Length > 260) continue;
|
||||
File.WriteAllText(file, Guid.NewGuid().ToString());
|
||||
}
|
||||
|
||||
if (prng.NextDouble() > 0.5) {
|
||||
var childDirectory = Path.Combine(directory, newId());
|
||||
if (childDirectory.Length > 248) return;
|
||||
directory = childDirectory;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static string newId()
|
||||
{
|
||||
var text = Guid.NewGuid().ToString();
|
||||
var bytes = Encoding.Unicode.GetBytes(text);
|
||||
var provider = SHA1.Create();
|
||||
var hashString = string.Empty;
|
||||
|
||||
foreach (var x in provider.ComputeHash(bytes)) {
|
||||
hashString += String.Format("{0:x2}", x);
|
||||
}
|
||||
|
||||
if (hashString.Length > 7) {
|
||||
return hashString.Substring(0, 7);
|
||||
}
|
||||
|
||||
return hashString;
|
||||
}
|
||||
|
||||
static byte[] combine(params byte[][] arrays)
|
||||
{
|
||||
var rv = new byte[arrays.Sum(a => a.Length)];
|
||||
var offset = 0;
|
||||
foreach (var array in arrays) {
|
||||
Buffer.BlockCopy(array, 0, rv, offset, array.Length);
|
||||
offset += array.Length;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
_output = output;
|
||||
}
|
||||
|
||||
[SkippableTheory]
|
||||
[InlineData("file.txt", "file.txt")]
|
||||
[InlineData("file", "file")]
|
||||
[InlineData("/file", "\\file")]
|
||||
[InlineData("/file/", "\\file")]
|
||||
[InlineData("one\\two\\..\\file", "one\\file")]
|
||||
[InlineData("C:/AnApp/file/", "C:\\AnApp\\file")]
|
||||
public void PathIsNormalized(string input, string expected)
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
var exp = Path.GetFullPath(expected);
|
||||
var normal = Utility.NormalizePath(input);
|
||||
Assert.Equal(exp, normal);
|
||||
}
|
||||
|
||||
[SkippableTheory]
|
||||
[InlineData("C:\\AnApp", "C:\\AnApp\\file.exe", true)]
|
||||
[InlineData("C:\\AnApp\\", "C:\\AnApp\\file.exe", true)]
|
||||
[InlineData("C:\\AnApp", "C:\\AnApp\\sub\\dir\\file.exe", true)]
|
||||
[InlineData("C:\\AnApp\\", "C:\\AnApp\\sub\\dir\\file.exe", true)]
|
||||
[InlineData("C:\\AnAppTwo", "C:\\AnApp\\file.exe", false)]
|
||||
[InlineData("C:\\AnAppTwo\\", "C:\\AnApp\\file.exe", false)]
|
||||
[InlineData("C:\\AnAppTwo", "C:\\AnApp\\sub\\dir\\file.exe", false)]
|
||||
[InlineData("C:\\AnAppTwo\\", "C:\\AnApp\\sub\\dir\\file.exe", false)]
|
||||
[InlineData("AnAppThree", "AnAppThree\\file.exe", true)]
|
||||
public void FileIsInDirectory(string directory, string file, bool isIn)
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
var fileInDir = Utility.IsFileInDirectory(file, directory);
|
||||
Assert.Equal(isIn, fileInDir);
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
[SupportedOSPlatform("windows")]
|
||||
public void SetAppIdOnShortcutTest()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
var sl = new ShellLink() {
|
||||
Target = @"C:\Windows\Notepad.exe",
|
||||
Description = "It's Notepad",
|
||||
};
|
||||
|
||||
sl.SetAppUserModelId("org.anaïsbetts.test");
|
||||
var path = Path.GetFullPath(@".\test.lnk");
|
||||
sl.Save(path);
|
||||
|
||||
Console.WriteLine("Saved to " + path);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveByteOrderMarkerIfPresent()
|
||||
{
|
||||
var utf32Be = new byte[] { 0x00, 0x00, 0xFE, 0xFF };
|
||||
var utf32Le = new byte[] { 0xFF, 0xFE, 0x00, 0x00 };
|
||||
var utf16Be = new byte[] { 0xFE, 0xFF };
|
||||
var utf16Le = new byte[] { 0xFF, 0xFE };
|
||||
var utf8 = new byte[] { 0xEF, 0xBB, 0xBF };
|
||||
|
||||
var utf32BeHelloWorld = combine(utf32Be, Encoding.UTF8.GetBytes("hello world"));
|
||||
var utf32LeHelloWorld = combine(utf32Le, Encoding.UTF8.GetBytes("hello world"));
|
||||
var utf16BeHelloWorld = combine(utf16Be, Encoding.UTF8.GetBytes("hello world"));
|
||||
var utf16LeHelloWorld = combine(utf16Le, Encoding.UTF8.GetBytes("hello world"));
|
||||
var utf8HelloWorld = combine(utf8, Encoding.UTF8.GetBytes("hello world"));
|
||||
|
||||
var asciiMultipleChars = Encoding.ASCII.GetBytes("hello world");
|
||||
var asciiSingleChar = Encoding.ASCII.GetBytes("A");
|
||||
|
||||
var emptyString = string.Empty;
|
||||
string nullString = null;
|
||||
byte[] nullByteArray = { };
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(emptyString));
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(nullString));
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(nullByteArray));
|
||||
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf32Be));
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf32Le));
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf16Be));
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf16Le));
|
||||
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf8));
|
||||
|
||||
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(utf32BeHelloWorld));
|
||||
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(utf32LeHelloWorld));
|
||||
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(utf16BeHelloWorld));
|
||||
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(utf16LeHelloWorld));
|
||||
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(utf8HelloWorld));
|
||||
|
||||
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(asciiMultipleChars));
|
||||
Assert.Equal("A", Utility.RemoveByteOrderMarkerIfPresent(asciiSingleChar));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShaCheckShouldBeCaseInsensitive()
|
||||
{
|
||||
var sha1FromExternalTool = "75255cfd229a1ed1447abe1104f5635e69975d30";
|
||||
var inputPackage = PathHelper.GetFixture("Squirrel.Core.1.0.0.0.nupkg");
|
||||
var stream = File.OpenRead(inputPackage);
|
||||
var sha1 = Utility.CalculateStreamSHA1(stream);
|
||||
|
||||
Assert.NotEqual(sha1FromExternalTool, sha1);
|
||||
Assert.Equal(sha1FromExternalTool, sha1, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanDeleteDeepRecursiveDirectoryStructure()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<UtilityTests>();
|
||||
string tempDir;
|
||||
using (Utility.GetTempDirectory(out tempDir)) {
|
||||
for (var i = 0; i < 50; i++) {
|
||||
var directory = Path.Combine(tempDir, newId());
|
||||
CreateSampleDirectory(directory);
|
||||
}
|
||||
|
||||
var files = Directory.GetFiles(tempDir, "*", SearchOption.AllDirectories);
|
||||
|
||||
var count = files.Count();
|
||||
|
||||
logger.Info($"Created {count} files under directory {tempDir}");
|
||||
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
Utility.DeleteFileOrDirectoryHard(tempDir);
|
||||
sw.Stop();
|
||||
logger.Info($"Delete took {sw.ElapsedMilliseconds}ms");
|
||||
|
||||
Assert.False(Directory.Exists(tempDir));
|
||||
}
|
||||
}
|
||||
|
||||
//[Fact]
|
||||
//public void CreateFakePackageSmokeTest()
|
||||
//{
|
||||
// string path;
|
||||
// using (Utility.GetTempDirectory(out path)) {
|
||||
// var output = IntegrationTestHelper.CreateFakeInstalledApp("0.3.0", path);
|
||||
// Assert.True(File.Exists(output));
|
||||
// }
|
||||
//}
|
||||
|
||||
[Theory]
|
||||
[InlineData("foo.dll", true)]
|
||||
[InlineData("foo.DlL", true)]
|
||||
[InlineData("C:\\Foo\\Bar\\foo.Exe", true)]
|
||||
[InlineData("Test.png", false)]
|
||||
[InlineData(".rels", false)]
|
||||
public void FileIsLikelyPEImageTest(string input, bool result)
|
||||
{
|
||||
Assert.Equal(result, Utility.FileIsLikelyPEImage(input));
|
||||
}
|
||||
|
||||
[Fact(Skip = "Only really need to run this test after changes to FileDownloader")]
|
||||
public async Task DownloaderReportsProgress()
|
||||
{
|
||||
// this probably should use a local http server instead.
|
||||
const string testUrl = "http://speedtest.tele2.net/1MB.zip";
|
||||
|
||||
var dl = Utility.CreateDefaultDownloader();
|
||||
|
||||
List<int> prog = new List<int>();
|
||||
using (Utility.GetTempFileName(out var tempPath))
|
||||
await dl.DownloadFile(testUrl, tempPath, prog.Add);
|
||||
|
||||
Assert.True(prog.Count > 10);
|
||||
Assert.Equal(100, prog.Last());
|
||||
Assert.True(prog[1] != 0);
|
||||
}
|
||||
|
||||
static void CreateSampleDirectory(string directory)
|
||||
{
|
||||
Random prng = new Random();
|
||||
while (true) {
|
||||
Directory.CreateDirectory(directory);
|
||||
|
||||
for (var j = 0; j < 100; j++) {
|
||||
var file = Path.Combine(directory, newId());
|
||||
if (file.Length > 260) continue;
|
||||
File.WriteAllText(file, Guid.NewGuid().ToString());
|
||||
}
|
||||
|
||||
if (prng.NextDouble() > 0.5) {
|
||||
var childDirectory = Path.Combine(directory, newId());
|
||||
if (childDirectory.Length > 248) return;
|
||||
directory = childDirectory;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static string newId()
|
||||
{
|
||||
var text = Guid.NewGuid().ToString();
|
||||
var bytes = Encoding.Unicode.GetBytes(text);
|
||||
var provider = SHA1.Create();
|
||||
var hashString = string.Empty;
|
||||
|
||||
foreach (var x in provider.ComputeHash(bytes)) {
|
||||
hashString += String.Format("{0:x2}", x);
|
||||
}
|
||||
|
||||
if (hashString.Length > 7) {
|
||||
return hashString.Substring(0, 7);
|
||||
}
|
||||
|
||||
return hashString;
|
||||
}
|
||||
|
||||
static byte[] combine(params byte[][] arrays)
|
||||
{
|
||||
var rv = new byte[arrays.Sum(a => a.Length)];
|
||||
var offset = 0;
|
||||
foreach (var array in arrays) {
|
||||
Buffer.BlockCopy(array, 0, rv, offset, array.Length);
|
||||
offset += array.Length;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,85 +4,84 @@ using Velopack.NuGet;
|
||||
using Velopack.Tests.TestHelpers;
|
||||
using ZipPackage = Velopack.NuGet.ZipPackage;
|
||||
|
||||
namespace Velopack.Tests
|
||||
namespace Velopack.Tests;
|
||||
|
||||
public class ZipPackageTests
|
||||
{
|
||||
public class ZipPackageTests
|
||||
[Fact]
|
||||
public void HasSameFilesAndDependenciesAsPackaging()
|
||||
{
|
||||
[Fact]
|
||||
public void HasSameFilesAndDependenciesAsPackaging()
|
||||
{
|
||||
using var _1 = Utility.GetTempDirectory(out var tempDir);
|
||||
var inputPackage = PathHelper.GetFixture("slack-1.1.8-full.nupkg");
|
||||
var copyPackage = Path.Combine(tempDir, "slack-1.1.8-full.nupkg");
|
||||
File.Copy(inputPackage, copyPackage);
|
||||
using var _1 = Utility.GetTempDirectory(out var tempDir);
|
||||
var inputPackage = PathHelper.GetFixture("slack-1.1.8-full.nupkg");
|
||||
var copyPackage = Path.Combine(tempDir, "slack-1.1.8-full.nupkg");
|
||||
File.Copy(inputPackage, copyPackage);
|
||||
|
||||
var zp = new ZipPackage(inputPackage);
|
||||
var zipf = zp.Files.OrderBy(f => f.Path).ToArray();
|
||||
var zipfLib = zp.Files.Where(f => f.IsLibFile()).OrderBy(f => f.Path).ToArray();
|
||||
var zp = new ZipPackage(inputPackage);
|
||||
var zipf = zp.Files.OrderBy(f => f.Path).ToArray();
|
||||
var zipfLib = zp.Files.Where(f => f.IsLibFile()).OrderBy(f => f.Path).ToArray();
|
||||
|
||||
using Package package = Package.Open(copyPackage);
|
||||
var packaging = GetFiles(package).OrderBy(f => f.Path).ToArray();
|
||||
var packagingLib = GetLibFiles(package).OrderBy(f => f.Path).ToArray();
|
||||
using Package package = Package.Open(copyPackage);
|
||||
var packaging = GetFiles(package).OrderBy(f => f.Path).ToArray();
|
||||
var packagingLib = GetLibFiles(package).OrderBy(f => f.Path).ToArray();
|
||||
|
||||
//for (int i = 0; i < zipf.Length; i++) {
|
||||
// if (zipf[i] != packagingLib[i])
|
||||
// throw new Exception();
|
||||
//}
|
||||
//for (int i = 0; i < zipf.Length; i++) {
|
||||
// if (zipf[i] != packagingLib[i])
|
||||
// throw new Exception();
|
||||
//}
|
||||
|
||||
Assert.Equal(packaging, zipf);
|
||||
Assert.Equal(packagingLib, zipfLib);
|
||||
}
|
||||
Assert.Equal(packaging, zipf);
|
||||
Assert.Equal(packagingLib, zipfLib);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParsesNuspecCorrectly()
|
||||
{
|
||||
var inputPackage = PathHelper.GetFixture("FullNuspec.1.0.0.nupkg");
|
||||
var zp = new ZipPackage(inputPackage);
|
||||
[Fact]
|
||||
public void ParsesNuspecCorrectly()
|
||||
{
|
||||
var inputPackage = PathHelper.GetFixture("FullNuspec.1.0.0.nupkg");
|
||||
var zp = new ZipPackage(inputPackage);
|
||||
|
||||
var dyn = ExposedObject.From(zp);
|
||||
var dyn = ExposedObject.From(zp);
|
||||
|
||||
Assert.Equal("FullNuspec", zp.Id);
|
||||
Assert.Equal(SemanticVersion.Parse("1.0.0"), zp.Version);
|
||||
Assert.Equal(new[] { "Anaïs Betts", "Caelan Sayler" }, dyn.Authors);
|
||||
Assert.Equal(new Uri("https://github.com/clowd/Clowd.Squirrel"), zp.ProjectUrl);
|
||||
Assert.Equal(new Uri("https://user-images.githubusercontent.com/1287295/131249078-9e131e51-0b66-4dc7-8c0a-99cbea6bcf80.png"), zp.IconUrl);
|
||||
Assert.Equal("A test description", dyn.Description);
|
||||
Assert.Equal("A summary", dyn.Summary);
|
||||
Assert.Equal("release notes\nwith multiple lines", zp.ReleaseNotes);
|
||||
Assert.Equal("Copyright ©", dyn.Copyright);
|
||||
Assert.Equal("en-US", zp.Language);
|
||||
Assert.Equal("Squirrel for Windows", dyn.Title);
|
||||
}
|
||||
Assert.Equal("FullNuspec", zp.Id);
|
||||
Assert.Equal(SemanticVersion.Parse("1.0.0"), zp.Version);
|
||||
Assert.Equal(new[] { "Anaïs Betts", "Caelan Sayler" }, dyn.Authors);
|
||||
Assert.Equal(new Uri("https://github.com/clowd/Clowd.Squirrel"), zp.ProjectUrl);
|
||||
Assert.Equal(new Uri("https://user-images.githubusercontent.com/1287295/131249078-9e131e51-0b66-4dc7-8c0a-99cbea6bcf80.png"), zp.IconUrl);
|
||||
Assert.Equal("A test description", dyn.Description);
|
||||
Assert.Equal("A summary", dyn.Summary);
|
||||
Assert.Equal("release notes\nwith multiple lines", zp.ReleaseNotes);
|
||||
Assert.Equal("Copyright ©", dyn.Copyright);
|
||||
Assert.Equal("en-US", zp.Language);
|
||||
Assert.Equal("Squirrel for Windows", dyn.Title);
|
||||
}
|
||||
|
||||
IEnumerable<ZipPackageFile> GetLibFiles(Package package)
|
||||
{
|
||||
return GetFiles(package, NugetUtil.LibDirectory);
|
||||
}
|
||||
IEnumerable<ZipPackageFile> GetLibFiles(Package package)
|
||||
{
|
||||
return GetFiles(package, NugetUtil.LibDirectory);
|
||||
}
|
||||
|
||||
IEnumerable<ZipPackageFile> GetFiles(Package package, string directory)
|
||||
{
|
||||
string folderPrefix = directory + Path.DirectorySeparatorChar;
|
||||
return GetFiles(package).Where(file => file.Path.StartsWith(folderPrefix, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
IEnumerable<ZipPackageFile> GetFiles(Package package, string directory)
|
||||
{
|
||||
string folderPrefix = directory + Path.DirectorySeparatorChar;
|
||||
return GetFiles(package).Where(file => file.Path.StartsWith(folderPrefix, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
List<ZipPackageFile> GetFiles(Package package)
|
||||
{
|
||||
return (from part in package.GetParts()
|
||||
where IsPackageFile(part)
|
||||
select new ZipPackageFile(part.Uri)).ToList();
|
||||
}
|
||||
List<ZipPackageFile> GetFiles(Package package)
|
||||
{
|
||||
return (from part in package.GetParts()
|
||||
where IsPackageFile(part)
|
||||
select new ZipPackageFile(part.Uri)).ToList();
|
||||
}
|
||||
|
||||
bool IsPackageFile(PackagePart part)
|
||||
{
|
||||
string path = NugetUtil.GetPath(part.Uri);
|
||||
string directory = Path.GetDirectoryName(path);
|
||||
string[] ExcludePaths = new[] { "_rels", "package" };
|
||||
return !ExcludePaths.Any(p => directory.StartsWith(p, StringComparison.OrdinalIgnoreCase)) && !IsManifest(path);
|
||||
}
|
||||
bool IsPackageFile(PackagePart part)
|
||||
{
|
||||
string path = NugetUtil.GetPath(part.Uri);
|
||||
string directory = Path.GetDirectoryName(path);
|
||||
string[] ExcludePaths = new[] { "_rels", "package" };
|
||||
return !ExcludePaths.Any(p => directory.StartsWith(p, StringComparison.OrdinalIgnoreCase)) && !IsManifest(path);
|
||||
}
|
||||
|
||||
bool IsManifest(string p)
|
||||
{
|
||||
return Path.GetExtension(p).Equals(NugetUtil.ManifestExtension, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
bool IsManifest(string p)
|
||||
{
|
||||
return Path.GetExtension(p).Equals(NugetUtil.ManifestExtension, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user