OSX Pack command tests done

Starting on Windows command tests
This commit is contained in:
Kevin Bost
2022-09-23 07:41:36 -07:00
parent 844239704a
commit 78fc8edb1b
8 changed files with 346 additions and 42 deletions

View File

@@ -90,7 +90,7 @@ namespace Squirrel.CommandLine.OSX
NoDelta = new Option<bool>("--noDelta", "Skip the generation of delta packages");
Add(NoDelta);
NoPackage = new Option<bool>("--nopkg", "Skip generating a .pkg installer");
NoPackage = new Option<bool>("--noPkg", "Skip generating a .pkg installer");
Add(NoPackage);
//TODO: Would be nice to setup completions at least for the keys of this option
@@ -145,7 +145,7 @@ namespace Squirrel.CommandLine.OSX
SigningEntitlements = new Option<FileInfo>("--signEntitlements", "{PATH} to entitlements file for hardened runtime") {
ArgumentHelpName = "PATH"
};
SigningEntitlements.ExistingOnly().RequiresExtension("entitlements");
SigningEntitlements.ExistingOnly().RequiresExtension(".entitlements");
Add(SigningEntitlements);
NotaryProfile = new Option<string>("--notaryProfile", "{NAME} of profile containing Apple credentials stored with notarytool") {

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.IO;
using System.CommandLine.Parsing;
using Squirrel.CommandLine.Deployment;
using Squirrel.SimpleSplat;
@@ -69,7 +68,7 @@ namespace Squirrel.CommandLine
new GitHubCommand()
};
rootCommand.Add(deploymentCommand);
return rootCommand.Invoke(args);
}
}

View File

