diff --git a/src/Microsoft.TestPlatform.Build/ArgumentEscaper.cs b/src/Microsoft.TestPlatform.Build/ArgumentEscaper.cs
deleted file mode 100644
index 46f64427e6..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..eaf6791b0c 100644
--- a/src/Microsoft.TestPlatform.Build/Microsoft.TestPlatform.targets
+++ b/src/Microsoft.TestPlatform.Build/Microsoft.TestPlatform.targets
@@ -25,7 +25,7 @@ Copyright (c) .NET Foundation. All rights reserved.
============================================================
-->
-
+
@@ -53,7 +53,8 @@ Copyright (c) .NET Foundation. All rights reserved.
VSTestBlameHangTimeout="$(VSTestBlameHangTimeout)"
VSTestTraceDataCollectorDirectoryPath="$(TraceDataCollectorDirectoryPath)"
VSTestNoLogo="$(VSTestNoLogo)"
- Condition="'$(IsTestProject)' == 'true'"
+ YieldDuringToolExecution="True"
+ Condition="$(IsTestProject)"
/>
@@ -68,37 +69,37 @@ Copyright (c) .NET Foundation. All rights reserved.
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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/VSTestTask.cs b/src/Microsoft.TestPlatform.Build/Tasks/VSTestTask.cs
index df681503ed..14f4c670a1 100644
--- a/src/Microsoft.TestPlatform.Build/Tasks/VSTestTask.cs
+++ b/src/Microsoft.TestPlatform.Build/Tasks/VSTestTask.cs
@@ -5,21 +5,19 @@ namespace Microsoft.TestPlatform.Build.Tasks
{
using System;
using System.Collections.Generic;
+ using System.IO;
using System.Linq;
+ 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
{
- // The process which is invoking vstest.console
- private VSTestForwardingApp vsTestForwardingApp;
- private const string vsTestAppName = "vstest.console.dll";
-
- public string TestFileFullPath
+ [Required]
+ //TODO: rename, as relative paths are allowed?
+ public ITaskItem TestFileFullPath
{
get;
set;
@@ -31,7 +29,7 @@ public string VSTestSetting
set;
}
- public string[] VSTestTestAdapterPath
+ public ITaskItem[] VSTestTestAdapterPath
{
get;
set;
@@ -60,7 +58,7 @@ public string[] VSTestLogger
set;
}
- public string VSTestListTests
+ public bool VSTestListTests
{
get;
set;
@@ -79,13 +77,13 @@ public string[] VSTestCLIRunSettings
}
[Required]
- public string VSTestConsolePath
+ public ITaskItem VSTestConsolePath
{
get;
set;
}
- public string VSTestResultsDirectory
+ public ITaskItem VSTestResultsDirectory
{
get;
set;
@@ -103,13 +101,13 @@ public string[] VSTestCollect
set;
}
- public string VSTestBlame
+ public bool VSTestBlame
{
get;
set;
}
- public string VSTestBlameCrash
+ public bool VSTestBlameCrash
{
get;
set;
@@ -121,13 +119,13 @@ public string VSTestBlameCrashDumpType
set;
}
- public string VSTestBlameCrashCollectAlways
+ public bool VSTestBlameCrashCollectAlways
{
get;
set;
}
- public string VSTestBlameHang
+ public bool VSTestBlameHang
{
get;
set;
@@ -138,110 +136,87 @@ public string VSTestBlameHangDumpType
get;
set;
}
+
public string VSTestBlameHangTimeout
{
get;
set;
}
- public string VSTestTraceDataCollectorDirectoryPath
+ public ITaskItem VSTestTraceDataCollectorDirectoryPath
{
get;
set;
}
- public string VSTestNoLogo
+ public bool VSTestNoLogo
{
get;
set;
}
- public override bool Execute()
+ protected override string ToolName
{
- var traceEnabledValue = Environment.GetEnvironmentVariable("VSTEST_BUILD_TRACE");
- Tracing.traceEnabled = !string.IsNullOrEmpty(traceEnabledValue) && traceEnabledValue.Equals("1", StringComparison.OrdinalIgnoreCase);
-
- vsTestForwardingApp = new VSTestForwardingApp(this.VSTestConsolePath, this.CreateArgument());
- if (!string.IsNullOrEmpty(this.VSTestFramework))
+ get
{
- Console.WriteLine(Resources.TestRunningSummary, this.TestFileFullPath, this.VSTestFramework);
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ return "dotnet.exe";
+ else
+ return "dotnet";
}
-
- return vsTestForwardingApp.Execute() == 0;
- }
-
- public void Cancel()
- {
- Tracing.Trace("VSTest: Killing the process...");
- vsTestForwardingApp.Cancel();
- }
-
- internal IEnumerable CreateArgument()
- {
- var allArgs = this.AddArgs();
-
- // VSTestCLIRunSettings should be last argument in allArgs as vstest.console ignore options after "--"(CLIRunSettings option).
- this.AddCLIRunSettingsArgs(allArgs);
-
- return allArgs;
}
- private void AddCLIRunSettingsArgs(List allArgs)
+ public VSTestTask()
{
- if (this.VSTestCLIRunSettings != null && this.VSTestCLIRunSettings.Length > 0)
- {
- allArgs.Add("--");
- foreach (var arg in this.VSTestCLIRunSettings)
- {
- allArgs.Add(ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(arg));
- }
- }
+ this.LogStandardErrorAsError = true;
+ this.StandardOutputImportance = "Normal";
}
- private List AddArgs()
+ protected override string GenerateCommandLineCommands()
{
var isConsoleLoggerSpecifiedByUser = false;
var isCollectCodeCoverageEnabled = false;
var isRunSettingsEnabled = false;
- var allArgs = new List();
- // TODO log arguments in task
- if (!string.IsNullOrEmpty(this.VSTestSetting))
+ var builder = new CommandLineBuilder();
+ builder.AppendSwitch("exec");
+ builder.AppendSwitchIfNotNull("", this.VSTestConsolePath);
+
+ if (this.VSTestSetting != null)
{
isRunSettingsEnabled = true;
- allArgs.Add("--settings:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(this.VSTestSetting));
+ builder.AppendSwitchIfNotNull("--settings:", this.VSTestSetting);
}
- if (this.VSTestTestAdapterPath != null && this.VSTestTestAdapterPath.Length > 0)
+ if (this.VSTestTestAdapterPath != null && this.VSTestTestAdapterPath.Any())
{
foreach (var arg in this.VSTestTestAdapterPath)
{
- allArgs.Add("--testAdapterPath:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(arg));
+ builder.AppendSwitchIfNotNull("--testAdapterPath:", arg);
}
}
if (!string.IsNullOrEmpty(this.VSTestFramework))
{
- allArgs.Add("--framework:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(this.VSTestFramework));
+ builder.AppendSwitchIfNotNull("--framework:", 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));
+ builder.AppendSwitchIfNotNull("--platform:", this.VSTestPlatform);
}
if (!string.IsNullOrEmpty(this.VSTestTestCaseFilter))
{
- allArgs.Add("--testCaseFilter:" +
- ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(this.VSTestTestCaseFilter));
+ builder.AppendSwitchIfNotNull("--testCaseFilter:", this.VSTestTestCaseFilter);
}
if (this.VSTestLogger != null && this.VSTestLogger.Length > 0)
{
foreach (var arg in this.VSTestLogger)
{
- allArgs.Add("--logger:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(arg));
+ builder.AppendSwitchIfNotNull("--logger:", arg);
if (arg.StartsWith("console", StringComparison.OrdinalIgnoreCase))
{
@@ -250,29 +225,24 @@ private List AddArgs()
}
}
- if (!string.IsNullOrEmpty(this.VSTestResultsDirectory))
+ if (this.VSTestResultsDirectory != null && !string.IsNullOrEmpty(this.VSTestResultsDirectory.ItemSpec))
{
- allArgs.Add("--resultsDirectory:" +
- ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(this.VSTestResultsDirectory));
+ builder.AppendSwitchIfNotNull("--resultsDirectory:", this.VSTestResultsDirectory);
}
- if (!string.IsNullOrEmpty(this.VSTestListTests))
+ if (this.VSTestListTests)
{
- allArgs.Add("--listTests");
+ builder.AppendSwitch("--listTests");
}
if (!string.IsNullOrEmpty(this.VSTestDiag))
{
- allArgs.Add("--Diag:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(this.VSTestDiag));
+ builder.AppendSwitchIfNotNull("--Diag:", this.VSTestDiag);
}
- if (string.IsNullOrEmpty(this.TestFileFullPath))
+ if (this.TestFileFullPath != null)
{
- this.Log.LogError("Test file path cannot be empty or null.");
- }
- else
- {
- allArgs.Add(ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(this.TestFileFullPath));
+ builder.AppendFileNameIfNotNull(this.TestFileFullPath);
}
// Console logger was not specified by user, but verbosity was, hence add default console logger with verbosity as specified
@@ -282,31 +252,28 @@ private List AddArgs()
var quietTestLogging = new List() { "q", "quiet" };
string vsTestVerbosity = "minimal";
- if (normalTestLogging.Contains(this.VSTestVerbosity.ToLowerInvariant()))
+ if (normalTestLogging.Contains(this.VSTestVerbosity, StringComparer.InvariantCultureIgnoreCase))
{
vsTestVerbosity = "normal";
}
- else if (quietTestLogging.Contains(this.VSTestVerbosity.ToLowerInvariant()))
+ else if (quietTestLogging.Contains(this.VSTestVerbosity, StringComparer.InvariantCultureIgnoreCase))
{
vsTestVerbosity = "quiet";
}
- allArgs.Add("--logger:Console;Verbosity=" + vsTestVerbosity);
+ builder.AppendSwitchUnquotedIfNotNull("--logger:", $"Console;Verbosity={vsTestVerbosity}");
}
- var blameCrash = !string.IsNullOrEmpty(this.VSTestBlameCrash);
- var blameHang = !string.IsNullOrEmpty(this.VSTestBlameHang);
- if (!string.IsNullOrEmpty(this.VSTestBlame) || blameCrash || blameHang)
+ if (this.VSTestBlame)
{
- var blameArgs = "--Blame";
-
var dumpArgs = new List();
- if (blameCrash || blameHang)
+ if (this.VSTestBlameCrash || this.VSTestBlameHang)
{
- if (blameCrash)
+ if (this.VSTestBlameCrash)
{
dumpArgs.Add("CollectDump");
- if (!string.IsNullOrEmpty(this.VSTestBlameCrashCollectAlways))
+
+ if (this.VSTestBlameCrashCollectAlways)
{
dumpArgs.Add($"CollectAlways={this.VSTestBlameCrashCollectAlways}");
}
@@ -317,7 +284,7 @@ private List AddArgs()
}
}
- if (blameHang)
+ if (this.VSTestBlameHang)
{
dumpArgs.Add("CollectHangDump");
@@ -331,14 +298,15 @@ private List AddArgs()
dumpArgs.Add($"TestTimeout={this.VSTestBlameHangTimeout}");
}
}
-
- if (dumpArgs.Any())
- {
- blameArgs += $":\"{string.Join(";", dumpArgs)}\"";
- }
}
- allArgs.Add(blameArgs);
+ if (dumpArgs.Any())
+ {
+ builder.AppendSwitchIfNotNull("--Blame:", string.Join(";", dumpArgs));
+ } else
+ {
+ builder.AppendSwitch("--Blame");
+ }
}
if (this.VSTestCollect != null && this.VSTestCollect.Length > 0)
@@ -350,7 +318,7 @@ private List AddArgs()
isCollectCodeCoverageEnabled = true;
}
- allArgs.Add("--collect:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(arg));
+ builder.AppendSwitchIfNotNull("--collect:", arg);
}
}
@@ -363,29 +331,71 @@ private List AddArgs()
// 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))
+ if (this.VSTestTraceDataCollectorDirectoryPath != null && !string.IsNullOrEmpty(this.VSTestTraceDataCollectorDirectoryPath.ItemSpec))
{
- allArgs.Add("--testAdapterPath:" +
- ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(this
- .VSTestTraceDataCollectorDirectoryPath));
- }
- else
+ builder.AppendSwitchIfNotNull("--testAdapterPath:", 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);
+ this.Log.LogWarning(Resources.UpdateTestSdkForCollectingCodeCoverage);
}
}
}
- if (!string.IsNullOrWhiteSpace(this.VSTestNoLogo))
+ if (this.VSTestNoLogo)
+ {
+ builder.AppendSwitch("--nologo");
+ }
+
+ // VSTestCLIRunSettings should be last argument as vstest.console ignore options after "--"(CLIRunSettings option).
+ if (this.VSTestCLIRunSettings != null && this.VSTestCLIRunSettings.Any())
+ {
+ builder.AppendSwitch("--");
+
+ foreach (var arg in this.VSTestCLIRunSettings)
+ {
+ builder.AppendSwitchIfNotNull(string.Empty, arg);
+ }
+ }
+
+ return builder.ToString();
+ }
+
+ protected override string GenerateFullPathToTool()
+ {
+ string path = null;
+
+ if (!string.IsNullOrEmpty(ToolPath))
+ {
+ path = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(ToolPath)), ToolExe);
+ } else
{
- allArgs.Add("--nologo");
+ //TODO: https://github.com/dotnet/sdk/issues/20 Need to get the dotnet path from MSBuild
+ if (File.Exists(ToolExe))
+ {
+ path = Path.GetFullPath(ToolExe);
+ } else
+ {
+ var values = Environment.GetEnvironmentVariable("PATH");
+ foreach (var p in values.Split(Path.PathSeparator))
+ {
+ var fullPath = Path.Combine(p, ToolExe);
+ if (File.Exists(fullPath))
+ path = fullPath;
+ }
+ }
}
- return allArgs;
+ return path;
+ }
+
+ /// To be used by unit tests only
+ internal protected string CreateCommandLineArguments()
+ {
+ return this.GenerateCommandLineCommands();
}
}
}
diff --git a/test/Microsoft.TestPlatform.Build.UnitTests/ArgumentEscaperTests.cs b/test/Microsoft.TestPlatform.Build.UnitTests/ArgumentEscaperTests.cs
deleted file mode 100644
index 31bfa52afc..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..f6b2421e1b
--- /dev/null
+++ b/test/Microsoft.TestPlatform.Build.UnitTests/FakeBuildEngine.cs
@@ -0,0 +1,41 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+namespace Microsoft.TestPlatform.Build.UnitTests
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ 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)
+ {
+ }
+ }
+}
diff --git a/test/Microsoft.TestPlatform.Build.UnitTests/VsTestTaskTests.cs b/test/Microsoft.TestPlatform.Build.UnitTests/VsTestTaskTests.cs
index 8bdc6d282d..6307c31122 100644
--- a/test/Microsoft.TestPlatform.Build.UnitTests/VsTestTaskTests.cs
+++ b/test/Microsoft.TestPlatform.Build.UnitTests/VsTestTaskTests.cs
@@ -2,9 +2,10 @@
namespace Microsoft.TestPlatform.Build.UnitTests
{
- using System;
- using System.Linq;
-
+ using System.Collections;
+ using System.Text.RegularExpressions;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
using Microsoft.TestPlatform.Build.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -17,7 +18,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 +34,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 +47,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 +56,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:\"{resultsDirectoryValue}\"");
}
[TestMethod]
@@ -82,10 +80,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(allArguments.FirstOrDefault(arg => arg.Contains("--logger:Console;Verbosity=normal")));
- Assert.IsNotNull(allArguments.FirstOrDefault(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 +91,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLogger
{
this.vsTestTask.VSTestVerbosity = "n";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(allArguments.FirstOrDefault(arg => arg.Contains("--logger:Console;Verbosity=normal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal");
}
[TestMethod]
@@ -103,9 +101,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLogger
{
this.vsTestTask.VSTestVerbosity = "normal";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(allArguments.FirstOrDefault(arg => arg.Contains("--logger:Console;Verbosity=normal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal");
}
[TestMethod]
@@ -113,9 +111,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLogger
{
this.vsTestTask.VSTestVerbosity = "d";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(allArguments.FirstOrDefault(arg => arg.Contains("--logger:Console;Verbosity=normal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal");
}
[TestMethod]
@@ -123,9 +121,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLogger
{
this.vsTestTask.VSTestVerbosity = "detailed";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(allArguments.FirstOrDefault(arg => arg.Contains("--logger:Console;Verbosity=normal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal");
}
[TestMethod]
@@ -133,9 +131,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLogger
{
this.vsTestTask.VSTestVerbosity = "diag";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(allArguments.FirstOrDefault(arg => arg.Contains("--logger:Console;Verbosity=normal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal");
}
[TestMethod]
@@ -143,9 +141,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLogger
{
this.vsTestTask.VSTestVerbosity = "diagnostic";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(allArguments.FirstOrDefault(arg => arg.Contains("--logger:Console;Verbosity=normal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal");
}
[TestMethod]
@@ -153,9 +151,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToQuietIfConsoleLoggerI
{
this.vsTestTask.VSTestVerbosity = "q";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(allArguments.FirstOrDefault(arg => arg.Contains("--logger:Console;Verbosity=quiet")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=quiet");
}
[TestMethod]
@@ -163,9 +161,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToQuietIfConsoleLoggerI
{
this.vsTestTask.VSTestVerbosity = "quiet";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(allArguments.FirstOrDefault(arg => arg.Contains("--logger:Console;Verbosity=quiet")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=quiet");
}
[TestMethod]
@@ -173,9 +171,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToMinimalIfConsoleLogge
{
this.vsTestTask.VSTestVerbosity = "m";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(allArguments.FirstOrDefault(arg => arg.Contains("--logger:Console;Verbosity=minimal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=minimal");
}
[TestMethod]
@@ -183,9 +181,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToMinimalIfConsoleLogge
{
this.vsTestTask.VSTestVerbosity = "minimal";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(allArguments.FirstOrDefault(arg => arg.Contains("--logger:Console;Verbosity=minimal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=minimal");
}
[TestMethod]
@@ -193,9 +191,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToNormalIfConsoleLogger
{
this.vsTestTask.VSTestVerbosity = "Normal";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(allArguments.FirstOrDefault(arg => arg.Contains("--logger:Console;Verbosity=normal")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=normal");
}
[TestMethod]
@@ -203,9 +201,9 @@ public void CreateArgumentShouldSetConsoleLoggerVerbosityToQuietIfConsoleLoggerI
{
this.vsTestTask.VSTestVerbosity = "Quiet";
- var allArguments = this.vsTestTask.CreateArgument().ToArray();
+ var commandline = this.vsTestTask.CreateCommandLineArguments();
- Assert.IsNotNull(allArguments.FirstOrDefault(arg => arg.Contains("--logger:Console;Verbosity=quiet")));
+ StringAssert.Contains(commandline, "--logger:Console;Verbosity=quiet");
}
[TestMethod]
@@ -213,9 +211,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(allArguments.FirstOrDefault(arg => arg.Contains("--logger:\"trx;LogFileName=foo bar.trx\"")));
+ StringAssert.Contains(commandline, "--logger:\"trx;LogFileName=foo bar.trx\"");
}
[TestMethod]
@@ -226,91 +224,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(allArguments.FirstOrDefault(arg => arg.Contains("--collect:name1")));
- Assert.IsNotNull(allArguments.FirstOrDefault(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(allArguments.FirstOrDefault(arg => arg.Contains("--testAdapterPath:path1")));
- Assert.IsNotNull(allArguments.FirstOrDefault(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(allArguments.FirstOrDefault(arg => arg.Contains("--logger:\"trx;LogFileName=foo bar.trx\"")));
- Assert.IsNotNull(allArguments.FirstOrDefault(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)}]");
+ 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)}]");
+ 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)}]");
+ 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(allArguments.FirstOrDefault(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(allArguments.FirstOrDefault(arg => arg.Contains("--nologo")));
+ StringAssert.Contains(commandline, "--nologo");
}
}
}