Skip to content

Commit

Permalink
Fix msbuild integration (#2389)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoRossignoli committed Feb 20, 2024
1 parent 14bbaab commit 8226e7d
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 65 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(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

0 comments on commit 8226e7d

Please sign in to comment.