Merge pull request #13 from premun/prvysoky/test-command

Unify common argument parsing for test/package commands
This commit is contained in:
Přemek Vysoký 2020-03-30 20:53:31 +02:00 коммит произвёл Matt Galbraith
Родитель dfc0b9a8ec
Коммит 802929e792
17 изменённых файлов: 501 добавлений и 147 удалений

2
.gitattributes поставляемый Normal file
Просмотреть файл

@ -0,0 +1,2 @@
# Apply LF to shell scripts automatically
*.sh text eol=lf

Просмотреть файл

@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.0
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@ -10,7 +10,7 @@ namespace Microsoft.DotNet.XHarness.CLI.Android
{
public class AndroidGetStateCommand : Command
{
bool ShowHelp = false;
private bool _showHelp = false;
public AndroidGetStateCommand() : base("state")
{
@ -18,7 +18,7 @@ namespace Microsoft.DotNet.XHarness.CLI.Android
"usage: android state",
"",
"Print information about the current machine, such as host machine info, path/version of ADB.exe used and device status",
{ "help|h", "Show this message", v => ShowHelp = v != null }
{ "help|h", "Show this message", v => _showHelp = v != null }
};
}
@ -26,18 +26,21 @@ namespace Microsoft.DotNet.XHarness.CLI.Android
{
// Deal with unknown options and print nicely
var extra = Options.Parse(arguments);
if (ShowHelp)
if (_showHelp)
{
Options.WriteOptionDescriptions(Console.Out);
return 1;
}
if (extra.Count > 0)
{
Console.WriteLine($"Unknown arguments: {string.Join(" ", extra)}");
Options.WriteOptionDescriptions(Console.Out);
return 2;
}
Console.WriteLine("Android state command called (no args supported)");
return 0;
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.0
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@ -6,28 +6,14 @@ using Microsoft.DotNet.XHarness.CLI.Common;
using Mono.Options;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Microsoft.DotNet.XHarness.CLI.Android
{
public class AndroidTestCommand : TestCommand
internal class AndroidTestCommand : TestCommand
{
// Path to packaged app
string ApplicationPath;
// If specified, attempt to run instrumentation with this name instead of the default for the supplied APK.
string InstrumentationName;
// Path where the outputs of execution will be stored.
string OutputDirectory;
// Path where run logs will hbe stored and projects
string WorkingDirectory;
// How long XHarness should wait until a test execution completes before clean up (kill running apps, uninstall, etc)
int TimeoutInSeconds = 300;
readonly Dictionary<string, string> InstrumentationArguments = new Dictionary<string, string>();
bool ShowHelp = false;
private readonly AndroidTestCommandArguments _arguments = new AndroidTestCommandArguments();
protected override ITestCommandArguments TestArguments => _arguments;
public AndroidTestCommand() : base()
{
@ -35,7 +21,6 @@ namespace Microsoft.DotNet.XHarness.CLI.Android
"usage: android test [OPTIONS]",
"",
"Executes tests on and Android device, waits up to a given timeout, then copies files off the device.",
{ "app|a=", "Path to .apk file", v => ApplicationPath = v},
{ "arg=", "Argument to pass to the instrumentation, in form key=value", v =>
{
string[] argPair = v.Split('=');
@ -47,44 +32,36 @@ namespace Microsoft.DotNet.XHarness.CLI.Android
}
else
{
InstrumentationArguments.Add(argPair[0].Trim(), argPair[1].Trim());
_arguments.InstrumentationArguments.Add(argPair[0].Trim(), argPair[1].Trim());
}
}
},
{ "instrumentation|i=", "If specified, attempt to run instrumentation with this name instead of the default for the supplied APK.", v => InstrumentationName = v},
{ "output-directory=", "Directory in which test results will be outputted", v => OutputDirectory = v},
{ "targets=", "Unused on Android", v => { /* Ignore v but don't throw */ } },
{ "timeout=", "Time span, in seconds, to wait for instrumentation to complete.", v => TimeoutInSeconds = int.Parse(v)},
{ "working-directory=", "Directory in which other files (logs, etc) will be outputted", v => WorkingDirectory = v},
{ "help|h", "Show this message", v => ShowHelp = v != null }
{ "instrumentation|i=", "If specified, attempt to run instrumentation with this name instead of the default for the supplied APK.", v => _arguments.InstrumentationName = v},
};
foreach (var option in CommonOptions)
{
Options.Add(option);
}
}
public override int Invoke(IEnumerable<string> arguments)
protected override Task<int> InvokeInternal()
{
// Deal with unknown options and print nicely
var extra = Options.Parse(arguments);
if (ShowHelp)
{
Options.WriteOptionDescriptions(Console.Out);
return 1;
}
if (extra.Count > 0)
{
Console.WriteLine($"Unknown arguments: {string.Join(" ", extra)}");
Options.WriteOptionDescriptions(Console.Out);
return 2;
}
Console.WriteLine($"Android Test command called: App = {ApplicationPath}{Environment.NewLine}Instrumentation Name = {InstrumentationName}");
Console.WriteLine($"Output Directory:{OutputDirectory}{Environment.NewLine}Working Directory = {WorkingDirectory}{Environment.NewLine}Timeout = {TimeoutInSeconds} seconds.");
Console.WriteLine($"iOS Test command called:");
Console.WriteLine($" App: {_arguments.AppPackagePath}");
Console.WriteLine($" Targets: {string.Join(',', _arguments.Targets)}");
Console.WriteLine($" Output Directory: {_arguments.OutputDirectory}");
Console.WriteLine($" Working Directory: {_arguments.WorkingDirectory}");
Console.WriteLine($" Timeout: {_arguments.Timeout.TotalSeconds}s");
Console.WriteLine("Arguments to instrumentation:");
foreach (var key in InstrumentationArguments.Keys)
foreach (KeyValuePair<string, string> pair in _arguments.InstrumentationArguments)
{
Console.WriteLine($" {key} = {InstrumentationArguments[key]}");
Console.WriteLine($" {pair.Key} = {pair.Value}");
}
return 0;
return Task.FromResult(0);
}
}
}

