Skip to content

Fix TreeNodeFilter OR-pattern diagnostics#7415

Open
Evangelink wants to merge 8 commits into
mainfrom
dev/amauryleve/tree-node-filter
Open

Fix TreeNodeFilter OR-pattern diagnostics#7415
Evangelink wants to merge 8 commits into
mainfrom
dev/amauryleve/tree-node-filter

Conversation

@Evangelink
Copy link
Copy Markdown
Member

@Evangelink Evangelink commented Feb 14, 2026

Description

Partially addresses (does not fully fix) #7300. That issue reports four broken --treenode-filter patterns; this PR only improves the diagnostics and documentation for one of them and clarifies a known matching limitation that affects the other three.

Symptoms reported in #7300

# Pattern Observation
1 /*/*/*/(MyTest1) Does not match a test named MyTest1
2 /*/*/*/(MyTest1)|(MyTest2) Does not match either test
3 /*/*/*/(MyTest1|MyTest2) Does not match either test
4 (/*/*/*/MyTest1)|(/*/*/*/MyTest2) Crashes with a generic InvalidOperationException

Analysis

  • Cases 1–3 are not a parser bug: (MyTest1) and (MyTest1\|MyTest2) do match a node whose final segment is exactly MyTest1 (see the new OrExpression_WorksForSinglePathSegmentInsideParentheses test). Path segments are matched against an anchored regex ^value$, so a literal MyTest1 will not match a node whose actual ID is MyTest1() (or anything else with extra suffix). TUnit appends method-signature info to the displayed name, so the node IDs the user is actually filtering against are most likely MyTest1(), MyTest2(), etc. — which is why every pattern with a wildcard like MyTest1* "works" while every literal one does not. This is a UX mismatch (display vs. node ID), not a TreeNodeFilter parser defect. Properly resolving it requires either action in TUnit's adapter (use stable IDs that match the displayed name) or a design change to relax literal-segment matching — both are out of scope here.
  • Case 4 is a real parser bug: full-path OR like (/A/B/C/X)\|(/A/B/C/Y) hits separator processing inside parentheses and throws a generic InvalidOperationException with no guidance. This PR replaces that with an actionable message that points the user to the supported form /A/B/C/(X|Y).

Changes

  • TreeNodeFilter.cs: thread the filter string into ProcessStackOperator so the "unexpected / inside parenthesized expression" error can include the filter and a suggested fix. Add grammar remarks noting that OR over a single path segment is supported but OR over full paths is not.
  • PlatformResources.resx (+ all xlf): new TreeNodeFilterUnexpectedSlashOperatorInPathSegmentErrorMessage resource (the previous one is preserved for back-compat; tests use the new message).
  • TreeNodeFilterTests.cs: regression tests for single-segment OR (OrExpression_WorksForSinglePathSegmentInsideParentheses), for the actionable error on full-path OR (FullPathOrInsideParenthesizedExpressions_IsNotSupported_ThrowsActionableMessage), and LiteralSegment_RequiresWildcardToMatchNodesWithAdditionalSuffix which documents (with a comment) the surprising literal-vs-suffix limitation behind cases 1–3.
  • Changelog-Platform.md: entry framed as a diagnostics/docs clarification, not a behavior fix.

Validation

dotnet test Microsoft.Testing.Platform.UnitTests.csproj -c Debug --filter "FullyQualifiedName~TreeNodeFilterTests" → 46/46 passing on net9.0/net8.0/net462.

Follow-ups (not in this PR)

Copy link
Copy Markdown
Member

@Youssef1313 Youssef1313 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have doubts that the problem here is clarity of error message. The behavior seems buggy IMO. Let's discuss offline.

Copilot AI review requested due to automatic review settings May 16, 2026 12:20
@Evangelink
Copy link
Copy Markdown
Member Author

Merged latest main into the PR branch (was ~941 commits behind). The merge was clean with no conflicts. Verified the fix is still relevant — TreeNodeFilter.cs on main has not received an equivalent fix.

Verification:

  • Built Microsoft.Testing.Platform.csproj (Debug): 0 warnings, 0 errors.
  • Ran Microsoft.Testing.Platform.UnitTests filtered to TreeNodeFilter: 165 passed / 0 failed across net8.0, net9.0, net48.

