diff --git a/src/Microsoft.TestPlatform.Build/ArgumentEscaper.cs b/src/Microsoft.TestPlatform.Build/ArgumentEscaper.cs deleted file mode 100644 index 8d9f22b6b5..0000000000 --- a/src/Microsoft.TestPlatform.Build/ArgumentEscaper.cs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Text; - -namespace Microsoft.TestPlatform.Build.Utils; - -public static class ArgumentEscaper -{ - /// - /// Undo the processing which took place to create string[] args in Main, - /// so that the next process will receive the same string[] args - /// - /// See here for more info: - /// http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx - /// - /// - /// Return original string passed by client - public static string HandleEscapeSequenceInArgForProcessStart(string arg) - { - var sb = new StringBuilder(); - - var needsQuotes = ShouldSurroundWithQuotes(arg); - var isQuoted = needsQuotes || IsSurroundedWithQuotes(arg); - - if (needsQuotes) - { - sb.Append('\"'); - } - - for (int i = 0; i < arg.Length; ++i) - { - var backslashCount = 0; - - // Consume All Backslashes - while (i < arg.Length && arg[i] == '\\') - { - backslashCount++; - i++; - } - - // Escape any backslashes at the end of the arg - // when the argument is also quoted. - // This ensures the outside quote is interpreted as - // an argument delimiter - if (i == arg.Length && isQuoted) - { - sb.Append('\\', 2 * backslashCount); - } - - // At then end of the arg, which isn't quoted, - // just add the backslashes, no need to escape - else if (i == arg.Length) - { - sb.Append('\\', backslashCount); - } - - // Escape any preceding backslashes and the quote - else if (arg[i] == '"') - { - sb.Append('\\', (2 * backslashCount) + 1); - sb.Append('"'); - } - - // Output any consumed backslashes and the character - else - { - sb.Append('\\', backslashCount); - sb.Append(arg[i]); - } - } - - if (needsQuotes) - { - sb.Append('\"'); - } - - return sb.ToString(); - } - - internal static bool ShouldSurroundWithQuotes(string argument) - { - // Don't quote already quoted strings - if (IsSurroundedWithQuotes(argument)) - { - return false; - } - - // Only quote if whitespace exists in the string - return ArgumentContainsWhitespace(argument); - } - - internal static bool IsSurroundedWithQuotes(string argument) - => argument.StartsWith("\"", StringComparison.Ordinal) - && argument.EndsWith("\"", StringComparison.Ordinal); - - internal static bool ArgumentContainsWhitespace(string argument) - => argument.Contains(" ") || argument.Contains("\t") || argument.Contains("\n"); -} diff --git a/src/Microsoft.TestPlatform.Build/Microsoft.TestPlatform.targets b/src/Microsoft.TestPlatform.Build/Microsoft.TestPlatform.targets index 7329157c46..6e639a1731 100644 --- a/src/Microsoft.TestPlatform.Build/Microsoft.TestPlatform.targets +++ b/src/Microsoft.TestPlatform.Build/Microsoft.TestPlatform.targets @@ -14,9 +14,12 @@ Copyright (c) .NET Foundation. All rights reserved. Microsoft.TestPlatform.Build.dll $([System.IO.Path]::Combine($(MSBuildThisFileDirectory),"vstest.console.dll")) + False + False + + + + + + + + + + + + + + + + - - + - + - + - + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/src/Microsoft.TestPlatform.Build/PublicAPI/PublicAPI.Unshipped.txt b/src/Microsoft.TestPlatform.Build/PublicAPI/PublicAPI.Unshipped.txt index 7c0e9679c9..5d3611c8d9 100644 --- a/src/Microsoft.TestPlatform.Build/PublicAPI/PublicAPI.Unshipped.txt +++ b/src/Microsoft.TestPlatform.Build/PublicAPI/PublicAPI.Unshipped.txt @@ -1,8 +1,4 @@ #nullable enable -Microsoft.TestPlatform.Build.Tasks.VSTestForwardingApp -Microsoft.TestPlatform.Build.Tasks.VSTestForwardingApp.Cancel() -> void -Microsoft.TestPlatform.Build.Tasks.VSTestForwardingApp.Execute() -> int -Microsoft.TestPlatform.Build.Tasks.VSTestForwardingApp.VSTestForwardingApp(string! vsTestExePath, System.Collections.Generic.IEnumerable! argsToForward) -> void Microsoft.TestPlatform.Build.Tasks.VSTestLogsTask Microsoft.TestPlatform.Build.Tasks.VSTestLogsTask.LogType.get -> string? Microsoft.TestPlatform.Build.Tasks.VSTestLogsTask.LogType.set -> void @@ -11,19 +7,19 @@ Microsoft.TestPlatform.Build.Tasks.VSTestLogsTask.ProjectFilePath.set -> void Microsoft.TestPlatform.Build.Tasks.VSTestLogsTask.VSTestLogsTask() -> void Microsoft.TestPlatform.Build.Tasks.VSTestTask Microsoft.TestPlatform.Build.Tasks.VSTestTask.Cancel() -> void -Microsoft.TestPlatform.Build.Tasks.VSTestTask.TestFileFullPath.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask.TestFileFullPath.get -> Microsoft.Build.Framework.ITaskItem? Microsoft.TestPlatform.Build.Tasks.VSTestTask.TestFileFullPath.set -> void Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestArtifactsProcessingMode.get -> string? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestArtifactsProcessingMode.set -> void -Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlame.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlame.get -> bool Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlame.set -> void -Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlameCrash.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlameCrash.get -> bool Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlameCrash.set -> void -Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlameCrashCollectAlways.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlameCrashCollectAlways.get -> bool Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlameCrashCollectAlways.set -> void Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlameCrashDumpType.get -> string? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlameCrashDumpType.set -> void -Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlameHang.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlameHang.get -> bool Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlameHang.set -> void Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlameHangDumpType.get -> string? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestBlameHangDumpType.set -> void @@ -33,39 +29,93 @@ Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestCLIRunSettings.get -> string Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestCLIRunSettings.set -> void Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestCollect.get -> string![]? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestCollect.set -> void -Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestConsolePath.get -> string! +Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestConsolePath.get -> Microsoft.Build.Framework.ITaskItem? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestConsolePath.set -> void Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestDiag.get -> string? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestDiag.set -> void Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestFramework.get -> string? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestFramework.set -> void -Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestListTests.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestListTests.get -> bool Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestListTests.set -> void Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestLogger.get -> string![]? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestLogger.set -> void -Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestNoLogo.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestNoLogo.get -> bool Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestNoLogo.set -> void Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestPlatform.get -> string? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestPlatform.set -> void -Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestResultsDirectory.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestResultsDirectory.get -> Microsoft.Build.Framework.ITaskItem? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestResultsDirectory.set -> void Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestSessionCorrelationId.get -> string? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestSessionCorrelationId.set -> void Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestSetting.get -> string? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestSetting.set -> void Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestTask() -> void -Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestTestAdapterPath.get -> string![]? +Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestTestAdapterPath.get -> Microsoft.Build.Framework.ITaskItem![]? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestTestAdapterPath.set -> void Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestTestCaseFilter.get -> string? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestTestCaseFilter.set -> void -Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestTraceDataCollectorDirectoryPath.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestTraceDataCollectorDirectoryPath.get -> Microsoft.Build.Framework.ITaskItem? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestTraceDataCollectorDirectoryPath.set -> void Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestVerbosity.get -> string? Microsoft.TestPlatform.Build.Tasks.VSTestTask.VSTestVerbosity.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2 +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.TestFileFullPath.get -> Microsoft.Build.Framework.ITaskItem? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.TestFileFullPath.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestArtifactsProcessingMode.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestArtifactsProcessingMode.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestBlame.get -> bool +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestBlame.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestBlameCrash.get -> bool +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestBlameCrash.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestBlameCrashCollectAlways.get -> bool +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestBlameCrashCollectAlways.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestBlameCrashDumpType.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestBlameCrashDumpType.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestBlameHang.get -> bool +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestBlameHang.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestBlameHangDumpType.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestBlameHangDumpType.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestBlameHangTimeout.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestBlameHangTimeout.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestCLIRunSettings.get -> string![]? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestCLIRunSettings.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestCollect.get -> string![]? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestCollect.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestConsolePath.get -> Microsoft.Build.Framework.ITaskItem? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestConsolePath.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestDiag.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestDiag.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestFramework.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestFramework.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestListTests.get -> bool +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestListTests.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestLogger.get -> string![]? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestLogger.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestNoLogo.get -> bool +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestNoLogo.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestPlatform.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestPlatform.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestResultsDirectory.get -> Microsoft.Build.Framework.ITaskItem? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestResultsDirectory.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestSessionCorrelationId.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestSessionCorrelationId.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestSetting.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestSetting.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestTask2() -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestTestAdapterPath.get -> Microsoft.Build.Framework.ITaskItem![]? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestTestAdapterPath.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestTestCaseFilter.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestTestCaseFilter.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestTraceDataCollectorDirectoryPath.get -> Microsoft.Build.Framework.ITaskItem? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestTraceDataCollectorDirectoryPath.set -> void +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestVerbosity.get -> string? +Microsoft.TestPlatform.Build.Tasks.VSTestTask2.VSTestVerbosity.set -> void Microsoft.TestPlatform.Build.Trace.Tracing -Microsoft.TestPlatform.Build.Utils.ArgumentEscaper override Microsoft.TestPlatform.Build.Tasks.VSTestLogsTask.Execute() -> bool override Microsoft.TestPlatform.Build.Tasks.VSTestTask.Execute() -> bool +override Microsoft.TestPlatform.Build.Tasks.VSTestTask2.GenerateCommandLineCommands() -> string? +override Microsoft.TestPlatform.Build.Tasks.VSTestTask2.GenerateFullPathToTool() -> string? +override Microsoft.TestPlatform.Build.Tasks.VSTestTask2.LogEventsFromTextOutput(string! singleLine, Microsoft.Build.Framework.MessageImportance messageImportance) -> void +override Microsoft.TestPlatform.Build.Tasks.VSTestTask2.ToolName.get -> string? static Microsoft.TestPlatform.Build.Trace.Tracing.Trace(string! message) -> void static Microsoft.TestPlatform.Build.Trace.Tracing.traceEnabled -> bool -static Microsoft.TestPlatform.Build.Utils.ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(string! arg) -> string! diff --git a/src/Microsoft.TestPlatform.Build/Resources/Resources.Designer.cs b/src/Microsoft.TestPlatform.Build/Resources/Resources.Designer.cs index 689e046619..6800dc697a 100644 --- a/src/Microsoft.TestPlatform.Build/Resources/Resources.Designer.cs +++ b/src/Microsoft.TestPlatform.Build/Resources/Resources.Designer.cs @@ -10,7 +10,6 @@ namespace Microsoft.TestPlatform.Build.Resources { using System; - using System.Reflection; /// @@ -20,7 +19,7 @@ namespace Microsoft.TestPlatform.Build.Resources { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -40,7 +39,7 @@ internal Resources() { internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.TestPlatform.Build.Resources.Resources", typeof(Resources).GetTypeInfo().Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.TestPlatform.Build.Resources.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; @@ -89,7 +88,16 @@ internal static string NoIsTestProjectProperty { } /// - /// Looks up a localized string similar to Test run for {0}({1}). + /// Looks up a localized string similar to Test file path cannot be empty or null.. + /// + internal static string TestFilePathCannotBeEmptyOrNull { + get { + return ResourceManager.GetString("TestFilePathCannotBeEmptyOrNull", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Test run for {0} ({1}). /// internal static string TestRunningSummary { get { diff --git a/src/Microsoft.TestPlatform.Build/Resources/Resources.resx b/src/Microsoft.TestPlatform.Build/Resources/Resources.resx index e3277bc036..ff08e2a3bf 100644 --- a/src/Microsoft.TestPlatform.Build/Resources/Resources.resx +++ b/src/Microsoft.TestPlatform.Build/Resources/Resources.resx @@ -126,6 +126,9 @@ Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. + + Test file path cannot be empty or null. + Test run for {0} ({1}) diff --git a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.cs.xlf b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.cs.xlf index b74c6a609b..879716f63d 100644 --- a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.cs.xlf +++ b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.cs.xlf @@ -1,32 +1,37 @@ - - - - - - Build completed. - Sestavení bylo dokončeno. - - - - Build started, please wait... - Začalo sestavování. Počkejte prosím... - - - - Test run for {0} ({1}) - Testovací běh pro {0} ({1}) - - - - Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. - Upozornění: Aktualizujte odkaz na balíček Microsoft.NET.Test.Sdk na verzi 15.8.0 nebo novější, aby se získalo pokrytí kódu. - - - - Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. - Přeskakuje se spuštění testu pro projekt {0}. Pokud chcete spustit testy pomocí příkazu dotnet test, přidejte do souboru projektu vlastnost <IsTestProject>true</IsTestProject>. - - - - + + + + + + Build completed. + Sestavení bylo dokončeno. + + + + Build started, please wait... + Začalo sestavování. Počkejte prosím... + + + + Test file path cannot be empty or null. + Test file path cannot be empty or null. + + + + Test run for {0} ({1}) + Testovací běh pro {0} ({1}) + + + + Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. + Upozornění: Aktualizujte odkaz na balíček Microsoft.NET.Test.Sdk na verzi 15.8.0 nebo novější, aby se získalo pokrytí kódu. + + + + Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. + Přeskakuje se spuštění testu pro projekt {0}. Pokud chcete spustit testy pomocí příkazu dotnet test, přidejte do souboru projektu vlastnost <IsTestProject>true</IsTestProject>. + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.de.xlf b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.de.xlf index 097000b274..0ca2507fb9 100644 --- a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.de.xlf +++ b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.de.xlf @@ -1,32 +1,37 @@ - - - - - - Build completed. - Buildvorgang abgeschlossen. - - - - Build started, please wait... - Buildvorgang gestartet, bitte warten... - - - - Test run for {0} ({1}) - Testlauf für "{0}" ({1}) - - - - Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. - Warnung: Aktualisieren Sie die Microsoft.NET.Test.Sdk-Paketreferenz auf Version 15.8.0 oder höher, um von Code Coverage zu profitieren. - - - - Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. - Die Ausführung des Tests für das Projekt "{0}" wird übersprungen. Um Tests mit "dotnet test" auszuführen, fügen Sie der Projektdatei die Eigenschaft <IsTestProject>true</IsTestProject> hinzu. - - - - + + + + + + Build completed. + Buildvorgang abgeschlossen. + + + + Build started, please wait... + Buildvorgang gestartet, bitte warten... + + + + Test file path cannot be empty or null. + Test file path cannot be empty or null. + + + + Test run for {0} ({1}) + Testlauf für "{0}" ({1}) + + + + Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. + Warnung: Aktualisieren Sie die Microsoft.NET.Test.Sdk-Paketreferenz auf Version 15.8.0 oder höher, um von Code Coverage zu profitieren. + + + + Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. + Die Ausführung des Tests für das Projekt "{0}" wird übersprungen. Um Tests mit "dotnet test" auszuführen, fügen Sie der Projektdatei die Eigenschaft <IsTestProject>true</IsTestProject> hinzu. + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.es.xlf b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.es.xlf index 663b65b466..c9cea130b0 100644 --- a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.es.xlf +++ b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.es.xlf @@ -1,32 +1,37 @@ - - - - - - Build completed. - Se completó la compilación. - - - - Build started, please wait... - Compilación iniciada, espere... - - - - Test run for {0} ({1}) - Serie de pruebas para {0} ({1}) - - - - Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. - Advertencia: Actualice la referencia del paquete Microsoft.NET.Test.Sdk a la versión 15.8.0 o posterior para recopilar la cobertura de código. - - - - Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. - Omitiendo la ejecución de la prueba para el proyecto {0}. Para ejecutar pruebas con dotnet test, agregue la propiedad "<IsTestProject>true</IsTestProject>" al archivo del proyecto. - - - - + + + + + + Build completed. + Se completó la compilación. + + + + Build started, please wait... + Compilación iniciada, espere... + + + + Test file path cannot be empty or null. + Test file path cannot be empty or null. + + + + Test run for {0} ({1}) + Serie de pruebas para {0} ({1}) + + + + Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. + Advertencia: Actualice la referencia del paquete Microsoft.NET.Test.Sdk a la versión 15.8.0 o posterior para recopilar la cobertura de código. + + + + Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. + Omitiendo la ejecución de la prueba para el proyecto {0}. Para ejecutar pruebas con dotnet test, agregue la propiedad "<IsTestProject>true</IsTestProject>" al archivo del proyecto. + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.fr.xlf b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.fr.xlf index b8f5761abf..74d554987b 100644 --- a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.fr.xlf +++ b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.fr.xlf @@ -1,32 +1,37 @@ - - - - - - Build completed. - Fin de la build. - - - - Build started, please wait... - La build a démarré. Patientez… - - - - Test run for {0} ({1}) - Série de tests pour {0} ({1}) - - - - Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. - Avertissement : mettez à jour la référence de package Microsoft.NET.Test.Sdk vers la version 15.8.0 ou ultérieure pour collecter la couverture du code. - - - - Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. - Le test en cours d'exécution est ignoré pour le projet {0}. Pour exécuter des tests avec dotnet test, ajoutez la propriété "<IsTestProject>true</IsTestProject>" au fichier projet. - - - - + + + + + + Build completed. + Fin de la build. + + + + Build started, please wait... + La build a démarré. Patientez… + + + + Test file path cannot be empty or null. + Test file path cannot be empty or null. + + + + Test run for {0} ({1}) + Série de tests pour {0} ({1}) + + + + Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. + Avertissement : mettez à jour la référence de package Microsoft.NET.Test.Sdk vers la version 15.8.0 ou ultérieure pour collecter la couverture du code. + + + + Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. + Le test en cours d'exécution est ignoré pour le projet {0}. Pour exécuter des tests avec dotnet test, ajoutez la propriété "<IsTestProject>true</IsTestProject>" au fichier projet. + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.it.xlf b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.it.xlf index 6c707ff8d9..f4ce72fd43 100644 --- a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.it.xlf +++ b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.it.xlf @@ -1,32 +1,37 @@ - - - - - - Build completed. - Compilazione completata. - - - - Build started, please wait... - Compilazione avviata. Attendere... - - - - Test run for {0} ({1}) - Esecuzione dei test per {0} ({1}) - - - - Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. - Avviso: per raccogliere i dati di code coverage, aggiornare il riferimento al pacchetto Microsoft.NET.Test.Sdk alla versione 15.8.0 o successiva. - - - - Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. - L'esecuzione del test per il progetto {0} verrà ignorata. Per eseguire test con dotnet test, aggiungere la proprietà "<IsTestProject>true</IsTestProject>" al file di progetto. - - - - + + + + + + Build completed. + Compilazione completata. + + + + Build started, please wait... + Compilazione avviata. Attendere... + + + + Test file path cannot be empty or null. + Test file path cannot be empty or null. + + + + Test run for {0} ({1}) + Esecuzione dei test per {0} ({1}) + + + + Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. + Avviso: per raccogliere i dati di code coverage, aggiornare il riferimento al pacchetto Microsoft.NET.Test.Sdk alla versione 15.8.0 o successiva. + + + + Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. + L'esecuzione del test per il progetto {0} verrà ignorata. Per eseguire test con dotnet test, aggiungere la proprietà "<IsTestProject>true</IsTestProject>" al file di progetto. + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.ja.xlf b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.ja.xlf index 17beb21646..dd12070d45 100644 --- a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.ja.xlf +++ b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.ja.xlf @@ -1,32 +1,37 @@ - - - - - - Build completed. - ビルドが完了しました。 - - - - Build started, please wait... - ビルドが開始されました。しばらくお待ちください... - - - - Test run for {0} ({1}) - {0} ({1}) のテスト実行 - - - - Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. - 警告: コード カバレッジを収集するには、Microsoft.NET.Test.Sdk パッケージ参照をバージョン 15.8.0 以降に更新してください。 - - - - Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. - プロジェクト {0} へのテストの実行をスキップしています。dotnet テストでテストを実行するには、"<IsTestProject>true</IsTestProject>" プロパティをプロジェクト ファイルに追加します。 - - - - + + + + + + Build completed. + ビルドが完了しました。 + + + + Build started, please wait... + ビルドが開始されました。しばらくお待ちください... + + + + Test file path cannot be empty or null. + Test file path cannot be empty or null. + + + + Test run for {0} ({1}) + {0} ({1}) のテスト実行 + + + + Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. + 警告: コード カバレッジを収集するには、Microsoft.NET.Test.Sdk パッケージ参照をバージョン 15.8.0 以降に更新してください。 + + + + Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. + プロジェクト {0} へのテストの実行をスキップしています。dotnet テストでテストを実行するには、"<IsTestProject>true</IsTestProject>" プロパティをプロジェクト ファイルに追加します。 + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.ko.xlf b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.ko.xlf index 83ae74691e..9068a8fc2b 100644 --- a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.ko.xlf +++ b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.ko.xlf @@ -1,32 +1,37 @@ - - - - - - Build completed. - 빌드가 완료되었습니다. - - - - Build started, please wait... - 빌드가 시작되었습니다. 잠시 기다려 주세요. - - - - Test run for {0} ({1}) - {0}({1})에 대한 테스트 실행 - - - - Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. - 경고: 코드 검사를 수집하려면 Microsoft.NET.Test.Sdk 패키지 참조를 버전 15.8.0 이상으로 업데이트하세요. - - - - Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. - 프로젝트 {0}에 대한 테스트 실행을 건너뜁니다. dotnet 테스트와 함께 테스트를 실행하려면 "<IsTestProject>true</IsTestProject>" 속성을 프로젝트 파일에 추가합니다. - - - - + + + + + + Build completed. + 빌드가 완료되었습니다. + + + + Build started, please wait... + 빌드가 시작되었습니다. 잠시 기다려 주세요. + + + + Test file path cannot be empty or null. + Test file path cannot be empty or null. + + + + Test run for {0} ({1}) + {0}({1})에 대한 테스트 실행 + + + + Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. + 경고: 코드 검사를 수집하려면 Microsoft.NET.Test.Sdk 패키지 참조를 버전 15.8.0 이상으로 업데이트하세요. + + + + Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. + 프로젝트 {0}에 대한 테스트 실행을 건너뜁니다. dotnet 테스트와 함께 테스트를 실행하려면 "<IsTestProject>true</IsTestProject>" 속성을 프로젝트 파일에 추가합니다. + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.pl.xlf b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.pl.xlf index 48f474faf4..37c042f7eb 100644 --- a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.pl.xlf +++ b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.pl.xlf @@ -1,32 +1,37 @@ - - - - - - Build completed. - Kompilacja zakończona. - - - - Build started, please wait... - Kompilacja została rozpoczęta, czekaj... - - - - Test run for {0} ({1}) - Przebieg testu dla: {0} ({1}) - - - - Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. - Ostrzeżenie: zaktualizuj odwołanie do pakietu Microsoft.NET.Test.Sdk do wersji 15.8.0 lub nowszej w celu zbierania danych dotyczących pokrycia kodu. - - - - Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. - Pomijanie uruchamiania testu dla projektu {0}. Aby uruchomić testy za pomocą polecenia dotnet test, dodaj właściwość „<IsTestProject>true</IsTestProject>” do pliku projektu. - - - - + + + + + + Build completed. + Kompilacja zakończona. + + + + Build started, please wait... + Kompilacja została rozpoczęta, czekaj... + + + + Test file path cannot be empty or null. + Test file path cannot be empty or null. + + + + Test run for {0} ({1}) + Przebieg testu dla: {0} ({1}) + + + + Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. + Ostrzeżenie: zaktualizuj odwołanie do pakietu Microsoft.NET.Test.Sdk do wersji 15.8.0 lub nowszej w celu zbierania danych dotyczących pokrycia kodu. + + + + Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. + Pomijanie uruchamiania testu dla projektu {0}. Aby uruchomić testy za pomocą polecenia dotnet test, dodaj właściwość „<IsTestProject>true</IsTestProject>” do pliku projektu. + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.pt-BR.xlf b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.pt-BR.xlf index 1fbecc2281..2756f1e9e1 100644 --- a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.pt-BR.xlf +++ b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.pt-BR.xlf @@ -1,32 +1,37 @@ - - - - - - Build completed. - Build concluído. - - - - Build started, please wait... - Build iniciada, aguarde... - - - - Test run for {0} ({1}) - Execução de teste para {0} ({1}) - - - - Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. - Aviso: Atualize a referência do pacote Microsoft.NET.Test.Sdk para a versão 15.8.0 ou posterior para coletar a cobertura do código. - - - - Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. - Ignorando a execução de teste do projeto {0}. Para executar testes com dotnet test, adicione a propriedade "<IsTestProject>true</IsTestProject>" ao arquivo de projeto. - - - - + + + + + + Build completed. + Build concluído. + + + + Build started, please wait... + Build iniciada, aguarde... + + + + Test file path cannot be empty or null. + Test file path cannot be empty or null. + + + + Test run for {0} ({1}) + Execução de teste para {0} ({1}) + + + + Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. + Aviso: Atualize a referência do pacote Microsoft.NET.Test.Sdk para a versão 15.8.0 ou posterior para coletar a cobertura do código. + + + + Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. + Ignorando a execução de teste do projeto {0}. Para executar testes com dotnet test, adicione a propriedade "<IsTestProject>true</IsTestProject>" ao arquivo de projeto. + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.ru.xlf b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.ru.xlf index 754035a805..81366e3f52 100644 --- a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.ru.xlf +++ b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.ru.xlf @@ -1,32 +1,37 @@ - - - - - - Build completed. - Сборка выполнена. - - - - Build started, please wait... - Сборка начата, подождите... - - - - Test run for {0} ({1}) - Тестовый запуск для {0} ({1}) - - - - Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. - Внимание. Для сбора данных об объеме протестированного кода обновите пакет Microsoft.NET.Test.Sdk по ссылке как минимум до версии 15.8.0. - - - - Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. - Пропуск выполнения теста для проекта {0}. Чтобы выполнить тесты с помощью теста dotnet, добавьте свойство "<IsTestProject>true</IsTestProject>" в файл проекта. - - - - + + + + + + Build completed. + Сборка выполнена. + + + + Build started, please wait... + Сборка начата, подождите... + + + + Test file path cannot be empty or null. + Test file path cannot be empty or null. + + + + Test run for {0} ({1}) + Тестовый запуск для {0} ({1}) + + + + Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. + Внимание. Для сбора данных об объеме протестированного кода обновите пакет Microsoft.NET.Test.Sdk по ссылке как минимум до версии 15.8.0. + + + + Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. + Пропуск выполнения теста для проекта {0}. Чтобы выполнить тесты с помощью теста dotnet, добавьте свойство "<IsTestProject>true</IsTestProject>" в файл проекта. + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.tr.xlf b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.tr.xlf index 497bf2b840..413bcec06e 100644 --- a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.tr.xlf +++ b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.tr.xlf @@ -1,32 +1,37 @@ - - - - - - Build completed. - Derleme tamamlandı. - - - - Build started, please wait... - Derleme başlatıldı. Lütfen bekleyin... - - - - Test run for {0} ({1}) - {0} ({1}) için test çalıştırması - - - - Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. - Uyarı: Kod kapsamını toplamak için Microsoft.NET.Test.Sdk paketinin başvurusunu 15.8.0 veya üzeri bir sürüme güncelleştirin. - - - - Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. - {0} projesi için test çalıştırma atlanıyor. Testleri dotnet test ile çalıştırmak için proje dosyasına "<IsTestProject>true</IsTestProject>" özelliğini ekleyin. - - - - + + + + + + Build completed. + Derleme tamamlandı. + + + + Build started, please wait... + Derleme başlatıldı. Lütfen bekleyin... + + + + Test file path cannot be empty or null. + Test file path cannot be empty or null. + + + + Test run for {0} ({1}) + {0} ({1}) için test çalıştırması + + + + Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. + Uyarı: Kod kapsamını toplamak için Microsoft.NET.Test.Sdk paketinin başvurusunu 15.8.0 veya üzeri bir sürüme güncelleştirin. + + + + Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. + {0} projesi için test çalıştırma atlanıyor. Testleri dotnet test ile çalıştırmak için proje dosyasına "<IsTestProject>true</IsTestProject>" özelliğini ekleyin. + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.zh-Hans.xlf b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.zh-Hans.xlf index f853215269..924e973105 100644 --- a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.zh-Hans.xlf +++ b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.zh-Hans.xlf @@ -1,32 +1,37 @@ - - - - - - Build completed. - 完成的生成。 - - - - Build started, please wait... - 已开始生成,请等待... - - - - Test run for {0} ({1}) - {0} ({1})的测试运行 - - - - Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. - 警告: 将 Microsoft.NET.Test.Sdk 包引用更新为版本 15.8.0 或更高版本,以便收集代码覆盖率。 - - - - Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. - 正在跳过项目 {0} 的运行测试。若要使用 dotnet test 运行 dotnet 测试,请向项目文件添加 "<IsTestProject>true</IsTestProject>" 属性。 - - - - + + + + + + Build completed. + 完成的生成。 + + + + Build started, please wait... + 已开始生成,请等待... + + + + Test file path cannot be empty or null. + Test file path cannot be empty or null. + + + + Test run for {0} ({1}) + {0} ({1})的测试运行 + + + + Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. + 警告: 将 Microsoft.NET.Test.Sdk 包引用更新为版本 15.8.0 或更高版本,以便收集代码覆盖率。 + + + + Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. + 正在跳过项目 {0} 的运行测试。若要使用 dotnet test 运行 dotnet 测试,请向项目文件添加 "<IsTestProject>true</IsTestProject>" 属性。 + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.zh-Hant.xlf b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.zh-Hant.xlf index 250f0e4166..73db576be3 100644 --- a/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.zh-Hant.xlf +++ b/src/Microsoft.TestPlatform.Build/Resources/xlf/Resources.zh-Hant.xlf @@ -1,32 +1,37 @@ - - - - - - Build completed. - 建置完成。 - - - - Build started, please wait... - 已開始建置,請稍候... - - - - Test run for {0} ({1}) - {0} 的測試回合 ({1}) - - - - Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. - 警告: 將 Microsoft.NET.Test.Sdk 套件參考更新至版本 15.8.0 或更新版本,才可收集程式碼涵蓋範圍。 - - - - Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. - 跳過專案 {0} 目前正在執行中的測試。若要執行有 dotnet 測試的測試項目,請對專案檔新增 "<IsTestProject>true</IsTestProject>" 屬性。 - - - - + + + + + + Build completed. + 建置完成。 + + + + Build started, please wait... + 已開始建置,請稍候... + + + + Test file path cannot be empty or null. + Test file path cannot be empty or null. + + + + Test run for {0} ({1}) + {0} 的測試回合 ({1}) + + + + Warning: Update the Microsoft.NET.Test.Sdk package reference to version 15.8.0 or later to collect code coverage. + 警告: 將 Microsoft.NET.Test.Sdk 套件參考更新至版本 15.8.0 或更新版本,才可收集程式碼涵蓋範圍。 + + + + Skipping running test for project {0}. To run tests with dotnet test add "<IsTestProject>true</IsTestProject>" property to project file. + 跳過專案 {0} 目前正在執行中的測試。若要執行有 dotnet 測試的測試項目,請對專案檔新增 "<IsTestProject>true</IsTestProject>" 屬性。 + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Build/Tasks/ITestTask.cs b/src/Microsoft.TestPlatform.Build/Tasks/ITestTask.cs new file mode 100644 index 0000000000..ecd6ec5848 --- /dev/null +++ b/src/Microsoft.TestPlatform.Build/Tasks/ITestTask.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Microsoft.TestPlatform.Build.Tasks; + +internal interface ITestTask : ITask, ICancelableTask +{ + ITaskItem? TestFileFullPath { get; set; } + string? VSTestSetting { get; set; } + ITaskItem[]? VSTestTestAdapterPath { get; set; } + string? VSTestFramework { get; set; } + string? VSTestPlatform { get; set; } + string? VSTestTestCaseFilter { get; set; } + string[]? VSTestLogger { get; set; } + bool VSTestListTests { get; set; } + string? VSTestDiag { get; set; } + string[]? VSTestCLIRunSettings { get; set; } + ITaskItem? VSTestConsolePath { get; set; } + ITaskItem? VSTestResultsDirectory { get; set; } + string? VSTestVerbosity { get; set; } + string[]? VSTestCollect { get; set; } + bool VSTestBlame { get; set; } + bool VSTestBlameCrash { get; set; } + string? VSTestBlameCrashDumpType { get; set; } + bool VSTestBlameCrashCollectAlways { get; set; } + bool VSTestBlameHang { get; set; } + string? VSTestBlameHangDumpType { get; set; } + string? VSTestBlameHangTimeout { get; set; } + ITaskItem? VSTestTraceDataCollectorDirectoryPath { get; set; } + bool VSTestNoLogo { get; set; } + string? VSTestArtifactsProcessingMode { get; set; } + string? VSTestSessionCorrelationId { get; set; } + + TaskLoggingHelper Log { get; } +} diff --git a/src/Microsoft.TestPlatform.Build/Tasks/TestTaskUtils.cs b/src/Microsoft.TestPlatform.Build/Tasks/TestTaskUtils.cs new file mode 100644 index 0000000000..97b6fe4ec9 --- /dev/null +++ b/src/Microsoft.TestPlatform.Build/Tasks/TestTaskUtils.cs @@ -0,0 +1,239 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; + +using Microsoft.Build.Utilities; + +namespace Microsoft.TestPlatform.Build.Tasks; + +internal static class TestTaskUtils +{ + public static string CreateCommandLineArguments(ITestTask task) + { + const string codeCoverageString = "Code Coverage"; + const string vsTestAppName = "vstest.console.dll"; + + // We have 2 tasks: + // VSTestTask that writes directly to console output and does not write via msbuild + // and VSTestTask2 that uses msbuild tools task to capture standard output and translates + // all output to Error to msbuild errors. + // + // Here we are choosing a vstest.console logger to use. Those loggers both write to standard output + // and error output in vstest.console process, but MSBuild task is not focusing on writing with nice colors + // but instead on writing cohesive messages in one go, so MSBuild can capture them as single message, and not + // as 20 different messages for 20 lines. + var loggerToUse = task is VSTestTask ? "Console" : "Microsoft.TestPlatform.MSBuildLogger"; + // User is free to override the logging using the standard vstest.parameters + // otherwise we just add the appropriate logger and use the msbuild verbosity + // to forward it to the vstest.console logger. + var isLoggerSpecifiedByUser = false; + var isCollectCodeCoverageEnabled = false; + var isRunSettingsEnabled = false; + + var builder = new CommandLineBuilder(); + builder.AppendSwitch("exec"); + if (task.VSTestConsolePath != null && !task.VSTestConsolePath.ItemSpec.IsNullOrEmpty()) + { + builder.AppendFileNameIfNotNull(task.VSTestConsolePath); + } + else + { + builder.AppendFileNameIfNotNull(vsTestAppName); + } + + // TODO log arguments in task + if (!task.VSTestSetting.IsNullOrEmpty()) + { + isRunSettingsEnabled = true; + builder.AppendSwitchIfNotNull("--settings:", task.VSTestSetting); + } + + if (task.VSTestTestAdapterPath != null) + { + foreach (var arg in task.VSTestTestAdapterPath) + { + builder.AppendSwitchIfNotNull("--testAdapterPath:", arg); + } + } + + builder.AppendSwitchIfNotNull("--framework:", task.VSTestFramework); + + // vstest.console only support x86 and x64 for argument platform + if (!task.VSTestPlatform.IsNullOrEmpty() && !task.VSTestPlatform.Contains("AnyCPU")) + { + builder.AppendSwitchIfNotNull("--platform:", task.VSTestPlatform); + } + + builder.AppendSwitchIfNotNull("--testCaseFilter:", task.VSTestTestCaseFilter); + + if (task.VSTestLogger != null) + { + foreach (var arg in task.VSTestLogger) + { + builder.AppendSwitchIfNotNull("--logger:", arg); + + if (arg != null && arg.StartsWith(loggerToUse, StringComparison.OrdinalIgnoreCase)) + { + System.Diagnostics.Trace.WriteLine($">>>> : User specified logger: {arg}"); + isLoggerSpecifiedByUser = true; + } + } + } + + builder.AppendSwitchIfNotNull("--resultsDirectory:", task.VSTestResultsDirectory); + + if (task.VSTestListTests) + { + builder.AppendSwitch("--listTests"); + } + + builder.AppendSwitchIfNotNull("--diag:", task.VSTestDiag); + + if (task.TestFileFullPath == null || task.TestFileFullPath.ItemSpec.IsNullOrEmpty()) + { + task.Log.LogError(Resources.Resources.TestFilePathCannotBeEmptyOrNull); + } + else + { + builder.AppendFileNameIfNotNull(task.TestFileFullPath); + } + + // The logger to use (console or msbuild) logger was not specified by user, + // add the logger and verbosity, so we know what to use in vstest.console. + if (!isLoggerSpecifiedByUser) + { + string vsTestVerbosity = "minimal"; + if (!task.VSTestVerbosity.IsNullOrWhiteSpace()) + { + var normalTestLogging = new List() { "n", "normal", "d", "detailed", "diag", "diagnostic" }; + var quietTestLogging = new List() { "q", "quiet" }; + + string taskVsTestVerbosity = task.VSTestVerbosity.ToLowerInvariant(); + if (normalTestLogging.Contains(taskVsTestVerbosity)) + { + vsTestVerbosity = "normal"; + } + else if (quietTestLogging.Contains(taskVsTestVerbosity)) + { + vsTestVerbosity = "quiet"; + } + } + + builder.AppendSwitchUnquotedIfNotNull("--logger:", $"{loggerToUse};Verbosity={vsTestVerbosity}"); + } + + if (task.VSTestBlame || task.VSTestBlameCrash || task.VSTestBlameHang) + { + var dumpArgs = new List(); + if (task.VSTestBlameCrash || task.VSTestBlameHang) + { + if (task.VSTestBlameCrash) + { + dumpArgs.Add("CollectDump"); + if (task.VSTestBlameCrashCollectAlways) + { + dumpArgs.Add($"CollectAlways={task.VSTestBlameCrashCollectAlways}"); + } + + if (!task.VSTestBlameCrashDumpType.IsNullOrEmpty()) + { + dumpArgs.Add($"DumpType={task.VSTestBlameCrashDumpType}"); + } + } + + if (task.VSTestBlameHang) + { + dumpArgs.Add("CollectHangDump"); + + if (!task.VSTestBlameHangDumpType.IsNullOrEmpty()) + { + dumpArgs.Add($"HangDumpType={task.VSTestBlameHangDumpType}"); + } + + if (!task.VSTestBlameHangTimeout.IsNullOrEmpty()) + { + dumpArgs.Add($"TestTimeout={task.VSTestBlameHangTimeout}"); + } + } + } + + if (dumpArgs.Count != 0) + { + builder.AppendSwitchIfNotNull("--Blame:", string.Join(";", dumpArgs)); + } + else + { + builder.AppendSwitch("--Blame"); + } + } + + if (task.VSTestCollect != null) + { + foreach (var arg in task.VSTestCollect) + { + if (arg == null) + { + continue; + } + + // For collecting code coverage, argument value can be either "Code Coverage" or "Code Coverage;a=b;c=d". + // Split the argument with ';' and compare first token value. + var tokens = arg.Split(';'); + if (arg.Equals(codeCoverageString, StringComparison.OrdinalIgnoreCase) || + tokens[0].Equals(codeCoverageString, StringComparison.OrdinalIgnoreCase)) + { + isCollectCodeCoverageEnabled = true; + } + + builder.AppendSwitchIfNotNull("--collect:", arg); + } + } + + if (isCollectCodeCoverageEnabled || isRunSettingsEnabled) + { + // Pass TraceDataCollector path to vstest.console as TestAdapterPath if --collect "Code Coverage" + // or --settings (User can enable code coverage from runsettings) option given. + // Not parsing the runsettings for two reason: + // 1. To keep no knowledge of runsettings structure in VSTestTask. + // 2. Impact of adding adapter path always is minimal. (worst case: loads additional data collector assembly in datacollector process.) + // This is required due to currently trace datacollector not ships with dotnet sdk, can be remove once we have + // go code coverage x-plat. + if (task.VSTestTraceDataCollectorDirectoryPath != null && !task.VSTestTraceDataCollectorDirectoryPath.ItemSpec.IsNullOrEmpty()) + { + builder.AppendSwitchIfNotNull("--testAdapterPath:", task.VSTestTraceDataCollectorDirectoryPath); + } + else if (isCollectCodeCoverageEnabled) + { + // Not showing message in runsettings scenario, because we are not sure that code coverage is enabled. + // User might be using older Microsoft.NET.Test.Sdk which don't have CodeCoverage infra. + task.Log.LogWarning(Resources.Resources.UpdateTestSdkForCollectingCodeCoverage); + } + } + + if (task.VSTestNoLogo) + { + builder.AppendSwitch("--nologo"); + } + + if (string.Equals(task.VSTestArtifactsProcessingMode, "collect", StringComparison.OrdinalIgnoreCase)) + { + builder.AppendSwitch("--artifactsProcessingMode-collect"); + } + + builder.AppendSwitchIfNotNull("--testSessionCorrelationId:", task.VSTestSessionCorrelationId); + + // VSTestCLIRunSettings should be last argument as vstest.console ignore options after "--" (CLIRunSettings option). + if (task.VSTestCLIRunSettings != null) + { + builder.AppendSwitch("--"); + foreach (var arg in task.VSTestCLIRunSettings) + { + builder.AppendSwitchIfNotNull(string.Empty, arg); + } + } + + return builder.ToString(); + } +} diff --git a/src/Microsoft.TestPlatform.Build/Tasks/VSTestForwardingApp.cs b/src/Microsoft.TestPlatform.Build/Tasks/VSTestForwardingApp.cs deleted file mode 100644 index 618cdf342c..0000000000 --- a/src/Microsoft.TestPlatform.Build/Tasks/VSTestForwardingApp.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -using Microsoft.TestPlatform.Build.Trace; -using Microsoft.TestPlatform.Build.Utils; - -namespace Microsoft.TestPlatform.Build.Tasks; - -public class VSTestForwardingApp -{ - private const string HostExe = "dotnet"; - private readonly List _allArgs = new(); - private int _activeProcessId; - - public VSTestForwardingApp(string vsTestExePath, IEnumerable argsToForward) - { - _allArgs.Add("exec"); - - // Ensure that path to vstest.console is whitespace friendly. User may install - // dotnet-cli to any folder containing whitespace (e.g. VS installs to program files). - // Arguments are already whitespace friendly. - _allArgs.Add(ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(vsTestExePath)); - _allArgs.AddRange(argsToForward); - } - - public int Execute() - { - var processInfo = new ProcessStartInfo - { - FileName = HostExe, - Arguments = string.Join(" ", _allArgs), - UseShellExecute = false, - }; - - Tracing.Trace("VSTest: Starting vstest.console..."); - Tracing.Trace("VSTest: Arguments: " + processInfo.FileName + " " + processInfo.Arguments); - - using var activeProcess = new Process { StartInfo = processInfo }; - activeProcess.Start(); - _activeProcessId = activeProcess.Id; - - activeProcess.WaitForExit(); - Tracing.Trace("VSTest: Exit code: " + activeProcess.ExitCode); - return activeProcess.ExitCode; - } - - public void Cancel() - { - try - { - Process.GetProcessById(_activeProcessId).Kill(); - } - catch (ArgumentException ex) - { - Tracing.Trace($"VSTest: Killing process throws ArgumentException with the following message {ex}. It may be that process is not running"); - } - } -} diff --git a/src/Microsoft.TestPlatform.Build/Tasks/VSTestTask.cs b/src/Microsoft.TestPlatform.Build/Tasks/VSTestTask.cs index 7c05e36683..413e58acad 100644 --- a/src/Microsoft.TestPlatform.Build/Tasks/VSTestTask.cs +++ b/src/Microsoft.TestPlatform.Build/Tasks/VSTestTask.cs @@ -2,84 +2,56 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Collections.Generic; using System.Diagnostics; using System.Threading; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using Microsoft.TestPlatform.Build.Trace; -using Microsoft.TestPlatform.Build.Utils; namespace Microsoft.TestPlatform.Build.Tasks; -public class VSTestTask : Task, ICancelableTask +public class VSTestTask : Task, ITestTask { - // The process which is invoking vstest.console - private VSTestForwardingApp? _vsTestForwardingApp; + private int _activeProcessId; - private const string CodeCoverageString = "Code Coverage"; - - public string? TestFileFullPath { get; set; } + private const string DotnetExe = "dotnet"; + [Required] + public ITaskItem? TestFileFullPath { get; set; } public string? VSTestSetting { get; set; } - - public string[]? VSTestTestAdapterPath { get; set; } - + public ITaskItem[]? VSTestTestAdapterPath { get; set; } public string? VSTestFramework { get; set; } - public string? VSTestPlatform { get; set; } - public string? VSTestTestCaseFilter { get; set; } - public string[]? VSTestLogger { get; set; } - - public string? VSTestListTests { get; set; } - + public bool VSTestListTests { get; set; } public string? VSTestDiag { get; set; } - public string[]? VSTestCLIRunSettings { get; set; } - [Required] - // Initialized to empty string to allow declaring as non-nullable, the property is marked as - // required so we can ensure that the property is set to non-null before the task is executed. - public string VSTestConsolePath { get; set; } = ""; - - public string? VSTestResultsDirectory { get; set; } - + public ITaskItem? VSTestConsolePath { get; set; } + public ITaskItem? VSTestResultsDirectory { get; set; } public string? VSTestVerbosity { get; set; } - public string[]? VSTestCollect { get; set; } - - public string? VSTestBlame { get; set; } - - public string? VSTestBlameCrash { get; set; } - + public bool VSTestBlame { get; set; } + public bool VSTestBlameCrash { get; set; } public string? VSTestBlameCrashDumpType { get; set; } - - public string? VSTestBlameCrashCollectAlways { get; set; } - - public string? VSTestBlameHang { get; set; } - + public bool VSTestBlameCrashCollectAlways { get; set; } + public bool VSTestBlameHang { get; set; } public string? VSTestBlameHangDumpType { get; set; } - public string? VSTestBlameHangTimeout { get; set; } - - public string? VSTestTraceDataCollectorDirectoryPath { get; set; } - - public string? VSTestNoLogo { get; set; } - + public ITaskItem? VSTestTraceDataCollectorDirectoryPath { get; set; } + public bool VSTestNoLogo { get; set; } public string? VSTestArtifactsProcessingMode { get; set; } - public string? VSTestSessionCorrelationId { get; set; } public override bool Execute() { var traceEnabledValue = Environment.GetEnvironmentVariable("VSTEST_BUILD_TRACE"); - Tracing.traceEnabled = !traceEnabledValue.IsNullOrEmpty() && traceEnabledValue.Equals("1", StringComparison.OrdinalIgnoreCase); + Tracing.traceEnabled = string.Equals(traceEnabledValue, "1", StringComparison.OrdinalIgnoreCase); var debugEnabled = Environment.GetEnvironmentVariable("VSTEST_BUILD_DEBUG"); - if (!debugEnabled.IsNullOrEmpty() && debugEnabled.Equals("1", StringComparison.Ordinal)) + if (string.Equals(debugEnabled, "1", StringComparison.Ordinal)) { Console.WriteLine("Waiting for debugger attach..."); @@ -96,248 +68,43 @@ public override bool Execute() // Avoid logging "Task returned false but did not log an error." on test failure, because we don't // write MSBuild error. https://github.com/dotnet/msbuild/blob/51a1071f8871e0c93afbaf1b2ac2c9e59c7b6491/src/Framework/IBuildEngine7.cs#L12 - var allowfailureWithoutError = BuildEngine.GetType().GetProperty("AllowFailureWithoutError"); - allowfailureWithoutError?.SetValue(BuildEngine, true); + var allowFailureWithoutError = BuildEngine.GetType().GetProperty("AllowFailureWithoutError"); + allowFailureWithoutError?.SetValue(BuildEngine, true); + + var processInfo = new ProcessStartInfo + { + FileName = DotnetExe, + Arguments = TestTaskUtils.CreateCommandLineArguments(this), + UseShellExecute = false, + }; - _vsTestForwardingApp = new VSTestForwardingApp(VSTestConsolePath, CreateArgument()); if (!VSTestFramework.IsNullOrEmpty()) { Console.WriteLine(Resources.Resources.TestRunningSummary, TestFileFullPath, VSTestFramework); } - return _vsTestForwardingApp.Execute() == 0; - } - - public void Cancel() - { - Tracing.Trace("VSTest: Killing the process..."); - _vsTestForwardingApp?.Cancel(); - } - - internal IEnumerable CreateArgument() - { - var allArgs = AddArgs(); - - // VSTestCLIRunSettings should be last argument in allArgs as vstest.console ignore options after "--"(CLIRunSettings option). - AddCliRunSettingsArgs(allArgs); + Tracing.Trace("VSTest: Starting vstest.console..."); + Tracing.Trace($"VSTest: Arguments: {processInfo.FileName} {processInfo.Arguments}"); - return allArgs; - } + using var activeProcess = new Process { StartInfo = processInfo }; + activeProcess.Start(); + _activeProcessId = activeProcess.Id; - private void AddCliRunSettingsArgs(List allArgs) - { - if (VSTestCLIRunSettings != null && VSTestCLIRunSettings.Length > 0) - { - allArgs.Add("--"); - foreach (var arg in VSTestCLIRunSettings) - { - allArgs.Add(ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(arg)); - } - } + activeProcess.WaitForExit(); + Tracing.Trace($"VSTest: Exit code: {activeProcess.ExitCode}"); + return activeProcess.ExitCode == 0; } - private List AddArgs() + public void Cancel() { - var isConsoleLoggerSpecifiedByUser = false; - var isCollectCodeCoverageEnabled = false; - var isRunSettingsEnabled = false; - var allArgs = new List(); - - // TODO log arguments in task - if (!VSTestSetting.IsNullOrEmpty()) - { - isRunSettingsEnabled = true; - allArgs.Add("--settings:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(VSTestSetting)); - } - - if (VSTestTestAdapterPath != null && VSTestTestAdapterPath.Length > 0) - { - foreach (var arg in VSTestTestAdapterPath) - { - allArgs.Add("--testAdapterPath:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(arg)); - } - } - - if (!VSTestFramework.IsNullOrEmpty()) - { - allArgs.Add("--framework:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(VSTestFramework)); - } - - // vstest.console only support x86 and x64 for argument platform - if (!VSTestPlatform.IsNullOrEmpty() && !VSTestPlatform.Contains("AnyCPU")) - { - allArgs.Add("--platform:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(VSTestPlatform)); - } - - if (!VSTestTestCaseFilter.IsNullOrEmpty()) - { - allArgs.Add("--testCaseFilter:" + - ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(VSTestTestCaseFilter)); - } - - if (VSTestLogger != null && VSTestLogger.Length > 0) - { - foreach (var arg in VSTestLogger) - { - allArgs.Add("--logger:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(arg)); - - if (arg.StartsWith("console", StringComparison.OrdinalIgnoreCase)) - { - isConsoleLoggerSpecifiedByUser = true; - } - } - } - - if (!VSTestResultsDirectory.IsNullOrEmpty()) - { - allArgs.Add("--resultsDirectory:" + - ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(VSTestResultsDirectory)); - } - - if (!VSTestListTests.IsNullOrEmpty()) - { - allArgs.Add("--listTests"); - } - - if (!VSTestDiag.IsNullOrEmpty()) - { - allArgs.Add("--Diag:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(VSTestDiag)); - } - - if (TestFileFullPath.IsNullOrEmpty()) - { - Log.LogError("Test file path cannot be empty or null."); - } - else - { - allArgs.Add(ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(TestFileFullPath)); - } - - // Console logger was not specified by user, but verbosity was, hence add default console logger with verbosity as specified - if (!VSTestVerbosity.IsNullOrWhiteSpace() && !isConsoleLoggerSpecifiedByUser) - { - var normalTestLogging = new List() { "n", "normal", "d", "detailed", "diag", "diagnostic" }; - var quietTestLogging = new List() { "q", "quiet" }; - - string vsTestVerbosity = "minimal"; - if (normalTestLogging.Contains(VSTestVerbosity.ToLowerInvariant())) - { - vsTestVerbosity = "normal"; - } - else if (quietTestLogging.Contains(VSTestVerbosity.ToLowerInvariant())) - { - vsTestVerbosity = "quiet"; - } - - allArgs.Add("--logger:Console;Verbosity=" + vsTestVerbosity); - } - - var blameCrash = !VSTestBlameCrash.IsNullOrEmpty(); - var blameHang = !VSTestBlameHang.IsNullOrEmpty(); - if (!VSTestBlame.IsNullOrEmpty() || blameCrash || blameHang) - { - var blameArgs = "--Blame"; - - var dumpArgs = new List(); - if (blameCrash || blameHang) - { - if (blameCrash) - { - dumpArgs.Add("CollectDump"); - if (!VSTestBlameCrashCollectAlways.IsNullOrEmpty()) - { - dumpArgs.Add($"CollectAlways={VSTestBlameCrashCollectAlways}"); - } - - if (!VSTestBlameCrashDumpType.IsNullOrEmpty()) - { - dumpArgs.Add($"DumpType={VSTestBlameCrashDumpType}"); - } - } - - if (blameHang) - { - dumpArgs.Add("CollectHangDump"); - - if (!VSTestBlameHangDumpType.IsNullOrEmpty()) - { - dumpArgs.Add($"HangDumpType={VSTestBlameHangDumpType}"); - } - - if (!VSTestBlameHangTimeout.IsNullOrEmpty()) - { - dumpArgs.Add($"TestTimeout={VSTestBlameHangTimeout}"); - } - } - - if (dumpArgs.Count != 0) - { - blameArgs += $":\"{string.Join(";", dumpArgs)}\""; - } - } - - allArgs.Add(blameArgs); - } - - if (VSTestCollect != null && VSTestCollect.Length > 0) - { - foreach (var arg in VSTestCollect) - { - // For collecting code coverage, argument value can be either "Code Coverage" or "Code Coverage;a=b;c=d". - // Split the argument with ';' and compare first token value. - var tokens = arg.Split(';'); - - if (arg.Equals(CodeCoverageString, StringComparison.OrdinalIgnoreCase) || - tokens[0].Equals(CodeCoverageString, StringComparison.OrdinalIgnoreCase)) - { - isCollectCodeCoverageEnabled = true; - } - - allArgs.Add("--collect:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(arg)); - } - } - - if (isCollectCodeCoverageEnabled || isRunSettingsEnabled) - { - // Pass TraceDataCollector path to vstest.console as TestAdapterPath if --collect "Code Coverage" - // or --settings (User can enable code coverage from runsettings) option given. - // Not parsing the runsettings for two reason: - // 1. To keep no knowledge of runsettings structure in VSTestTask. - // 2. Impact of adding adapter path always is minimal. (worst case: loads additional data collector assembly in datacollector process.) - // This is required due to currently trace datacollector not ships with dotnet sdk, can be remove once we have - // go code coverage x-plat. - if (!VSTestTraceDataCollectorDirectoryPath.IsNullOrEmpty()) - { - allArgs.Add("--testAdapterPath:" + - ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart( - VSTestTraceDataCollectorDirectoryPath)); - } - else - { - if (isCollectCodeCoverageEnabled) - { - // Not showing message in runsettings scenario, because we are not sure that code coverage is enabled. - // User might be using older Microsoft.NET.Test.Sdk which don't have CodeCoverage infra. - Console.WriteLine(Resources.Resources.UpdateTestSdkForCollectingCodeCoverage); - } - } - } - - if (!VSTestNoLogo.IsNullOrWhiteSpace()) - { - allArgs.Add("--nologo"); - } - - if (!VSTestArtifactsProcessingMode.IsNullOrEmpty() && VSTestArtifactsProcessingMode.Equals("collect", StringComparison.OrdinalIgnoreCase)) + Tracing.Trace("VSTest: Killing the process..."); + try { - allArgs.Add("--artifactsProcessingMode-collect"); + Process.GetProcessById(_activeProcessId).Kill(); } - - if (!VSTestSessionCorrelationId.IsNullOrEmpty()) + catch (ArgumentException ex) { - allArgs.Add("--testSessionCorrelationId:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(VSTestSessionCorrelationId)); + Tracing.Trace($"VSTest: Killing process throws ArgumentException with the following message {ex}. It may be that process is not running"); } - - return allArgs; } } diff --git a/src/Microsoft.TestPlatform.Build/Tasks/VSTestTask2.cs b/src/Microsoft.TestPlatform.Build/Tasks/VSTestTask2.cs new file mode 100644 index 0000000000..d99c3e89d0 --- /dev/null +++ b/src/Microsoft.TestPlatform.Build/Tasks/VSTestTask2.cs @@ -0,0 +1,165 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.IO; +using System.Runtime.InteropServices; + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Microsoft.TestPlatform.Build.Tasks; + +public class VSTestTask2 : ToolTask, ITestTask +{ + [Required] + public ITaskItem? TestFileFullPath { get; set; } + public string? VSTestSetting { get; set; } + public ITaskItem[]? VSTestTestAdapterPath { get; set; } + public string? VSTestFramework { get; set; } + public string? VSTestPlatform { get; set; } + public string? VSTestTestCaseFilter { get; set; } + public string[]? VSTestLogger { get; set; } + public bool VSTestListTests { get; set; } + public string? VSTestDiag { get; set; } + public string[]? VSTestCLIRunSettings { get; set; } + [Required] + public ITaskItem? VSTestConsolePath { get; set; } + public ITaskItem? VSTestResultsDirectory { get; set; } + public string? VSTestVerbosity { get; set; } + public string[]? VSTestCollect { get; set; } + public bool VSTestBlame { get; set; } + public bool VSTestBlameCrash { get; set; } + public string? VSTestBlameCrashDumpType { get; set; } + public bool VSTestBlameCrashCollectAlways { get; set; } + public bool VSTestBlameHang { get; set; } + public string? VSTestBlameHangDumpType { get; set; } + public string? VSTestBlameHangTimeout { get; set; } + public ITaskItem? VSTestTraceDataCollectorDirectoryPath { get; set; } + public bool VSTestNoLogo { get; set; } + public string? VSTestArtifactsProcessingMode { get; set; } + public string? VSTestSessionCorrelationId { get; set; } + + + private readonly string _errorSplitter = "||||"; + private readonly string[] _errorSplitterArray = new[] { "||||" }; + + private readonly string _fullErrorSplitter = "~~~~"; + private readonly string[] _fullErrorSplitterArray = new[] { "~~~~" }; + + private readonly string _fullErrorNewlineSplitter = "!!!!"; + + protected override string? ToolName + { + get + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return "dotnet.exe"; + else + return "dotnet"; + } + } + + public VSTestTask2() + { + LogStandardErrorAsError = false; + StandardOutputImportance = "Normal"; + } + + protected override void LogEventsFromTextOutput(string singleLine, MessageImportance messageImportance) + { + if (singleLine.StartsWith(_errorSplitter)) + { + var parts = singleLine.Split(_errorSplitterArray, StringSplitOptions.None); + if (parts.Length == 5) + { + var line = 0; + var file = parts[1]; + var _ = !StringUtils.IsNullOrWhiteSpace(parts[3]) && int.TryParse(parts[2], out line); + var code = parts[3]; + var message = parts[4]; + + // Join them with space if both are not null, + // otherwise use the one that is not null. + string? error = code != null && message != null + ? code + " " + message + : code ?? message; + + file ??= string.Empty; + + Log.LogError(null, "VSTEST1", null, file, line, 0, 0, 0, error, null); + return; + } + } + + if (singleLine.StartsWith(_fullErrorSplitter)) + { + var parts = singleLine.Split(_fullErrorSplitterArray, StringSplitOptions.None); + if (parts.Length > 1) + { + var message = parts[1]; + if (message != null) + { + message = message.Replace(_fullErrorNewlineSplitter, Environment.NewLine); + } + + string? stackTrace = null; + if (parts.Length > 2) + { + stackTrace = parts[2]; + if (stackTrace != null) + { + stackTrace = stackTrace.Replace(_fullErrorNewlineSplitter, Environment.NewLine); + } + } + + var logMessage = $"{message}{Environment.NewLine}StackTrace:{Environment.NewLine}{stackTrace}"; + + Log.LogMessage(MessageImportance.Low, logMessage); + return; + } + } + + base.LogEventsFromTextOutput(singleLine, messageImportance); + } + + protected override string? GenerateCommandLineCommands() + { + return TestTaskUtils.CreateCommandLineArguments(this); + } + + protected override string? GenerateFullPathToTool() + { + if (!ToolPath.IsNullOrEmpty()) + { + return Path.Combine(Path.GetDirectoryName(Path.GetFullPath(ToolPath))!, ToolExe); + } + + //TODO: https://github.com/dotnet/sdk/issues/20 Need to get the dotnet path from MSBuild? + + var dhp = Environment.GetEnvironmentVariable("DOTNET_HOST_PATH"); + if (!dhp.IsNullOrEmpty()) + { + var path = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(dhp))!, ToolExe); + if (File.Exists(path)) + { + return path; + } + } + + if (File.Exists(ToolExe)) + { + return Path.GetFullPath(ToolExe); + } + + var values = Environment.GetEnvironmentVariable("PATH"); + foreach (var p in values!.Split(Path.PathSeparator)) + { + var fullPath = Path.Combine(p, ToolExe); + if (File.Exists(fullPath)) + return fullPath; + } + + return null; + } +} diff --git a/src/vstest.console/Internal/MSBuildLogger.cs b/src/vstest.console/Internal/MSBuildLogger.cs new file mode 100644 index 0000000000..9eb5a820af --- /dev/null +++ b/src/vstest.console/Internal/MSBuildLogger.cs @@ -0,0 +1,223 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; + +using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; +using Microsoft.VisualStudio.TestPlatform.Utilities; + +using CommandLineResources = Microsoft.VisualStudio.TestPlatform.CommandLine.Resources.Resources; + +namespace Microsoft.VisualStudio.TestPlatform.CommandLine.Internal; + +// Not using FriendlyName because it +[ExtensionUri(ExtensionUri)] +[FriendlyName(FriendlyName)] +internal class MSBuildLogger : ITestLoggerWithParameters +{ + public const string ExtensionUri = "logger://Microsoft/TestPlatform/MSBuildLogger/v1"; + + // This name is not so friendly on purpose, because MSBuild seems like a name that someone might have + // already claimed, and we will use this just programmatically. + public const string FriendlyName = "Microsoft.TestPlatform.MSBuildLogger"; + + /// + /// Gets instance of IOutput used for sending output. + /// + /// Protected so this can be detoured for testing purposes. + protected static IOutput? Output + { + get; + private set; + } + + // Default constructor is needed for a logger to be able to activate it. + public MSBuildLogger() { } + + /// + /// Constructor added for testing purpose + /// + internal MSBuildLogger(IOutput output) + { + Output = output; + } + + [MemberNotNull(nameof(Output))] + public void Initialize(TestLoggerEvents events, string testRunDirectory) + { + ValidateArg.NotNull(events, nameof(events)); + + Output ??= ConsoleOutput.Instance; + + // Register for the events. + // events.TestRunMessage += TestMessageHandler; + events.TestResult += TestResultHandler; + events.TestRunComplete += TestRunCompleteHandler; + // events.TestRunStart += TestRunStartHandler; + + // Register for the discovery events. + // events.DiscoveryMessage += TestMessageHandler; + } + + public void Initialize(TestLoggerEvents events, Dictionary parameters) + { + Initialize(events, string.Empty); + } + + private void TestRunCompleteHandler(object? sender, TestRunCompleteEventArgs e) + { + TPDebug.Assert(Output != null, "Initialize should have been called"); + + if (e.IsCanceled) + { + Output.Error(false, CommandLineResources.TestRunCanceled); + } + else if (e.IsAborted) + { + if (e.Error == null) + { + Output.Error(false, CommandLineResources.TestRunAborted); + } + else + { + Output.Error(false, CommandLineResources.TestRunAbortedWithError, e.Error); + } + } + } + + private void TestResultHandler(object? sender, TestResultEventArgs e) + { + ValidateArg.NotNull(sender, nameof(sender)); + ValidateArg.NotNull(e, nameof(e)); + TPDebug.Assert(Output != null, "Initialize should have been called."); + switch (e.Result.Outcome) + { + case TestOutcome.Failed: + { + var result = e.Result; + if (!StringUtils.IsNullOrWhiteSpace(result.ErrorStackTrace)) + { + var maxLength = 1000; + string? error = null; + if (result.ErrorMessage != null) + { + var oneLineMessage = result.ErrorMessage.Replace(Environment.NewLine, " "); + error = oneLineMessage.Length > maxLength ? oneLineMessage.Substring(0, maxLength) : oneLineMessage; + } + + string? stackFrame = null; + var stackFrames = Regex.Split(result.ErrorStackTrace, Environment.NewLine); + string? line = null; + string? file = null; + string? place = null; + if (stackFrames.Length > 0) + { + foreach (var frame in stackFrames.Take(20)) + { + if (TryGetStackFrameLocation(frame, out line, out file, out place)) + { + break; + } + } + } + + // We did not find any stack frame with location in the first 20 frames. + // Try getting location of the test. + if (file == null) + { + if (!StringUtils.IsNullOrEmpty(result.TestCase.CodeFilePath)) + { + // if there are no symbols but we collect source info, us the source info. + file = result.TestCase.CodeFilePath; + line = result.TestCase.LineNumber > 0 ? result.TestCase.LineNumber.ToString(CultureInfo.InvariantCulture) : null; + place = stackFrame; + } + else + { + // if there are no symbols and no source info use the dll + place = result.TestCase.DisplayName; + file = result.TestCase.Source; + } + } + + place = $"({result.TestCase.DisplayName}) {place}"; + var message = $"||||{ReplacePipeSeparator(file)}||||{line}||||{ReplacePipeSeparator(place)}||||{ReplacePipeSeparator(error)}"; + + Trace.WriteLine(">>>>MESSAGE:" + message); + Output.Error(false, message); + + var fullError = $"~~~~{ReplaceTildaSeparator(result.ErrorMessage)}~~~~{ReplaceTildaSeparator(result.ErrorStackTrace)}"; + Output.Information(false, fullError); + return; + } + else + { + Output.Error(false, result.DisplayName?.Replace(Environment.NewLine, " ") ?? string.Empty); + } + + + break; + } + } + } + + private static bool TryGetStackFrameLocation(string stackFrame, out string? line, out string? file, out string? place) + { + // stack frame looks like this ' at Program.
$(String[] args) in S:\t\ConsoleApp81\ConsoleApp81\Program.cs:line 9' + var match = Regex.Match(stackFrame, @"^\s+at (?.+) in (?.+):line (?\d+)$?"); + + line = null; + file = null; + place = null; + + if (match.Success) + { + // get the exact info from stack frame. + place = match.Groups["code"].Value; + file = match.Groups["file"].Value; + line = match.Groups["line"].Value; + } + + Trace.WriteLine($">>>> {(match.Success ? "MATCH" : "NOMATCH")} {stackFrame}"); + + return match.Success; + } + + + private static string? ReplacePipeSeparator(string? text) + { + if (text == null) + { + return null; + } + + // Remove any occurrence of message splitter. + return text.Replace("||||", "____"); + } + + private static string? ReplaceTildaSeparator(string? text) + { + if (text == null) + { + return null; + } + + // Remove any occurrence of message splitter. + text = text.Replace("~~~~", "____"); + // Clean up any occurrence of newline splitter. + text = text.Replace("!!!!", "____"); + // Replace newlines with newline splitter. + text = text.Replace(Environment.NewLine, "!!!!"); + + return text; + } + +} diff --git a/src/vstest.console/TestPlatformHelpers/TestRequestManager.cs b/src/vstest.console/TestPlatformHelpers/TestRequestManager.cs index 8bb19062b6..33d3e4d1dd 100644 --- a/src/vstest.console/TestPlatformHelpers/TestRequestManager.cs +++ b/src/vstest.console/TestPlatformHelpers/TestRequestManager.cs @@ -809,7 +809,7 @@ private bool UpdateRunSettingsIfRequired( settingsUpdated |= UpdateDesignMode(document, runConfiguration); settingsUpdated |= UpdateCollectSourceInformation(document, runConfiguration); settingsUpdated |= UpdateTargetDevice(navigator, document); - settingsUpdated |= AddOrUpdateConsoleLogger(document, runConfiguration, loggerRunSettings); + settingsUpdated |= AddOrUpdateBuiltInLoggers(document, runConfiguration, loggerRunSettings); settingsUpdated |= AddOrUpdateBatchSize(document, runConfiguration, isDiscovery); updatedRunSettingsXml = navigator.OuterXml; @@ -892,27 +892,43 @@ private string AddFakesConfigurationToRunsettings(IList? sources, string return runsettings; } - private bool AddOrUpdateConsoleLogger( + private bool AddOrUpdateBuiltInLoggers( XmlDocument document, RunConfiguration runConfiguration, LoggerRunSettings loggerRunSettings) { - // Update console logger settings. + // Update built-in logger settings if requested by the user on command line to populate + // the default assembly path to those loggers so we can find them. bool consoleLoggerUpdated = UpdateConsoleLoggerIfExists(document, loggerRunSettings); + bool msbuildLoggerUpdated = UpdateMSBuildLoggerIfExists(document, loggerRunSettings); - // In case of CLI, add console logger if not already present. bool designMode = runConfiguration.DesignModeSet ? runConfiguration.DesignMode : _commandLineOptions.IsDesignMode; - if (!designMode && !consoleLoggerUpdated) + + // In design mode (under IDE) don't add the default logger, we are "logging" + // via messages to vstest console wrapper. + if (!designMode) { - AddConsoleLogger(document, loggerRunSettings); + // When we are not in design mode, add one of the default loggers. + + // If msbuild logger was present on the command line, we are being called from + // dotnet sdk via vstest task, and should output to msbuild. If user additionally + // specified console logger it is allowed but we won't add automatically. + if (!msbuildLoggerUpdated) // msbuild logger is not present on command line + { + if (!consoleLoggerUpdated) // console logger is not present on commandline + { + // Add console logger because that is the default + AddConsoleLogger(document, loggerRunSettings); + } + } } // Update is required: // 1) in case of CLI; // 2) in case of design mode if console logger is present in runsettings. - return !designMode || consoleLoggerUpdated; + return !designMode || consoleLoggerUpdated || msbuildLoggerUpdated; } private static bool UpdateTargetDevice( @@ -1135,13 +1151,13 @@ private static bool UpdateConsoleLoggerIfExists( XmlDocument document, LoggerRunSettings loggerRunSettings) { - var defaultConsoleLogger = new LoggerSettings + var logger = new LoggerSettings { FriendlyName = ConsoleLogger.FriendlyName, Uri = new Uri(ConsoleLogger.ExtensionUri) }; - var existingLoggerIndex = loggerRunSettings.GetExistingLoggerIndex(defaultConsoleLogger); + var existingLoggerIndex = loggerRunSettings.GetExistingLoggerIndex(logger); // Update assemblyQualifiedName and codeBase of existing logger. if (existingLoggerIndex >= 0) @@ -1160,6 +1176,41 @@ private static bool UpdateConsoleLoggerIfExists( return false; } + /// + /// Add MSBuild console logger in runsettings if exists. + /// + /// Runsettings document. + /// Logger run settings. + /// True if updated console logger in runsettings successfully. + private static bool UpdateMSBuildLoggerIfExists( + XmlDocument document, + LoggerRunSettings loggerRunSettings) + { + var logger = new LoggerSettings + { + FriendlyName = MSBuildLogger.FriendlyName, + Uri = new Uri(MSBuildLogger.ExtensionUri) + }; + + var existingLoggerIndex = loggerRunSettings.GetExistingLoggerIndex(logger); + + // Update assemblyQualifiedName and codeBase of existing logger. + if (existingLoggerIndex >= 0) + { + var msBuildLogger = loggerRunSettings.LoggerSettingsList[existingLoggerIndex]; + msBuildLogger.AssemblyQualifiedName = typeof(MSBuildLogger).AssemblyQualifiedName; + msBuildLogger.CodeBase = typeof(MSBuildLogger).Assembly.Location; + RunSettingsProviderExtensions.UpdateRunSettingsXmlDocumentInnerXml( + document, + ObjectModel.Constants.LoggerRunSettingsName, + loggerRunSettings.ToXml().InnerXml); + + return true; + } + + return false; + } + private void RunTests( IRequestData requestData, TestRunCriteria testRunCriteria, diff --git a/test/Microsoft.TestPlatform.Acceptance.IntegrationTests/Build.cs b/test/Microsoft.TestPlatform.Acceptance.IntegrationTests/Build.cs index 2f22dffdba..8fab97215f 100644 --- a/test/Microsoft.TestPlatform.Acceptance.IntegrationTests/Build.cs +++ b/test/Microsoft.TestPlatform.Acceptance.IntegrationTests/Build.cs @@ -49,10 +49,22 @@ private static void SetDotnetEnvironment() private static void CopyAndPatchDotnet() { - // TODO: patch dotnet with latest build targets var patchedDotnetDir = Path.GetFullPath(Path.Combine(Root, "artifacts", "tmp", ".dotnet")); + // Copy dotnet. DirectoryUtils.CopyDirectory(new DirectoryInfo(DotnetDir), new DirectoryInfo(patchedDotnetDir)); + + // Copy target file and build task dll into it. + var netTestSdkVersion = IntegrationTestEnvironment.LatestLocallyBuiltNugetVersion; + var packageName = $"Microsoft.TestPlatform.Build.{netTestSdkVersion}.nupkg"; + var packagePath = Path.GetFullPath(Path.Combine(IntegrationTestEnvironment.PublishDirectory, packageName)); + + // e.g. artifacts\tmp\.dotnet\sdk\ + var sdkDirectory = Path.Combine(patchedDotnetDir, "sdk"); + // e.g. artifacts\tmp\.dotnet\sdk\8.0.100-preview.6.23330.14 + var dotnetSdkDirectory = Directory.GetDirectories(sdkDirectory).Single(); + DirectoryUtils.CopyDirectory(Path.Combine(packagePath, "lib", "netstandard2.0"), dotnetSdkDirectory); + DirectoryUtils.CopyDirectory(Path.Combine(packagePath, "runtimes", "any", "native"), dotnetSdkDirectory); } private static void BuildTestAssetsCompatibility() @@ -337,6 +349,7 @@ private static void BuildTestAssetsAndUnzipPackages() { $"Microsoft.TestPlatform.{netTestSdkVersion}.nupkg", $"Microsoft.TestPlatform.CLI.{netTestSdkVersion}.nupkg", + $"Microsoft.TestPlatform.Build.{netTestSdkVersion}.nupkg", $"Microsoft.CodeCoverage.{netTestSdkVersion}.nupkg", $"Microsoft.TestPlatform.Portable.{netTestSdkVersion}.nupkg", }; diff --git a/test/Microsoft.TestPlatform.Acceptance.IntegrationTests/DotnetTestMSBuildOutputTests.cs b/test/Microsoft.TestPlatform.Acceptance.IntegrationTests/DotnetTestMSBuildOutputTests.cs new file mode 100644 index 0000000000..831356bd73 --- /dev/null +++ b/test/Microsoft.TestPlatform.Acceptance.IntegrationTests/DotnetTestMSBuildOutputTests.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.TestPlatform.TestUtilities; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Microsoft.TestPlatform.AcceptanceTests; + +/// +/// Running dotnet test + csproj and using MSBuild for the output. +/// +[TestClass] +public class DotnetTestMSBuildOutputTests : AcceptanceTestBase +{ + [TestMethod] + // patched dotnet is not published on non-windows systems + [TestCategory("Windows-Review")] + [NetCoreTargetFrameworkDataSource(useDesktopRunner: false)] + public void RunDotnetTestWithCsproj(RunnerInfo runnerInfo) + { + SetTestEnvironment(_testEnvironment, runnerInfo); + + var projectPath = GetIsolatedTestAsset("SimpleTestProject.csproj"); + InvokeDotnetTest($@"{projectPath} /p:VsTestUseMSBuildOutput=true /p:PackageVersion={IntegrationTestEnvironment.LatestLocallyBuiltNugetVersion}"); + + // The output: + // Determining projects to restore... + // Restored C:\Users\nohwnd\AppData\Local\Temp\vstest\xvoVt\SimpleTestProject.csproj (in 441 ms). + // SimpleTestProject -> C:\Users\nohwnd\AppData\Local\Temp\vstest\xvoVt\artifacts\bin\TestAssets\SimpleTestProject\Debug\net462\SimpleTestProject.dll + // SimpleTestProject -> C:\Users\nohwnd\AppData\Local\Temp\vstest\xvoVt\artifacts\bin\TestAssets\SimpleTestProject\Debug\netcoreapp3.1\SimpleTestProject.dll + // C:\Users\nohwnd\AppData\Local\Temp\vstest\xvoVt\UnitTest1.cs(41): error VSTEST1: (FailingTest) SampleUnitTestProject.UnitTest1.FailingTest() Assert.AreEqual failed. Expected:<2>. Actual:<3>. [C:\Users\nohwnd\AppData\Local\Temp\vstest\xvoVt\SimpleTestProject.csproj::TargetFramework=net462] + // C:\Users\nohwnd\AppData\Local\Temp\vstest\xvoVt\UnitTest1.cs(41): error VSTEST1: (FailingTest) SampleUnitTestProject.UnitTest1.FailingTest() Assert.AreEqual failed. Expected:<2>. Actual:<3>. [C:\Users\nohwnd\AppData\Local\Temp\vstest\xvoVt\SimpleTestProject.csproj::TargetFramework=netcoreapp3.1] + + StdOutputContains("error VSTEST1: (FailingTest) SampleUnitTestProject.UnitTest1.FailingTest() Assert.AreEqual failed. Expected:<2>. Actual:<3>."); + ExitCodeEquals(1); + } +} diff --git a/test/Microsoft.TestPlatform.Build.UnitTests/ArgumentEscaperTests.cs b/test/Microsoft.TestPlatform.Build.UnitTests/ArgumentEscaperTests.cs deleted file mode 100644 index 6b60c1e807..0000000000 --- a/test/Microsoft.TestPlatform.Build.UnitTests/ArgumentEscaperTests.cs +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Microsoft.TestPlatform.Build.Utils.UnitTests; - -[TestClass] -public class ArgumentEscaperTests -{ - [TestMethod] - public void EscapeArgForProcessStartShouldAddDoubleQuoteIfThereIsSpace() - { - string stringWithSpace = "Some string"; - - string expected = "\"Some string\""; - string result = ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(stringWithSpace); - - Assert.AreEqual(expected, result); - } - - [TestMethod] - public void EscapeArgForProcessStartShouldAddDoubleQuoteIfThereIsSpaceAtEnd() - { - string stringWithSpaceAtEnd = "Some string "; - - string expected = "\"Some string \""; - string result = ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(stringWithSpaceAtEnd); - - Assert.AreEqual(expected, result); - } - - [TestMethod] - public void EscapeArgForProcessStartShouldHandleForwardSlash() - { - string stringWithForwardSlash = "Some/string"; - - string expected = "Some/string"; - string result = ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(stringWithForwardSlash); - - Assert.AreEqual(expected, result); - } - - [TestMethod] - public void EscapeArgForProcessStartShouldPreserveDoubleQuote() - { - string stringWithDoubleQuote = "Some\"string"; - - string expected = "Some\\\"string"; - string result = ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(stringWithDoubleQuote); - - Assert.AreEqual(expected, result); - } - - [TestMethod] - public void EscapeArgForProcessStartShouldPreserveSingleQuote() - { - string stringWithSingleQuote = "Some'string"; - - string expected = "Some'string"; - string result = ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(stringWithSingleQuote); - - Assert.AreEqual(expected, result); - } - - [TestMethod] - public void EscapeArgForProcessStartShouldPreserveBackSlash() - { - string stringWithBackSlash = @"Some\\string"; - - string expected = "Some\\\\string"; - string result = ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(stringWithBackSlash); - - Assert.AreEqual(expected, result); - } - - [TestMethod] - public void EscapeArgForProcessStartShouldPreserveBackSlashIfStringHasWhiteSpace() - { - string stringWithBackSlash = @"Some string With Space\\"; - - string expected = @"""Some string With Space\\\\"""; - string result = ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(stringWithBackSlash); - - Assert.AreEqual(expected, result); - } - - [TestMethod] - public void ShouldSurroundWithQuotesShouldReturnFalseIfAlreadySurroundWithQuotes() - { - string stringSurroundWithQuotes = "\"some string\""; - - Assert.IsFalse(ArgumentEscaper.ShouldSurroundWithQuotes(stringSurroundWithQuotes)); - } - - [TestMethod] - public void ShouldSurroundWithQuotesShouldReturnFalseIfItIsNotSurroundWithQuotesAndHasNoWhiteSpace() - { - string stringWithoutSpace = "someStringWithNoWhiteSpace"; - - Assert.IsFalse(ArgumentEscaper.ShouldSurroundWithQuotes(stringWithoutSpace)); - } - - [TestMethod] - public void ShouldSurroundWithQuotesShouldReturnTrueIfItIsNotSurroundWithQuotesAndHasWhiteSpace() - { - string stringWithSpace = "some String With WhiteSpace"; - - Assert.IsTrue(ArgumentEscaper.ShouldSurroundWithQuotes(stringWithSpace)); - } - - [TestMethod] - public void IsSurroundedWithQuotesShouldReturnTrueIfStringIsSurroundedByQuotes() - { - string stringSurroundWithQuotes = "\"some string\""; - - Assert.IsTrue(ArgumentEscaper.IsSurroundedWithQuotes(stringSurroundWithQuotes)); - } - - [TestMethod] - public void IsSurroundedWithQuotesShouldReturnFalseIfStringIsNotSurroundedByQuotes() - { - string stringNotSurroundWithQuotes = "some string"; - - Assert.IsFalse(ArgumentEscaper.IsSurroundedWithQuotes(stringNotSurroundWithQuotes)); - } -} diff --git a/test/Microsoft.TestPlatform.Build.UnitTests/FakeBuildEngine.cs b/test/Microsoft.TestPlatform.Build.UnitTests/FakeBuildEngine.cs new file mode 100644 index 0000000000..c0d077d74e --- /dev/null +++ b/test/Microsoft.TestPlatform.Build.UnitTests/FakeBuildEngine.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections; + +using Microsoft.Build.Framework; + +namespace Microsoft.TestPlatform.Build.UnitTests; + +public class FakeBuildEngine : IBuildEngine +{ + public bool ContinueOnError => false; + + public int LineNumberOfTaskNode => 0; + + public int ColumnNumberOfTaskNode => 0; + + public string ProjectFileOfTaskNode => string.Empty; + + public bool BuildProjectFile(string projectFileName, string[] targetNames, IDictionary globalProperties, IDictionary targetOutputs) + { + return false; + } + + public void LogCustomEvent(CustomBuildEventArgs e) + { + } + + public void LogErrorEvent(BuildErrorEventArgs e) + { + } + + public void LogMessageEvent(BuildMessageEventArgs e) + { + } + + public void LogWarningEvent(BuildWarningEventArgs e) + { + } +} diff --git a/test/Microsoft.TestPlatform.Build.UnitTests/TestTaskUtilsTests.cs b/test/Microsoft.TestPlatform.Build.UnitTests/TestTaskUtilsTests.cs new file mode 100644 index 0000000000..7c464bb381 --- /dev/null +++ b/test/Microsoft.TestPlatform.Build.UnitTests/TestTaskUtilsTests.cs @@ -0,0 +1,315 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Text.RegularExpressions; + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Microsoft.TestPlatform.Build.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Microsoft.TestPlatform.Build.UnitTests; + +[TestClass] +public class TestTaskUtilsTests +{ + private readonly ITestTask _vsTestTask; + + public TestTaskUtilsTests() + { + _vsTestTask = new VSTestTask + { + BuildEngine = new FakeBuildEngine(), + TestFileFullPath = new TaskItem(@"C:\path\to\test-assembly.dll"), + VSTestFramework = ".NETCoreapp,Version2.0" + }; + } + + [TestMethod] + public void CreateArgumentShouldAddOneEntryForCLIRunSettings() + { + const string arg1 = "RunConfiguration.ResultsDirectory=Path having Space"; + const string arg2 = "MSTest.DeploymentEnabled"; + + _vsTestTask.VSTestCLIRunSettings = new string[2]; + _vsTestTask.VSTestCLIRunSettings[0] = arg1; + _vsTestTask.VSTestCLIRunSettings[1] = arg2; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, " -- "); + StringAssert.Contains(commandline, $"\"{arg1}\""); + StringAssert.Contains(commandline, $"{arg2}"); + } + + [TestMethod] + public void CreateArgumentShouldAddCLIRunSettingsArgAtEnd() + { + const string codeCoverageOption = "Code Coverage"; + + _vsTestTask.VSTestCollect = new string[] { codeCoverageOption }; + _vsTestTask.VSTestBlame = true; + + const string arg1 = "RunConfiguration.ResultsDirectory=Path having Space"; + const string arg2 = "MSTest.DeploymentEnabled"; + + _vsTestTask.VSTestCLIRunSettings = new string[2]; + _vsTestTask.VSTestCLIRunSettings[0] = arg1; + _vsTestTask.VSTestCLIRunSettings[1] = arg2; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, " -- "); + StringAssert.Contains(commandline, $"\"{arg1}\""); + StringAssert.Contains(commandline, $"{arg2}"); + } + + [TestMethod] + public void CreateArgumentShouldPassResultsDirectoryCorrectly() + { + const string resultsDirectoryValue = @"C:\tmp\Results Directory"; + _vsTestTask.VSTestResultsDirectory = new TaskItem(resultsDirectoryValue); + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, $"--resultsDirectory:\"{_vsTestTask.VSTestResultsDirectory?.ItemSpec}\""); + } + + [TestMethod] + public void CreateArgumentShouldNotSetConsoleLoggerVerbosityIfConsoleLoggerIsGivenInArgs() + { + _vsTestTask.VSTestVerbosity = "diag"; + _vsTestTask.VSTestLogger = new string[] { "Console;Verbosity=quiet" }; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.DoesNotMatch(commandline, new Regex("(--logger:\"Console;Verbosity=normal\")")); + StringAssert.Contains(commandline, "--logger:\"Console;Verbosity=quiet\""); + } + + [TestMethod] + public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsn() + { + _vsTestTask.VSTestVerbosity = "n"; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal"); + } + + [TestMethod] + public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsnormal() + { + _vsTestTask.VSTestVerbosity = "normal"; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal"); + } + + [TestMethod] + public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsd() + { + _vsTestTask.VSTestVerbosity = "d"; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal"); + } + + [TestMethod] + public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsdetailed() + { + _vsTestTask.VSTestVerbosity = "detailed"; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal"); + } + + [TestMethod] + public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsdiag() + { + _vsTestTask.VSTestVerbosity = "diag"; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal"); + } + + [TestMethod] + public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsdiagnostic() + { + _vsTestTask.VSTestVerbosity = "diagnostic"; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal"); + } + + [TestMethod] + public void CreateArgumentShouldSetConsoleLoggerVerbosityToQuietIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsq() + { + _vsTestTask.VSTestVerbosity = "q"; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--logger:Console;Verbosity=quiet"); + } + + [TestMethod] + public void CreateArgumentShouldSetConsoleLoggerVerbosityToQuietIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsquiet() + { + _vsTestTask.VSTestVerbosity = "quiet"; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--logger:Console;Verbosity=quiet"); + } + + [TestMethod] + public void CreateArgumentShouldSetConsoleLoggerVerbosityToMinimalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsm() + { + _vsTestTask.VSTestVerbosity = "m"; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--logger:Console;Verbosity=minimal"); + } + + [TestMethod] + public void CreateArgumentShouldSetConsoleLoggerVerbosityToMinimalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsminimal() + { + _vsTestTask.VSTestVerbosity = "minimal"; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--logger:Console;Verbosity=minimal"); + } + + [TestMethod] + public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsNormalWithCapitalN() + { + _vsTestTask.VSTestVerbosity = "Normal"; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal"); + } + + [TestMethod] + public void CreateArgumentShouldSetConsoleLoggerVerbosityToQuietIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsQuietWithCapitalQ() + { + _vsTestTask.VSTestVerbosity = "Quiet"; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--logger:Console;Verbosity=quiet"); + } + + [TestMethod] + public void CreateArgumentShouldPreserveWhiteSpaceInLogger() + { + _vsTestTask.VSTestLogger = new string[] { "trx;LogFileName=foo bar.trx" }; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--logger:\"trx;LogFileName=foo bar.trx\""); + } + + [TestMethod] + public void CreateArgumentShouldAddOneCollectArgumentForEachCollect() + { + _vsTestTask.VSTestCollect = new string[2]; + + _vsTestTask.VSTestCollect[0] = "name1"; + _vsTestTask.VSTestCollect[1] = "name 2"; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--collect:name1"); + StringAssert.Contains(commandline, "--collect:\"name 2\""); + } + + [TestMethod] + public void CreateArgumentShouldAddMultipleTestAdapterPaths() + { + _vsTestTask.VSTestTestAdapterPath = new ITaskItem[] { new TaskItem("path1"), new TaskItem("path2") }; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--testAdapterPath:path1"); + StringAssert.Contains(commandline, "--testAdapterPath:path2"); + } + + [TestMethod] + public void CreateArgumentShouldAddMultipleLoggers() + { + _vsTestTask.VSTestLogger = new string[] { "trx;LogFileName=foo bar.trx", "console" }; + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--logger:\"trx;LogFileName=foo bar.trx\""); + StringAssert.Contains(commandline, "--logger:console"); + } + + [TestMethod] + public void CreateArgumentShouldAddTraceCollectorDirectoryPathAsTestAdapterForCodeCoverageCollect() + { + const string traceDataCollectorDirectoryPath = @"c:\path\to\tracedata collector"; + _vsTestTask.VSTestTraceDataCollectorDirectoryPath = new TaskItem(traceDataCollectorDirectoryPath); + _vsTestTask.VSTestCollect = new string[] { "code coverage" }; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + string expectedArg = $"--testAdapterPath:\"{_vsTestTask.VSTestTraceDataCollectorDirectoryPath?.ItemSpec}\""; + StringAssert.Contains(commandline, expectedArg); + } + + [TestMethod] + public void CreateArgumentShouldNotAddTraceCollectorDirectoryPathAsTestAdapterForNonCodeCoverageCollect() + { + const string traceDataCollectorDirectoryPath = @"c:\path\to\tracedata collector"; + _vsTestTask.VSTestTraceDataCollectorDirectoryPath = new TaskItem(traceDataCollectorDirectoryPath); + _vsTestTask.VSTestCollect = new string[] { "not code coverage" }; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + string notExpectedArg = $"--testAdapterPath:\"{_vsTestTask.VSTestTraceDataCollectorDirectoryPath?.ItemSpec}\""; + StringAssert.DoesNotMatch(commandline, new Regex(Regex.Escape(notExpectedArg))); + } + + [TestMethod] + public void CreateArgumentShouldAddTraceCollectorDirectoryPathAsTestAdapterIfSettingsGiven() + { + const string traceDataCollectorDirectoryPath = @"c:\path\to\tracedatacollector\"; + _vsTestTask.VSTestTraceDataCollectorDirectoryPath = new TaskItem(traceDataCollectorDirectoryPath); + _vsTestTask.VSTestSetting = @"c:\path\to\sample.runsettings"; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + string expectedArg = $"--testAdapterPath:{_vsTestTask.VSTestTraceDataCollectorDirectoryPath?.ItemSpec}"; + StringAssert.Contains(commandline, expectedArg); + } + + [TestMethod] + public void CreateArgumentShouldNotAddTestAdapterPathIfVSTestTraceDataCollectorDirectoryPathIsEmpty() + { + _vsTestTask.VSTestTraceDataCollectorDirectoryPath = null; + _vsTestTask.VSTestSetting = @"c:\path\to\sample.runsettings"; + _vsTestTask.VSTestCollect = new string[] { "code coverage" }; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.DoesNotMatch(commandline, new Regex(@"(--testAdapterPath:)")); + } + + [TestMethod] + public void CreateArgumentShouldAddNoLogoOptionIfSpecifiedByUser() + { + _vsTestTask.VSTestNoLogo = true; + + var commandline = TestTaskUtils.CreateCommandLineArguments(_vsTestTask); + + StringAssert.Contains(commandline, "--nologo"); + } +} diff --git a/test/Microsoft.TestPlatform.Build.UnitTests/VsTestTaskTests.cs b/test/Microsoft.TestPlatform.Build.UnitTests/VsTestTaskTests.cs deleted file mode 100644 index b8884568ba..0000000000 --- a/test/Microsoft.TestPlatform.Build.UnitTests/VsTestTaskTests.cs +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; - -using Microsoft.TestPlatform.Build.Tasks; - -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Microsoft.TestPlatform.Build.UnitTests; - -[TestClass] -public class VsTestTaskTests -{ - private readonly VSTestTask _vsTestTask; - - public VsTestTaskTests() - { - _vsTestTask = new VSTestTask - { - TestFileFullPath = @"C:\path\to\test-assembly.dll", - VSTestFramework = ".NETCoreapp,Version2.0" - }; - } - - [TestMethod] - public void CreateArgumentShouldAddOneEntryForCLIRunSettings() - { - const string arg1 = "RunConfiguration.ResultsDirectory=Path having Space"; - const string arg2 = "MSTest.DeploymentEnabled"; - - _vsTestTask.VSTestCLIRunSettings = new string[2]; - _vsTestTask.VSTestCLIRunSettings[0] = arg1; - _vsTestTask.VSTestCLIRunSettings[1] = arg2; - - var result = _vsTestTask.CreateArgument().ToArray(); - - Assert.AreEqual(5, result.Length); - - // First, second and third args would be framework:".NETCoreapp,Version2.0", testfilepath and -- respectively. - Assert.AreEqual($"\"{arg1}\"", result[3]); - Assert.AreEqual($"{arg2}", result[4]); - } - - [TestMethod] - public void CreateArgumentShouldAddCliRunSettingsArgAtEnd() - { - const string codeCoverageOption = "Code Coverage"; - - _vsTestTask.VSTestCollect = new string[] { codeCoverageOption }; - _vsTestTask.VSTestBlame = "Blame"; - - const string arg1 = "RunConfiguration.ResultsDirectory=Path having Space"; - const string arg2 = "MSTest.DeploymentEnabled"; - - _vsTestTask.VSTestCLIRunSettings = new string[2]; - _vsTestTask.VSTestCLIRunSettings[0] = arg1; - _vsTestTask.VSTestCLIRunSettings[1] = arg2; - - var result = _vsTestTask.CreateArgument().ToArray(); - - Assert.AreEqual(7, result.Length); - - // Following are expected --framework:".NETCoreapp,Version2.0", testfilepath, blame, collect:"Code coverage" -- respectively. - Assert.AreEqual($"\"{arg1}\"", result[5]); - Assert.AreEqual($"{arg2}", result[6]); - } - - [TestMethod] - public void CreateArgumentShouldPassResultsDirectoryCorrectly() - { - const string resultsDirectoryValue = @"C:\tmp\Results Directory"; - _vsTestTask.VSTestResultsDirectory = resultsDirectoryValue; - - var result = _vsTestTask.CreateArgument().ToArray(); - - Assert.AreEqual($"--resultsDirectory:\"{resultsDirectoryValue}\"", result[1]); - } - - [TestMethod] - public void CreateArgumentShouldNotSetConsoleLoggerVerbosityIfConsoleLoggerIsGivenInArgs() - { - _vsTestTask.VSTestVerbosity = "diag"; - _vsTestTask.VSTestLogger = new string[] { "Console;Verbosity=quiet" }; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal"))); - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=quiet"))); - } - - [TestMethod] - public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsn() - { - _vsTestTask.VSTestVerbosity = "n"; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal"))); - } - - [TestMethod] - public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsnormal() - { - _vsTestTask.VSTestVerbosity = "normal"; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal"))); - } - - [TestMethod] - public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsd() - { - _vsTestTask.VSTestVerbosity = "d"; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal"))); - } - - [TestMethod] - public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsdetailed() - { - _vsTestTask.VSTestVerbosity = "detailed"; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal"))); - } - - [TestMethod] - public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsdiag() - { - _vsTestTask.VSTestVerbosity = "diag"; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal"))); - } - - [TestMethod] - public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsdiagnostic() - { - _vsTestTask.VSTestVerbosity = "diagnostic"; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal"))); - } - - [TestMethod] - public void CreateArgumentShouldSetConsoleLoggerVerbosityToQuietIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsq() - { - _vsTestTask.VSTestVerbosity = "q"; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=quiet"))); - } - - [TestMethod] - public void CreateArgumentShouldSetConsoleLoggerVerbosityToQuietIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsquiet() - { - _vsTestTask.VSTestVerbosity = "quiet"; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=quiet"))); - } - - [TestMethod] - public void CreateArgumentShouldSetConsoleLoggerVerbosityToMinimalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsm() - { - _vsTestTask.VSTestVerbosity = "m"; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=minimal"))); - } - - [TestMethod] - public void CreateArgumentShouldSetConsoleLoggerVerbosityToMinimalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsminimal() - { - _vsTestTask.VSTestVerbosity = "minimal"; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=minimal"))); - } - - [TestMethod] - public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsNormalWithCapitalN() - { - _vsTestTask.VSTestVerbosity = "Normal"; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal"))); - } - - [TestMethod] - public void CreateArgumentShouldSetConsoleLoggerVerbosityToQuietIfConsoleLoggerIsNotGivenInArgsAndVerbosityIsQuietWithCapitalQ() - { - _vsTestTask.VSTestVerbosity = "Quiet"; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=quiet"))); - } - - [TestMethod] - public void CreateArgumentShouldPreserveWhiteSpaceInLogger() - { - _vsTestTask.VSTestLogger = new string[] { "trx;LogFileName=foo bar.trx" }; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:\"trx;LogFileName=foo bar.trx\""))); - } - - [TestMethod] - public void CreateArgumentShouldAddOneCollectArgumentForEachCollect() - { - _vsTestTask.VSTestCollect = new string[2]; - - _vsTestTask.VSTestCollect[0] = "name1"; - _vsTestTask.VSTestCollect[1] = "name 2"; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--collect:name1"))); - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--collect:\"name 2\""))); - } - - [TestMethod] - public void CreateArgumentShouldAddMultipleTestAdapterPaths() - { - _vsTestTask.VSTestTestAdapterPath = new string[] { "path1", "path2" }; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--testAdapterPath:path1"))); - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--testAdapterPath:path2"))); - } - - [TestMethod] - public void CreateArgumentShouldAddMultipleLoggers() - { - _vsTestTask.VSTestLogger = new string[] { "trx;LogFileName=foo bar.trx", "console" }; - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:\"trx;LogFileName=foo bar.trx\""))); - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:console"))); - } - - [TestMethod] - public void CreateArgumentShouldAddTraceCollectorDirectoryPathAsTestAdapterForCodeCoverageCollect() - { - const string traceDataCollectorDirectoryPath = @"c:\path\to\tracedata collector"; - _vsTestTask.VSTestTraceDataCollectorDirectoryPath = traceDataCollectorDirectoryPath; - _vsTestTask.VSTestCollect = new string[] { "code coverage" }; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - const string expectedArg = "--testAdapterPath:\"c:\\path\\to\\tracedata collector\""; - CollectionAssert.Contains(allArguments, expectedArg, $"Expected argument: '''{expectedArg}''' not present in [{string.Join(", ", allArguments)}]"); - } - - [TestMethod] - public void CreateArgumentShouldAddTraceCollectorDirectoryPathAsTestAdapterForCodeCoverageCollectWithExtraConfigurations() - { - const string traceDataCollectorDirectoryPath = @"c:\path\to\tracedata collector"; - _vsTestTask.VSTestTraceDataCollectorDirectoryPath = traceDataCollectorDirectoryPath; - _vsTestTask.VSTestCollect = new string[] { "code coverage;someParameter=someValue" }; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - const string expectedArg = "--testAdapterPath:\"c:\\path\\to\\tracedata collector\""; - CollectionAssert.Contains(allArguments, expectedArg, $"Expected argument: '''{expectedArg}''' not present in [{string.Join(", ", allArguments)}]"); - } - - [TestMethod] - public void CreateArgumentShouldNotAddTraceCollectorDirectoryPathAsTestAdapterForNonCodeCoverageCollect() - { - const string traceDataCollectorDirectoryPath = @"c:\path\to\tracedata collector"; - _vsTestTask.VSTestTraceDataCollectorDirectoryPath = traceDataCollectorDirectoryPath; - _vsTestTask.VSTestCollect = new string[] { "not code coverage" }; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - const string notExpectedArg = "--testAdapterPath:\"c:\\path\\to\\tracedata collector\""; - CollectionAssert.DoesNotContain(allArguments, notExpectedArg, $"Not expected argument: '''{notExpectedArg}''' present in [{string.Join(", ", allArguments)}]"); - } - - [TestMethod] - public void CreateArgumentShouldAddTraceCollectorDirectoryPathAsTestAdapterIfSettingsGiven() - { - const string traceDataCollectorDirectoryPath = @"c:\path\to\tracedatacollector\"; - _vsTestTask.VSTestTraceDataCollectorDirectoryPath = traceDataCollectorDirectoryPath; - _vsTestTask.VSTestSetting = @"c:\path\to\sample.runsettings"; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - const string expectedArg = "--testAdapterPath:c:\\path\\to\\tracedatacollector\\"; - CollectionAssert.Contains(allArguments, expectedArg, $"Expected argument: '''{expectedArg}''' not present in [{string.Join(", ", allArguments)}]"); - } - - [TestMethod] - public void CreateArgumentShouldNotAddTestAdapterPathIfVsTestTraceDataCollectorDirectoryPathIsEmpty() - { - _vsTestTask.VSTestTraceDataCollectorDirectoryPath = string.Empty; - _vsTestTask.VSTestSetting = @"c:\path\to\sample.runsettings"; - _vsTestTask.VSTestCollect = new string[] { "code coverage" }; - - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNull(Array.Find(allArguments, arg => arg.Contains("--testAdapterPath:"))); - } - - [TestMethod] - public void CreateArgumentShouldAddNoLogoOptionIfSpecifiedByUser() - { - _vsTestTask.VSTestNoLogo = "--nologo"; - var allArguments = _vsTestTask.CreateArgument().ToArray(); - - Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--nologo"))); - } -}