Просмотреть файл

@ -0,0 +1,40 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.DotNet.XHarness.CLI.Common;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.DotNet.XHarness.CLI.Android
{
internal class AndroidTestCommandArguments : TestCommandArguments
{
/// <summary>
/// If specified, attempt to run instrumentation with this name instead of the default for the supplied APK
/// </summary>
public string InstrumentationName { get; set; }
public Dictionary<string, string> InstrumentationArguments { get; set; } = new Dictionary<string, string>();
public override bool TryValidate([NotNullWhen(true)] out IEnumerable<string> errors)
{
if (!base.TryValidate(out errors))
{
return false;
}
// TODO: Validate instrumentation
return true;
}
internal override IEnumerable<string> GetAvailableTargets()
{
return new[]
{
"TODO: To be filled in", // TODO
};
}
}
}

Просмотреть файл

@ -0,0 +1,43 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.DotNet.XHarness.CLI.Common
{
internal interface ICommandArguments
{
bool TryValidate([NotNullWhen(true)]out IEnumerable<string> errors);
}
internal interface ITestCommandArguments : ICommandArguments
{
/// <summary>
/// Path to packaged app
/// </summary>
string AppPackagePath { get; set; }
/// <summary>
/// List of targets to test
/// </summary>
IReadOnlyCollection<string> Targets { get; set; }
/// <summary>
/// How long XHarness should wait until a test execution completes before clean up (kill running apps, uninstall, etc)
/// </summary>
TimeSpan Timeout { get; set; }
/// <summary>
/// Path where the outputs of execution will be stored
/// </summary>
string OutputDirectory { get; set; }
/// <summary>
/// Path where run logs will hbe stored and projects
/// </summary>
string WorkingDirectory { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,27 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Mono.Options;
namespace Microsoft.DotNet.XHarness.CLI.Common
{
internal abstract class PackageCommand : XHarnessCommand
{
protected override ICommandArguments Arguments => PackageArguments;
protected abstract IPackageCommandArguments PackageArguments { get; }
protected readonly OptionSet CommonOptions;
public PackageCommand() : base("package")
{
CommonOptions = new OptionSet
{
{ "name=|n=", "Name of the test application", v => PackageArguments.AppPackageName = v},
{ "output-directory=|o=", "Directory in which the resulting package will be outputted", v => PackageArguments.OutputDirectory = v},
{ "working-directory=|w=", "Directory in which the resulting package will be outputted", v => PackageArguments.WorkingDirectory = v},
{ "help|h", "Show this message", v => ShowHelp = v != null }
};
}
}
}

Просмотреть файл

@ -0,0 +1,83 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
namespace Microsoft.DotNet.XHarness.CLI.Common
{
internal interface IPackageCommandArguments : ICommandArguments
{
/// <summary>
/// Name of the packaged app
/// </summary>
string AppPackageName { get; set; }
/// <summary>
/// Path where the outputs of execution will be stored
/// </summary>
string OutputDirectory { get; set; }
/// <summary>
/// Path where run logs will hbe stored and projects
/// </summary>
string WorkingDirectory { get; set; }
}
internal abstract class PackageCommandArguments : IPackageCommandArguments
{
public string AppPackageName { get; set; }
public string OutputDirectory { get; set; }
public string WorkingDirectory { get; set; }
public virtual bool TryValidate([NotNullWhen(true)] out IEnumerable<string> errors)
{
var errs = new List<string>();
errors = errs;
if (string.IsNullOrEmpty(AppPackageName))
{
errs.Add("You must provide a name for the application to be created.");
}
if (string.IsNullOrEmpty(OutputDirectory))
{
errs.Add("Output directory path missing.");
}
else
{
if (!Path.IsPathRooted(OutputDirectory))
{
OutputDirectory = Path.Combine(Directory.GetCurrentDirectory(), OutputDirectory);
}
if (!Directory.Exists(OutputDirectory))
{
Directory.CreateDirectory(OutputDirectory);
}
}
if (string.IsNullOrEmpty(WorkingDirectory))
{
errs.Add("Working directory path missing.");
}
else
{
if (!Path.IsPathRooted(WorkingDirectory))
{
WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), WorkingDirectory);
}
if (!Directory.Exists(WorkingDirectory))
{
Directory.CreateDirectory(WorkingDirectory);
}
}
return !errors.Any();
}
}
}

Просмотреть файл

@ -2,14 +2,29 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Mono.Options;
namespace Microsoft.DotNet.XHarness.CLI.Common
{
public abstract class TestCommand : Command
internal abstract class TestCommand : XHarnessCommand
{
protected override ICommandArguments Arguments => TestArguments;
protected abstract ITestCommandArguments TestArguments { get; }
protected readonly OptionSet CommonOptions;
public TestCommand() : base("test")
{
CommonOptions = new OptionSet
{
{ "app|a=", "Path to already-packaged app", v => TestArguments.AppPackagePath = v },
{ "output-directory=|o=", "Directory in which the resulting package will be outputted", v => TestArguments.OutputDirectory = v},
{ "targets=", "Comma-delineated list of targets to test for", v=> TestArguments.Targets = v.Split(',') },
{ "timeout=|t=", "Time span, in seconds, to wait for instrumentation to complete.", v => TestArguments.Timeout = TimeSpan.FromSeconds(int.Parse(v))},
{ "working-directory=|w=", "Directory in which the resulting package will be outputted", v => TestArguments.WorkingDirectory = v},
{ "help|h", "Show this message", v => ShowHelp = v != null }
};
}
}
}

Просмотреть файл

@ -0,0 +1,78 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
namespace Microsoft.DotNet.XHarness.CLI.Common
{
internal abstract class TestCommandArguments : ITestCommandArguments
{
public string AppPackagePath { get; set; }
public IReadOnlyCollection<string> Targets { get; set; }
public TimeSpan Timeout { get; set; } = TimeSpan.FromMinutes(5);
public string OutputDirectory { get; set; }
public string WorkingDirectory { get; set; }
public virtual bool TryValidate([NotNullWhen(true)] out IEnumerable<string> errors)
{
var errs = new List<string>();
errors = errs;
if (string.IsNullOrEmpty(AppPackagePath))
{
errs.Add("You must provide a name for the application that will be tested.");
}
if (string.IsNullOrEmpty(OutputDirectory))
{
errs.Add("Output directory path missing.");
}
else
{
if (!Path.IsPathRooted(OutputDirectory))
{
OutputDirectory = Path.Combine(Directory.GetCurrentDirectory(), OutputDirectory);
}
if (!Directory.Exists(OutputDirectory))
{
Directory.CreateDirectory(OutputDirectory);
}
}
if (string.IsNullOrEmpty(WorkingDirectory))
{
errs.Add("Working directory path missing.");
}
else
{
if (!Path.IsPathRooted(WorkingDirectory))
{
WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), WorkingDirectory);
}
if (!Directory.Exists(WorkingDirectory))
{
Directory.CreateDirectory(WorkingDirectory);
}
}
if (Targets == null || Targets.Count == 0)
{
errs.Add("0 targets specified. At least one target must be provided. " +
"Available targets are:" +
Environment.NewLine + "\t" +
string.Join(Environment.NewLine + "\t", GetAvailableTargets()));
}
return !errors.Any();
}
internal abstract IEnumerable<string> GetAvailableTargets();
}
}