Ready for CI re-run and review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR clarifies TreeNodeFilter behavior for OR patterns and improves diagnostics when unsupported full-path OR expressions are parenthesized.

Changes:

  • Adds regression coverage for single-segment OR patterns and exact-match behavior.
  • Updates TreeNodeFilter grammar remarks and propagates filter text into parser error construction.
  • Improves the unexpected slash diagnostic for parenthesized full-path OR patterns.
Show a summary per file
File Description
test/UnitTests/Microsoft.Testing.Platform.UnitTests/Requests/TreeNodeFilterTests.cs Adds tests for supported OR syntax and unsupported parenthesized full-path OR diagnostics.
src/Platform/Microsoft.Testing.Platform/Requests/TreeNodeFilter/TreeNodeFilter.cs Documents OR syntax limitations and augments the unexpected slash exception message.

Copilot's findings

  • Files reviewed: 2/2 changed files
  • Comments generated: 1

Comment thread src/Platform/Microsoft.Testing.Platform/Requests/TreeNodeFilter/TreeNodeFilter.cs Outdated
Copilot AI added 2 commits May 16, 2026 16:04
The merge of origin/main into this branch brought in many new resx entries
(IsGreaterThan, IsLessThan, IsPositive, IsNegative, IsInRange, Contains*,
DoesNotContain*, ContainsSingle, etc.). Regenerated all 13 XLF files via
'dotnet msbuild /t:UpdateXlf' to keep them in sync.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the inline hint diagnostic appended to TreeNodeFilterUnexpectedSlashOperatorErrorMessage into a new PlatformResources entry (TreeNodeFilterUnexpectedSlashOperatorInPathSegmentErrorMessage) so the full message is localized like the surrounding parser diagnostics. XLFs regenerated via UpdateXlf.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 16, 2026 15:07
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 29/29 changed files
  • Comments generated: 1

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Copy link
Copy Markdown
Member Author

