diff --git a/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineHandler.cs b/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineHandler.cs index 62ce03dbc5..d0eda4b9f4 100644 --- a/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineHandler.cs +++ b/src/Platform/Microsoft.Testing.Platform/CommandLine/CommandLineHandler.cs @@ -52,7 +52,7 @@ internal sealed class CommandLineHandler(string[] args, CommandLineParseResult p public string Description => string.Empty; - public async Task ParseAndValidateAsync() + public async Task ParseAndValidateAsync(Func printBanner) { if (_parseResult.HasError) { @@ -63,30 +63,35 @@ public async Task 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(); @@ -95,6 +100,7 @@ public async Task ParseAndValidateAsync() if (ExtensionArgumentArityAreInvalid(out string? arityErrors)) { + await printBanner(); await _platformOutputDevice.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(arityErrors)); return false; } @@ -102,6 +108,7 @@ public async Task ParseAndValidateAsync() var optionsResult = await ValidateOptionsArgumentsAsync(); if (!optionsResult.IsValid) { + await printBanner(); await _platformOutputDevice.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(optionsResult.ErrorMessage)); return false; } @@ -109,6 +116,7 @@ public async Task ParseAndValidateAsync() var configurationResult = await ValidateConfigurationAsync(); if (!configurationResult.IsValid) { + await printBanner(); await _platformOutputDevice.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText(configurationResult.ErrorMessage)); return false; } diff --git a/src/Platform/Microsoft.Testing.Platform/CommandLine/ICommandLineHandler.cs b/src/Platform/Microsoft.Testing.Platform/CommandLine/ICommandLineHandler.cs index b96d45f117..54ca187492 100644 --- a/src/Platform/Microsoft.Testing.Platform/CommandLine/ICommandLineHandler.cs +++ b/src/Platform/Microsoft.Testing.Platform/CommandLine/ICommandLineHandler.cs @@ -13,5 +13,5 @@ internal interface ICommandLineHandler Task PrintHelpAsync(ITool[]? availableTools = null); - Task ParseAndValidateAsync(); + Task ParseAndValidateAsync(Func printBanner); } diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs index fe28b950af..637412a646 100644 --- a/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs +++ b/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs @@ -195,7 +195,7 @@ public async Task 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); } @@ -230,13 +230,7 @@ public async Task 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. @@ -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(); + } + } } diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/ArgumentArityTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/ArgumentArityTests.cs index f2633d4132..d7dd8de826 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/ArgumentArityTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/ArgumentArityTests.cs @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineHandlerTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineHandlerTests.cs index b132857e3d..e28cd3b81c 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineHandlerTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/CommandLineHandlerTests.cs @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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);