Просмотреть файл

@ -0,0 +1,55 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Mono.Options;
namespace Microsoft.DotNet.XHarness.CLI.Common
{
internal abstract class XHarnessCommand : Command
{
protected abstract ICommandArguments Arguments { get; }
protected bool ShowHelp = false;
protected XHarnessCommand(string name) : base(name)
{
}
public override sealed int Invoke(IEnumerable<string> arguments)
{
var extra = Options.Parse(arguments);
if (ShowHelp)
{
Options.WriteOptionDescriptions(Console.Out);
return 0;
}
if (extra.Count > 0)
{
Console.Error.WriteLine($"Unknown arguments{string.Join(" ", extra)}");
Options.WriteOptionDescriptions(Console.Out);
return 1;
}
if (!Arguments.TryValidate(out var errors))
{
Console.Error.WriteLine("Invalid arguments:");
foreach (string error in errors)
{
Console.Error.WriteLine(" - " + error);
}
return 1;
}
return InvokeInternal().GetAwaiter().GetResult();
}
protected abstract Task<int> InvokeInternal();
}
}

Просмотреть файл

@ -10,7 +10,7 @@ using System.Collections.Generic;
namespace Microsoft.DotNet.XHarness.CLI.Common
{
class XHarnessHelpCommand : HelpCommand
internal class XHarnessHelpCommand : HelpCommand
{
public override int Invoke(IEnumerable<string> arguments)
{
@ -41,8 +41,8 @@ namespace Microsoft.DotNet.XHarness.CLI.Common
Console.WriteLine($"No help available for command '{args[0]}'");
return -1;
}
return 0;
return 0;
}
private void PrintAllHelp(CommandSet commandSet, string v)

Просмотреть файл

@ -17,14 +17,15 @@ namespace Microsoft.DotNet.XHarness.CLI
Console.WriteLine(string.Join(' ', args));
// Root command: will use the platform specific commands to perform the appropriate action.
var commands = new CommandSet("xharness");
var commands = new CommandSet("xharness")
{
// Add per-platform CommandSets - If adding a new supported set, that goes here.
new iOSCommandSet(),
new AndroidCommandSet(),
// Add per-platform CommandSets - If adding a new supported set, that goes here.
commands.Add(new iOSCommandSet());
commands.Add(new AndroidCommandSet());
// add shared commands, for example, help and so on. --version, --help, --verbosity and so on
commands.Add(new XHarnessHelpCommand());
// add shared commands, for example, help and so on. --version, --help, --verbosity and so on
new XHarnessHelpCommand()
};
return commands.Run(args);
}