Reviewed the outstanding feedback and pushed bc8c8cf. Addressed the remaining actionable Copilot comment by adding the missing Changelog-Platform.md entry, then re-ran .\build.cmd successfully (0 warnings, 0 errors). I did not make further code changes for the older Youssef review because it reads as a discussion note ('Let's discuss offline') rather than concrete change guidance, and I skipped the already-handled localization thread because Evangelink had already replied there.

…ode-filter

# Conflicts:
#	src/Platform/Microsoft.Testing.Platform/Requests/TreeNodeFilter/TreeNodeFilter.cs
Copilot AI review requested due to automatic review settings May 23, 2026 15:18
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 30/30 changed files
  • Comments generated: 1

Comment thread src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf Outdated
@Evangelink
Copy link
Copy Markdown
Member Author

🔍 Build Failure Analysis

Summary — Build failed due to out-of-sync localization files (.xlf) after modifying the FrameworkMessages.resx resource file.

Root cause: Localization files (.xlf) out of sync with .resx changes

The PR modifies src/TestFramework/TestFramework/Resources/FrameworkMessages.resx by adding multiple new resource keys and renaming existing ones (e.g., AreEqualDeltaFailMsgAreEqualDeltaFailedSummary). While the corresponding .xlf localization files were updated in the PR, the Microsoft.DotNet.XliffTasks build validation detected that they are still out of sync with the source .resx file.

The XliffTasks validation enforces that all localization files must be perfectly synchronized with the source resource file to prevent translation drift in CI/official builds.

Affected files / errors

Resource keys modified in FrameworkMessages.resx:

  • Renamed: AreEqualDeltaFailMsgAreEqualDeltaFailedSummary
  • Renamed: AreNotEqualDeltaFailMsgAreNotEqualDeltaFailedSummary
  • Renamed: HasCountFailMsgHasCountFailedSummary
  • Renamed: IsNotEmptyFailMsgIsNotEmptyFailedSummary
  • Added: AreNotSequenceEqualInAnyOrderFailedSummary, AreNotSequenceEqualInOrderFailedSummary, AreSequenceEqualInAnyOrderFailedSummary, AreSequenceEqualInOrderFailedSummary, and many more new resource keys

Proposed fix

Run the UpdateXlf MSBuild target to regenerate all .xlf files from the source .resx file:

dotnet build src/TestFramework/TestFramework/TestFramework.csproj /t:UpdateXlf

This will update all 13 localization files:

  • FrameworkMessages.cs.xlf (Czech)
  • FrameworkMessages.de.xlf (German)
  • FrameworkMessages.es.xlf (Spanish)
  • FrameworkMessages.fr.xlf (French)
  • FrameworkMessages.it.xlf (Italian)
  • FrameworkMessages.ja.xlf (Japanese)
  • FrameworkMessages.ko.xlf (Korean)
  • FrameworkMessages.pl.xlf (Polish)
  • FrameworkMessages.pt-BR.xlf (Portuguese-Brazil)
  • FrameworkMessages.ru.xlf (Russian)
  • FrameworkMessages.tr.xlf (Turkish)
  • FrameworkMessages.zh-Hans.xlf (Simplified Chinese)
  • FrameworkMessages.zh-Hant.xlf (Traditional Chinese)

After running the command, commit the updated .xlf files and push to this PR.


Build overview

Configuration: Debug
Exit code: 1 (failure)
Failed target: Build (XliffTasks validation)
Projects affected: TestFramework.csproj (all target frameworks: net8.0, net9.0, netstandard2.0)

All MSBuild errors (3)
Code Project File:Line Message
(XliffTasks) TestFramework.csproj::net8.0 Microsoft.DotNet.XliffTasks.targets:84 'Resources/xlf/FrameworkMessages.cs.xlf' is out-of-date with 'Resources/FrameworkMessages.resx'. Run msbuild /t:UpdateXlf to update .xlf files...
(XliffTasks) TestFramework.csproj::net9.0 Microsoft.DotNet.XliffTasks.targets:84 'Resources/xlf/FrameworkMessages.cs.xlf' is out-of-date with 'Resources/FrameworkMessages.resx'. Run msbuild /t:UpdateXlf to update .xlf files...
(XliffTasks) TestFramework.csproj::netstandard2.0 Microsoft.DotNet.XliffTasks.targets:84 'Resources/xlf/FrameworkMessages.cs.xlf' is out-of-date with 'Resources/FrameworkMessages.resx'. Run msbuild /t:UpdateXlf to update .xlf files...

🤖 Generated by the Build Failure Analysis workflow using binlog analysis · commit 948f3bd

Generated by Build Failure Analysis for issue #7415 · ● 5.3M ·

Evangelink and others added 2 commits May 25, 2026 13:37
Rename ExactMatch_DoesNotMatchAdditionalSuffixUnlessWildcardIsUsed to
LiteralSegment_RequiresWildcardToMatchNodesWithAdditionalSuffix and add an
explanatory comment so the test documents (not endorses) the surprising
behavior reported in issue #7300 where node IDs include suffixes like '()'
that literal filter segments don't match.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The earlier 'Sync FrameworkMessages XLF files after merge with main' commit
wiped existing translations and marked entries as state="new" because the
resx values in this branch were unchanged from main. This PR does not touch
FrameworkMessages.resx or AzureDevOpsResources.resx, so their xlf files
must match main. Restore them from main.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 25, 2026 11:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 25/25 changed files
  • Comments generated: 3

{
InvalidOperationException exception = Assert.ThrowsExactly<InvalidOperationException>(
() => _ = new TreeNodeFilter("(/*/*/*/MyTest1)|(/*/*/*/MyTest2)"));

<trans-unit id="AzureDevOpsFlakyHistoryRequiresAzureDevOps">
<source>'--report-azdo-flaky-history' requires '--report-azdo' to be enabled</source>
<target state="new">'--report-azdo-flaky-history' requires '--report-azdo' to be enabled</target>
<target state="translated">Aby bylo možné použít parametr ---report-azdo-flaky-history, musí být povolený parametr --report-azdo.</target>
<trans-unit id="OptionDescription">
<source>Enable Azure DevOps report generator to write errors to the output in a way that Azure DevOps understands.</source>
<target state="new">Enable Azure DevOps report generator to write errors to the output in a way that Azure DevOps understands.</target>
<target state="translated">Umožňuje generátoru sestav Azure DevOps zapisovat chyby do výstupu způsobem, který je pro AzureDev Ops srozumitelný.</target>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants