Skip to content

Commit

Permalink
Fix command line output validation (#2314) (#2317)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoRossignoli authored Feb 12, 2024
1 parent 5bbf199 commit ecfe813
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ internal sealed class CommandLineHandler(string[] args, CommandLineParseResult p

public string Description => string.Empty;

public async Task<bool> ParseAndValidateAsync()
public async Task<bool> ParseAndValidateAsync(Func<Task> printBanner)
{
if (_parseResult.HasError)
{
Expand All @@ -63,30 +63,35 @@ public async Task<bool> ParseAndValidateAsync()
stringBuilder.AppendLine(CultureInfo.InvariantCulture, $"\t- {error}");
}

await printBanner();
await _platformOutputDevice.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(stringBuilder.ToString()));
return false;
}

if (ExtensionOptionsContainReservedPrefix(out string? reservedPrefixError))
{
await printBanner();
await _platformOutputDevice.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(reservedPrefixError));
return false;
}

if (ExtensionOptionsContainReservedOptions(out string? reservedOptionError))
{
await printBanner();
await _platformOutputDevice.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(reservedOptionError));
return false;
}

if (ExtensionOptionAreDuplicated(out string? duplicationError))
{
await printBanner();
await _platformOutputDevice.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(duplicationError));
return false;
}

if (UnknownOptions(out string? unknownOptionsError))
{
await printBanner();
await _platformOutputDevice.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(unknownOptionsError));
await _platformOutputDevice.DisplayAsync(this, EmptyText);
await PrintHelpAsync();
Expand All @@ -95,20 +100,23 @@ public async Task<bool> ParseAndValidateAsync()

if (ExtensionArgumentArityAreInvalid(out string? arityErrors))
{
await printBanner();
await _platformOutputDevice.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(arityErrors));
return false;
}

var optionsResult = await ValidateOptionsArgumentsAsync();
if (!optionsResult.IsValid)
{
await printBanner();
await _platformOutputDevice.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(optionsResult.ErrorMessage));
return false;
}

var configurationResult = await ValidateConfigurationAsync();
if (!configurationResult.IsValid)
{
await printBanner();
await _platformOutputDevice.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(configurationResult.ErrorMessage));
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ internal interface ICommandLineHandler

Task PrintHelpAsync(ITool[]? availableTools = null);

Task<bool> ParseAndValidateAsync();
Task<bool> ParseAndValidateAsync(Func<Task> printBanner);
}
21 changes: 13 additions & 8 deletions src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ public async Task<ITestHost> BuildAsync(
CommandLineHandler commandLineHandler = await ((CommandLineManager)CommandLine).BuildAsync(args, platformOutputDevice, loggingState.CommandLineParseResult);

// If command line is not valid we return immediately.
if (!loggingState.CommandLineParseResult.HasTool && !await commandLineHandler.ParseAndValidateAsync())
if (!loggingState.CommandLineParseResult.HasTool && !await commandLineHandler.ParseAndValidateAsync(async () => await DisplayBannerIfEnabledAsync(loggingState, platformOutputDevice)))
{
return new InformativeCommandLineTestHost(ExitCodes.InvalidCommandLine);
}
Expand Down Expand Up @@ -230,13 +230,7 @@ public async Task<ITestHost> BuildAsync(

// Display banner now because we need capture the output in case of MSBuild integration and we want to forward
// to file disc also the banner, so at this point we need to have all services and configuration(result directory) built.
bool isNoBannerSet = loggingState.CommandLineParseResult.IsOptionSet(PlatformCommandLineProvider.NoBannerOptionKey);
string? noBannerEnvironmentVar = environment.GetEnvironmentVariable(EnvironmentVariableConstants.TESTINGPLATFORM_NOBANNER);
string? dotnetNoLogoEnvironmentVar = environment.GetEnvironmentVariable(EnvironmentVariableConstants.DOTNET_NOLOGO);
if (!isNoBannerSet && !(noBannerEnvironmentVar is "1" or "true") && !(dotnetNoLogoEnvironmentVar is "1" or "true"))
{
await platformOutputDevice.DisplayBannerAsync();
}
await DisplayBannerIfEnabledAsync(loggingState, platformOutputDevice);

// Add global telemetry service.
// Add at this point or the telemetry banner appearance order will be wrong, we want the testing app banner before the telemetry banner.
Expand Down Expand Up @@ -718,4 +712,15 @@ private async Task RegisterAsServiceOrConsumerOrBothAsync(object service, Servic

await AddServiceIfNotSkippedAsync(service, serviceProvider);
}

private async Task DisplayBannerIfEnabledAsync(ApplicationLoggingState loggingState, IPlatformOutputDevice platformOutputDevice)
{
bool isNoBannerSet = loggingState.CommandLineParseResult.IsOptionSet(PlatformCommandLineProvider.NoBannerOptionKey);
string? noBannerEnvironmentVar = environment.GetEnvironmentVariable(EnvironmentVariableConstants.TESTINGPLATFORM_NOBANNER);
string? dotnetNoLogoEnvironmentVar = environment.GetEnvironmentVariable(EnvironmentVariableConstants.DOTNET_NOLOGO);
if (!isNoBannerSet && !(noBannerEnvironmentVar is "1" or "true") && !(dotnetNoLogoEnvironmentVar is "1" or "true"))
{
await platformOutputDevice.DisplayBannerAsync();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public async Task ParseAndValidate_WhenOptionWithArityZeroIsCalledWithOneArgumen
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

// Act
bool result = await commandLineHandler.ParseAndValidateAsync();
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);

// Assert
Assert.IsFalse(result);
Expand All @@ -71,7 +71,7 @@ public async Task ParseAndValidate_WhenOptionWithArityExactlyOneIsCalledWithTwoA
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

// Act
bool result = await commandLineHandler.ParseAndValidateAsync();
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);

// Assert
Assert.IsFalse(result);
Expand All @@ -91,7 +91,7 @@ public async Task ParseAndValidate_WhenOptionWithArityExactlyOneIsCalledWithoutA
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

// Act
bool result = await commandLineHandler.ParseAndValidateAsync();
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);

// Assert
Assert.IsFalse(result);
Expand All @@ -111,7 +111,7 @@ public async Task ParseAndValidate_WhenOptionWithArityZeroOrOneIsCalledWithTwoAr
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

// Act
bool result = await commandLineHandler.ParseAndValidateAsync();
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);

