Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static async Task<ValidationResult> ValidateAsync(
stringBuilder.AppendLine(CultureInfo.InvariantCulture, $"\t- {error}");
}

return ValidationResult.Invalid(stringBuilder.ToTrimmedString());
return InvalidWithCommandLine(commandLineParseResult, stringBuilder.ToTrimmedString());
}

var extensionOptionsByProvider = extensionCommandLineOptionsProviders.ToDictionary(p => p, p => p.GetCommandLineOptions());
Expand All @@ -47,7 +47,7 @@ public static async Task<ValidationResult> ValidateAsync(

if (ValidateNoUnknownOptions(commandLineParseResult, extensionOptionsByProvider, systemOptionsByProvider) is { IsValid: false } result4)
{
return result4;
return AddCommandLine(commandLineParseResult, result4);
}

var providerAndOptionByOptionName = extensionOptionsByProvider.Union(systemOptionsByProvider)
Expand All @@ -56,12 +56,12 @@ public static async Task<ValidationResult> ValidateAsync(

if (ValidateOptionsArgumentArity(commandLineParseResult, providerAndOptionByOptionName) is { IsValid: false } result5)
{
return result5;
return AddCommandLine(commandLineParseResult, result5);
}

if (await ValidateOptionsArgumentsAsync(commandLineParseResult, providerAndOptionByOptionName).ConfigureAwait(false) is { IsValid: false } result6)
{
return result6;
return AddCommandLine(commandLineParseResult, result6);
}

// Last validation step
Expand Down Expand Up @@ -323,4 +323,20 @@ private static string ToTrimmedString(this StringBuilder stringBuilder)

return stringBuilder.ToString();
}

private static ValidationResult AddCommandLine(CommandLineParseResult parseResult, ValidationResult result)
=> result.IsValid ? result : InvalidWithCommandLine(parseResult, result.ErrorMessage);

private static ValidationResult InvalidWithCommandLine(CommandLineParseResult parseResult, string errorMessage)
{
if (parseResult.CommandLine.Length == 0)
{
return ValidationResult.Invalid(errorMessage);
}

var stringBuilder = new StringBuilder(errorMessage);
stringBuilder.AppendLine();
stringBuilder.AppendFormat(CultureInfo.InvariantCulture, PlatformResources.CommandLineValidationCommandLine, parseResult.CommandLine);
return ValidationResult.Invalid(stringBuilder.ToString());
}
}
32 changes: 25 additions & 7 deletions src/Platform/Microsoft.Testing.Platform/CommandLine/ParseResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@ namespace Microsoft.Testing.Platform.CommandLine;
/// <summary>
/// Represents the result of parsing a command line.
/// </summary>
/// <param name="toolName">The name of the tool.</param>
/// <param name="options">The collection of parsed options.</param>
/// <param name="errors">The collection of errors associated to the parsing.</param>
[Experimental("TPEXP", UrlFormat = "https://aka.ms/testingplatform/diagnostics#{0}")]
public sealed class CommandLineParseResult(string? toolName, IReadOnlyList<CommandLineParseOption> options, IReadOnlyList<string> errors) : IEquatable<CommandLineParseResult>
public sealed class CommandLineParseResult : IEquatable<CommandLineParseResult>
{
/// <summary>
/// The prefix for options.
Expand All @@ -22,20 +19,41 @@ public sealed class CommandLineParseResult(string? toolName, IReadOnlyList<Comma
/// </summary>
public static CommandLineParseResult Empty => new(null, [], []);

/// <summary>
/// Initializes a new instance of the <see cref="CommandLineParseResult"/> class.
/// </summary>
/// <param name="toolName">The name of the tool.</param>
/// <param name="options">The collection of parsed options.</param>
/// <param name="errors">The collection of errors associated to the parsing.</param>
public CommandLineParseResult(string? toolName, IReadOnlyList<CommandLineParseOption> options, IReadOnlyList<string> errors)
: this(toolName, options, errors, [])
{
}

internal CommandLineParseResult(string? toolName, IReadOnlyList<CommandLineParseOption> options, IReadOnlyList<string> errors, IReadOnlyList<string> arguments)
{
ToolName = toolName;
Options = options;
Errors = errors;
CommandLine = string.Join(" ", arguments);
}

/// <summary>
/// Gets the name of the tool.
/// </summary>
public string? ToolName { get; } = toolName;
public string? ToolName { get; }

/// <summary>
/// Gets the collection of parsed options.
/// </summary>
public IReadOnlyList<CommandLineParseOption> Options { get; } = options;
public IReadOnlyList<CommandLineParseOption> Options { get; }

/// <summary>
/// Gets the collection of errors associated to the parsing.
/// </summary>
public IReadOnlyList<string> Errors { get; } = errors;
public IReadOnlyList<string> Errors { get; }

internal string CommandLine { get; }

/// <summary>
/// Gets a value indicating whether the parsing has errors.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public static CommandLineParseResult Parse(string[] args, IEnvironment environme

private static CommandLineParseResult Parse(List<string> args, IEnvironment environment)
{
string[] originalArgs = [.. args];
List<CommandLineParseOption> options = [];
List<string> errors = [];

Expand Down Expand Up @@ -101,7 +102,7 @@ private static CommandLineParseResult Parse(List<string> args, IEnvironment envi
options.Add(new(currentOption, [.. currentOptionArguments]));
}

return new CommandLineParseResult(toolName, options, errors);
return new CommandLineParseResult(toolName, options, errors, originalArgs);

static void ParseOptionAndSeparators(string arg, out string? currentOption, out string? currentArg)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,10 @@
<data name="InvalidCommandLineArguments" xml:space="preserve">
<value>Invalid command line arguments:</value>
</data>
<data name="CommandLineValidationCommandLine" xml:space="preserve">
<value>Command line: {0}</value>
<comment>{0} is the command line used to run the application.</comment>
</data>
<data name="CommandLineInvalidArityErrorMessage" xml:space="preserve">
<value>Invalid arity, maximum must be greater than minimum</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">Neznámá možnost --{0}</target>
<note />
</trans-unit>
<trans-unit id="CommandLineValidationCommandLine">
<source>Command line: {0}</source>
<target state="new">Command line: {0}</target>
<note>{0} is the command line used to run the application.</note>
</trans-unit>
<trans-unit id="CompositeServiceFactoryInstanceAlreadyRegistered">
<source>The same instance of 'CompositeExtensionFactory' is already registered</source>
<target state="translated">Už je zaregistrovaná stejná instance CompositeExtensionFactory.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">Unbekannte Option "--{0}"</target>
<note />
</trans-unit>
<trans-unit id="CommandLineValidationCommandLine">
<source>Command line: {0}</source>
<target state="new">Command line: {0}</target>
<note>{0} is the command line used to run the application.</note>
</trans-unit>
<trans-unit id="CompositeServiceFactoryInstanceAlreadyRegistered">
<source>The same instance of 'CompositeExtensionFactory' is already registered</source>
<target state="translated">Die gleiche Instanz von „CompositeExtensionFactory“ ist bereits registriert</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">Opción desconocida “--{0}”</target>
<note />
</trans-unit>
<trans-unit id="CommandLineValidationCommandLine">
<source>Command line: {0}</source>
<target state="new">Command line: {0}</target>
<note>{0} is the command line used to run the application.</note>
</trans-unit>
<trans-unit id="CompositeServiceFactoryInstanceAlreadyRegistered">
<source>The same instance of 'CompositeExtensionFactory' is already registered</source>
<target state="translated">La misma instancia de "CompositeExtensionFactory" ya está registrada</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">Option « --{0} » inconnue.</target>
<note />
</trans-unit>
<trans-unit id="CommandLineValidationCommandLine">
<source>Command line: {0}</source>
<target state="new">Command line: {0}</target>
<note>{0} is the command line used to run the application.</note>
</trans-unit>
<trans-unit id="CompositeServiceFactoryInstanceAlreadyRegistered">
<source>The same instance of 'CompositeExtensionFactory' is already registered</source>
<target state="translated">La même instance de 'CompositeExtensionFactory' est déjà enregistrée</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">Opzione sconosciuta: '--{0}'</target>
<note />
</trans-unit>
<trans-unit id="CommandLineValidationCommandLine">
<source>Command line: {0}</source>
<target state="new">Command line: {0}</target>
<note>{0} is the command line used to run the application.</note>
</trans-unit>
<trans-unit id="CompositeServiceFactoryInstanceAlreadyRegistered">
<source>The same instance of 'CompositeExtensionFactory' is already registered</source>
<target state="translated">L'istanza di 'CompositeExtensionFactory' specificata è già registrata</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">不明なオプション: '--{0}'</target>
<note />
</trans-unit>
<trans-unit id="CommandLineValidationCommandLine">
<source>Command line: {0}</source>
<target state="new">Command line: {0}</target>
<note>{0} is the command line used to run the application.</note>
</trans-unit>
<trans-unit id="CompositeServiceFactoryInstanceAlreadyRegistered">
<source>The same instance of 'CompositeExtensionFactory' is already registered</source>
<target state="translated">'CompositeExtensionFactory' の同じインスタンスが既に登録されています</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">알 수 없는 옵션 '--{0}'</target>
<note />
</trans-unit>
<trans-unit id="CommandLineValidationCommandLine">
<source>Command line: {0}</source>
<target state="new">Command line: {0}</target>
<note>{0} is the command line used to run the application.</note>
</trans-unit>
<trans-unit id="CompositeServiceFactoryInstanceAlreadyRegistered">
<source>The same instance of 'CompositeExtensionFactory' is already registered</source>
<target state="translated">동일한 'CompositeExtensionFactory' 인스턴스가 이미 등록됨</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">Nieznana opcja: „--{0}”</target>
<note />
</trans-unit>
<trans-unit id="CommandLineValidationCommandLine">
<source>Command line: {0}</source>
<target state="new">Command line: {0}</target>
<note>{0} is the command line used to run the application.</note>
</trans-unit>
<trans-unit id="CompositeServiceFactoryInstanceAlreadyRegistered">
<source>The same instance of 'CompositeExtensionFactory' is already registered</source>
<target state="translated">To samo wystąpienie elementu „CompositeExtensionFactory” jest już zarejestrowane</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">Opção desconhecida '--{0}'</target>
<note />
</trans-unit>
<trans-unit id="CommandLineValidationCommandLine">
<source>Command line: {0}</source>
<target state="new">Command line: {0}</target>
<note>{0} is the command line used to run the application.</note>
</trans-unit>
<trans-unit id="CompositeServiceFactoryInstanceAlreadyRegistered">
<source>The same instance of 'CompositeExtensionFactory' is already registered</source>
<target state="translated">A mesma instância de 'CompositeExtensionFactory' já está registrada</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">Неизвестный параметр "--{0}"</target>
<note />
</trans-unit>
<trans-unit id="CommandLineValidationCommandLine">
<source>Command line: {0}</source>
<target state="new">Command line: {0}</target>
<note>{0} is the command line used to run the application.</note>
</trans-unit>
<trans-unit id="CompositeServiceFactoryInstanceAlreadyRegistered">
<source>The same instance of 'CompositeExtensionFactory' is already registered</source>
<target state="translated">Такой же экземпляр "CompositeExtensonFactory" уже зарегистрирован</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">'--{0}' seçeneği bilinmiyor</target>
<note />
</trans-unit>
<trans-unit id="CommandLineValidationCommandLine">
<source>Command line: {0}</source>
<target state="new">Command line: {0}</target>
<note>{0} is the command line used to run the application.</note>
</trans-unit>
<trans-unit id="CompositeServiceFactoryInstanceAlreadyRegistered">
<source>The same instance of 'CompositeExtensionFactory' is already registered</source>
<target state="translated">Aynı 'CompositeExtensionFactory' örneği zaten kayıtlı</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">未知选项:“--{0}”</target>
<note />
</trans-unit>
<trans-unit id="CommandLineValidationCommandLine">
<source>Command line: {0}</source>
<target state="new">Command line: {0}</target>
<note>{0} is the command line used to run the application.</note>
</trans-unit>
<trans-unit id="CompositeServiceFactoryInstanceAlreadyRegistered">
<source>The same instance of 'CompositeExtensionFactory' is already registered</source>
<target state="translated">"CompositeExtensionFactory" 的同一实例已注册</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">未知的選項 '--{0}'</target>
<note />
</trans-unit>
<trans-unit id="CommandLineValidationCommandLine">
<source>Command line: {0}</source>
<target state="new">Command line: {0}</target>
<note>{0} is the command line used to run the application.</note>
</trans-unit>
<trans-unit id="CompositeServiceFactoryInstanceAlreadyRegistered">
<source>The same instance of 'CompositeExtensionFactory' is already registered</source>
<target state="translated">已註冊 'CompositeExtensonFactory' 的同一執行個體</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ public async Task Help_WhenNoExtensionRegisteredAndUnknownOptionIsSpecified_Outp
const string wildcardMatchPattern = $"""
Microsoft.Testing.Platform v*
Unknown option '--{UnknownOption}'
Command line: --no-ansi --no-progress -{UnknownOption}
Usage {TestAssetFixture.NoExtensionAssetName}* [option providers] [extension option providers]
Execute a .NET Test Application.
Options:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ public async Task ParseAndValidate_WhenOptionWithArityZeroIsCalledWithOneArgumen

// Assert
Assert.IsFalse(result.IsValid);
Assert.AreEqual("Option '--zeroArgumentsOption' from provider 'Microsoft Testing Platform command line provider' (UID: PlatformCommandLineProvider) expects no arguments", result.ErrorMessage, StringComparer.Ordinal);
Assert.AreEqual(
"""
Option '--zeroArgumentsOption' from provider 'Microsoft Testing Platform command line provider' (UID: PlatformCommandLineProvider) expects no arguments
Command line: --zeroArgumentsOption arg
""", result.ErrorMessage, StringComparer.Ordinal);
}

[TestMethod]
Expand All @@ -74,7 +78,11 @@ public async Task ParseAndValidate_WhenOptionWithArityExactlyOneIsCalledWithTwoA

// Assert
Assert.IsFalse(result.IsValid);
Assert.AreEqual("Option '--exactlyOneArgumentsOption' from provider 'Microsoft Testing Platform command line provider' (UID: PlatformCommandLineProvider) expects at most 1 arguments", result.ErrorMessage);
Assert.AreEqual(
"""
Option '--exactlyOneArgumentsOption' from provider 'Microsoft Testing Platform command line provider' (UID: PlatformCommandLineProvider) expects at most 1 arguments
Command line: --exactlyOneArgumentsOption arg1 arg2
""", result.ErrorMessage);
}

[TestMethod]
Expand All @@ -90,7 +98,11 @@ public async Task ParseAndValidate_WhenOptionWithArityExactlyOneIsCalledWithoutA

// Assert
Assert.IsFalse(result.IsValid);
Assert.AreEqual("Option '--exactlyOneArgumentsOption' from provider 'Microsoft Testing Platform command line provider' (UID: PlatformCommandLineProvider) expects at least 1 arguments", result.ErrorMessage);
Assert.AreEqual(
"""
Option '--exactlyOneArgumentsOption' from provider 'Microsoft Testing Platform command line provider' (UID: PlatformCommandLineProvider) expects at least 1 arguments
Command line: --exactlyOneArgumentsOption
""", result.ErrorMessage);
}

[TestMethod]
Expand All @@ -106,7 +118,11 @@ public async Task ParseAndValidate_WhenOptionWithArityZeroOrOneIsCalledWithTwoAr

// Assert
Assert.IsFalse(result.IsValid);
Assert.AreEqual("Option '--zeroOrOneArgumentsOption' from provider 'Microsoft Testing Platform command line provider' (UID: PlatformCommandLineProvider) expects at most 1 arguments", result.ErrorMessage);
Assert.AreEqual(
"""
Option '--zeroOrOneArgumentsOption' from provider 'Microsoft Testing Platform command line provider' (UID: PlatformCommandLineProvider) expects at most 1 arguments
Command line: --zeroOrOneArgumentsOption arg1 --zeroOrOneArgumentsOption arg2
""", result.ErrorMessage);
}

[TestMethod]
Expand All @@ -122,7 +138,11 @@ public async Task ParseAndValidate_WhenOptionWithArityOneOrMoreIsCalledWithoutAr

// Assert
Assert.IsFalse(result.IsValid);
Assert.AreEqual("Option '--oneOrMoreArgumentsOption' from provider 'Microsoft Testing Platform command line provider' (UID: PlatformCommandLineProvider) expects at least 1 arguments", result.ErrorMessage);
Assert.AreEqual(
"""
Option '--oneOrMoreArgumentsOption' from provider 'Microsoft Testing Platform command line provider' (UID: PlatformCommandLineProvider) expects at least 1 arguments
Command line: --oneOrMoreArgumentsOption
""", result.ErrorMessage);
}

[TestMethod]
Expand Down
Loading
Loading