Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix msbuild integration (#2389) #2395

Merged
merged 1 commit into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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(Func<Task> printBanner)
public async Task<(bool IsValid, string? ValidationError)> TryParseAndValidateAsync()
{
if (_parseResult.HasError)
{
Expand All @@ -63,65 +63,49 @@ public async Task<bool> ParseAndValidateAsync(Func<Task> printBanner)
stringBuilder.AppendLine(CultureInfo.InvariantCulture, $"\t- {error}");
}

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

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

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

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

if (UnknownOptions(out string? unknownOptionsError))
{
await printBanner();
await _platformOutputDevice.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(unknownOptionsError));
await _platformOutputDevice.DisplayAsync(this, EmptyText);
await PrintHelpAsync();
return false;
return (false, unknownOptionsError);
}

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

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

var configurationResult = await ValidateConfigurationAsync();
#pragma warning disable IDE0046 // Convert to conditional expression - make the code less readable
if (!configurationResult.IsValid)
{
await printBanner();
await _platformOutputDevice.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(configurationResult.ErrorMessage));
return false;
return (false, configurationResult.ErrorMessage);
}
#pragma warning restore IDE0046 // Convert to conditional expression

return true;
return (true, null);
}

private bool ExtensionOptionsContainReservedPrefix([NotNullWhen(true)] out string? error)
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(Func<Task> printBanner);
Task<(bool IsValid, string? ValidationError)> TryParseAndValidateAsync();
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ public void SetTestHostWorkingDirectory(string workingDirectory)
_testHostWorkingDirectory = workingDirectory;
}

public void CreateDefaultTestResultDirectory()
{
_currentWorkingDirectory = Path.GetDirectoryName(_testApplicationModuleInfo.GetCurrentTestApplicationFullPath())!;
_resultDirectory ??= Path.Combine(_currentWorkingDirectory, DefaultTestResultFolderName);
_resultDirectory = _fileSystem.CreateDirectory(_resultDirectory);
}

public async Task CheckTestResultsDirectoryOverrideAndCreateItAsync(ICommandLineOptions commandLineOptions, IFileLoggerProvider? fileLoggerProvider)
{
// Load Configuration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,13 @@ internal class TestHostBuilder(IFileSystem fileSystem, IRuntimeFeature runtimeFe
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(async () => await DisplayBannerIfEnabledAsync(loggingState, platformOutputDevice)))
(bool parseSucceded, string? validationError) = await commandLineHandler.TryParseAndValidateAsync();
if (!loggingState.CommandLineParseResult.HasTool && !parseSucceded)
{
await DisplayBannerIfEnabledAsync(loggingState, platformOutputDevice);
ArgumentGuard.IsNotNull(validationError);
await platformOutputDevice.DisplayAsync(commandLineHandler, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(validationError));
await commandLineHandler.PrintHelpAsync();
return new InformativeCommandLineTestHost(ExitCodes.InvalidCommandLine);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,31 +51,26 @@ public async Task ParseAndValidate_WhenOptionWithArityZeroIsCalledWithOneArgumen
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

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

// Assert
Assert.IsFalse(result);
_outputDisplayMock.Verify(o => o.DisplayAsync(It.IsAny<IOutputDeviceDataProducer>(), It.IsAny<IOutputDeviceData>()), Times.Once);
}

public async Task ParseAndValidate_WhenOptionWithArityExactlyOneIsCalledWithTwoArguments_ReturnsFalse()
{
// Arrange
string[] args = ["--exactlyOneArgumentsOption arg1", "arg2"];
CommandLineParseResult parseResult = CommandLineParser.Parse(args, new SystemEnvironment());
_outputDisplayMock.Setup(x => x.DisplayAsync(It.IsAny<IOutputDeviceDataProducer>(), It.IsAny<IOutputDeviceData>()))
.Callback((IOutputDeviceDataProducer message, IOutputDeviceData data) =>
Assert.AreEqual($"Option '--exactlyOneArgumentsOption' from provider 'Microsoft Testing Platform command line provider' (UID: PlatformCommandLineProvider) expects at most 1 arguments{Environment.NewLine}", ((TextOutputDeviceData)data).Text, StringComparer.Ordinal));

var commandLineHandler = new CommandLineHandler(args, parseResult,
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

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

// Assert
Assert.IsFalse(result);
_outputDisplayMock.Verify(o => o.DisplayAsync(It.IsAny<IOutputDeviceDataProducer>(), It.IsAny<IOutputDeviceData>()), Times.Once);
}

public async Task ParseAndValidate_WhenOptionWithArityExactlyOneIsCalledWithoutArguments_ReturnsFalse()
Expand All @@ -91,11 +86,10 @@ public async Task ParseAndValidate_WhenOptionWithArityExactlyOneIsCalledWithoutA
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

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

// Assert
Assert.IsFalse(result);
_outputDisplayMock.Verify(o => o.DisplayAsync(It.IsAny<IOutputDeviceDataProducer>(), It.IsAny<IOutputDeviceData>()), Times.Once);
}

public async Task ParseAndValidate_WhenOptionWithArityZeroOrOneIsCalledWithTwoArguments_ReturnsFalse()
Expand All @@ -111,11 +105,10 @@ public async Task ParseAndValidate_WhenOptionWithArityZeroOrOneIsCalledWithTwoAr
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

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

// Assert
Assert.IsFalse(result);
_outputDisplayMock.Verify(o => o.DisplayAsync(It.IsAny<IOutputDeviceDataProducer>(), It.IsAny<IOutputDeviceData>()), Times.Once);
}

