diff --git a/sources/tests/xunit.runner.stride/StrideXunitRunner.cs b/sources/tests/xunit.runner.stride/StrideXunitRunner.cs index 1a09e87e4..11ce7e976 100644 --- a/sources/tests/xunit.runner.stride/StrideXunitRunner.cs +++ b/sources/tests/xunit.runner.stride/StrideXunitRunner.cs @@ -171,9 +171,9 @@ public static class StrideXunitRunner return 1; } - // Minimal `dotnet test --filter` / VSTest filter parser: single binary op `` - // where op ∈ { =, !=, ~, !~ } and Property ∈ { FullyQualifiedName, DisplayName, Name }. - // Compound (& |) and parens aren't supported — the "run one test" path doesn't need them. + // Minimal `dotnet test --filter` / VSTest filter parser: binary ops `` + // where op ∈ { =, !=, ~, !~ } and Property ∈ { FullyQualifiedName, DisplayName, Name }, + // combinable with | and & (OR binds loosest, as in vstest). Parens/escapes unsupported. private static Func? ParseVstestFilter(string[] args) { for (int i = 0; i + 1 < args.Length; i++) @@ -187,6 +187,18 @@ public static class StrideXunitRunner internal static Func? ParseVstestFilter(string expr) { if (string.IsNullOrEmpty(expr)) return null; + var orParts = expr.Split('|'); + if (orParts.Length > 1) + { + var parsed = Array.ConvertAll(orParts, ParseVstestFilter); + return Array.IndexOf(parsed, null) >= 0 ? null : tc => Array.Exists(parsed, p => p!(tc)); + } + var andParts = expr.Split('&'); + if (andParts.Length > 1) + { + var parsed = Array.ConvertAll(andParts, ParseVstestFilter); + return Array.IndexOf(parsed, null) >= 0 ? null : tc => Array.TrueForAll(parsed, p => p!(tc)); + } // Order matters: check 2-char ops before 1-char ones to avoid splitting on the wrong byte. foreach (var op in new[] { "!~", "!=", "~", "=" }) { diff --git a/tests/android/run-android-tests.ps1 b/tests/android/run-android-tests.ps1 index 0b1ed7db3..8487baa40 100644 --- a/tests/android/run-android-tests.ps1 +++ b/tests/android/run-android-tests.ps1 @@ -301,11 +301,12 @@ if ($StreamLogcat) { } # 7. Launch with intent extras -# adb shell joins args with spaces before the device shell re-splits, so a filter value -# with spaces wouldn't survive; name-based vstest filters (no spaces) round-trip fine. +# adb shell joins args with spaces and the device shell re-interprets them, so the filter +# is single-quoted for the device shell: an unquoted `|` (vstest OR) would silently truncate +# the expression into a device-side pipeline. Spaces still don't survive. Write-Host "Launching with xunit_command=run$(if ($Filter) { " xunit_filter=$Filter" })..." $amArgs = @('shell', 'am', 'start', '-W', '-n', $activity, '--es', 'xunit_command', 'run', '--ez', 'xunit_exit_on_complete', 'true') -if ($Filter) { $amArgs += @('--es', 'xunit_filter', $Filter) } +if ($Filter) { $amArgs += @('--es', 'xunit_filter', "'$Filter'") } if ($Repeat -gt 1) { $amArgs += @('--es', 'xunit_repeat', "$Repeat") } Invoke-Adb @amArgs | Out-Null