tests: support compound vstest filters on-device (| and & in parser, quote Android filter extra)

This commit is contained in:
Virgile Bello
2026-06-12 01:21:46 +09:00
parent 3ca403f0b2
commit 3765d5cfc7
2 changed files with 19 additions and 6 deletions
@@ -171,9 +171,9 @@ public static class StrideXunitRunner
return 1;
}
// Minimal `dotnet test --filter` / VSTest filter parser: single binary op `<Property><op><Value>`
// 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 `<Property><op><Value>`
// where op ∈ { =, !=, ~, !~ } and Property ∈ { FullyQualifiedName, DisplayName, Name },
// combinable with | and & (OR binds loosest, as in vstest). Parens/escapes unsupported.
private static Func<ITestCase, bool>? ParseVstestFilter(string[] args)
{
for (int i = 0; i + 1 < args.Length; i++)
@@ -187,6 +187,18 @@ public static class StrideXunitRunner
internal static Func<ITestCase, bool>? 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[] { "!~", "!=", "~", "=" })
{
+4 -3
View File
@@ -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