in src/Microsoft.TestPlatform.Build/Tasks/VSTestTask.cs [227:420]
private List<string> AddArgs()
{
var isConsoleLoggerSpecifiedByUser = false;
var isCollectCodeCoverageEnabled = false;
var isRunSettingsEnabled = false;
var allArgs = new List<string>();
// TODO log arguments in task
if (!string.IsNullOrEmpty(VSTestSetting))
{
isRunSettingsEnabled = true;
allArgs.Add("--settings:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(VSTestSetting));
}
if (VSTestTestAdapterPath != null && VSTestTestAdapterPath.Length > 0)
{
foreach (var arg in VSTestTestAdapterPath)
{
allArgs.Add("--testAdapterPath:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(arg));
}
}
if (!string.IsNullOrEmpty(VSTestFramework))
{
allArgs.Add("--framework:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(VSTestFramework));
}
// vstest.console only support x86 and x64 for argument platform
if (!string.IsNullOrEmpty(VSTestPlatform) && !VSTestPlatform.Contains("AnyCPU"))
{
allArgs.Add("--platform:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(VSTestPlatform));
}
if (!string.IsNullOrEmpty(VSTestTestCaseFilter))
{
allArgs.Add("--testCaseFilter:" +
ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(VSTestTestCaseFilter));
}
if (VSTestLogger != null && VSTestLogger.Length > 0)
{
foreach (var arg in VSTestLogger)
{
allArgs.Add("--logger:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(arg));
if (arg.StartsWith("console", StringComparison.OrdinalIgnoreCase))
{
isConsoleLoggerSpecifiedByUser = true;
}
}
}
if (!string.IsNullOrEmpty(VSTestResultsDirectory))
{
allArgs.Add("--resultsDirectory:" +
ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(VSTestResultsDirectory));
}
if (!string.IsNullOrEmpty(VSTestListTests))
{
allArgs.Add("--listTests");
}
if (!string.IsNullOrEmpty(VSTestDiag))
{
allArgs.Add("--Diag:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(VSTestDiag));
}
if (string.IsNullOrEmpty(TestFileFullPath))
{
Log.LogError("Test file path cannot be empty or null.");
}
else
{
allArgs.Add(ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(TestFileFullPath));
}
// Console logger was not specified by user, but verbosity was, hence add default console logger with verbosity as specified
if (!string.IsNullOrWhiteSpace(VSTestVerbosity) && !isConsoleLoggerSpecifiedByUser)
{
var normalTestLogging = new List<string>() { "n", "normal", "d", "detailed", "diag", "diagnostic" };
var quietTestLogging = new List<string>() { "q", "quiet" };
string vsTestVerbosity = "minimal";
if (normalTestLogging.Contains(VSTestVerbosity.ToLowerInvariant()))
{
vsTestVerbosity = "normal";
}
else if (quietTestLogging.Contains(VSTestVerbosity.ToLowerInvariant()))
{
vsTestVerbosity = "quiet";
}
allArgs.Add("--logger:Console;Verbosity=" + vsTestVerbosity);
}
var blameCrash = !string.IsNullOrEmpty(VSTestBlameCrash);
var blameHang = !string.IsNullOrEmpty(VSTestBlameHang);
if (!string.IsNullOrEmpty(VSTestBlame) || blameCrash || blameHang)
{
var blameArgs = "--Blame";
var dumpArgs = new List<string>();
if (blameCrash || blameHang)
{
if (blameCrash)
{
dumpArgs.Add("CollectDump");
if (!string.IsNullOrEmpty(VSTestBlameCrashCollectAlways))
{
dumpArgs.Add($"CollectAlways={VSTestBlameCrashCollectAlways}");
}
if (!string.IsNullOrEmpty(VSTestBlameCrashDumpType))
{
dumpArgs.Add($"DumpType={VSTestBlameCrashDumpType}");
}
}
if (blameHang)
{
dumpArgs.Add("CollectHangDump");
if (!string.IsNullOrEmpty(VSTestBlameHangDumpType))
{
dumpArgs.Add($"HangDumpType={VSTestBlameHangDumpType}");
}
if (!string.IsNullOrEmpty(VSTestBlameHangTimeout))
{
dumpArgs.Add($"TestTimeout={VSTestBlameHangTimeout}");
}
}
if (dumpArgs.Any())
{
blameArgs += $":\"{string.Join(";", dumpArgs)}\"";
}
}
allArgs.Add(blameArgs);
}
if (VSTestCollect != null && VSTestCollect.Length > 0)
{
foreach (var arg in VSTestCollect)
{
// For collecting code coverage, argument value can be either "Code Coverage" or "Code Coverage;a=b;c=d".
// Split the argument with ';' and compare first token value.
var tokens = arg.Split(';');
if (arg.Equals(CodeCovergaeString, StringComparison.OrdinalIgnoreCase) ||
tokens[0].Equals(CodeCovergaeString, StringComparison.OrdinalIgnoreCase))
{
isCollectCodeCoverageEnabled = true;
}
allArgs.Add("--collect:" + ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(arg));
}
}
if (isCollectCodeCoverageEnabled || isRunSettingsEnabled)
{
// Pass TraceDataCollector path to vstest.console as TestAdapterPath if --collect "Code Coverage"
// or --settings (User can enable code coverage from runsettings) option given.
// Not parsing the runsettings for two reason:
// 1. To keep no knowledge of runsettings structure in VSTestTask.
// 2. Impact of adding adapter path always is minimal. (worst case: loads additional data collector assembly in datacollector process.)
// This is required due to currently trace datacollector not ships with dotnet sdk, can be remove once we have
// go code coverage x-plat.
if (!string.IsNullOrEmpty(VSTestTraceDataCollectorDirectoryPath))
{
allArgs.Add("--testAdapterPath:" +
ArgumentEscaper.HandleEscapeSequenceInArgForProcessStart(
VSTestTraceDataCollectorDirectoryPath));
}
else
{
if (isCollectCodeCoverageEnabled)
{
// Not showing message in runsettings scenario, because we are not sure that code coverage is enabled.
// User might be using older Microsoft.NET.Test.Sdk which don't have CodeCoverage infra.
Console.WriteLine(Resources.UpdateTestSdkForCollectingCodeCoverage);
}
}
}
if (!string.IsNullOrWhiteSpace(VSTestNoLogo))
{
allArgs.Add("--nologo");
}
return allArgs;
}