[fix] Fix backslash normalization in VSTestCLIRunSettings on Unix

Merged
NO
2mo ago
+191-13

Fixes #15043

Root Cause

VSTestCLIRunSettings was declared as string[] in ITestTask, VSTestTask, and VSTestTask2. When MSBuild processes a string[] task parameter, it wraps each element in an ITaskItem. On Unix, ITaskItem.ItemSpec normalizes path separators, silently converting \ to /.

This corrupted any run setting containing backslash characters — such as regex patterns passed via:

dotnet test -- NUnit.Where='namespace =~ /Abc\.Space1($|\.)/'

The \. sequences became //, causing the regex to fail.

Fix

Changed VSTestCLIRunSettings from string[] to string in ITestTask, VSTestTask, and VSTestTask2. This bypasses ITaskItem creation entirely, so no path normalization occurs. In TestTaskUtils.CreateCommandLineArguments, the string is now split manually by newlines and semicolons (maintaining backward compatibility with both separators).

Tests

  • Updated existing CreateArgumentShouldAddOneEntryForCLIRunSettings and CreateArgumentShouldAddCLIRunSettingsArgAtEnd tests to use the new string type with newline separator.
  • Added CreateArgumentShouldPreserveBackslashesInCLIRunSettings that verifies backslashes in CLI run settings are not converted to forward slashes.
  • Added VSTestCLIRunSettingsMustBindAsStringToSurviveUnixPathNormalization, which asserts the parameter stays a string on both tasks. That is the regression worth guarding against and it runs on every platform.

Why CI was red

RunDotnetTestWithCLIRunSettingsContainingBackslashes failed on Linux and macOS with Namespace//.Class//b. That doubled slash is what ITaskItem.ItemSpec produces, so the inner dotnet test was still running the old string[] binding even though this branch declares the property as string. I checked the binding on Linux with a small MSBuild project that takes the same value as both a string and a string[] parameter:

Parameter typeValue the task received
stringTestRunParameters.Parameter(name=\"pattern\",;value=\"Namespace\\.Class\\b\")
string[]TestRunParameters.Parameter(name=/"pattern/", value=/"Namespace//.Class//b/")

The string[] row is exactly what CI reported, so the fix itself is correct and the test was simply not loading the task we build. It now passes /p:VSTestTaskAssemblyFile to point the VSTest targets at the task from our own package instead of whatever Microsoft.TestPlatform.Build.dll the SDK ships, and it checks that file exists first so a wrong path fails with a clear message instead of quietly falling back.

šŸ¤– Fix submitted by Issue Repro Triage & Auto-Fix šŸ”

šŸ” Triaged by Issue Repro Triage & Auto-Fix šŸ”

šŸ¤–