diff --git a/src/Microsoft.TestPlatform.Build/ArgumentEscaper.cs b/src/Microsoft.TestPlatform.Build/ArgumentEscaper.cs
deleted file mode 100644
index 86178efb95..0000000000
--- a/src/Microsoft.TestPlatform.Build/ArgumentEscaper.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-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)
- {
- return argument.StartsWith("\"", StringComparison.Ordinal) &&
- argument.EndsWith("\"", StringComparison.Ordinal);
- }
-
- internal static bool ArgumentContainsWhitespace(string argument)
- {
- return 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 8f9d5c4c20..cffc0eca2b 100644
--- a/src/Microsoft.TestPlatform.Build/Microsoft.TestPlatform.targets
+++ b/src/Microsoft.TestPlatform.Build/Microsoft.TestPlatform.targets
@@ -12,10 +12,14 @@ Copyright (c) .NET Foundation. All rights reserved.
- Microsoft.TestPlatform.Build.dll
- $([System.IO.Path]::Combine($(MSBuildThisFileDirectory),"vstest.console.dll"))
+ Microsoft.TestPlatform.Build.dll
+ $([System.IO.Path]::Combine($(MSBuildThisFileDirectory),"vstest.console.dll"))
+ False
+ False
+ <_VSTestMSBuildDependsOn Condition="$(_VSTestMSBuildDependsOn) == '' And !$(VSTestNoBuild)">$(MSBuildProjectDefaultTargets)
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
@@ -68,37 +118,36 @@ Copyright (c) .NET Foundation. All rights reserved.
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
diff --git a/src/Microsoft.TestPlatform.Build/Tasks/ITestTask.cs b/src/Microsoft.TestPlatform.Build/Tasks/ITestTask.cs
new file mode 100644
index 0000000000..adf7791f36
--- /dev/null
+++ b/src/Microsoft.TestPlatform.Build/Tasks/ITestTask.cs
@@ -0,0 +1,41 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.TestPlatform.Build.Tasks
+{
+
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+
+ public 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; }
+
+ TaskLoggingHelper Log { get; }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.Build/Tasks/TestTaskExtensions.cs b/src/Microsoft.TestPlatform.Build/Tasks/TestTaskExtensions.cs
new file mode 100644
index 0000000000..eb2f3169d9
--- /dev/null
+++ b/src/Microsoft.TestPlatform.Build/Tasks/TestTaskExtensions.cs
@@ -0,0 +1,217 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.TestPlatform.Build.Tasks
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using Microsoft.Build.Utilities;
+ using Microsoft.TestPlatform.Build.Resources;
+
+ public static class TestTaskExtensions
+ {
+
+ public static string CreateCommandLineArguments(this ITestTask task)
+ {
+ var isConsoleLoggerSpecifiedByUser = false;
+ var isCollectCodeCoverageEnabled = false;
+ var isRunSettingsEnabled = false;
+
+ var builder = new CommandLineBuilder();
+ builder.AppendSwitch("exec");
+ if (task.VSTestConsolePath != null && !string.IsNullOrEmpty(task.VSTestConsolePath.ItemSpec))
+ {
+ builder.AppendSwitchIfNotNull("", task.VSTestConsolePath);
+ }
+ else
+ {
+ builder.AppendSwitch("vstest.console.dll");
+ }
+
+ // TODO log arguments in task
+ if (!string.IsNullOrEmpty(task.VSTestSetting))
+ {
+ isRunSettingsEnabled = true;
+ builder.AppendSwitchIfNotNull("--settings:", task.VSTestSetting);
+ }
+
+ if (task.VSTestTestAdapterPath != null && task.VSTestTestAdapterPath.Any())
+ {
+ foreach (var arg in task.VSTestTestAdapterPath)
+ {
+ builder.AppendSwitchIfNotNull("--testAdapterPath:", arg);
+ }
+ }
+
+ if (!string.IsNullOrEmpty(task.VSTestFramework))
+ {
+ builder.AppendSwitchIfNotNull("--framework:", task.VSTestFramework);
+ }
+
+ // vstest.console only support x86 and x64 for argument platform
+ if (!string.IsNullOrEmpty(task.VSTestPlatform) && !task.VSTestPlatform.Contains("AnyCPU"))
+ {
+ builder.AppendSwitchIfNotNull("--platform:", task.VSTestPlatform);
+ }
+
+ if (!string.IsNullOrEmpty(task.VSTestTestCaseFilter))
+ {
+ builder.AppendSwitchIfNotNull("--testCaseFilter:", task.VSTestTestCaseFilter);
+ }
+
+ if (task.VSTestLogger != null && task.VSTestLogger.Any())
+ {
+ foreach (var arg in task.VSTestLogger)
+ {
+ builder.AppendSwitchIfNotNull("--logger:", arg);
+
+ if (arg.StartsWith("console", StringComparison.OrdinalIgnoreCase))
+ {
+ isConsoleLoggerSpecifiedByUser = true;
+ }
+ }
+ }
+
+ if (task.VSTestResultsDirectory != null && !string.IsNullOrEmpty(task.VSTestResultsDirectory.ItemSpec))
+ {
+ builder.AppendSwitchIfNotNull("--resultsDirectory:", task.VSTestResultsDirectory);
+ }
+
+ if (task.VSTestListTests)
+ {
+ builder.AppendSwitch("--listTests");
+ }
+
+ if (!string.IsNullOrEmpty(task.VSTestDiag))
+ {
+ builder.AppendSwitchIfNotNull("--Diag:", task.VSTestDiag);
+ }
+
+ if (task.TestFileFullPath != null)
+ {
+ builder.AppendFileNameIfNotNull(task.TestFileFullPath);
+ }
+
+ // Console logger was not specified by user, but verbosity was, hence add default console logger with verbosity as specified
+ if (!string.IsNullOrWhiteSpace(task.VSTestVerbosity) && !isConsoleLoggerSpecifiedByUser)
+ {
+ var normalTestLogging = new List() { "n", "normal", "d", "detailed", "diag", "diagnostic" };
+ var quietTestLogging = new List() { "q", "quiet" };
+
+ string vsTestVerbosity = "minimal";
+ if (normalTestLogging.Contains(task.VSTestVerbosity, StringComparer.InvariantCultureIgnoreCase))
+ {
+ vsTestVerbosity = "normal";
+ }
+ else if (quietTestLogging.Contains(task.VSTestVerbosity, StringComparer.InvariantCultureIgnoreCase))
+ {
+ vsTestVerbosity = "quiet";
+ }
+
+ builder.AppendSwitchUnquotedIfNotNull("--logger:", $"Console;Verbosity={vsTestVerbosity}");
+ }
+
+ if (task.VSTestBlame)
+ {
+ var dumpArgs = new List();
+ if (task.VSTestBlameCrash || task.VSTestBlameHang)
+ {
+ if (task.VSTestBlameCrash)
+ {
+ dumpArgs.Add("CollectDump");
+
+ if (task.VSTestBlameCrashCollectAlways)
+ {
+ dumpArgs.Add($"CollectAlways={task.VSTestBlameCrashCollectAlways}");
+ }
+
+ if (!string.IsNullOrEmpty(task.VSTestBlameCrashDumpType))
+ {
+ dumpArgs.Add($"DumpType={task.VSTestBlameCrashDumpType}");
+ }
+ }
+
+ if (task.VSTestBlameHang)
+ {
+ dumpArgs.Add("CollectHangDump");
+
+ if (!string.IsNullOrEmpty(task.VSTestBlameHangDumpType))
+ {
+ dumpArgs.Add($"HangDumpType={task.VSTestBlameHangDumpType}");
+ }
+
+ if (!string.IsNullOrEmpty(task.VSTestBlameHangTimeout))
+ {
+ dumpArgs.Add($"TestTimeout={task.VSTestBlameHangTimeout}");
+ }
+ }
+ }
+
+ if (dumpArgs.Any())
+ {
+ builder.AppendSwitchIfNotNull("--Blame:", string.Join(";", dumpArgs));
+ }
+ else
+ {
+ builder.AppendSwitch("--Blame");
+ }
+ }
+
+ if (task.VSTestCollect != null && task.VSTestCollect.Any())
+ {
+ foreach (var arg in task.VSTestCollect)
+ {
+ if (arg.Equals("Code Coverage", 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 && !string.IsNullOrEmpty(task.VSTestTraceDataCollectorDirectoryPath.ItemSpec))
+ {
+ 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.UpdateTestSdkForCollectingCodeCoverage);
+ }
+ }
+ }
+
+ if (task.VSTestNoLogo)
+ {
+ builder.AppendSwitch("--nologo");
+ }
+
+ // VSTestCLIRunSettings should be last argument as vstest.console ignore options after "--"(CLIRunSettings option).
+ if (task.VSTestCLIRunSettings != null && task.VSTestCLIRunSettings.Any())
+ {
+ 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 0131b222d5..0000000000
--- a/src/Microsoft.TestPlatform.Build/Tasks/VSTestForwardingApp.cs
+++ /dev/null
@@ -1,64 +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.
-
-namespace Microsoft.TestPlatform.Build.Tasks
-{
- using Microsoft.TestPlatform.Build.Utils;
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using Trace;
-
- public class VSTestForwardingApp
- {
- private const string hostExe = "dotnet";
- private readonly List allArgs = new List();
- private int activeProcessId;
-
- public VSTestForwardingApp(string vsTestExePath, IEnumerable argsToForward)
- {
- this.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.
- this.allArgs.Add(ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(vsTestExePath));
- this.allArgs.AddRange(argsToForward);
- }
-
- public int Execute()
- {
- var processInfo = new ProcessStartInfo
- {
- FileName = hostExe,
- Arguments = string.Join(" ", this.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();
- this.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(string.Format("VSTest: Killing process throws ArgumentException with the following message {0}. It may be that process is not running", ex));
- }
- }
- }
-}
diff --git a/src/Microsoft.TestPlatform.Build/Tasks/VSTestForwardingTask.cs b/src/Microsoft.TestPlatform.Build/Tasks/VSTestForwardingTask.cs
new file mode 100644
index 0000000000..52c3bea16a
--- /dev/null
+++ b/src/Microsoft.TestPlatform.Build/Tasks/VSTestForwardingTask.cs
@@ -0,0 +1,108 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.TestPlatform.Build.Tasks
+{
+ using System;
+ using System.Diagnostics;
+ using System.Threading;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+ using Microsoft.TestPlatform.Build.Resources;
+ using Microsoft.TestPlatform.Build.Trace;
+
+ public class VSTestForwardingTask : Task, ITestTask
+ {
+ private const string toolExe = "dotnet";
+ private int activeProcessId;
+
+ 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 override bool Execute()
+ {
+ var traceEnabledValue = Environment.GetEnvironmentVariable("VSTEST_BUILD_TRACE");
+ Tracing.traceEnabled = !string.IsNullOrEmpty(traceEnabledValue) && traceEnabledValue.Equals("1", StringComparison.OrdinalIgnoreCase);
+
+ var debugEnabled = Environment.GetEnvironmentVariable("VSTEST_BUILD_DEBUG");
+ if (!string.IsNullOrEmpty(debugEnabled) && debugEnabled.Equals("1", StringComparison.Ordinal))
+ {
+ Console.WriteLine("Waiting for debugger attach...");
+
+ var currentProcess = Process.GetCurrentProcess();
+ Console.WriteLine(string.Format("Process Id: {0}, Name: {1}", currentProcess.Id, currentProcess.ProcessName));
+
+ while (!Debugger.IsAttached)
+ {
+ Thread.Sleep(1000);
+ }
+
+ Debugger.Break();
+ }
+
+ // 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 processInfo = new ProcessStartInfo
+ {
+ FileName = toolExe,
+ Arguments = this.CreateCommandLineArguments(),
+ UseShellExecute = false,
+ };
+
+ if (!string.IsNullOrEmpty(this.VSTestFramework))
+ {
+ Console.WriteLine(Resources.TestRunningSummary, this.TestFileFullPath, this.VSTestFramework);
+ }
+
+ Tracing.Trace("VSTest: Starting vstest.console...");
+ Tracing.Trace("VSTest: Arguments: " + processInfo.FileName + " " + processInfo.Arguments);
+
+ using (var activeProcess = new Process { StartInfo = processInfo })
+ {
+ activeProcess.Start();
+ this.activeProcessId = activeProcess.Id;
+
+ activeProcess.WaitForExit();
+ Tracing.Trace("VSTest: Exit code: " + activeProcess.ExitCode);
+ return activeProcess.ExitCode == 0;
+ }
+ }
+ public void Cancel()
+ {
+ Tracing.Trace("VSTest: Killing the process...");
+ try
+ {
+ Process.GetProcessById(activeProcessId).Kill();
+ }
+ catch (ArgumentException ex)
+ {
+ Tracing.Trace(string.Format("VSTest: Killing process throws ArgumentException with the following message {0}. It may be that process is not running", ex));
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.Build/Tasks/VSTestTask.cs b/src/Microsoft.TestPlatform.Build/Tasks/VSTestTask.cs
index 2d151decb3..4f9336ea65 100644
--- a/src/Microsoft.TestPlatform.Build/Tasks/VSTestTask.cs
+++ b/src/Microsoft.TestPlatform.Build/Tasks/VSTestTask.cs
@@ -4,411 +4,94 @@
namespace Microsoft.TestPlatform.Build.Tasks
{
using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Linq;
- using System.Threading;
+ using System.IO;
+ using System.Runtime.InteropServices;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
- using Microsoft.TestPlatform.Build.Resources;
- using Microsoft.TestPlatform.Build.Utils;
- using Trace;
- public class VSTestTask : Task, ICancelableTask
+ public class VSTestTask : ToolTask, ITestTask
{
- // The process which is invoking vstest.console
- private VSTestForwardingApp vsTestForwardingApp;
-
- private const string vsTestAppName = "vstest.console.dll";
-
- public string TestFileFullPath
- {
- get;
- set;
- }
-
- public string VSTestSetting
- {
- get;
- set;
- }
-
- public string[] 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 string VSTestDiag
- {
- get;
- set;
- }
-
- public string[] VSTestCLIRunSettings
- {
- get;
- set;
- }
+ 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 string VSTestConsolePath
- {
- get;
- set;
- }
-
- public string VSTestResultsDirectory
- {
- get;
- set;
- }
-
- public string VSTestVerbosity
- {
- get;
- set;
- }
-
- public string[] VSTestCollect
- {
- get;
- set;
- }
-
- public string VSTestBlame
- {
- get;
- set;
- }
-
- public string VSTestBlameCrash
- {
- get;
- set;
- }
-
- public string VSTestBlameCrashDumpType
- {
- get;
- set;
- }
-
- public string VSTestBlameCrashCollectAlways
- {
- get;
- set;
- }
-
- public string VSTestBlameHang
- {
- get;
- set;
- }
-
- public string VSTestBlameHangDumpType
- {
- get;
- set;
- }
- public string VSTestBlameHangTimeout
- {
- get;
- set;
- }
-
- public string VSTestTraceDataCollectorDirectoryPath
- {
- get;
- set;
- }
-
- public string VSTestNoLogo
- {
- get;
- set;
- }
-
- public override bool Execute()
- {
- var traceEnabledValue = Environment.GetEnvironmentVariable("VSTEST_BUILD_TRACE");
- Tracing.traceEnabled = !string.IsNullOrEmpty(traceEnabledValue) && traceEnabledValue.Equals("1", StringComparison.OrdinalIgnoreCase);
-
- var debugEnabled = Environment.GetEnvironmentVariable("VSTEST_BUILD_DEBUG");
- if (!string.IsNullOrEmpty(debugEnabled) && debugEnabled.Equals("1", StringComparison.Ordinal))
- {
- Console.WriteLine("Waiting for debugger attach...");
-
- var currentProcess = Process.GetCurrentProcess();
- Console.WriteLine(string.Format("Process Id: {0}, Name: {1}", currentProcess.Id, currentProcess.ProcessName));
-
- while (!Debugger.IsAttached)
- {
- Thread.Sleep(1000);
- }
-
- Debugger.Break();
- }
-
- // 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);
-
- vsTestForwardingApp = new VSTestForwardingApp(this.VSTestConsolePath, this.CreateArgument());
- if (!string.IsNullOrEmpty(this.VSTestFramework))
- {
- Console.WriteLine(Resources.TestRunningSummary, this.TestFileFullPath, this.VSTestFramework);
+ 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; }
+
+ protected override string ToolName
+ {
+ get
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ return "dotnet.exe";
+ else
+ return "dotnet";
}
-
- return vsTestForwardingApp.Execute() == 0;
}
- public void Cancel()
+ public VSTestTask()
{
- Tracing.Trace("VSTest: Killing the process...");
- vsTestForwardingApp.Cancel();
+ this.LogStandardErrorAsError = true;
+ this.StandardOutputImportance = "Normal";
}
- internal IEnumerable CreateArgument()
+ protected override string GenerateCommandLineCommands()
{
- var allArgs = this.AddArgs();
-
- // VSTestCLIRunSettings should be last argument in allArgs as vstest.console ignore options after "--"(CLIRunSettings option).
- this.AddCLIRunSettingsArgs(allArgs);
-
- return allArgs;
+ return this.CreateCommandLineArguments();
}
- private void AddCLIRunSettingsArgs(List allArgs)
+ protected override string GenerateFullPathToTool()
{
- if (this.VSTestCLIRunSettings != null && this.VSTestCLIRunSettings.Length > 0)
- {
- allArgs.Add("--");
- foreach (var arg in this.VSTestCLIRunSettings)
- {
- allArgs.Add(ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(arg));
- }
- }
- }
-
- private List AddArgs()
- {
- var isConsoleLoggerSpecifiedByUser = false;
- var isCollectCodeCoverageEnabled = false;
- var isRunSettingsEnabled = false;
- var allArgs = new List();
-
- // TODO log arguments in task
- if (!string.IsNullOrEmpty(this.VSTestSetting))
- {
- isRunSettingsEnabled = true;
- allArgs.Add("--settings:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(this.VSTestSetting));
- }
-
- if (this.VSTestTestAdapterPath != null && this.VSTestTestAdapterPath.Length > 0)
- {
- foreach (var arg in this.VSTestTestAdapterPath)
- {
- allArgs.Add("--testAdapterPath:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(arg));
- }
- }
-
- if (!string.IsNullOrEmpty(this.VSTestFramework))
- {
- allArgs.Add("--framework:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(this.VSTestFramework));
- }
-
- // vstest.console only support x86 and x64 for argument platform
- if (!string.IsNullOrEmpty(this.VSTestPlatform) && !this.VSTestPlatform.Contains("AnyCPU"))
- {
- allArgs.Add("--platform:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(this.VSTestPlatform));
- }
-
- if (!string.IsNullOrEmpty(this.VSTestTestCaseFilter))
- {
- allArgs.Add("--testCaseFilter:" +
- ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(this.VSTestTestCaseFilter));
- }
-
- if (this.VSTestLogger != null && this.VSTestLogger.Length > 0)
- {
- foreach (var arg in this.VSTestLogger)
- {
- allArgs.Add("--logger:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(arg));
-
- if (arg.StartsWith("console", StringComparison.OrdinalIgnoreCase))
- {
- isConsoleLoggerSpecifiedByUser = true;
- }
- }
- }
-
- if (!string.IsNullOrEmpty(this.VSTestResultsDirectory))
- {
- allArgs.Add("--resultsDirectory:" +
- ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(this.VSTestResultsDirectory));
- }
-
- if (!string.IsNullOrEmpty(this.VSTestListTests))
- {
- allArgs.Add("--listTests");
- }
-
- if (!string.IsNullOrEmpty(this.VSTestDiag))
- {
- allArgs.Add("--Diag:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(this.VSTestDiag));
- }
-
- if (string.IsNullOrEmpty(this.TestFileFullPath))
+ if (!string.IsNullOrEmpty(ToolPath))
{
- this.Log.LogError("Test file path cannot be empty or null.");
- }
- else
- {
- allArgs.Add(ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(this.TestFileFullPath));
- }
-
- // Console logger was not specified by user, but verbosity was, hence add default console logger with verbosity as specified
- if (!string.IsNullOrWhiteSpace(this.VSTestVerbosity) && !isConsoleLoggerSpecifiedByUser)
- {
- var normalTestLogging = new List() { "n", "normal", "d", "detailed", "diag", "diagnostic" };
- var quietTestLogging = new List() { "q", "quiet" };
-
- string vsTestVerbosity = "minimal";
- if (normalTestLogging.Contains(this.VSTestVerbosity.ToLowerInvariant()))
- {
- vsTestVerbosity = "normal";
- }
- else if (quietTestLogging.Contains(this.VSTestVerbosity.ToLowerInvariant()))
- {
- vsTestVerbosity = "quiet";
- }
-
- allArgs.Add("--logger:Console;Verbosity=" + vsTestVerbosity);
+ return Path.Combine(Path.GetDirectoryName(Path.GetFullPath(ToolPath)), ToolExe);
}
- var blameCrash = !string.IsNullOrEmpty(this.VSTestBlameCrash);
- var blameHang = !string.IsNullOrEmpty(this.VSTestBlameHang);
- if (!string.IsNullOrEmpty(this.VSTestBlame) || blameCrash || blameHang)
- {
- var blameArgs = "--Blame";
-
- var dumpArgs = new List();
- if (blameCrash || blameHang)
- {
- if (blameCrash)
- {
- dumpArgs.Add("CollectDump");
- if (!string.IsNullOrEmpty(this.VSTestBlameCrashCollectAlways))
- {
- dumpArgs.Add($"CollectAlways={this.VSTestBlameCrashCollectAlways}");
- }
-
- if (!string.IsNullOrEmpty(this.VSTestBlameCrashDumpType))
- {
- dumpArgs.Add($"DumpType={this.VSTestBlameCrashDumpType}");
- }
- }
-
- if (blameHang)
- {
- dumpArgs.Add("CollectHangDump");
-
- if (!string.IsNullOrEmpty(this.VSTestBlameHangDumpType))
- {
- dumpArgs.Add($"HangDumpType={this.VSTestBlameHangDumpType}");
- }
+ //TODO: https://github.com/dotnet/sdk/issues/20 Need to get the dotnet path from MSBuild?
- if (!string.IsNullOrEmpty(this.VSTestBlameHangTimeout))
- {
- dumpArgs.Add($"TestTimeout={this.VSTestBlameHangTimeout}");
- }
- }
-
- if (dumpArgs.Any())
- {
- blameArgs += $":\"{string.Join(";", dumpArgs)}\"";
- }
- }
-
- allArgs.Add(blameArgs);
- }
-
- if (this.VSTestCollect != null && this.VSTestCollect.Length > 0)
+ var dhp = Environment.GetEnvironmentVariable("DOTNET_HOST_PATH");
+ if (!string.IsNullOrEmpty(dhp))
{
- foreach (var arg in this.VSTestCollect)
+ var path = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(dhp)), ToolExe);
+ if (File.Exists(path))
{
- if (arg.Equals("Code Coverage", StringComparison.OrdinalIgnoreCase))
- {
- isCollectCodeCoverageEnabled = true;
- }
-
- allArgs.Add("--collect:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(arg));
+ return path;
}
}
- if (isCollectCodeCoverageEnabled || isRunSettingsEnabled)
+ if (File.Exists(ToolExe))
{
- // 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 (!string.IsNullOrEmpty(this.VSTestTraceDataCollectorDirectoryPath))
- {
- allArgs.Add("--testAdapterPath:" +
- ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(this
- .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.UpdateTestSdkForCollectingCodeCoverage);
- }
- }
+ return Path.GetFullPath(ToolExe);
}
- if (!string.IsNullOrWhiteSpace(this.VSTestNoLogo))
+ var values = Environment.GetEnvironmentVariable("PATH");
+ foreach (var p in values.Split(Path.PathSeparator))
{
- allArgs.Add("--nologo");
+ var fullPath = Path.Combine(p, ToolExe);
+ if (File.Exists(fullPath))
+ return fullPath;
}
- return allArgs;
+ return null;
}
}
}
diff --git a/test/Microsoft.TestPlatform.Build.UnitTests/ArgumentEscaperTests.cs b/test/Microsoft.TestPlatform.Build.UnitTests/ArgumentEscaperTests.cs
deleted file mode 100644
index e71cb67c55..0000000000
--- a/test/Microsoft.TestPlatform.Build.UnitTests/ArgumentEscaperTests.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-namespace Microsoft.TestPlatform.Build.Utils.UnitTests
-{
- using Microsoft.VisualStudio.TestTools.UnitTesting;
-
- [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 IsSurroundedWithQuotesShouldReturnTrueIfStringIsSurrondedByQuotes()
- {
- string stringSurroundWithQuotes = "\"some string\"";
-
- Assert.IsTrue(ArgumentEscaper.IsSurroundedWithQuotes(stringSurroundWithQuotes));
- }
-
- [TestMethod]
- public void IsSurroundedWithQuotesShouldReturnFalseIfStringIsNotSurrondedByQuotes()
- {
- 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..fd94e651c6
--- /dev/null
+++ b/test/Microsoft.TestPlatform.Build.UnitTests/FakeBuildEngine.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+namespace Microsoft.TestPlatform.Build.UnitTests
+{
+ using System.Collections;
+ using Microsoft.Build.Framework;
+
+ 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)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.TestPlatform.Build.UnitTests/VsTestTaskTests.cs b/test/Microsoft.TestPlatform.Build.UnitTests/VsTestTaskTests.cs
index e3ddc98587..d8e7989d4a 100644
--- a/test/Microsoft.TestPlatform.Build.UnitTests/VsTestTaskTests.cs
+++ b/test/Microsoft.TestPlatform.Build.UnitTests/VsTestTaskTests.cs
@@ -2,9 +2,9 @@
namespace Microsoft.TestPlatform.Build.UnitTests
{
- using System;
- using System.Linq;
-
+ using System.Text.RegularExpressions;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
using Microsoft.TestPlatform.Build.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -17,7 +17,8 @@ public VSTestTaskTests()
{
this.vsTestTask = new VSTestTask
{
- TestFileFullPath = @"C:\path\to\test-assembly.dll",
+ BuildEngine = new FakeBuildEngine(),
+ TestFileFullPath = new TaskItem(@"C:\path\to\test-assembly.dll"),
VSTestFramework = ".NETCoreapp,Version2.0"
};
}
@@ -32,13 +33,11 @@ public void CreateArgumentShouldAddOneEntryForCLIRunSettings()
this.vsTestTask.VSTestCLIRunSettings[0] = arg1;
this.vsTestTask.VSTestCLIRunSettings[1] = arg2;
- var result = this.vsTestTask.CreateArgument().ToArray();
-
- Assert.AreEqual(5, result.Length);
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- // First, second and third args would be framework:".NETCoreapp,Version2.0", testfilepath and -- respectively.
- Assert.AreEqual($"\"{arg1}\"", result[3]);
- Assert.AreEqual($"{arg2}", result[4]);
+ StringAssert.Contains(commandline, " -- ");
+ StringAssert.Contains(commandline, $"\"{arg1}\"");
+ StringAssert.Contains(commandline, $"{arg2}");
}
[TestMethod]
@@ -47,7 +46,7 @@ public void CreateArgumentShouldAddCLIRunSettingsArgAtEnd()
const string codeCoverageOption = "Code Coverage";
this.vsTestTask.VSTestCollect = new string[] { codeCoverageOption };
- this.vsTestTask.VSTestBlame = "Blame";
+ this.vsTestTask.VSTestBlame = true;
const string arg1 = "RunConfiguration.ResultsDirectory=Path having Space";
const string arg2 = "MSTest.DeploymentEnabled";
@@ -56,24 +55,22 @@ public void CreateArgumentShouldAddCLIRunSettingsArgAtEnd()
this.vsTestTask.VSTestCLIRunSettings[0] = arg1;
this.vsTestTask.VSTestCLIRunSettings[1] = arg2;
- var result = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- 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]);
+ StringAssert.Contains(commandline, " -- ");
+ StringAssert.Contains(commandline, $"\"{arg1}\"");
+ StringAssert.Contains(commandline, $"{arg2}");
}
[TestMethod]
public void CreateArgumentShouldPassResultsDirectoryCorrectly()
{
const string resultsDirectoryValue = @"C:\tmp\Results Directory";
- this.vsTestTask.VSTestResultsDirectory = resultsDirectoryValue;
+ this.vsTestTask.VSTestResultsDirectory = new TaskItem(resultsDirectoryValue);
- var result = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.AreEqual($"--resultsDirectory:\"{resultsDirectoryValue}\"", result[1]);
+ StringAssert.Contains(commandline, $"--resultsDirectory:\"{this.vsTestTask.VSTestResultsDirectory.ItemSpec}\"");
}
[TestMethod]
@@ -82,10 +79,10 @@ public void CreateArgumentShouldNotSetConsoleLoggerVerbosityIfConsoleLoggerIsGiv
this.vsTestTask.VSTestVerbosity = "diag";
this.vsTestTask.VSTestLogger = new string[] { "Console;Verbosity=quiet" };
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal")));
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=quiet")));
+ StringAssert.DoesNotMatch(commandline, new Regex("(--logger:\"Console;Verbosity=normal\")"));
+ StringAssert.Contains(commandline, "--logger:\"Console;Verbosity=quiet\"");
}
[TestMethod]
@@ -93,9 +90,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLogger
{
this.vsTestTask.VSTestVerbosity = "n";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal");
}
[TestMethod]
@@ -103,9 +100,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLogger
{
this.vsTestTask.VSTestVerbosity = "normal";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal");
}
[TestMethod]
@@ -113,9 +110,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLogger
{
this.vsTestTask.VSTestVerbosity = "d";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal");
}
[TestMethod]
@@ -123,9 +120,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLogger
{
this.vsTestTask.VSTestVerbosity = "detailed";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal");
}
[TestMethod]
@@ -133,9 +130,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLogger
{
this.vsTestTask.VSTestVerbosity = "diag";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal");
}
[TestMethod]
@@ -143,9 +140,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLogger
{
this.vsTestTask.VSTestVerbosity = "diagnostic";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal");
}
[TestMethod]
@@ -153,9 +150,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToQuietIfConsoleLoggerI
{
this.vsTestTask.VSTestVerbosity = "q";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=quiet")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=quiet");
}
[TestMethod]
@@ -163,9 +160,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToQuietIfConsoleLoggerI
{
this.vsTestTask.VSTestVerbosity = "quiet";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=quiet")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=quiet");
}
[TestMethod]
@@ -173,9 +170,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToMinimalIfConsoleLogge
{
this.vsTestTask.VSTestVerbosity = "m";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=minimal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=minimal");
}
[TestMethod]
@@ -183,9 +180,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToMinimalIfConsoleLogge
{
this.vsTestTask.VSTestVerbosity = "minimal";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=minimal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=minimal");
}
[TestMethod]
@@ -193,9 +190,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLogger
{
this.vsTestTask.VSTestVerbosity = "Normal";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=normal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal");
}
[TestMethod]
@@ -203,9 +200,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToQuietIfConsoleLoggerI
{
this.vsTestTask.VSTestVerbosity = "Quiet";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:Console;Verbosity=quiet")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=quiet");
}
[TestMethod]
@@ -213,9 +210,9 @@ public void CreateArgumentShouldPreserveWhiteSpaceInLogger()
{
this.vsTestTask.VSTestLogger = new string[] { "trx;LogFileName=foo bar.trx" };
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:\"trx;LogFileName=foo bar.trx\"")));
+ StringAssert.Contains(commandline, "--logger:\"trx;LogFileName=foo bar.trx\"");
}
[TestMethod]
@@ -226,91 +223,92 @@ public void CreateArgumentShouldAddOneCollectArgumentForEachCollect()
this.vsTestTask.VSTestCollect[0] = "name1";
this.vsTestTask.VSTestCollect[1] = "name 2";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--collect:name1")));
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--collect:\"name 2\"")));
+ StringAssert.Contains(commandline, "--collect:name1");
+ StringAssert.Contains(commandline, "--collect:\"name 2\"");
}
[TestMethod]
public void CreateArgumentShouldAddMultipleTestAdapterPaths()
{
- this.vsTestTask.VSTestTestAdapterPath = new string[] { "path1", "path2" };
+ this.vsTestTask.VSTestTestAdapterPath = new ITaskItem[] { new TaskItem("path1"), new TaskItem("path2") };
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--testAdapterPath:path1")));
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--testAdapterPath:path2")));
+ StringAssert.Contains(commandline, "--testAdapterPath:path1");
+ StringAssert.Contains(commandline, "--testAdapterPath:path2");
}
[TestMethod]
public void CreateArgumentShouldAddMultipleLoggers()
{
this.vsTestTask.VSTestLogger = new string[] { "trx;LogFileName=foo bar.trx", "console" };
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:\"trx;LogFileName=foo bar.trx\"")));
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--logger:console")));
+ 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";
- this.vsTestTask.VSTestTraceDataCollectorDirectoryPath = traceDataCollectorDirectoryPath;
+ this.vsTestTask.VSTestTraceDataCollectorDirectoryPath = new TaskItem(traceDataCollectorDirectoryPath);
this.vsTestTask.VSTestCollect = new string[] { "code coverage" };
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- const string expectedArg = "--testAdapterPath:\"c:\\path\\to\\tracedata collector\"";
- CollectionAssert.Contains(allArguments, expectedArg, $"Expected argument: '''{expectedArg}''' not present in [{string.Join(", ", allArguments)}]");
+ string expectedArg = $"--testAdapterPath:\"{this.vsTestTask.VSTestTraceDataCollectorDirectoryPath.ItemSpec}\"";
+ StringAssert.Contains(commandline, expectedArg);
}
[TestMethod]
public void CreateArgumentShouldNotAddTraceCollectorDirectoryPathAsTestAdapterForNonCodeCoverageCollect()
{
const string traceDataCollectorDirectoryPath = @"c:\path\to\tracedata collector";
- this.vsTestTask.VSTestTraceDataCollectorDirectoryPath = traceDataCollectorDirectoryPath;
+ this.vsTestTask.VSTestTraceDataCollectorDirectoryPath = new TaskItem(traceDataCollectorDirectoryPath);
this.vsTestTask.VSTestCollect = new string[] { "not code coverage" };
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- const string notExpectedArg = "--testAdapterPath:\"c:\\path\\to\\tracedata collector\"";
- CollectionAssert.DoesNotContain(allArguments, notExpectedArg, $"Not expected argument: '''{notExpectedArg}''' present in [{string.Join(", ", allArguments)}]");
+ string notExpectedArg = $"--testAdapterPath:\"{this.vsTestTask.VSTestTraceDataCollectorDirectoryPath.ItemSpec}\"";
+ StringAssert.DoesNotMatch(commandline, new Regex(Regex.Escape(notExpectedArg)));
}
[TestMethod]
public void CreateArgumentShouldAddTraceCollectorDirectoryPathAsTestAdapterIfSettingsGiven()
{
const string traceDataCollectorDirectoryPath = @"c:\path\to\tracedatacollector\";
- this.vsTestTask.VSTestTraceDataCollectorDirectoryPath = traceDataCollectorDirectoryPath;
+ this.vsTestTask.VSTestTraceDataCollectorDirectoryPath = new TaskItem(traceDataCollectorDirectoryPath);
this.vsTestTask.VSTestSetting = @"c:\path\to\sample.runsettings";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- const string expectedArg = "--testAdapterPath:c:\\path\\to\\tracedatacollector\\";
- CollectionAssert.Contains(allArguments, expectedArg, $"Expected argument: '''{expectedArg}''' not present in [{string.Join(", ", allArguments)}]");
+ string expectedArg = $"--testAdapterPath:{this.vsTestTask.VSTestTraceDataCollectorDirectoryPath.ItemSpec}";
+ StringAssert.Contains(commandline, expectedArg);
}
[TestMethod]
public void CreateArgumentShouldNotAddTestAdapterPathIfVSTestTraceDataCollectorDirectoryPathIsEmpty()
{
- this.vsTestTask.VSTestTraceDataCollectorDirectoryPath = string.Empty;
+ this.vsTestTask.VSTestTraceDataCollectorDirectoryPath = null;
this.vsTestTask.VSTestSetting = @"c:\path\to\sample.runsettings";
this.vsTestTask.VSTestCollect = new string[] { "code coverage" };
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNull(Array.Find(allArguments, arg => arg.Contains("--testAdapterPath:")));
+ StringAssert.DoesNotMatch(commandline, new Regex(@"(--testAdapterPath:)"));
}
[TestMethod]
public void CreateArgumentShouldAddNoLogoOptionIfSpecifiedByUser()
{
- this.vsTestTask.VSTestNoLogo = "--nologo";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ this.vsTestTask.VSTestNoLogo = true;
+
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(Array.Find(allArguments, arg => arg.Contains("--nologo")));
+ StringAssert.Contains(commandline, "--nologo");
}
}
-}
+}
\ No newline at end of file
diff --git a/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs b/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs
index b7181a2fe6..b38d5a4cd6 100644
--- a/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs
+++ b/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs
@@ -139,7 +139,7 @@ public void InvokeDotnetTest(string arguments)
Environment.SetEnvironmentVariable(env, vstestConsolePath);
if (arguments.Contains(".csproj"))
{
- arguments = $@"-p:VsTestConsolePath=""{vstestConsolePath}"" " + arguments;
+ arguments = $@"-p:VsTestConsolePath=""{vstestConsolePath}"" -p:VSTestUseConsole=True " + arguments;
}
this.ExecutePatchedDotnet("test", arguments, out this.standardTestOutput, out this.standardTestError, out this.runnerExitCode);