Просмотреть файл

@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.0
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@ -10,7 +10,7 @@ namespace Microsoft.DotNet.XHarness.CLI.iOS
{
public class iOSGetStateCommand : Command
{
bool ShowHelp = false;
private bool _showHelp = false;
public iOSGetStateCommand() : base("state")
{
@ -18,7 +18,7 @@ namespace Microsoft.DotNet.XHarness.CLI.iOS
"usage: ios state",
"",
"Print information about the current machine, such as host machine info and device status",
{ "help|h", "Show this message", v => ShowHelp = v != null }
{ "help|h", "Show this message", v => _showHelp = v != null }
};
}
@ -26,17 +26,20 @@ namespace Microsoft.DotNet.XHarness.CLI.iOS
{
// Deal with unknown options and print nicely
var extra = Options.Parse(arguments);
if (ShowHelp)
if (_showHelp)
{
Options.WriteOptionDescriptions(Console.Out);
return 1;
}
if (extra.Count > 0)
{
Console.WriteLine($"Unknown arguments: {string.Join(" ", extra)}");
Options.WriteOptionDescriptions(Console.Out);
}
Console.WriteLine("iOS state command called (no args supported)");
return 0;
}
}

Просмотреть файл

@ -2,9 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Mono.Options;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.DotNet.XHarness.CLI.Common;
using Mono.Options;
namespace Microsoft.DotNet.XHarness.CLI.iOS
{
@ -19,36 +20,23 @@ namespace Microsoft.DotNet.XHarness.CLI.iOS
// Command that will create the required project generation for the iOS plaform. The command will ensure that all
// required .csproj and src are created. The command is part of the parent CommandSet iOS and exposes similar
// plus extra options to the one that its Android counterpart exposes.
public class iOSPackageCommand : Command
internal class iOSPackageCommand : PackageCommand
{
// working directories
string WorkingDirectory;
// will be used as the output dir of the generated projects.
string OutputDirectory;
// path that is the root of the .ignore files that will be used to skip tests if needed.
string IgnoreFilesRootDirectory;
// path that is the root of the traits txt files that will be used to skip tests if needed.
string TraitsRootDirectory;
private readonly iOSPackageCommandArguments _arguments = new iOSPackageCommandArguments();
protected override IPackageCommandArguments PackageArguments => _arguments;
string ApplicationName;
string MtouchExtraArgs;
TemplateType SelectedTemplateType;
bool ShowHelp = false;
public iOSPackageCommand() : base("package")
public iOSPackageCommand() : base()
{
Options = new OptionSet() {
"usage: ios package [OPTIONS]",
"",
"Packaging command that will create a iOS/tvOS/watchOS or macOS application that can be used to run NUnit or XUnit-based test dlls",
{ "mtouch-extraargs=|m=", "Extra arguments to be passed to mtouch.", v => MtouchExtraArgs = v },
{ "ignore-directory=|i=", "Root directory containing all the *.ignore files used to skip tests if needed.", v => IgnoreFilesRootDirectory = v },
{ "name=|n=", "Name of the test application", v => ApplicationName = v},
{ "output-directory=|o=", "Directory in which the resulting package will be outputted", v => OutputDirectory = v},
{ "mtouch-extraargs=|m=", "Extra arguments to be passed to mtouch.", v => _arguments.MtouchExtraArgs = v },
{ "ignore-directory=|i=", "Root directory containing all the *.ignore files used to skip tests if needed.", v => _arguments.IgnoreFilesRootDirectory = v },
{ "template=|t=", "Indicates which template to use. There are two available ones: Managed, which uses Xamarin.[iOS|Mac] and Native (default:Managed).",
v=> {
if (Enum.TryParse<TemplateType>(v, out var template)) {
SelectedTemplateType = template;
if (Enum.TryParse<TemplateType>(v, out TemplateType template)) {
_arguments.SelectedTemplateType = template;
} else
{
Console.WriteLine($"Unknown template type '{v}'");
@ -56,33 +44,23 @@ namespace Microsoft.DotNet.XHarness.CLI.iOS
}
}
},
{ "traits-directory=|td=", "Root directory that contains all the .txt files with traits that will be skipped if needed.", v => TraitsRootDirectory = v },
{ "working-directory=|w=", "Directory that will be used to output generated projects", v => WorkingDirectory = v },
{ "help|h", "Show this message", v => ShowHelp = v != null },
{ "traits-directory=|td=", "Root directory that contains all the .txt files with traits that will be skipped if needed.", v => _arguments.TraitsRootDirectory = v },
};
foreach (var option in CommonOptions)
{
Options.Add(option);
}
}
public override int Invoke(IEnumerable<string> arguments)
protected override Task<int> InvokeInternal()
{
// Deal with unknown options and print nicely
var extra = Options.Parse(arguments);
if (ShowHelp)
{
Options.WriteOptionDescriptions(Console.Out);
return 1;
}
if (extra.Count > 0)
{
Console.WriteLine($"Unknown arguments{string.Join(" ", extra)}");
Options.WriteOptionDescriptions(Console.Out);
return 2;
}
Console.WriteLine($"iOS Package command called:{Environment.NewLine}Application Name = {ApplicationName}");
Console.WriteLine($"Working Directory:{WorkingDirectory}{Environment.NewLine}Output Directory:{OutputDirectory}");
Console.WriteLine($"Ignore Files Root Directory:{IgnoreFilesRootDirectory}{Environment.NewLine}Traits Root Directory:{TraitsRootDirectory}");
Console.WriteLine($"MTouch Args:{MtouchExtraArgs}{Environment.NewLine}Template Type:{Enum.GetName(typeof(TemplateType), SelectedTemplateType)}");
Console.WriteLine($"iOS Package command called:{Environment.NewLine}Application Name = {_arguments.AppPackageName}");
Console.WriteLine($"Working Directory:{_arguments.WorkingDirectory}{Environment.NewLine}Output Directory:{_arguments.OutputDirectory}");
Console.WriteLine($"Ignore Files Root Directory:{_arguments.IgnoreFilesRootDirectory}{Environment.NewLine}Traits Root Directory:{_arguments.TraitsRootDirectory}");
Console.WriteLine($"MTouch Args:{_arguments.MtouchExtraArgs}{Environment.NewLine}Template Type:{Enum.GetName(typeof(TemplateType), _arguments.SelectedTemplateType)}");
return 0;
return Task.FromResult(0);
}
}
}

Просмотреть файл

@ -0,0 +1,39 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.DotNet.XHarness.CLI.Common;
namespace Microsoft.DotNet.XHarness.CLI.iOS
{
internal class iOSPackageCommandArguments : PackageCommandArguments
{
/// <summary>
/// A path that is the root of the .ignore files that will be used to skip tests if needed
/// </summary>
public string IgnoreFilesRootDirectory { get; set; }
/// <summary>
/// A path that is the root of the traits txt files that will be used to skip tests if needed
/// </summary>
public string TraitsRootDirectory { get; set; }
public string MtouchExtraArgs { get; set; }
public TemplateType SelectedTemplateType { get; set; }
public override bool TryValidate([NotNullWhen(true)] out IEnumerable<string> errors)
{
if (!base.TryValidate(out errors))
{
return false;
}
// TODO: Validate the above
return true;
}
}
}

Просмотреть файл

@ -5,27 +5,17 @@
using Microsoft.DotNet.XHarness.CLI.Common;
using Mono.Options;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Microsoft.DotNet.XHarness.CLI.iOS
{
/// <summary>
/// Command which executes a given, already-packaged iOS application, waits on it and returns status based on the outcome.
/// </summary>
public class iOSTestCommand : TestCommand
internal class iOSTestCommand : TestCommand
{
// Path to packaged app
string ApplicationPath = "";
// List of targets to test.
string[] Targets = Array.Empty<string>();
// Path where the outputs of execution will be stored.
string OutputDirectory = "";
// Path where run logs will hbe stored and projects
string WorkingDirectory = "";
// How long XHarness should wait until a test execution completes before clean up (kill running apps, uninstall, etc)
int TimeoutInSeconds = 300;
bool ShowHelp = false;
private readonly iOSTestCommandArguments _arguments = new iOSTestCommandArguments();
protected override ITestCommandArguments TestArguments => _arguments;
public iOSTestCommand() : base()
{
@ -33,33 +23,24 @@ namespace Microsoft.DotNet.XHarness.CLI.iOS
"usage: ios test [OPTIONS]",
"",
"Packaging command that will create a iOS/tvOS/watchOS or macOS application that can be used to run NUnit or XUnit-based test dlls",
{ "app|a=", "Path to already-packaged app", v => ApplicationPath = v},
{ "output-directory=|o=", "Directory in which the resulting package will be outputted", v => OutputDirectory = v},
{ "targets=", "Comma-delineated list of targets to test for", v=> Targets = v.Split(',') },
{ "timeout=|t=", "Time span, in seconds, to wait for instrumentation to complete.", v => TimeoutInSeconds = int.Parse(v)},
{ "working-directory=|w=", "Directory in which the resulting package will be outputted", v => WorkingDirectory = v},
{ "help|h", "Show this message", v => ShowHelp = v != null }
};
foreach (var option in CommonOptions)
{
Options.Add(option);
}
}
public override int Invoke(IEnumerable<string> arguments)
protected override Task<int> InvokeInternal()
{
// Deal with unknown options and print nicely
var extra = Options.Parse(arguments);
if (ShowHelp)
{
Options.WriteOptionDescriptions(Console.Out);
return 1;
}
if (extra.Count > 0)
{
Console.WriteLine($"Unknown arguments: {string.Join(" ", extra)}");
Options.WriteOptionDescriptions(Console.Out);
return 2;
}
Console.WriteLine($"iOS Test command called:{Environment.NewLine}App:{ApplicationPath}{Environment.NewLine}Targets:{string.Join(',', Targets)}");
Console.WriteLine($"Output Directory:{OutputDirectory}{Environment.NewLine}Working Directory:{WorkingDirectory}{Environment.NewLine}Timeout:{TimeoutInSeconds}s");
return 0;
Console.WriteLine($"iOS Test command called:");
Console.WriteLine($" App: {_arguments.AppPackagePath}");
Console.WriteLine($" Targets: {string.Join(',', _arguments.Targets)}");
Console.WriteLine($" Output Directory: {_arguments.OutputDirectory}");
Console.WriteLine($" Working Directory: {_arguments.WorkingDirectory}");
Console.WriteLine($" Timeout: {_arguments.Timeout.TotalSeconds}s");
return Task.FromResult(0);
}
}
}

Просмотреть файл

@ -0,0 +1,29 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.DotNet.XHarness.CLI.Common;
using System.Collections.Generic;
namespace Microsoft.DotNet.XHarness.CLI.iOS
{
internal class iOSTestCommandArguments : TestCommandArguments
{
internal override IEnumerable<string> GetAvailableTargets()
{
return new[]
{
"None",
"Simulator_iOS",
"Simulator_iOS32",
"Simulator_iOS64",
"Simulator_tvOS",
"Simulator_watchOS",
"Device_iOS",
"Device_tvOS",
"Device_watchOS",
};
}
}
}