Convert all files to file-scoped name space

This commit is contained in:
Caelan Sayler
2024-02-02 12:26:31 +00:00
parent c10b15278f
commit 2caa7852d3
59 changed files with 5196 additions and 5256 deletions

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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));
}
}

View File

@@ -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}'");
}
}
}
}

View File

@@ -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());
}
}

View File

@@ -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.");
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();
//}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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; }
}
}

View File

@@ -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
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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));
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}
}

View File

@@ -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));
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}