public async Task ParseAndValidate_WhenOptionWithArityOneOrMoreIsCalledWithoutArguments_ReturnsFalse()
Expand All @@ -131,11 +124,10 @@ public async Task ParseAndValidate_WhenOptionWithArityOneOrMoreIsCalledWithoutAr
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

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

// Assert
Assert.IsFalse(result);
_outputDisplayMock.Verify(o => o.DisplayAsync(It.IsAny<IOutputDeviceDataProducer>(), It.IsAny<IOutputDeviceData>()), Times.Once);
}

public async Task ParseAndValidate_WhenOptionsGetsTheExpectedNumberOfArguments_ReturnsTrue()
Expand All @@ -147,7 +139,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(() => Task.CompletedTask);
(bool result, _) = await commandLineHandler.TryParseAndValidateAsync();

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

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

// Assert
Assert.IsFalse(result);
_outputDisplayMock.Verify(o => o.DisplayAsync(It.IsAny<IOutputDeviceDataProducer>(), It.IsAny<IOutputDeviceData>()), Times.Once);
}

public async Task ParseAndValidateAsync_EmptyCommandLineArguments_ReturnsTrue()
Expand All @@ -67,7 +66,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(() => Task.CompletedTask);
(bool result, _) = await commandLineHandler.TryParseAndValidateAsync();

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

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

// Assert
Assert.IsFalse(result);
_outputDisplayMock.Verify(o => o.DisplayAsync(It.IsAny<IOutputDeviceDataProducer>(), It.IsAny<IOutputDeviceData>()), Times.Once);
}

public async Task ParseAndValidateAsync_InvalidOption_ReturnsFalse()
Expand All @@ -206,11 +204,10 @@ public async Task ParseAndValidateAsync_InvalidOption_ReturnsFalse()
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

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

// Assert
Assert.IsFalse(result);
_outputDisplayMock.Verify(o => o.DisplayAsync(It.IsAny<IOutputDeviceDataProducer>(), It.IsAny<IOutputDeviceData>()), Times.Once);
}

public async Task ParseAndValidateAsync_InvalidArgumentArity_ReturnsFalse()
Expand All @@ -226,11 +223,10 @@ public async Task ParseAndValidateAsync_InvalidArgumentArity_ReturnsFalse()
_extensionCommandLineOptionsProviders, _systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

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

// Assert
Assert.IsFalse(result);
_outputDisplayMock.Verify(o => o.DisplayAsync(It.IsAny<IOutputDeviceDataProducer>(), It.IsAny<IOutputDeviceData>()), Times.Once);
}

public async Task ParseAndValidateAsync_ReservedOptions_ReturnsFalse()
Expand All @@ -250,11 +246,10 @@ public async Task ParseAndValidateAsync_ReservedOptions_ReturnsFalse()
_systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

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

// Assert
Assert.IsFalse(result);
_outputDisplayMock.Verify(o => o.DisplayAsync(It.IsAny<IOutputDeviceDataProducer>(), It.IsAny<IOutputDeviceData>()), Times.Once);
}

public async Task ParseAndValidateAsync_ReservedOptionsPrefix_ReturnsFalse()
Expand All @@ -274,21 +269,17 @@ public async Task ParseAndValidateAsync_ReservedOptionsPrefix_ReturnsFalse()
_systemCommandLineOptionsProviders, _testApplicationModuleInfoMock.Object, _runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

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

// Assert
Assert.IsFalse(result);
_outputDisplayMock.Verify(o => o.DisplayAsync(It.IsAny<IOutputDeviceDataProducer>(), It.IsAny<IOutputDeviceData>()), Times.Once);
}

public async Task ParseAndValidateAsync_UnknownOption_ReturnsFalse()
{
// Arrange
string[] args = ["--x"];
CommandLineParseResult parseResult = CommandLineParser.Parse(args, new SystemEnvironment());
var messages = new List<string>();
_outputDisplayMock.Setup(x => x.DisplayAsync(It.IsAny<IOutputDeviceDataProducer>(), It.IsAny<IOutputDeviceData>()))
.Callback((IOutputDeviceDataProducer message, IOutputDeviceData data) => messages.Add(((TextOutputDeviceData)data).Text));

ICommandLineOptionsProvider[] extensionCommandLineProvider = new[]
{
Expand All @@ -299,12 +290,11 @@ public async Task ParseAndValidateAsync_UnknownOption_ReturnsFalse()
_runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

// Act
bool result = await commandLineHandler.ParseAndValidateAsync(() => Task.CompletedTask);
(bool result, string? errorMessage) = await commandLineHandler.TryParseAndValidateAsync();

// Assert
Assert.IsFalse(result);
Assert.IsTrue(messages.Count is 23);
Assert.IsTrue(messages[0].Equals($"Unknown option '--x'{Environment.NewLine}", StringComparison.Ordinal));
Assert.IsTrue(errorMessage!.Equals($"Unknown option '--x'{Environment.NewLine}", StringComparison.Ordinal));
}

public async Task ParseAndValidateAsync_InvalidValidConfiguration_ReturnsFalse()
Expand All @@ -325,11 +315,10 @@ public async Task ParseAndValidateAsync_InvalidValidConfiguration_ReturnsFalse()
_runtimeFeatureMock.Object, _outputDisplayMock.Object, _environmentMock.Object, _processHandlerMock.Object);

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

// Assert
Assert.IsFalse(result);
_outputDisplayMock.Verify(o => o.DisplayAsync(It.IsAny<IOutputDeviceDataProducer>(), It.IsAny<IOutputDeviceData>()), Times.Once);
}

private sealed class ExtensionCommandLineProviderMockReservedOptions : ICommandLineOptionsProvider
Expand Down