// Assert
Assert.IsFalse(result);
Expand All @@ -131,7 +131,7 @@ public async Task ParseAndValidate_WhenOptionWithArityOneOrMoreIsCalledWithoutAr
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

// Act
bool result = await commandLineHandler.ParseAndValidateAsync();
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);

// Assert
Assert.IsFalse(result);
Expand All @@ -147,7 +147,7 @@ public async Task ParseAndValidate_WhenOptionsGetsTheExpectedNumberOfArguments_R
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

// Act
bool result = await commandLineHandler.ParseAndValidateAsync();
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);

// Assert
Assert.IsTrue(result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public async Task ParseAndValidateAsync_InvalidCommandLineArguments_ReturnsFalse
});

// Act
bool result = await commandLineHandler.ParseAndValidateAsync();
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);

// Assert
Assert.IsFalse(result);
Expand All @@ -67,7 +67,7 @@ public async Task ParseAndValidateAsync_EmptyCommandLineArguments_ReturnsTrue()
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

// Act
bool result = await commandLineHandler.ParseAndValidateAsync();
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);

// Assert
Assert.IsTrue(result);
Expand Down Expand Up @@ -186,7 +186,7 @@ public async Task ParseAndValidateAsync_DuplicateOption_ReturnsFalse()
extensionCommandLineOptionsProviders, [], _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

// Act
bool result = await commandLineHandler.ParseAndValidateAsync();
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);

// Assert
Assert.IsFalse(result);
Expand All @@ -206,7 +206,7 @@ public async Task ParseAndValidateAsync_InvalidOption_ReturnsFalse()
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

// Act
bool result = await commandLineHandler.ParseAndValidateAsync();
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);

// Assert
Assert.IsFalse(result);
Expand All @@ -226,7 +226,7 @@ public async Task ParseAndValidateAsync_InvalidArgumentArity_ReturnsFalse()
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

// Act
bool result = await commandLineHandler.ParseAndValidateAsync();
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);

// Assert
Assert.IsFalse(result);
Expand All @@ -250,7 +250,7 @@ public async Task ParseAndValidateAsync_ReservedOptions_ReturnsFalse()
_systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

// Act
bool result = await commandLineHandler.ParseAndValidateAsync();
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);

// Assert
Assert.IsFalse(result);
Expand All @@ -274,7 +274,7 @@ public async Task ParseAndValidateAsync_ReservedOptionsPrefix_ReturnsFalse()
_systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

// Act
bool result = await commandLineHandler.ParseAndValidateAsync();
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);

// Assert
Assert.IsFalse(result);
Expand All @@ -299,7 +299,7 @@ public async Task ParseAndValidateAsync_UnknownOption_ReturnsFalse()
_runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

// Act
bool result = await commandLineHandler.ParseAndValidateAsync();
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);

// Assert
Assert.IsFalse(result);
Expand All @@ -325,7 +325,7 @@ public async Task ParseAndValidateAsync_InvalidValidConfiguration_ReturnsFalse()
_runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

// Act
bool result = await commandLineHandler.ParseAndValidateAsync();
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);

// Assert
Assert.IsFalse(result);
Expand Down

0 comments on commit ecfe813

Please sign in to comment.