From eee7296a3de0d64dc30d010785d59a09b3a86d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Matou=C5=A1ek?= Date: Mon, 1 Dec 2025 12:08:57 -0800 Subject: [PATCH 1/3] Add Microsoft.DotNet.ProjectTools project (#51788) --- sdk.slnx | 5 +- .../Microsoft.DotNet.HotReload.Watch.csproj | 4 + .../Watch/Process/LaunchSettingsProfile.cs | 38 ++---- src/BuiltInTools/dotnet-watch.slnf | 1 + .../xlf/CliResources.cs.xlf | 19 +++ .../xlf/CliResources.de.xlf | 19 +++ .../xlf/CliResources.es.xlf | 19 +++ .../xlf/CliResources.fr.xlf | 19 +++ .../xlf/CliResources.it.xlf | 19 +++ .../xlf/CliResources.ja.xlf | 19 +++ .../xlf/CliResources.ko.xlf | 19 +++ .../xlf/CliResources.pl.xlf | 19 +++ .../xlf/CliResources.pt-BR.xlf | 19 +++ .../xlf/CliResources.ru.xlf | 19 +++ .../xlf/CliResources.tr.xlf | 19 +++ .../xlf/CliResources.zh-Hans.xlf | 19 +++ .../xlf/CliResources.zh-Hant.xlf | 19 +++ .../dotnet/Commands/Run/CommonRunHelpers.cs | 7 - src/Cli/dotnet/Commands/Run/RunCommand.cs | 60 ++------ .../Test/MTP/SolutionAndProjectUtility.cs | 5 +- src/Cli/dotnet/dotnet.csproj | 13 +- .../LaunchSettings/LaunchSettingsLocator.cs | 60 ++++++++ .../Microsoft.DotNet.ProjectTools.csproj | 12 ++ .../Resources.resx | 128 ++++++++++++++++++ .../xlf/Resources.cs.xlf | 19 +++ .../xlf/Resources.de.xlf | 19 +++ .../xlf/Resources.es.xlf | 19 +++ .../xlf/Resources.fr.xlf | 19 +++ .../xlf/Resources.it.xlf | 19 +++ .../xlf/Resources.ja.xlf | 19 +++ .../xlf/Resources.ko.xlf | 19 +++ .../xlf/Resources.pl.xlf | 19 +++ .../xlf/Resources.pt-BR.xlf | 19 +++ .../xlf/Resources.ru.xlf | 19 +++ .../xlf/Resources.tr.xlf | 19 +++ .../xlf/Resources.zh-Hans.xlf | 19 +++ .../xlf/Resources.zh-Hant.xlf | 19 +++ 37 files changed, 731 insertions(+), 96 deletions(-) create mode 100644 src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.cs.xlf create mode 100644 src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.de.xlf create mode 100644 src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.es.xlf create mode 100644 src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.fr.xlf create mode 100644 src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.it.xlf create mode 100644 src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ja.xlf create mode 100644 src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ko.xlf create mode 100644 src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.pl.xlf create mode 100644 src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.pt-BR.xlf create mode 100644 src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ru.xlf create mode 100644 src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.tr.xlf create mode 100644 src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.zh-Hans.xlf create mode 100644 src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.zh-Hant.xlf create mode 100644 src/Microsoft.DotNet.ProjectTools/LaunchSettings/LaunchSettingsLocator.cs create mode 100644 src/Microsoft.DotNet.ProjectTools/Microsoft.DotNet.ProjectTools.csproj create mode 100644 src/Microsoft.DotNet.ProjectTools/Resources.resx create mode 100644 src/Microsoft.DotNet.ProjectTools/xlf/Resources.cs.xlf create mode 100644 src/Microsoft.DotNet.ProjectTools/xlf/Resources.de.xlf create mode 100644 src/Microsoft.DotNet.ProjectTools/xlf/Resources.es.xlf create mode 100644 src/Microsoft.DotNet.ProjectTools/xlf/Resources.fr.xlf create mode 100644 src/Microsoft.DotNet.ProjectTools/xlf/Resources.it.xlf create mode 100644 src/Microsoft.DotNet.ProjectTools/xlf/Resources.ja.xlf create mode 100644 src/Microsoft.DotNet.ProjectTools/xlf/Resources.ko.xlf create mode 100644 src/Microsoft.DotNet.ProjectTools/xlf/Resources.pl.xlf create mode 100644 src/Microsoft.DotNet.ProjectTools/xlf/Resources.pt-BR.xlf create mode 100644 src/Microsoft.DotNet.ProjectTools/xlf/Resources.ru.xlf create mode 100644 src/Microsoft.DotNet.ProjectTools/xlf/Resources.tr.xlf create mode 100644 src/Microsoft.DotNet.ProjectTools/xlf/Resources.zh-Hans.xlf create mode 100644 src/Microsoft.DotNet.ProjectTools/xlf/Resources.zh-Hant.xlf diff --git a/sdk.slnx b/sdk.slnx index 5077b0285a6c..40c831048edc 100644 --- a/sdk.slnx +++ b/sdk.slnx @@ -23,6 +23,7 @@ + @@ -57,10 +58,10 @@ - - + + diff --git a/src/BuiltInTools/Watch/Microsoft.DotNet.HotReload.Watch.csproj b/src/BuiltInTools/Watch/Microsoft.DotNet.HotReload.Watch.csproj index 48e96f316ba5..aa3590c0c328 100644 --- a/src/BuiltInTools/Watch/Microsoft.DotNet.HotReload.Watch.csproj +++ b/src/BuiltInTools/Watch/Microsoft.DotNet.HotReload.Watch.csproj @@ -36,4 +36,8 @@ + + + + diff --git a/src/BuiltInTools/Watch/Process/LaunchSettingsProfile.cs b/src/BuiltInTools/Watch/Process/LaunchSettingsProfile.cs index 1ec08ab04ea2..90dbadffb2cb 100644 --- a/src/BuiltInTools/Watch/Process/LaunchSettingsProfile.cs +++ b/src/BuiltInTools/Watch/Process/LaunchSettingsProfile.cs @@ -1,10 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; using System.Text.Json; using System.Text.Json.Serialization; +using Microsoft.DotNet.ProjectTools; using Microsoft.Extensions.Logging; namespace Microsoft.DotNet.Watch @@ -26,28 +25,19 @@ internal sealed class LaunchSettingsProfile internal static LaunchSettingsProfile? ReadLaunchProfile(string projectPath, string? launchProfileName, ILogger logger) { - var projectDirectory = Path.GetDirectoryName(projectPath); - Debug.Assert(projectDirectory != null); - - var launchSettingsPath = GetPropertiesLaunchSettingsPath(projectDirectory, "Properties"); - bool hasLaunchSettings = File.Exists(launchSettingsPath); - - var projectNameWithoutExtension = Path.GetFileNameWithoutExtension(projectPath); - var runJsonPath = GetFlatLaunchSettingsPath(projectDirectory, projectNameWithoutExtension); - bool hasRunJson = File.Exists(runJsonPath); - - if (hasLaunchSettings) + var launchSettingsPath = LaunchSettingsLocator.TryFindLaunchSettings(projectPath, launchProfileName, (message, isError) => { - if (hasRunJson) + if (isError) { - logger.LogWarning("Warning: Settings from '{JsonPath}' are not used because '{LaunchSettingsPath}' has precedence.", runJsonPath, launchSettingsPath); + logger.LogError(message); } - } - else if (hasRunJson) - { - launchSettingsPath = runJsonPath; - } - else + else + { + logger.LogWarning(message); + } + }); + + if (launchSettingsPath == null) { return null; } @@ -96,12 +86,6 @@ internal sealed class LaunchSettingsProfile return namedProfile; } - private static string GetPropertiesLaunchSettingsPath(string directoryPath, string propertiesDirectoryName) - => Path.Combine(directoryPath, propertiesDirectoryName, "launchSettings.json"); - - private static string GetFlatLaunchSettingsPath(string directoryPath, string projectNameWithoutExtension) - => Path.Join(directoryPath, $"{projectNameWithoutExtension}.run.json"); - private static LaunchSettingsProfile? ReadDefaultLaunchProfile(LaunchSettingsJson? launchSettings, ILogger logger) { if (launchSettings is null || launchSettings.Profiles is null) diff --git a/src/BuiltInTools/dotnet-watch.slnf b/src/BuiltInTools/dotnet-watch.slnf index 8e454226e0d0..181ae2f51023 100644 --- a/src/BuiltInTools/dotnet-watch.slnf +++ b/src/BuiltInTools/dotnet-watch.slnf @@ -23,6 +23,7 @@ "src\\BuiltInTools\\Watch.Aspire\\Microsoft.DotNet.HotReload.Watch.Aspire.csproj", "src\\BuiltInTools\\Watch\\Microsoft.DotNet.HotReload.Watch.csproj", "src\\BuiltInTools\\dotnet-watch\\dotnet-watch.csproj", + "src\\Microsoft.DotNet.ProjectTools\\Microsoft.DotNet.ProjectTools.csproj", "test\\Microsoft.AspNetCore.Watch.BrowserRefresh.Tests\\Microsoft.AspNetCore.Watch.BrowserRefresh.Tests.csproj", "test\\Microsoft.DotNet.HotReload.Client.Tests\\Microsoft.DotNet.HotReload.Client.Tests.csproj", "test\\Microsoft.Extensions.DotNetDeltaApplier.Tests\\Microsoft.Extensions.DotNetDeltaApplier.Tests.csproj", diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.cs.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.cs.xlf new file mode 100644 index 000000000000..0acffa5e309e --- /dev/null +++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.cs.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.de.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.de.xlf new file mode 100644 index 000000000000..222ad213cc7c --- /dev/null +++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.de.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.es.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.es.xlf new file mode 100644 index 000000000000..aac33465eda7 --- /dev/null +++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.es.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.fr.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.fr.xlf new file mode 100644 index 000000000000..37db8eede2f2 --- /dev/null +++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.fr.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.it.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.it.xlf new file mode 100644 index 000000000000..59d52e5ed8b6 --- /dev/null +++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.it.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ja.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ja.xlf new file mode 100644 index 000000000000..03d8fb57849b --- /dev/null +++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ja.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ko.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ko.xlf new file mode 100644 index 000000000000..e8f5349a61f3 --- /dev/null +++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ko.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.pl.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.pl.xlf new file mode 100644 index 000000000000..fd5dd04c8e3b --- /dev/null +++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.pl.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.pt-BR.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.pt-BR.xlf new file mode 100644 index 000000000000..cf75b96d20cb --- /dev/null +++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.pt-BR.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ru.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ru.xlf new file mode 100644 index 000000000000..e785452d408c --- /dev/null +++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.ru.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.tr.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.tr.xlf new file mode 100644 index 000000000000..b535535503ac --- /dev/null +++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.tr.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.zh-Hans.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.zh-Hans.xlf new file mode 100644 index 000000000000..498ecf30dc47 --- /dev/null +++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.zh-Hans.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.zh-Hant.xlf b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.zh-Hant.xlf new file mode 100644 index 000000000000..5d1edadd8e3f --- /dev/null +++ b/src/Cli/Microsoft.DotNet.Cli.CommandLine/xlf/CliResources.zh-Hant.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs b/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs index 64d2b8a1075a..59ad5ce7dbba 100644 --- a/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs +++ b/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs @@ -21,13 +21,6 @@ public static Dictionary GetGlobalPropertiesFromArgs(MSBuildArgs return globalProperties; } - public static string GetPropertiesLaunchSettingsPath(string directoryPath, string propertiesDirectoryName) - => Path.Combine(directoryPath, propertiesDirectoryName, "launchSettings.json"); - - public static string GetFlatLaunchSettingsPath(string directoryPath, string projectNameWithoutExtension) - => Path.Join(directoryPath, $"{projectNameWithoutExtension}.run.json"); - - /// /// Applies adjustments to MSBuild arguments to better suit LLM/agentic environments, if such an environment is detected. /// diff --git a/src/Cli/dotnet/Commands/Run/RunCommand.cs b/src/Cli/dotnet/Commands/Run/RunCommand.cs index 09cfbe91720f..a07f6358606c 100644 --- a/src/Cli/dotnet/Commands/Run/RunCommand.cs +++ b/src/Cli/dotnet/Commands/Run/RunCommand.cs @@ -20,6 +20,7 @@ using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils.Extensions; using Microsoft.DotNet.FileBasedPrograms; +using Microsoft.DotNet.ProjectTools; namespace Microsoft.DotNet.Cli.Commands.Run; @@ -327,7 +328,13 @@ internal bool TryGetLaunchProfileSettingsIfNeeded(out ProjectLaunchSettingsModel return true; } - var launchSettingsPath = ReadCodeFromStdin ? null : TryFindLaunchSettings(projectOrEntryPointFilePath: ProjectFileFullPath ?? EntryPointFileFullPath!, launchProfile: LaunchProfile); + var launchSettingsPath = ReadCodeFromStdin + ? null + : LaunchSettingsLocator.TryFindLaunchSettings( + projectOrEntryPointFilePath: ProjectFileFullPath ?? EntryPointFileFullPath!, + launchProfile: LaunchProfile, + static (message, isError) => (isError ? Reporter.Error : Reporter.Output).WriteLine(message)); + if (launchSettingsPath is null) { return true; @@ -360,57 +367,6 @@ internal bool TryGetLaunchProfileSettingsIfNeeded(out ProjectLaunchSettingsModel } return true; - - static string? TryFindLaunchSettings(string projectOrEntryPointFilePath, string? launchProfile) - { - var buildPathContainer = Path.GetDirectoryName(projectOrEntryPointFilePath)!; - - string propsDirectory; - - // VB.NET projects store the launch settings file in the - // "My Project" directory instead of a "Properties" directory. - // TODO: use the `AppDesignerFolder` MSBuild property instead, which captures this logic already - if (string.Equals(Path.GetExtension(projectOrEntryPointFilePath), ".vbproj", StringComparison.OrdinalIgnoreCase)) - { - propsDirectory = "My Project"; - } - else - { - propsDirectory = "Properties"; - } - - string launchSettingsPath = CommonRunHelpers.GetPropertiesLaunchSettingsPath(buildPathContainer, propsDirectory); - bool hasLaunchSetttings = File.Exists(launchSettingsPath); - - string appName = Path.GetFileNameWithoutExtension(projectOrEntryPointFilePath); - string runJsonPath = CommonRunHelpers.GetFlatLaunchSettingsPath(buildPathContainer, appName); - bool hasRunJson = File.Exists(runJsonPath); - - if (hasLaunchSetttings) - { - if (hasRunJson) - { - Reporter.Output.WriteLine(string.Format(CliCommandStrings.RunCommandWarningRunJsonNotUsed, runJsonPath, launchSettingsPath).Yellow()); - } - - return launchSettingsPath; - } - - if (hasRunJson) - { - return runJsonPath; - } - - if (!string.IsNullOrEmpty(launchProfile)) - { - Reporter.Error.WriteLine(string.Format(CliCommandStrings.RunCommandExceptionCouldNotLocateALaunchSettingsFile, launchProfile, $""" - {launchSettingsPath} - {runJsonPath} - """).Bold().Red()); - } - - return null; - } } private void EnsureProjectIsBuilt(out Func? projectFactory, out RunProperties? cachedRunProperties, out VirtualProjectBuildingCommand? virtualCommand) diff --git a/src/Cli/dotnet/Commands/Test/MTP/SolutionAndProjectUtility.cs b/src/Cli/dotnet/Commands/Test/MTP/SolutionAndProjectUtility.cs index dbf96859bd17..9179762e0914 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/SolutionAndProjectUtility.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/SolutionAndProjectUtility.cs @@ -10,6 +10,7 @@ using Microsoft.DotNet.Cli.Commands.Run.LaunchSettings; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils.Extensions; +using Microsoft.DotNet.ProjectTools; namespace Microsoft.DotNet.Cli.Commands.Test; @@ -378,10 +379,10 @@ static RunProperties GetRunProperties(ProjectInstance project) return null; } - var launchSettingsPath = CommonRunHelpers.GetPropertiesLaunchSettingsPath(projectDirectory, appDesignerFolder); + var launchSettingsPath = LaunchSettingsLocator.GetPropertiesLaunchSettingsPath(projectDirectory, appDesignerFolder); bool hasLaunchSettings = File.Exists(launchSettingsPath); - var runJsonPath = CommonRunHelpers.GetFlatLaunchSettingsPath(projectDirectory, projectNameWithoutExtension); + var runJsonPath = LaunchSettingsLocator.GetFlatLaunchSettingsPath(projectDirectory, projectNameWithoutExtension); bool hasRunJson = File.Exists(runJsonPath); if (hasLaunchSettings) diff --git a/src/Cli/dotnet/dotnet.csproj b/src/Cli/dotnet/dotnet.csproj index 65df2389a343..8a9a238dfab0 100644 --- a/src/Cli/dotnet/dotnet.csproj +++ b/src/Cli/dotnet/dotnet.csproj @@ -38,13 +38,14 @@ - - - + + + - - - + + + + diff --git a/src/Microsoft.DotNet.ProjectTools/LaunchSettings/LaunchSettingsLocator.cs b/src/Microsoft.DotNet.ProjectTools/LaunchSettings/LaunchSettingsLocator.cs new file mode 100644 index 000000000000..f20e3445dbfe --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/LaunchSettings/LaunchSettingsLocator.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +namespace Microsoft.DotNet.ProjectTools; + +public static class LaunchSettingsLocator +{ + public static string GetPropertiesLaunchSettingsPath(string directoryPath, string propertiesDirectoryName) + => Path.Combine(directoryPath, propertiesDirectoryName, "launchSettings.json"); + + public static string GetFlatLaunchSettingsPath(string directoryPath, string projectNameWithoutExtension) + => Path.Join(directoryPath, $"{projectNameWithoutExtension}.run.json"); + + public static string? TryFindLaunchSettings(string projectOrEntryPointFilePath, string? launchProfile, Action report) + { + var buildPathContainer = Path.GetDirectoryName(projectOrEntryPointFilePath); + Debug.Assert(buildPathContainer != null); + + // VB.NET projects store the launch settings file in the + // "My Project" directory instead of a "Properties" directory. + // TODO: use the `AppDesignerFolder` MSBuild property instead, which captures this logic already + var propsDirectory = string.Equals(Path.GetExtension(projectOrEntryPointFilePath), ".vbproj", StringComparison.OrdinalIgnoreCase) + ? "My Project" + : "Properties"; + + string launchSettingsPath = GetPropertiesLaunchSettingsPath(buildPathContainer, propsDirectory); + bool hasLaunchSetttings = File.Exists(launchSettingsPath); + + string appName = Path.GetFileNameWithoutExtension(projectOrEntryPointFilePath); + string runJsonPath = GetFlatLaunchSettingsPath(buildPathContainer, appName); + bool hasRunJson = File.Exists(runJsonPath); + + if (hasLaunchSetttings) + { + if (hasRunJson) + { + report(string.Format(Resources.RunCommandWarningRunJsonNotUsed, runJsonPath, launchSettingsPath), false); + } + + return launchSettingsPath; + } + + if (hasRunJson) + { + return runJsonPath; + } + + if (!string.IsNullOrEmpty(launchProfile)) + { + report(string.Format(Resources.RunCommandExceptionCouldNotLocateALaunchSettingsFile, launchProfile, $""" + {launchSettingsPath} + {runJsonPath} + """), true); + } + + return null; + } +} diff --git a/src/Microsoft.DotNet.ProjectTools/Microsoft.DotNet.ProjectTools.csproj b/src/Microsoft.DotNet.ProjectTools/Microsoft.DotNet.ProjectTools.csproj new file mode 100644 index 000000000000..5dd909306acd --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/Microsoft.DotNet.ProjectTools.csproj @@ -0,0 +1,12 @@ + + + $(SdkTargetFramework) + enable + true + enable + + + + + + diff --git a/src/Microsoft.DotNet.ProjectTools/Resources.resx b/src/Microsoft.DotNet.ProjectTools/Resources.resx new file mode 100644 index 000000000000..9de7f944cb9e --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/Resources.resx @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.cs.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.cs.xlf new file mode 100644 index 000000000000..f8d9db92ba48 --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.cs.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.de.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.de.xlf new file mode 100644 index 000000000000..ac6216d4b292 --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.de.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.es.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.es.xlf new file mode 100644 index 000000000000..217f925c00e3 --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.es.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.fr.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.fr.xlf new file mode 100644 index 000000000000..e133378ad4e1 --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.fr.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.it.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.it.xlf new file mode 100644 index 000000000000..5620ef6944b3 --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.it.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ja.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ja.xlf new file mode 100644 index 000000000000..7dd1492ebe32 --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ja.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ko.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ko.xlf new file mode 100644 index 000000000000..162f27b4efb9 --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ko.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.pl.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.pl.xlf new file mode 100644 index 000000000000..6f0cecb49573 --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.pl.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.pt-BR.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.pt-BR.xlf new file mode 100644 index 000000000000..4d381aba1acf --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.pt-BR.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ru.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ru.xlf new file mode 100644 index 000000000000..20c6d3be68ad --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.ru.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.tr.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.tr.xlf new file mode 100644 index 000000000000..ff180d8a45c3 --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.tr.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.zh-Hans.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.zh-Hans.xlf new file mode 100644 index 000000000000..7225552ec73b --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.zh-Hans.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectTools/xlf/Resources.zh-Hant.xlf b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.zh-Hant.xlf new file mode 100644 index 000000000000..c99df83fdd56 --- /dev/null +++ b/src/Microsoft.DotNet.ProjectTools/xlf/Resources.zh-Hant.xlf @@ -0,0 +1,19 @@ + + + + + + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + Cannot use launch profile '{0}' because the launch settings file could not be located. Locations tried: +{1} + + + + Warning: Settings from '{0}' are not used because '{1}' has precedence. + Warning: Settings from '{0}' are not used because '{1}' has precedence. + {0} is an app.run.json file path. {1} is a launchSettings.json file path. + + + + \ No newline at end of file From 7edd13b854980827d034bbff901b789bec954ee7 Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Mon, 1 Dec 2025 21:33:56 +0100 Subject: [PATCH 2/3] Cleanup test command (#51883) --- .../Commands/Test/MTP/MSBuildUtility.cs | 2 +- .../MTP/MicrosoftTestingPlatformOptions.cs | 6 +- .../Commands/Test/MTP/ValidationUtility.cs | 4 +- .../Commands/Test/TestCommandDefinition.cs | 268 ++---------------- .../dotnet/Commands/Test/TestCommandParser.cs | 2 +- .../Commands/Test/VSTest/TestCommand.cs | 8 +- .../Commands/Test/VSTest/VSTestOptions.cs | 205 ++++++++++++++ .../Extensions/OptionForwardingExtensions.cs | 2 +- .../GivenDotnetTestBuildsAndDiscoversTests.cs | 14 +- .../Test/GivenDotnetTestBuildsAndRunsHelp.cs | 6 +- .../Test/GivenDotnetTestBuildsAndRunsTests.cs | 36 +-- ...etTestBuildsAndRunsTestsForMultipleTFMs.cs | 8 +- ...tnetTestBuildsAndRunsTestsWithArtifacts.cs | 4 +- ...tBuildsAndRunsTestsWithDifferentOptions.cs | 62 ++-- ...otnetTestRunsConsoleAppWithoutHandshake.cs | 4 +- .../Test/TestCommandParserTests.cs | 12 +- 16 files changed, 314 insertions(+), 329 deletions(-) create mode 100644 src/Cli/dotnet/Commands/Test/VSTest/VSTestOptions.cs diff --git a/src/Cli/dotnet/Commands/Test/MTP/MSBuildUtility.cs b/src/Cli/dotnet/Commands/Test/MTP/MSBuildUtility.cs index 3df4be2208ab..fc1d2eaf2b35 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/MSBuildUtility.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/MSBuildUtility.cs @@ -153,7 +153,7 @@ private static bool BuildOrRestoreProjectOrSolution(string filePath, BuildOption msbuildArgs.Add($"-verbosity:quiet"); } - var parsedMSBuildArgs = MSBuildArgs.AnalyzeMSBuildArguments(msbuildArgs, CommonOptions.PropertiesOption, CommonOptions.RestorePropertiesOption, TestCommandDefinition.MTPTargetOption, TestCommandDefinition.VerbosityOption, CommonOptions.NoLogoOption()); + var parsedMSBuildArgs = MSBuildArgs.AnalyzeMSBuildArguments(msbuildArgs, CommonOptions.PropertiesOption, CommonOptions.RestorePropertiesOption, MicrosoftTestingPlatformOptions.MTPTargetOption, TestCommandDefinition.VerbosityOption, CommonOptions.NoLogoOption()); int result = new RestoringCommand(parsedMSBuildArgs, buildOptions.HasNoRestore).Execute(); diff --git a/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformOptions.cs b/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformOptions.cs index f7678ca2b4f2..fff37275fd84 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformOptions.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformOptions.cs @@ -66,10 +66,6 @@ internal static class MicrosoftTestingPlatformOptions HelpName = CliCommandStrings.CmdNumberName }; - public static readonly Option ConfigurationOption = CommonOptions.ConfigurationOption(CliCommandStrings.TestConfigurationOptionDescription); - - public static readonly Option FrameworkOption = CommonOptions.FrameworkOption(CliCommandStrings.TestFrameworkOptionDescription); - public static readonly Option NoBuildOption = new("--no-build") { Description = CliCommandStrings.CmdNoBuildDescription @@ -109,6 +105,8 @@ internal static class MicrosoftTestingPlatformOptions Description = CliCommandStrings.CmdListTestsDescription, Arity = ArgumentArity.Zero }; + + public static readonly Option MTPTargetOption = CommonOptions.RequiredMSBuildTargetOption(CliConstants.MTPTarget); } internal enum OutputOptions diff --git a/src/Cli/dotnet/Commands/Test/MTP/ValidationUtility.cs b/src/Cli/dotnet/Commands/Test/MTP/ValidationUtility.cs index ed3990231883..1e16d5cea36a 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/ValidationUtility.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/ValidationUtility.cs @@ -40,8 +40,8 @@ static void ValidateOptionsIrrelevantToModulesFilter(ParseResult parseResult) } if (parseResult.HasOption(CommonOptions.ArchitectureOption) || - parseResult.HasOption(MicrosoftTestingPlatformOptions.ConfigurationOption) || - parseResult.HasOption(MicrosoftTestingPlatformOptions.FrameworkOption) || + parseResult.HasOption(TestCommandDefinition.ConfigurationOption) || + parseResult.HasOption(TestCommandDefinition.FrameworkOption) || parseResult.HasOption(CommonOptions.OperatingSystemOption) || parseResult.HasOption(CommonOptions.RuntimeOptionName)) { diff --git a/src/Cli/dotnet/Commands/Test/TestCommandDefinition.cs b/src/Cli/dotnet/Commands/Test/TestCommandDefinition.cs index 50c2ab027534..f7ed27695dad 100644 --- a/src/Cli/dotnet/Commands/Test/TestCommandDefinition.cs +++ b/src/Cli/dotnet/Commands/Test/TestCommandDefinition.cs @@ -5,7 +5,6 @@ using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.DotNet.Cli.CommandLine; -using Microsoft.DotNet.Cli.Extensions; using Command = System.CommandLine.Command; namespace Microsoft.DotNet.Cli.Commands.Test; @@ -33,145 +32,11 @@ private sealed class GlobalJsonTestNode public const string Name = "test"; public static readonly string DocsLink = "https://aka.ms/dotnet-test"; - public static readonly Option SettingsOption = new Option("--settings", "-s") - { - Description = CliCommandStrings.CmdSettingsDescription, - HelpName = CliCommandStrings.CmdSettingsFile - }.ForwardAsSingle(o => $"-property:VSTestSetting={SurroundWithDoubleQuotes(CommandDirectoryContext.GetFullPath(o))}"); - - public static readonly Option ListTestsOption = new Option("--list-tests", "-t") - { - Description = CliCommandStrings.CmdListTestsDescription, - Arity = ArgumentArity.Zero - }.ForwardAs("-property:VSTestListTests=true"); - - public static readonly Option FilterOption = new Option("--filter") - { - Description = CliCommandStrings.CmdTestCaseFilterDescription, - HelpName = CliCommandStrings.CmdTestCaseFilterExpression - }.ForwardAsSingle(o => $"-property:VSTestTestCaseFilter={SurroundWithDoubleQuotes(o!)}"); - - public static readonly Option> AdapterOption = new Option>("--test-adapter-path") - { - Description = CliCommandStrings.CmdTestAdapterPathDescription, - HelpName = CliCommandStrings.CmdTestAdapterPath - }.ForwardAsSingle(o => $"-property:VSTestTestAdapterPath={SurroundWithDoubleQuotes(string.Join(";", o!.Select(CommandDirectoryContext.GetFullPath)))}") - .AllowSingleArgPerToken(); - - public static readonly Option> LoggerOption = new Option>("--logger", "-l") - { - Description = CliCommandStrings.CmdLoggerDescription, - HelpName = CliCommandStrings.CmdLoggerOption - }.ForwardAsSingle(o => - { - var loggersString = string.Join(";", GetSemiColonEscapedArgs(o!)); - - return $"-property:VSTestLogger={SurroundWithDoubleQuotes(loggersString)}"; - }) - .AllowSingleArgPerToken(); - - public static readonly Option OutputOption = new Option("--output", "-o") - { - Description = CliCommandStrings.CmdOutputDescription, - HelpName = CliCommandStrings.TestCmdOutputDir - } - .ForwardAsOutputPath("OutputPath", true); - - public static readonly Option DiagOption = new Option("--diag", "-d") - { - Description = CliCommandStrings.CmdPathTologFileDescription, - HelpName = CliCommandStrings.CmdPathToLogFile - } - .ForwardAsSingle(o => $"-property:VSTestDiag={SurroundWithDoubleQuotes(CommandDirectoryContext.GetFullPath(o))}"); - - public static readonly Option NoBuildOption = new Option("--no-build") - { - Description = CliCommandStrings.CmdNoBuildDescription, - Arity = ArgumentArity.Zero - }.ForwardAs("-property:VSTestNoBuild=true"); - - public static readonly Option ResultsOption = new Option("--results-directory") - { - Description = CliCommandStrings.CmdResultsDirectoryDescription, - HelpName = CliCommandStrings.CmdPathToResultsDirectory - }.ForwardAsSingle(o => $"-property:VSTestResultsDirectory={SurroundWithDoubleQuotes(CommandDirectoryContext.GetFullPath(o))}"); - - public static readonly Option> CollectOption = new Option>("--collect") - { - Description = CliCommandStrings.cmdCollectDescription, - HelpName = CliCommandStrings.cmdCollectFriendlyName - }.ForwardAsSingle(o => $"-property:VSTestCollect=\"{string.Join(";", GetSemiColonEscapedArgs(o!))}\"") - .AllowSingleArgPerToken(); - - public static readonly Option BlameOption = new Option("--blame") - { - Description = CliCommandStrings.CmdBlameDescription, - Arity = ArgumentArity.Zero - }.ForwardIfEnabled("-property:VSTestBlame=true"); - - public static readonly Option BlameCrashOption = new Option("--blame-crash") - { - Description = CliCommandStrings.CmdBlameCrashDescription, - Arity = ArgumentArity.Zero - }.ForwardIfEnabled("-property:VSTestBlameCrash=true"); - - public static readonly Option BlameCrashDumpOption = CreateBlameCrashDumpOption(); - - private static Option CreateBlameCrashDumpOption() - { - Option result = new Option("--blame-crash-dump-type") - { - Description = CliCommandStrings.CmdBlameCrashDumpTypeDescription, - HelpName = CliCommandStrings.CrashDumpTypeArgumentName, - } - .ForwardAsMany(o => ["-property:VSTestBlameCrash=true", $"-property:VSTestBlameCrashDumpType={o}"]); - result.AcceptOnlyFromAmong(["full", "mini"]); - return result; - } - - public static readonly Option BlameCrashAlwaysOption = new Option("--blame-crash-collect-always") - { - Description = CliCommandStrings.CmdBlameCrashCollectAlwaysDescription, - Arity = ArgumentArity.Zero - }.ForwardIfEnabled(["-property:VSTestBlameCrash=true", "-property:VSTestBlameCrashCollectAlways=true"]); - - public static readonly Option BlameHangOption = new Option("--blame-hang") - { - Description = CliCommandStrings.CmdBlameHangDescription, - Arity = ArgumentArity.Zero - }.ForwardAs("-property:VSTestBlameHang=true"); - - public static readonly Option BlameHangDumpOption = CreateBlameHangDumpOption(); - - private static Option CreateBlameHangDumpOption() - { - Option result = new Option("--blame-hang-dump-type") - { - Description = CliCommandStrings.CmdBlameHangDumpTypeDescription, - HelpName = CliCommandStrings.HangDumpTypeArgumentName - } - .ForwardAsMany(o => ["-property:VSTestBlameHang=true", $"-property:VSTestBlameHangDumpType={o}"]); - result.AcceptOnlyFromAmong(["full", "mini", "none"]); - return result; - } - - public static readonly Option BlameHangTimeoutOption = new Option("--blame-hang-timeout") - { - Description = CliCommandStrings.CmdBlameHangTimeoutDescription, - HelpName = CliCommandStrings.HangTimeoutArgumentName - }.ForwardAsMany(o => ["-property:VSTestBlameHang=true", $"-property:VSTestBlameHangTimeout={o}"]); - - public static readonly Option NoLogoOption = CommonOptions.NoLogoOption(forwardAs: "--property:VSTestNoLogo=true", description: CliCommandStrings.TestCmdNoLogo); - - public static readonly Option NoRestoreOption = CommonOptions.NoRestoreOption; - public static readonly Option FrameworkOption = CommonOptions.FrameworkOption(CliCommandStrings.TestFrameworkOptionDescription); - public static readonly Option ConfigurationOption = CommonOptions.ConfigurationOption(CliCommandStrings.TestConfigurationOptionDescription); + public static readonly Option ConfigurationOption = CommonOptions.ConfigurationOption(CliCommandStrings.TestConfigurationOptionDescription); public static readonly Option VerbosityOption = CommonOptions.VerbosityOption(); - public static readonly Option VsTestTargetOption = CommonOptions.RequiredMSBuildTargetOption("VSTest"); - public static readonly Option MTPTargetOption = CommonOptions.RequiredMSBuildTargetOption(CliConstants.MTPTarget); public static TestRunner GetTestRunner() { @@ -223,28 +88,7 @@ public static TestRunner GetTestRunner() return null; } - public static Command Create() - { - var command = new Command(Name); - - switch (GetTestRunner()) - { - case TestRunner.VSTest: - ConfigureVSTestCommand(command); - break; - - case TestRunner.MicrosoftTestingPlatform: - ConfigureTestingPlatformCommand(command); - break; - - default: - throw new InvalidOperationException(); - }; - - return command; - } - - public static void ConfigureTestingPlatformCommand(Command command) + public static void ConfigureMicrosoftTestingPlatformCommand(Command command) { command.Description = CliCommandStrings.DotnetTestCommandMTPDescription; command.Options.Add(MicrosoftTestingPlatformOptions.ProjectOrSolutionOption); @@ -259,8 +103,8 @@ public static void ConfigureTestingPlatformCommand(Command command) command.Options.Add(CommonOptions.ArchitectureOption); command.Options.Add(CommonOptions.EnvOption); command.Options.Add(CommonOptions.PropertiesOption); - command.Options.Add(MicrosoftTestingPlatformOptions.ConfigurationOption); - command.Options.Add(MicrosoftTestingPlatformOptions.FrameworkOption); + command.Options.Add(ConfigurationOption); + command.Options.Add(FrameworkOption); command.Options.Add(CommonOptions.OperatingSystemOption); command.Options.Add(CommonOptions.RuntimeOption(CliCommandStrings.TestRuntimeOptionDescription)); command.Options.Add(VerbosityOption); @@ -272,7 +116,7 @@ public static void ConfigureTestingPlatformCommand(Command command) command.Options.Add(MicrosoftTestingPlatformOptions.ListTestsOption); command.Options.Add(MicrosoftTestingPlatformOptions.NoLaunchProfileOption); command.Options.Add(MicrosoftTestingPlatformOptions.NoLaunchProfileArgumentsOption); - command.Options.Add(MTPTargetOption); + command.Options.Add(MicrosoftTestingPlatformOptions.MTPTargetOption); } public static void ConfigureVSTestCommand(Command command) @@ -284,98 +128,36 @@ public static void ConfigureVSTestCommand(Command command) // We are on purpose not capturing the solution, project or directory here. We want to pass it to the // MSBuild command so we are letting it flow. - command.Options.Add(SettingsOption); - command.Options.Add(ListTestsOption); + command.Options.Add(VSTestOptions.SettingsOption); + command.Options.Add(VSTestOptions.ListTestsOption); command.Options.Add(CommonOptions.TestEnvOption); - command.Options.Add(FilterOption); - command.Options.Add(AdapterOption); - command.Options.Add(LoggerOption); - command.Options.Add(OutputOption); + command.Options.Add(VSTestOptions.FilterOption); + command.Options.Add(VSTestOptions.AdapterOption); + command.Options.Add(VSTestOptions.LoggerOption); + command.Options.Add(VSTestOptions.OutputOption); command.Options.Add(CommonOptions.ArtifactsPathOption); - command.Options.Add(DiagOption); - command.Options.Add(NoBuildOption); - command.Options.Add(ResultsOption); - command.Options.Add(CollectOption); - command.Options.Add(BlameOption); - command.Options.Add(BlameCrashOption); - command.Options.Add(BlameCrashDumpOption); - command.Options.Add(BlameCrashAlwaysOption); - command.Options.Add(BlameHangOption); - command.Options.Add(BlameHangDumpOption); - command.Options.Add(BlameHangTimeoutOption); - command.Options.Add(NoLogoOption); + command.Options.Add(VSTestOptions.DiagOption); + command.Options.Add(VSTestOptions.NoBuildOption); + command.Options.Add(VSTestOptions.ResultsOption); + command.Options.Add(VSTestOptions.CollectOption); + command.Options.Add(VSTestOptions.BlameOption); + command.Options.Add(VSTestOptions.BlameCrashOption); + command.Options.Add(VSTestOptions.BlameCrashDumpOption); + command.Options.Add(VSTestOptions.BlameCrashAlwaysOption); + command.Options.Add(VSTestOptions.BlameHangOption); + command.Options.Add(VSTestOptions.BlameHangDumpOption); + command.Options.Add(VSTestOptions.BlameHangTimeoutOption); + command.Options.Add(VSTestOptions.NoLogoOption); command.Options.Add(ConfigurationOption); command.Options.Add(FrameworkOption); command.Options.Add(CommonOptions.RuntimeOption(CliCommandStrings.TestRuntimeOptionDescription)); - command.Options.Add(NoRestoreOption); + command.Options.Add(CommonOptions.NoRestoreOption); command.Options.Add(CommonOptions.InteractiveMsBuildForwardOption); command.Options.Add(VerbosityOption); command.Options.Add(CommonOptions.ArchitectureOption); command.Options.Add(CommonOptions.OperatingSystemOption); command.Options.Add(CommonOptions.PropertiesOption); command.Options.Add(CommonOptions.DisableBuildServersOption); - command.Options.Add(VsTestTargetOption); - } - - private static string GetSemiColonEscapedstring(string arg) - { - if (arg.IndexOf(";") != -1) - { - return arg.Replace(";", "%3b"); - } - - return arg; - } - - private static string[] GetSemiColonEscapedArgs(IEnumerable args) - { - int counter = 0; - string[] array = new string[args.Count()]; - - foreach (string arg in args) - { - array[counter++] = GetSemiColonEscapedstring(arg); - } - - return array; - } - - /// - /// Adding double quotes around the property helps MSBuild arguments parser and avoid incorrect splits on ',' or ';'. - /// - internal /* for testing purposes */ static string SurroundWithDoubleQuotes(string input) - { - if (input is null) - { - throw new ArgumentNullException(nameof(input)); - } - - // If already escaped by double quotes then return original string. - if (input.StartsWith("\"", StringComparison.Ordinal) - && input.EndsWith("\"", StringComparison.Ordinal)) - { - return input; - } - - // We want to count the number of trailing backslashes to ensure - // we will have an even number before adding the final double quote. - // Otherwise the last \" will be interpreted as escaping the double - // quote rather than a backslash and a double quote. - var trailingBackslashesCount = 0; - for (int i = input.Length - 1; i >= 0; i--) - { - if (input[i] == '\\') - { - trailingBackslashesCount++; - } - else - { - break; - } - } - - return trailingBackslashesCount % 2 == 0 - ? string.Concat("\"", input, "\"") - : string.Concat("\"", input, "\\\""); + command.Options.Add(VSTestOptions.VsTestTargetOption); } } diff --git a/src/Cli/dotnet/Commands/Test/TestCommandParser.cs b/src/Cli/dotnet/Commands/Test/TestCommandParser.cs index 2ee6a66fc750..57300d5ee0ff 100644 --- a/src/Cli/dotnet/Commands/Test/TestCommandParser.cs +++ b/src/Cli/dotnet/Commands/Test/TestCommandParser.cs @@ -27,7 +27,7 @@ private static Command CreateCommand() private static Command CreateTestingPlatformCommand() { var command = new MicrosoftTestingPlatformTestCommand(TestCommandDefinition.Name); - TestCommandDefinition.ConfigureTestingPlatformCommand(command); + TestCommandDefinition.ConfigureMicrosoftTestingPlatformCommand(command); command.SetAction(parseResult => command.Run(parseResult)); return command; } diff --git a/src/Cli/dotnet/Commands/Test/VSTest/TestCommand.cs b/src/Cli/dotnet/Commands/Test/VSTest/TestCommand.cs index 32bc8cf23172..7ef075d87530 100644 --- a/src/Cli/dotnet/Commands/Test/VSTest/TestCommand.cs +++ b/src/Cli/dotnet/Commands/Test/VSTest/TestCommand.cs @@ -233,13 +233,13 @@ private static TestCommand FromParseResult(ParseResult result, string[] settings msbuildArgs.Add($"-property:VSTestSessionCorrelationId={testSessionCorrelationId}"); } - bool noRestore = result.GetValue(TestCommandDefinition.NoRestoreOption) || result.GetValue(TestCommandDefinition.NoBuildOption); + bool noRestore = result.GetValue(CommonOptions.NoRestoreOption) || result.GetValue(VSTestOptions.NoBuildOption); var parsedMSBuildArgs = MSBuildArgs.AnalyzeMSBuildArguments( msbuildArgs, CommonOptions.PropertiesOption, CommonOptions.RestorePropertiesOption, - TestCommandDefinition.VsTestTargetOption, + VSTestOptions.VsTestTargetOption, TestCommandDefinition.VerbosityOption, CommonOptions.NoLogoOption()) .CloneWithNoLogo(true); @@ -288,9 +288,9 @@ internal static int RunArtifactPostProcessingIfNeeded(string testSessionCorrelat var artifactsPostProcessArgs = new List { "--artifactsProcessingMode-postprocess", $"--testSessionCorrelationId:{testSessionCorrelationId}" }; - if (parseResult.GetResult(TestCommandDefinition.DiagOption) is not null) + if (parseResult.GetResult(VSTestOptions.DiagOption) is not null) { - artifactsPostProcessArgs.Add($"--diag:{parseResult.GetValue(TestCommandDefinition.DiagOption)}"); + artifactsPostProcessArgs.Add($"--diag:{parseResult.GetValue(VSTestOptions.DiagOption)}"); } try diff --git a/src/Cli/dotnet/Commands/Test/VSTest/VSTestOptions.cs b/src/Cli/dotnet/Commands/Test/VSTest/VSTestOptions.cs new file mode 100644 index 000000000000..05b018a485b1 --- /dev/null +++ b/src/Cli/dotnet/Commands/Test/VSTest/VSTestOptions.cs @@ -0,0 +1,205 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CommandLine; +using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.Cli.Extensions; + +namespace Microsoft.DotNet.Cli.Commands.Test; + +internal static class VSTestOptions +{ + public static readonly Option SettingsOption = new Option("--settings", "-s") + { + Description = CliCommandStrings.CmdSettingsDescription, + HelpName = CliCommandStrings.CmdSettingsFile + }.ForwardAsSingle(o => $"-property:VSTestSetting={SurroundWithDoubleQuotes(CommandDirectoryContext.GetFullPath(o))}"); + + public static readonly Option ListTestsOption = new Option("--list-tests", "-t") + { + Description = CliCommandStrings.CmdListTestsDescription, + Arity = ArgumentArity.Zero + }.ForwardAs("-property:VSTestListTests=true"); + + public static readonly Option FilterOption = new Option("--filter") + { + Description = CliCommandStrings.CmdTestCaseFilterDescription, + HelpName = CliCommandStrings.CmdTestCaseFilterExpression + }.ForwardAsSingle(o => $"-property:VSTestTestCaseFilter={SurroundWithDoubleQuotes(o!)}"); + + public static readonly Option> AdapterOption = new Option>("--test-adapter-path") + { + Description = CliCommandStrings.CmdTestAdapterPathDescription, + HelpName = CliCommandStrings.CmdTestAdapterPath + }.ForwardAsSingle(o => $"-property:VSTestTestAdapterPath={SurroundWithDoubleQuotes(string.Join(";", o!.Select(CommandDirectoryContext.GetFullPath)))}") + .AllowSingleArgPerToken(); + + public static readonly Option> LoggerOption = new Option>("--logger", "-l") + { + Description = CliCommandStrings.CmdLoggerDescription, + HelpName = CliCommandStrings.CmdLoggerOption + }.ForwardAsSingle(o => + { + var loggersString = string.Join(";", GetSemiColonEscapedArgs(o!)); + + return $"-property:VSTestLogger={SurroundWithDoubleQuotes(loggersString)}"; + }) + .AllowSingleArgPerToken(); + + public static readonly Option OutputOption = new Option("--output", "-o") + { + Description = CliCommandStrings.CmdOutputDescription, + HelpName = CliCommandStrings.TestCmdOutputDir + } + .ForwardAsOutputPath("OutputPath", true); + + public static readonly Option DiagOption = new Option("--diag", "-d") + { + Description = CliCommandStrings.CmdPathTologFileDescription, + HelpName = CliCommandStrings.CmdPathToLogFile + } + .ForwardAsSingle(o => $"-property:VSTestDiag={SurroundWithDoubleQuotes(CommandDirectoryContext.GetFullPath(o))}"); + + public static readonly Option NoBuildOption = new Option("--no-build") + { + Description = CliCommandStrings.CmdNoBuildDescription, + Arity = ArgumentArity.Zero + }.ForwardAs("-property:VSTestNoBuild=true"); + + public static readonly Option ResultsOption = new Option("--results-directory") + { + Description = CliCommandStrings.CmdResultsDirectoryDescription, + HelpName = CliCommandStrings.CmdPathToResultsDirectory + }.ForwardAsSingle(o => $"-property:VSTestResultsDirectory={SurroundWithDoubleQuotes(CommandDirectoryContext.GetFullPath(o))}"); + + public static readonly Option> CollectOption = new Option>("--collect") + { + Description = CliCommandStrings.cmdCollectDescription, + HelpName = CliCommandStrings.cmdCollectFriendlyName + }.ForwardAsSingle(o => $"-property:VSTestCollect=\"{string.Join(";", GetSemiColonEscapedArgs(o!))}\"") + .AllowSingleArgPerToken(); + + public static readonly Option BlameOption = new Option("--blame") + { + Description = CliCommandStrings.CmdBlameDescription, + Arity = ArgumentArity.Zero + }.ForwardIfEnabled("-property:VSTestBlame=true"); + + public static readonly Option BlameCrashOption = new Option("--blame-crash") + { + Description = CliCommandStrings.CmdBlameCrashDescription, + Arity = ArgumentArity.Zero + }.ForwardIfEnabled("-property:VSTestBlameCrash=true"); + + public static readonly Option BlameCrashDumpOption = CreateBlameCrashDumpOption(); + + private static Option CreateBlameCrashDumpOption() + { + Option result = new Option("--blame-crash-dump-type") + { + Description = CliCommandStrings.CmdBlameCrashDumpTypeDescription, + HelpName = CliCommandStrings.CrashDumpTypeArgumentName, + } + .ForwardAsMany(o => ["-property:VSTestBlameCrash=true", $"-property:VSTestBlameCrashDumpType={o}"]); + result.AcceptOnlyFromAmong(["full", "mini"]); + return result; + } + + public static readonly Option BlameCrashAlwaysOption = new Option("--blame-crash-collect-always") + { + Description = CliCommandStrings.CmdBlameCrashCollectAlwaysDescription, + Arity = ArgumentArity.Zero + }.ForwardIfEnabled(["-property:VSTestBlameCrash=true", "-property:VSTestBlameCrashCollectAlways=true"]); + + public static readonly Option BlameHangOption = new Option("--blame-hang") + { + Description = CliCommandStrings.CmdBlameHangDescription, + Arity = ArgumentArity.Zero + }.ForwardAs("-property:VSTestBlameHang=true"); + + public static readonly Option BlameHangDumpOption = CreateBlameHangDumpOption(); + + private static Option CreateBlameHangDumpOption() + { + Option result = new Option("--blame-hang-dump-type") + { + Description = CliCommandStrings.CmdBlameHangDumpTypeDescription, + HelpName = CliCommandStrings.HangDumpTypeArgumentName + } + .ForwardAsMany(o => ["-property:VSTestBlameHang=true", $"-property:VSTestBlameHangDumpType={o}"]); + result.AcceptOnlyFromAmong(["full", "mini", "none"]); + return result; + } + + public static readonly Option BlameHangTimeoutOption = new Option("--blame-hang-timeout") + { + Description = CliCommandStrings.CmdBlameHangTimeoutDescription, + HelpName = CliCommandStrings.HangTimeoutArgumentName + }.ForwardAsMany(o => ["-property:VSTestBlameHang=true", $"-property:VSTestBlameHangTimeout={o}"]); + + public static readonly Option NoLogoOption = CommonOptions.NoLogoOption(forwardAs: "--property:VSTestNoLogo=true", description: CliCommandStrings.TestCmdNoLogo); + + public static readonly Option VsTestTargetOption = CommonOptions.RequiredMSBuildTargetOption("VSTest"); + + private static string GetSemiColonEscapedstring(string arg) + { + if (arg.IndexOf(";") != -1) + { + return arg.Replace(";", "%3b"); + } + + return arg; + } + + private static string[] GetSemiColonEscapedArgs(IEnumerable args) + { + int counter = 0; + string[] array = new string[args.Count()]; + + foreach (string arg in args) + { + array[counter++] = GetSemiColonEscapedstring(arg); + } + + return array; + } + + /// + /// Adding double quotes around the property helps MSBuild arguments parser and avoid incorrect splits on ',' or ';'. + /// + internal /* for testing purposes */ static string SurroundWithDoubleQuotes(string input) + { + if (input is null) + { + throw new ArgumentNullException(nameof(input)); + } + + // If already escaped by double quotes then return original string. + if (input.StartsWith("\"", StringComparison.Ordinal) + && input.EndsWith("\"", StringComparison.Ordinal)) + { + return input; + } + + // We want to count the number of trailing backslashes to ensure + // we will have an even number before adding the final double quote. + // Otherwise the last \" will be interpreted as escaping the double + // quote rather than a backslash and a double quote. + var trailingBackslashesCount = 0; + for (int i = input.Length - 1; i >= 0; i--) + { + if (input[i] == '\\') + { + trailingBackslashesCount++; + } + else + { + break; + } + } + + return trailingBackslashesCount % 2 == 0 + ? string.Concat("\"", input, "\"") + : string.Concat("\"", input, "\\\""); + } +} diff --git a/src/Cli/dotnet/Extensions/OptionForwardingExtensions.cs b/src/Cli/dotnet/Extensions/OptionForwardingExtensions.cs index 6d191c02f8f3..9b70521a9ce2 100644 --- a/src/Cli/dotnet/Extensions/OptionForwardingExtensions.cs +++ b/src/Cli/dotnet/Extensions/OptionForwardingExtensions.cs @@ -30,7 +30,7 @@ public static Option ForwardAsOutputPath(this Option option, str { // Not sure if this is necessary, but this is what "dotnet test" previously did and so we are // preserving the behavior here after refactoring - argVal = TestCommandDefinition.SurroundWithDoubleQuotes(argVal); + argVal = VSTestOptions.SurroundWithDoubleQuotes(argVal); } return [ $"--property:{outputPropertyName}={argVal}", diff --git a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndDiscoversTests.cs b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndDiscoversTests.cs index 2b7c69805324..6435efdf0fcd 100644 --- a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndDiscoversTests.cs +++ b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndDiscoversTests.cs @@ -24,7 +24,7 @@ public void DiscoverTestProjectWithNoTests_ShouldReturnExitCodeGenericFailure(st CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ListTestsOption.Name, MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(MicrosoftTestingPlatformOptions.ListTestsOption.Name, TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -47,7 +47,7 @@ public void DiscoverMultipleTestProjectsWithNoTests_ShouldReturnExitCodeGenericF CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ListTestsOption.Name, MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(MicrosoftTestingPlatformOptions.ListTestsOption.Name, TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -70,7 +70,7 @@ public void DiscoverTestProjectWithTests_ShouldReturnExitCodeSuccess(string conf CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ListTestsOption.Name, MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(MicrosoftTestingPlatformOptions.ListTestsOption.Name, TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -91,7 +91,7 @@ public void DiscoverMultipleTestProjectsWithTests_ShouldReturnExitCodeSuccess(st CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ListTestsOption.Name, MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(MicrosoftTestingPlatformOptions.ListTestsOption.Name, TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -116,7 +116,7 @@ public void DiscoverProjectWithMSTestMetaPackageAndMultipleTFMsWithTests_ShouldR CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ListTestsOption.Name, MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(MicrosoftTestingPlatformOptions.ListTestsOption.Name, TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -137,7 +137,7 @@ public void DiscoverTestProjectsWithHybridModeTestRunners_ShouldReturnExitCodeGe CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ListTestsOption.Name, MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(MicrosoftTestingPlatformOptions.ListTestsOption.Name, TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -158,7 +158,7 @@ public void DiscoverTestProjectWithCustomRunArgumentsAndTestEscaping(string conf CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(MicrosoftTestingPlatformOptions.ListTestsOption.Name, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration, + TestCommandDefinition.ConfigurationOption.Name, configuration, "-p:RunArguments=--hello world \"\" world2", "Another arg with spaces", "My other arg with spaces", diff --git a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsHelp.cs b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsHelp.cs index 1847d3129c19..af5ed910bc00 100644 --- a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsHelp.cs +++ b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsHelp.cs @@ -23,7 +23,7 @@ public void RunHelpOnTestProject_ShouldReturnExitCodeSuccess(string configuratio CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(CliConstants.HelpOptionKey, MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(CliConstants.HelpOptionKey, TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -47,7 +47,7 @@ public void RunHelpOnMultipleTestProjects_ShouldReturnExitCodeSuccess(string con CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(CliConstants.HelpOptionKey, MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(CliConstants.HelpOptionKey, TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -72,7 +72,7 @@ public void RunHelpCommand_ShouldNotShowDuplicateOptions(string configuration) CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(CliConstants.HelpOptionKey, MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(CliConstants.HelpOptionKey, TestCommandDefinition.ConfigurationOption.Name, configuration); // Parse the help output to extract option names var helpOutput = result.StdOut; diff --git a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs index 23855c3cb442..6236560bb9f0 100644 --- a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs +++ b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs @@ -24,7 +24,7 @@ public void RunTestProjectWithNoTests_ShouldReturnExitCodeZeroTests(string confi CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -49,7 +49,7 @@ public void RunTestProjectWithWithRetryFeature_ShouldSucceed(string configuratio CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -76,7 +76,7 @@ public void RunMultipleTestProjectsWithNoTests_ShouldReturnExitCodeZeroTests(str CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -102,7 +102,7 @@ public void RunTestProjectWithTests_ShouldReturnExitCodeSuccess(string configura CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -132,7 +132,7 @@ public void RunTestProjectWithTestsAndLaunchSettings_ShouldReturnExitCodeSuccess CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -161,7 +161,7 @@ public void RunTestProjectWithTestsAndNoLaunchSettings_ShouldReturnExitCodeSucce CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute( - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration, + TestCommandDefinition.ConfigurationOption.Name, configuration, MicrosoftTestingPlatformOptions.NoLaunchProfileOption.Name); result.StdOut.Should() @@ -180,7 +180,7 @@ public void RunTestProjectWithTestsAndNoLaunchSettingsArguments_ShouldReturnExit CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute( - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration, + TestCommandDefinition.ConfigurationOption.Name, configuration, MicrosoftTestingPlatformOptions.NoLaunchProfileArgumentsOption.Name, "true"); result.StdOut.Should() @@ -199,7 +199,7 @@ public void RunMultipleTestProjectsWithFailingTests_ShouldReturnExitCodeAtLeastO CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -225,7 +225,7 @@ public void RunMultipleTestProjectsWithDifferentFailures_ShouldReturnExitCodeGen CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute("--minimum-expected-tests 2", - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -254,7 +254,7 @@ public void RunTestProjectsWithHybridModeTestRunners_ShouldReturnExitCodeGeneric CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -274,7 +274,7 @@ public void RunTestProjectsWithClassLibraryHavingIsTestProjectAndMTPProject_Shou CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -294,7 +294,7 @@ public void RunOnEmptyFolder_ShouldReturnExitCodeGenericFailure(string configura CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -314,7 +314,7 @@ public void RunOnMultipleProjectFoldersWithoutSolutionFile_ShouldReturnExitCodeG CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -334,7 +334,7 @@ public void RunOnProjectWithSolutionFile_ShouldReturnExitCodeGenericFailure(stri CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -355,8 +355,8 @@ public void RunOnProjectWithClassLibrary_ShouldReturnExitCodeSuccess( .WithSource(); string[] args = useFrameworkOption - ? new[] { MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration, MicrosoftTestingPlatformOptions.FrameworkOption.Name, ToolsetInfo.CurrentTargetFramework } - : new[] { MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration }; + ? new[] { TestCommandDefinition.ConfigurationOption.Name, configuration, TestCommandDefinition.FrameworkOption.Name, ToolsetInfo.CurrentTargetFramework } + : new[] { TestCommandDefinition.ConfigurationOption.Name, configuration }; CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) @@ -389,7 +389,7 @@ public void RunningWithGlobalPropertyShouldProperlyPropagate(string configuratio CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute( - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration, + TestCommandDefinition.ConfigurationOption.Name, configuration, CommonOptions.PropertiesOption.Name, "PROPERTY_TO_ENABLE_MTP=1"); if (!TestContext.IsLocalized()) @@ -488,7 +488,7 @@ public void RunTestProjectWithEnvVariable(string configuration) CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute( - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration, + TestCommandDefinition.ConfigurationOption.Name, configuration, CommonOptions.EnvOption.Name, "DUMMY_TEST_ENV_VAR=ENV_VAR_CMD_LINE"); if (!TestContext.IsLocalized()) diff --git a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestsForMultipleTFMs.cs b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestsForMultipleTFMs.cs index ee143e52bce3..5afb57f537ff 100644 --- a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestsForMultipleTFMs.cs +++ b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestsForMultipleTFMs.cs @@ -27,7 +27,7 @@ public void RunMultipleProjectWithDifferentTFMs_ShouldReturnExitCodeGenericFailu CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -67,7 +67,7 @@ public void RunProjectWithMultipleTFMs_ShouldReturnExitCodeGenericFailure(string CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -155,7 +155,7 @@ public void RunProjectWithMultipleTFMsWithArchOption_ShouldReturnExitCodeGeneric CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration, + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration, CommonOptions.ArchitectureOption.Name, arch); if (!TestContext.IsLocalized()) @@ -183,7 +183,7 @@ public void RunProjectWithMSTestMetaPackageAndMultipleTFMs_ShouldReturnExitCodeG CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { diff --git a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestsWithArtifacts.cs b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestsWithArtifacts.cs index 1677ca49276f..321d34f0ef48 100644 --- a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestsWithArtifacts.cs +++ b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestsWithArtifacts.cs @@ -23,7 +23,7 @@ public void RunTestProjectWithFailingTestsAndFileArtifacts_ShouldReturnExitCodeG CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -60,7 +60,7 @@ public void RunTestProjectWithCodeCoverage_ShouldReturnExitCodeGenericFailure(st CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute("--coverage", MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute("--coverage", TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { diff --git a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestsWithDifferentOptions.cs b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestsWithDifferentOptions.cs index 312f1c68ff90..7883e1f6e647 100644 --- a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestsWithDifferentOptions.cs +++ b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestsWithDifferentOptions.cs @@ -27,7 +27,7 @@ public void RunWithProjectPathWithFailingTests_ShouldReturnExitCodeGenericFailur CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(MicrosoftTestingPlatformOptions.ProjectOrSolutionOption.Name, testProjectPath, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); Regex.Matches(result.StdOut!, RegexPatternHelper.GenerateProjectRegexPattern("TestProject", true, configuration, "exec", addVersionAndArchPattern: false)); @@ -46,7 +46,7 @@ public void RunWithSolutionPathWithFailingTests_ShouldReturnExitCodeAtLeastOneTe CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(projectOrSolution, testSolutionPath, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); Assert.Matches(RegexPatternHelper.GenerateProjectRegexPattern("TestProject", TestingConstants.Failed, true, configuration), result.StdOut); Assert.Matches(RegexPatternHelper.GenerateProjectRegexPattern("OtherTestProject", TestingConstants.Passed, true, configuration), result.StdOut); @@ -66,7 +66,7 @@ public void RunWithSolutionFilterPathWithFailingTests_ShouldReturnExitCodeGeneri CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(projectOrSolution, testSolutionPath, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); Assert.Matches(RegexPatternHelper.GenerateProjectRegexPattern("TestProject", TestingConstants.Failed, true, configuration), result.StdOut); Assert.DoesNotMatch(RegexPatternHelper.GenerateProjectRegexPattern("OtherTestProject", TestingConstants.Passed, true, configuration), result.StdOut); @@ -83,7 +83,7 @@ public void RunWithSolutionFilterPathInOtherDirectory_ShouldReturnExitCodeGeneri CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory($"{testInstance.Path}{Path.DirectorySeparatorChar}SolutionFilter") - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); Assert.Matches(RegexPatternHelper.GenerateProjectRegexPattern("TestProject", TestingConstants.Failed, true, configuration), result.StdOut); Assert.DoesNotMatch(RegexPatternHelper.GenerateProjectRegexPattern("OtherTestProject", TestingConstants.Passed, true, configuration), result.StdOut); @@ -103,7 +103,7 @@ public void RunWithInvalidProjectExtension_ShouldReturnExitCodeGenericFailure(st CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(MicrosoftTestingPlatformOptions.ProjectOrSolutionOption.Name, invalidProjectPath, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); result.StdErr.Should().Contain(string.Format(CliCommandStrings.CmdInvalidProjectFileExtensionErrorDescription, invalidProjectPath)); @@ -122,7 +122,7 @@ public void RunWithDirectoryAsProjectOrSolutionOption_ShouldReturnExitCodeGeneri CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(MicrosoftTestingPlatformOptions.ProjectOrSolutionOption.Name, projectPath, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); // Validate that only TestProject ran Assert.Matches(RegexPatternHelper.GenerateProjectRegexPattern("TestProject", TestingConstants.Failed, true, configuration), result.StdOut); @@ -143,7 +143,7 @@ public void RunWithInvalidSolutionExtension_ShouldReturnExitCodeGenericFailure(s CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(MicrosoftTestingPlatformOptions.SolutionOption.Name, invalidSolutionPath, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); result.StdErr.Should().Contain(string.Format(CliCommandStrings.CmdInvalidSolutionFileExtensionErrorDescription, invalidSolutionPath)); @@ -164,7 +164,7 @@ public void RunWithBothProjectAndSolutionOptions_ShouldReturnExitCodeGenericFail .WithWorkingDirectory(testInstance.Path) .Execute(MicrosoftTestingPlatformOptions.ProjectOrSolutionOption.Name, testProjectPath, MicrosoftTestingPlatformOptions.SolutionOption.Name, testSolutionPath, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); result.StdErr.Should().Contain(CliCommandStrings.CmdMultipleBuildPathOptionsErrorDescription); @@ -183,7 +183,7 @@ public void RunWithNonExistentProjectPath_ShouldReturnExitCodeGenericFailure(str CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(MicrosoftTestingPlatformOptions.ProjectOrSolutionOption.Name, testProjectPath, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); string fullProjectPath = $"{testInstance.TestRoot}{Path.DirectorySeparatorChar}{testProjectPath}"; result.StdErr.Should().Contain(string.Format(CliCommandStrings.CmdNonExistentFileErrorDescription, fullProjectPath)); @@ -203,7 +203,7 @@ public void RunWithNonExistentSolutionPath_ShouldReturnExitCodeGenericFailure(st CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(MicrosoftTestingPlatformOptions.SolutionOption.Name, solutionPath, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); string fullSolutionPath = $"{testInstance.TestRoot}{Path.DirectorySeparatorChar}{solutionPath}"; result.StdErr.Should().Contain(string.Format(CliCommandStrings.CmdNonExistentFileErrorDescription, fullSolutionPath)); @@ -222,7 +222,7 @@ public void RunTestProjectWithArchOption_ShouldReturnExitCodeSuccess(string conf CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(CommonOptions.ArchitectureOption.Name, arch, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); string runtime = CommonOptions.ResolveRidShorthandOptionsToRuntimeIdentifier(string.Empty, arch); @@ -242,7 +242,7 @@ public void RunTestProjectSolutionWithArchOption_NotSupported(string configurati CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(CommonOptions.ArchitectureOption.Name, arch, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -270,7 +270,7 @@ public void RunTestProjectSolutionWithRuntimeOption_ShouldReturnExitCodeSuccess( CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(CommonOptions.RuntimeOptionName, runtime, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); Assert.Matches(RegexPatternHelper.GenerateProjectRegexPattern("TestProject", TestingConstants.Passed, true, configuration, runtime: runtime), result.StdOut); @@ -291,7 +291,7 @@ public void RunTestProjectSolutionWithArchAndRuntimeOptions_ShouldReturnExitCode .WithWorkingDirectory(testInstance.Path) .Execute(CommonOptions.RuntimeOptionName, runtime, CommonOptions.ArchitectureOption.Name, arch, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); result.ExitCode.Should().Be(ExitCodes.GenericFailure); } @@ -308,7 +308,7 @@ public void RunTestProjectSolutionWithOSOption_ShouldReturnExitCodeSuccess(strin CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(CommonOptions.OperatingSystemOption.Name, runtime.Split('-')[0], - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); Assert.Matches(RegexPatternHelper.GenerateProjectRegexPattern("TestProject", TestingConstants.Passed, true, configuration, runtime: runtime), result.StdOut); @@ -329,7 +329,7 @@ public void RunTestProjectSolutionWithArchAndOSOptions_ShouldReturnExitCodeSucce .WithWorkingDirectory(testInstance.Path) .Execute(CommonOptions.OperatingSystemOption.Name, runtime.Split('-')[0], CommonOptions.ArchitectureOption.Name, arch, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); Assert.Matches(RegexPatternHelper.GenerateProjectRegexPattern("TestProject", TestingConstants.Passed, true, configuration, runtime: runtime), result.StdOut); @@ -353,7 +353,7 @@ public void RunSpecificCSProjRunsWithNoBuildAndNoRestoreOptions_ShouldReturnExit CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(MicrosoftTestingPlatformOptions.ProjectOrSolutionOption.Name, "TestProject.csproj", - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration, + TestCommandDefinition.ConfigurationOption.Name, configuration, CommonOptions.NoRestoreOption.Name, MicrosoftTestingPlatformOptions.NoBuildOption.Name); @@ -372,7 +372,7 @@ public void RunTestProjectSolutionWithBinLogOption_ShouldReturnExitCodeSuccess(s CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute("-bl", MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute("-bl", TestCommandDefinition.ConfigurationOption.Name, configuration); Assert.True(File.Exists(string.Format("{0}{1}{2}", testInstance.TestRoot, Path.DirectorySeparatorChar, CliConstants.BinLogFileName))); @@ -389,7 +389,7 @@ public void RunSpecificCSProjRunsWithMSBuildArgs_ShouldReturnExitCodeSuccess(str CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(MicrosoftTestingPlatformOptions.ProjectOrSolutionOption.Name, "TestProject.csproj", - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration, + TestCommandDefinition.ConfigurationOption.Name, configuration, "--property:WarningLevel=2", $"--property:Configuration={configuration}"); if (!TestContext.IsLocalized()) @@ -414,7 +414,7 @@ public void RunOnSolutionWithMSBuildArgs_ShouldReturnExitCodeGenericFailure(stri CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration, + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration, "--property:WarningLevel=2"); if (!TestContext.IsLocalized()) @@ -439,8 +439,8 @@ public void RunTestProjectSolutionWithFrameworkOption_ShouldReturnExitCodeSucces CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.FrameworkOption.Name, ToolsetInfo.CurrentTargetFramework, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.FrameworkOption.Name, ToolsetInfo.CurrentTargetFramework, + TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -473,8 +473,8 @@ public void RunMultiTFMsProjectSolutionWithPreviousFramework_ShouldReturnExitCod // Restore then fails for OtherTestProject, and we run nothing. CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.FrameworkOption.Name, DotnetVersionHelper.GetPreviousDotnetVersion(), - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.FrameworkOption.Name, DotnetVersionHelper.GetPreviousDotnetVersion(), + TestCommandDefinition.ConfigurationOption.Name, configuration); // Output looks similar to the following /* @@ -511,8 +511,8 @@ public void RunMultiTFMsProjectSolutionWithCurrentFramework_ShouldReturnExitCode // In total, 2 passing, 2 skipped, 4 failing CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.FrameworkOption.Name, ToolsetInfo.CurrentTargetFramework, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.FrameworkOption.Name, ToolsetInfo.CurrentTargetFramework, + TestCommandDefinition.ConfigurationOption.Name, configuration); if (!TestContext.IsLocalized()) { @@ -542,7 +542,7 @@ public void RunWithTraceFileLogging_ShouldReturnExitCodeGenericFailure(string co CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .WithEnvironmentVariable(CliConstants.TestTraceLoggingEnvVar, traceFile) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); Assert.True(File.Exists(Path.Combine(testInstance.Path, traceFile)), "Trace file should exist after test execution."); @@ -560,7 +560,7 @@ public void RunWithTraceFileLoggingAndNonExistingDirectory_ShouldReturnExitCodeG CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .WithEnvironmentVariable(CliConstants.TestTraceLoggingEnvVar, traceFile) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); Assert.True(File.Exists(Path.Combine(testInstance.Path, traceFile)), "Trace file should exist after test execution."); @@ -579,7 +579,7 @@ public void RunWithSolutionFilterContainingSharedProject_ShouldSkipSharedProject CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(MicrosoftTestingPlatformOptions.SolutionOption.Name, testSolutionFilterPath, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + TestCommandDefinition.ConfigurationOption.Name, configuration); // Validate that TestProject ran (shared project should be skipped automatically) result.StdOut.Should().Contain("TestProject.dll"); @@ -602,7 +602,7 @@ public void RunWithSolutionAndPlatformConfiguration_ShouldRespectPlatform(string CommandResult resultX86 = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(MicrosoftTestingPlatformOptions.SolutionOption.Name, testSolutionPath, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration, + TestCommandDefinition.ConfigurationOption.Name, configuration, "--property:Platform=NonWindows"); // Validate that TestProject ran but OtherTestProject did not (not marked for build on x86) @@ -615,7 +615,7 @@ public void RunWithSolutionAndPlatformConfiguration_ShouldRespectPlatform(string CommandResult resultX64 = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) .Execute(MicrosoftTestingPlatformOptions.SolutionOption.Name, testSolutionPath, - MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration, + TestCommandDefinition.ConfigurationOption.Name, configuration, "--property:Platform=x64"); // Validate that both TestProject and OtherTestProject ran diff --git a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestRunsConsoleAppWithoutHandshake.cs b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestRunsConsoleAppWithoutHandshake.cs index be317b4d5ed4..239c7dd76273 100644 --- a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestRunsConsoleAppWithoutHandshake.cs +++ b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestRunsConsoleAppWithoutHandshake.cs @@ -25,9 +25,9 @@ public void RunConsoleAppDoesNothing_ShouldReturnCorrectExitCode(string configur CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) .WithWorkingDirectory(testInstance.Path) - .Execute(MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration); + .Execute(TestCommandDefinition.ConfigurationOption.Name, configuration); result.ExitCode.Should().Be(ExitCodes.GenericFailure, "dotnet test should fail with a meaningful error when run against console app without MTP handshake"); } } -} \ No newline at end of file +} diff --git a/test/dotnet.Tests/CommandTests/Test/TestCommandParserTests.cs b/test/dotnet.Tests/CommandTests/Test/TestCommandParserTests.cs index c6339a66369f..f566d659d2c6 100644 --- a/test/dotnet.Tests/CommandTests/Test/TestCommandParserTests.cs +++ b/test/dotnet.Tests/CommandTests/Test/TestCommandParserTests.cs @@ -13,7 +13,7 @@ public class TestCommandDefinitionTests public void SurroundWithDoubleQuotesWithNullThrows() { Assert.Throws(() => - TestCommandDefinition.SurroundWithDoubleQuotes(null!)); + VSTestOptions.SurroundWithDoubleQuotes(null!)); } [Theory] @@ -23,7 +23,7 @@ public void SurroundWithDoubleQuotesWithNullThrows() public void SurroundWithDoubleQuotesWhenAlreadySurroundedDoesNothing(string input) { var escapedInput = "\"" + input + "\""; - var result = TestCommandDefinition.SurroundWithDoubleQuotes(escapedInput); + var result = VSTestOptions.SurroundWithDoubleQuotes(escapedInput); result.Should().Be(escapedInput); } @@ -35,7 +35,7 @@ public void SurroundWithDoubleQuotesWhenAlreadySurroundedDoesNothing(string inpu [InlineData("a\"")] public void SurroundWithDoubleQuotesWhenNotSurroundedSurrounds(string input) { - var result = TestCommandDefinition.SurroundWithDoubleQuotes(input); + var result = VSTestOptions.SurroundWithDoubleQuotes(input); result.Should().Be("\"" + input + "\""); } @@ -46,7 +46,7 @@ public void SurroundWithDoubleQuotesWhenNotSurroundedSurrounds(string input) [InlineData("/\\/\\/\\\\")] public void SurroundWithDoubleQuotesHandlesCorrectlyEvenCountOfTrailingBackslashes(string input) { - var result = TestCommandDefinition.SurroundWithDoubleQuotes(input); + var result = VSTestOptions.SurroundWithDoubleQuotes(input); result.Should().Be("\"" + input + "\""); } @@ -57,14 +57,14 @@ public void SurroundWithDoubleQuotesHandlesCorrectlyEvenCountOfTrailingBackslash [InlineData("/\\/\\/\\")] public void SurroundWithDoubleQuotesHandlesCorrectlyOddCountOfTrailingBackslashes(string input) { - var result = TestCommandDefinition.SurroundWithDoubleQuotes(input); + var result = VSTestOptions.SurroundWithDoubleQuotes(input); result.Should().Be("\"" + input + "\\\""); } [Fact] public void VSTestCommandIncludesPropertiesOption() { - var command = TestCommandDefinition.Create(); + var command = TestCommandParser.GetCommand(); // Verify that the command includes a property option that supports the /p alias var propertyOption = command.Options.FirstOrDefault(o => From 22c641bcb497155010ff6bb143f9c97f75840852 Mon Sep 17 00:00:00 2001 From: Andy Zivkovic Date: Thu, 27 Nov 2025 09:27:16 +1030 Subject: [PATCH 3/3] Upgrade Spectre.Console to version 0.54.0 --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index b2bb43864d8d..1a83625bdc29 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -114,7 +114,7 @@ - +