@@ -34,9 +34,15 @@ namespace Squirrel.CommandLine
return command;
}
public static Command RequiredAllowObsoleteFallback(this Command command, Option option, Option obsoleteOption)
{
command.AddValidator(x => Validate.AtLeastOneRequired(x, new[] { option, obsoleteOption }, true));
return command;
}
public static Command AtLeastOneRequired(this Command command, params Option[] options)
{
command.AddValidator(x => Validate.AtLeastOneRequired(x, options));
command.AddValidator(x => Validate.AtLeastOneRequired(x, options, false));
return command;
}
@@ -57,7 +63,7 @@ namespace Squirrel.CommandLine
option.AddValidator(Validate.RequiresAbsolute);
return option;
}
public static Option<string> RequiresValidNuGetId(this Option<string> option)
{
option.AddValidator(Validate.RequiresValidNuGetId);
@@ -92,7 +98,8 @@ namespace Squirrel.CommandLine
}
}
public static void RequiresExtension(OptionResult result, string extension) {
public static void RequiresExtension(OptionResult result, string extension)
{
for (int i = 0; i < result.Tokens.Count; i++) {
if (!string.Equals(Path.GetExtension(result.Tokens[i].Value), extension, StringComparison.InvariantCultureIgnoreCase)) {
result.ErrorMessage = $"{result.Tokens[i].Value} for {result.Option.Name} does not have an {extension} extension";
@@ -111,13 +118,17 @@ namespace Squirrel.CommandLine
}
}
public static void AtLeastOneRequired(CommandResult result, Option[] options)
public static void AtLeastOneRequired(CommandResult result, Option[] options, bool onlyShowFirst = false)
{
var anySpecifiedOptions = options
.Any(x => result.FindResultFor(x) is not null);
if (!anySpecifiedOptions) {
string optionsString = string.Join(" and ", options.Select(x => $"'{x.Name}'"));
result.ErrorMessage = $"At least one of the following options are required {optionsString}.";
if (onlyShowFirst) {
result.ErrorMessage = $"Required argument missing for option: {options.First().Name}";
} else {
string optionsString = string.Join(" and ", options.Select(x => $"'{x.Name}'"));
result.ErrorMessage = $"At least one of the following options are required {optionsString}.";
}
}
}
@@ -134,7 +145,7 @@ namespace Squirrel.CommandLine
{
for (int i = 0; i < result.Tokens.Count; i++) {
if (Uri.TryCreate(result.Tokens[i].Value, UriKind.RelativeOrAbsolute, out Uri uri) &&
!validSchemes.Contains(uri.Scheme)){
!validSchemes.Contains(uri.Scheme)) {
result.ErrorMessage = $"{result.Option.Name} must contain a Uri with one of the following schems: {string.Join(", ", validSchemes)}. Current value is '{result.Tokens[i].Value}'";
}
}

View File

@@ -5,17 +5,17 @@ using System.IO;
namespace Squirrel.CommandLine.Windows
{
internal class PackCommand : ReleaseCommand
public class PackCommand : ReleaseCommand
{
//Question: Since these are already inside of the PackCommand should we drop the "Pack" prefix from the property names?
protected Option<string> PackName { get; }
protected Option<DirectoryInfo> PackDirectory { get; }
protected Option<string> PackId { get; }
protected Option<string> PackVersion { get; }
protected Option<string> PackTitle { get; }
protected Option<string> PackAuthors { get; }
protected Option<bool> IncludePdb { get; }
protected Option<FileInfo> ReleaseNotes { get; }
public Option<string> PackName { get; }
public Option<DirectoryInfo> PackDirectory { get; }
public Option<string> PackId { get; }
public Option<string> PackVersion { get; }
public Option<string> PackTitle { get; }
public Option<string> PackAuthors { get; }
public Option<bool> IncludePdb { get; }
public Option<FileInfo> ReleaseNotes { get; }
public PackCommand()
: base("pack", "Creates a Squirrel release from a folder containing application files")
@@ -26,13 +26,15 @@ namespace Squirrel.CommandLine.Windows
PackId.RequiresValidNuGetId();
Add(PackId);
//TODO: do we need to bring this forward since it is deprecated? Can we just remove it and make PackId a required option?
PackName = new Option<string>("--packName", $"The name of the package to create. This is deprecated, use {PackId.Name} instead.") {
IsHidden = true,
};
Add(PackName);
//Question: I included --packDirectory here even though it should be "hidden" how important is it to deprecate this alias?
this.RequiredAllowObsoleteFallback(PackId, PackName);
//Question: I included --packDirectory here even though it should be "hidden".
// To deprecate how important is it to deprecate this alias?
PackDirectory = new Option<DirectoryInfo>(new[] { "-p", "--packDir", "--packDirectory" }, "{DIRECTORY} containing application files for release") {
ArgumentHelpName = "DIRECTORY",
IsRequired = true,

View File

@@ -7,18 +7,18 @@ namespace Squirrel.CommandLine.Windows
{
public class ReleaseCommand : SigningCommand
{
protected Option<Uri> BaseUrl { get; }
public Option<Uri> BaseUrl { get; }
//Question this appears to only have an arity of 1, should you be able to specify it multiple times?
protected Option<string> AddSearchPath { get; }
protected Option<FileInfo> DebugSetupExe { get; }
public Option<string> AddSearchPath { get; }
public Option<FileInfo> DebugSetupExe { get; }
protected Option<bool> NoDelta { get; }
protected Option<string> Runtimes { get; }
protected Option<FileInfo> SplashImage { get; }
protected Option<FileInfo> Icon { get; }
protected Option<string> SquirrelAwareExecutable { get; }
protected Option<FileInfo> AppIcon { get; }
protected Option<Bitness> BuildMsi { get; }
public Option<bool> NoDelta { get; }
public Option<string> Runtimes { get; }
public Option<FileInfo> SplashImage { get; }
public Option<FileInfo> Icon { get; }
public Option<string> SquirrelAwareExecutable { get; }
public Option<FileInfo> AppIcon { get; }
public Option<Bitness> BuildMsi { get; }
protected ReleaseCommand(string name, string description)
: base(name, description)

View File

@@ -5,14 +5,19 @@ namespace Squirrel.CommandLine.Windows
{
public class SigningCommand : BaseCommand
{
protected Option<string> SignParameters { get; }
protected Option<bool> SignSkipDll { get; }
protected Option<int> SignParallel { get; }
protected Option<string> SignTemplate { get; }
public Option<string> SignParameters { get; }
public Option<bool> SignSkipDll { get; }
public Option<int> SignParallel { get; }
public Option<string> SignTemplate { get; }
protected SigningCommand(string name, string description)
: base(name, description)
{
SignTemplate = new Option<string>("--signTemplate", "Use a custom signing {COMMAND}. '{{file}}' will be replaced by the path of the file to sign.") {
ArgumentHelpName = "COMMAND"
};
SignTemplate.MustContain("{{file}}");
if (SquirrelRuntimeInfo.IsWindows) {
//TODO: Cannot be used with sign template
SignParameters = new Option<string>(new[] { "-n", "--signParams" }, "Sign files via signtool.exe using these {PARAMETERS}") {
@@ -28,10 +33,7 @@ namespace Squirrel.CommandLine.Windows
SignParallel.MustBeBetween(1, 1000);
Add(SignParallel);
}
SignTemplate = new Option<string>("--signTemplate", "Use a custom signing {COMMAND}. '{{file}}' will be replaced by the path of the file to sign.") {
ArgumentHelpName = "COMMAND"
};
SignTemplate.MustContain("{{file}}");
Add(SignTemplate);
}

View File

@@ -173,7 +173,7 @@ namespace Squirrel.CommandLine.Tests.OSX
}
[Fact]
public void BundleId_WithoutFile_ShowsError()
public void BundleId_WithoutId_ShowsError()
{
string file = Path.GetFullPath(Path.ChangeExtension(Path.GetRandomFileName(), ".ico"));
var command = new PackCommand();
@@ -186,6 +186,28 @@ namespace Squirrel.CommandLine.Tests.OSX
Assert.Contains(file, parseResult.Errors[0].Message);
}
[Fact]
public void NoDelta_BareOption_SetsFlag()
{
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + "--noDelta";
ParseResult parseResult = command.Parse(cli);
Assert.True(parseResult.GetValueForOption(command.NoDelta));
}
[Fact]
public void NoPackage_BareOption_SetsFlag()
{
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + "--noPkg";
ParseResult parseResult = command.Parse(cli);
Assert.True(parseResult.GetValueForOption(command.NoPackage));
}
[Fact]
public void PackageContent_CanSpecifyMultipleValues()
{
@@ -223,11 +245,72 @@ namespace Squirrel.CommandLine.Tests.OSX
Assert.Equal("Invalid pkgContent key: unknown. Must be one of: welcome, readme, license, conclusion", error.Message);
}
[Fact]
public void SigningAppIdentity_WithSubject_ParsesValue()
{
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + $"--signAppIdentity \"Mac Developer\"";
ParseResult parseResult = command.Parse(cli);
Assert.Equal("Mac Developer", parseResult.GetValueForOption(command.SigningAppIdentity));
}
[Fact]
public void SigningInstallIdentity_WithSubject_ParsesValue()
{
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + $"--signInstallIdentity \"Mac Developer\"";
ParseResult parseResult = command.Parse(cli);
Assert.Equal("Mac Developer", parseResult.GetValueForOption(command.SigningInstallIdentity));
}
[Fact]
public void SigningEntitlements_WithValidFile_ParsesValue()
{
FileInfo fileInfo = CreateTempFile(name: Path.ChangeExtension(Path.GetRandomFileName(), ".entitlements"));
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + $"--signEntitlements \"{fileInfo.FullName}\"";
ParseResult parseResult = command.Parse(cli);
Assert.Equal(fileInfo.FullName, parseResult.GetValueForOption(command.SigningEntitlements)?.FullName);
}
[Fact]
public void SigningEntitlements_WithBadFileExtension_ShowsError()
{
FileInfo fileInfo = CreateTempFile(name: Path.ChangeExtension(Path.GetRandomFileName(), ".wrong"));
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + $"--signEntitlements \"{fileInfo.FullName}\"";
ParseResult parseResult = command.Parse(cli);
Assert.Equal(1, parseResult.Errors.Count);
Assert.Equal($"{fileInfo.FullName} for signEntitlements does not have an .entitlements extension", parseResult.Errors[0].Message);
}
[Fact]
public void SigningEntitlements_WithoutFile_ShowsError()
{
string file = Path.GetFullPath(Path.ChangeExtension(Path.GetRandomFileName(), ".entitlements"));
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + $"--signEntitlements \"{file}\"";
ParseResult parseResult = command.Parse(cli);
Assert.Equal(1, parseResult.Errors.Count);
Assert.Equal(command.SigningEntitlements, parseResult.Errors[0].SymbolResult?.Symbol.Parents.Single());
Assert.Contains(file, parseResult.Errors[0].Message);
}
private string GetRequiredDefaultOptions()
{
DirectoryInfo packDir = CreateTempDirectory();
CreateTempFile(packDir);
var command = new PackCommand();
return $"-u Clowd.Squirrel -v 1.0.0 -p \"{packDir.FullName}\" ";
}

View File

@@ -0,0 +1,207 @@
using Xunit;
using Squirrel.CommandLine.Windows;
using System.CommandLine;
using System.CommandLine.Parsing;
namespace Squirrel.CommandLine.Tests.Windows
{
public class PackCommandTests : TempFileTestBase
{
[Fact]
public void Command_WithValidRequiredArguments_Parses()
{
DirectoryInfo packDir = CreateTempDirectory();
CreateTempFile(packDir);
var command = new PackCommand();
ParseResult parseResult = command.Parse($"-u Clowd.Squirrel -v 1.2.3 -p \"{packDir.FullName}\"");
Assert.Empty(parseResult.Errors);
Assert.Equal("Clowd.Squirrel", parseResult.GetValueForOption(command.PackId));
Assert.Equal("1.2.3", parseResult.GetValueForOption(command.PackVersion));
Assert.Equal(packDir.FullName, parseResult.GetValueForOption(command.PackDirectory)?.FullName);
}
[Fact]
public void PackId_WithInvalidNuGetId_ShowsError()
{
DirectoryInfo packDir = CreateTempDirectory();
CreateTempFile(packDir);
var command = new PackCommand();
ParseResult parseResult = command.Parse($"--packId $42@ -v 1.0.0 -p \"{packDir.FullName}\"");
Assert.Equal(1, parseResult.Errors.Count);
Assert.StartsWith("packId is an invalid NuGet package id.", parseResult.Errors[0].Message);
Assert.Contains("$42@", parseResult.Errors[0].Message);
}
[Fact]
public void PackId_WithInvalidVersion_ShowsError()
{
DirectoryInfo packDir = CreateTempDirectory();
CreateTempFile(packDir);
var command = new PackCommand();
ParseResult parseResult = command.Parse($"-u Clowd.Squirrel -v 1.a.c -p \"{packDir.FullName}\"");
Assert.Equal(1, parseResult.Errors.Count);
Assert.StartsWith("packVersion contains an invalid package version", parseResult.Errors[0].Message);
Assert.Contains("1.a.c", parseResult.Errors[0].Message);
}
[Fact]
public void PackDirectory_WithEmptyFolder_ShowsError()
{
DirectoryInfo packDir = CreateTempDirectory();
var command = new PackCommand();
ParseResult parseResult = command.Parse($"-u Clowd.Squirrel -v 1.0.0 -p \"{packDir.FullName}\"");
Assert.Equal(1, parseResult.Errors.Count);
Assert.StartsWith("packDir must a non-empty directory", parseResult.Errors[0].Message);
Assert.Contains(packDir.FullName, parseResult.Errors[0].Message);
}
[Fact]
public void PackAuthors_WithMultipleAuthors_ParsesValue()
{
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + "--packAuthors Me,mysel,I";
ParseResult parseResult = command.Parse(cli);
Assert.Equal("Me,mysel,I", parseResult.GetValueForOption(command.PackAuthors));
}
[Fact]
public void PackTitle_WithTitle_ParsesValue()
{
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + "--packTitle \"My Awesome Title\"";
ParseResult parseResult = command.Parse(cli);
Assert.Equal("My Awesome Title", parseResult.GetValueForOption(command.PackTitle));
}
[Fact]
public void IncludePdb_BareOption_SetsFlag()
{
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + "--includePdb";
ParseResult parseResult = command.Parse(cli);
Assert.True(parseResult.GetValueForOption(command.IncludePdb));
}
[Fact]
public void ReleaseNode_WithExistingFile_ParsesValue()
{
FileInfo releaseNotes = CreateTempFile();
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + $"--releaseNotes \"{releaseNotes.FullName}\"";
ParseResult parseResult = command.Parse(cli);
Assert.Equal(releaseNotes.FullName, parseResult.GetValueForOption(command.ReleaseNotes)?.FullName);
}
[Fact]
public void ReleaseNode_WithoutFile_ShowsError()
{
string releaseNotes = Path.GetFullPath(Path.GetRandomFileName());
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + $"--releaseNotes \"{releaseNotes}\"";
ParseResult parseResult = command.Parse(cli);
Assert.Equal(1, parseResult.Errors.Count);
Assert.Equal(command.ReleaseNotes, parseResult.Errors[0].SymbolResult?.Symbol.Parents.Single());
Assert.Contains(releaseNotes, parseResult.Errors[0].Message);
}
[Fact]
public void SquirrelAwareExecutable_WithFileName_ParsesValue()
{
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + $"--mainExe \"MyApp.exe\"";
ParseResult parseResult = command.Parse(cli);
Assert.Equal("MyApp.exe", parseResult.GetValueForOption(command.SquirrelAwareExecutable));
}
[Fact]
public void Icon_WithValidFile_ParsesValue()
{
FileInfo fileInfo = CreateTempFile(name: Path.ChangeExtension(Path.GetRandomFileName(), ".ico"));
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + $"--icon \"{fileInfo.FullName}\"";
ParseResult parseResult = command.Parse(cli);
Assert.Equal(fileInfo.FullName, parseResult.GetValueForOption(command.Icon)?.FullName);
}
[Fact]
public void Icon_WithBadFileExtension_ShowsError()
{
FileInfo fileInfo = CreateTempFile(name: Path.ChangeExtension(Path.GetRandomFileName(), ".wrong"));
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + $"--icon \"{fileInfo.FullName}\"";
ParseResult parseResult = command.Parse(cli);
Assert.Equal(1, parseResult.Errors.Count);
Assert.Equal($"{fileInfo.FullName} for icon does not have an .ico extension", parseResult.Errors[0].Message);
}
[Fact]
public void Icon_WithoutFile_ShowsError()
{
string file = Path.GetFullPath(Path.ChangeExtension(Path.GetRandomFileName(), ".ico"));
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + $"--icon \"{file}\"";
ParseResult parseResult = command.Parse(cli);
Assert.Equal(1, parseResult.Errors.Count);
Assert.Equal(command.Icon, parseResult.Errors[0].SymbolResult?.Symbol.Parents.Single());
Assert.Contains(file, parseResult.Errors[0].Message);
}
[Fact]
public void BundleId_WithoutId_ShowsError()
{
string file = Path.GetFullPath(Path.ChangeExtension(Path.GetRandomFileName(), ".ico"));
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + $"--icon \"{file}\"";
ParseResult parseResult = command.Parse(cli);
Assert.Equal(1, parseResult.Errors.Count);
Assert.Equal(command.Icon, parseResult.Errors[0].SymbolResult?.Symbol.Parents.Single());
Assert.Contains(file, parseResult.Errors[0].Message);
}
[Fact]
public void NoDelta_BareOption_SetsFlag()
{
var command = new PackCommand();
string cli = GetRequiredDefaultOptions() + "--noDelta";
ParseResult parseResult = command.Parse(cli);
Assert.True(parseResult.GetValueForOption(command.NoDelta));
}
private string GetRequiredDefaultOptions()
{
DirectoryInfo packDir = CreateTempDirectory();
CreateTempFile(packDir);
return $"-u Clowd.Squirrel -v 1.0.0 -p \"{packDir.FullName}\" ";
}
}
}