From 0b5fc3e047fa94545d3aea04c99ca6f3b74b3093 Mon Sep 17 00:00:00 2001
From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com>
Date: Thu, 28 May 2026 21:05:28 +0100
Subject: [PATCH 1/2] perf: use [GeneratedRegex] in MetadataFilterMatcher

Replace runtime Regex.Replace calls in ExtractFilterHints and the
metadata-match path with a source-generated PropertyFilterRegex on
net7+, falling back to a cached compiled Regex on netstandard2.0.
Avoids re-parsing the pattern per call and is Native AOT friendly.

Closes #6036
---
 TUnit.Engine/Services/MetadataFilterMatcher.cs | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/TUnit.Engine/Services/MetadataFilterMatcher.cs b/TUnit.Engine/Services/MetadataFilterMatcher.cs
index 28ee3729e7..451df8d915 100644
--- a/TUnit.Engine/Services/MetadataFilterMatcher.cs
+++ b/TUnit.Engine/Services/MetadataFilterMatcher.cs
@@ -1,6 +1,7 @@
 using System.Collections.Concurrent;
 using System.Diagnostics.CodeAnalysis;
 using System.Reflection;
+using System.Text.RegularExpressions;
 #if NET8_0_OR_GREATER
 using System.Buffers;
 #endif
@@ -117,7 +118,7 @@ public bool CouldMatch(string testClassName, string testMethodName)
 /// Implementation of metadata filter matching logic extracted from TestBuilder.
 /// Evaluates if test metadata could match an execution filter without building tests.
 /// </summary>
-internal sealed class MetadataFilterMatcher : IMetadataFilterMatcher
+internal sealed partial class MetadataFilterMatcher : IMetadataFilterMatcher
 {
 #pragma warning disable TPEXP
     private static readonly ConstructorInfo _treeNodeFilterConstructor =
@@ -129,6 +130,16 @@ internal sealed class MetadataFilterMatcher : IMetadataFilterMatcher
 
     private static readonly ConcurrentDictionary<string, string> _strippedFilterCache = new();
 
+    // Matches property-bag filters like [key=value]; used to strip them before path parsing.
+#if NET7_0_OR_GREATER
+    [GeneratedRegex(@"\[([^\]]*)\]")]
+    private static partial Regex PropertyFilterRegex();
+#else
+    private static readonly Regex _propertyFilterRegex = new(@"\[([^\]]*)\]", RegexOptions.Compiled);
+
+    private static Regex PropertyFilterRegex() => _propertyFilterRegex;
+#endif
+
     /// <summary>
     /// Extract hints from a filter that can be used to pre-filter test sources by type.
     /// </summary>
@@ -149,7 +160,7 @@ public static FilterHints ExtractFilterHints(ITestExecutionFilter? filter)
         // Strip property filters like [key=value]
         if (filterString.Contains('['))
         {
-            filterString = System.Text.RegularExpressions.Regex.Replace(filterString, @"\[([^\]]*)\]", "");
+            filterString = PropertyFilterRegex().Replace(filterString, "");
         }
 
         // Parse path: /{assembly}/{namespace}/{className}/{methodName}
@@ -407,7 +418,7 @@ private static bool CouldMatchTreeNodeFilter(TreeNodeFilter filter, TestMetadata
         if (filterString.Contains('['))
         {
             var strippedFilterString = _strippedFilterCache.GetOrAdd(filterString,
-                static fs => System.Text.RegularExpressions.Regex.Replace(fs, @"\[([^\]]*)\]", ""));
+                static fs => PropertyFilterRegex().Replace(fs, ""));
             pathOnlyFilter = CreateTreeNodeFilterViaReflection(strippedFilterString);
         }
         else

From 856ad920469ba06d866038c0eef54644a178b9a0 Mon Sep 17 00:00:00 2001
From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com>
Date: Thu, 28 May 2026 21:36:31 +0100
Subject: [PATCH 2/2] perf: use NET8 guard and drop unused capture group in
 PropertyFilterRegex

Address review: align #if with rest of file (net7 TFM never built) and
remove the discarded capturing group to avoid per-match capture overhead.
---
 TUnit.Engine/Services/MetadataFilterMatcher.cs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/TUnit.Engine/Services/MetadataFilterMatcher.cs b/TUnit.Engine/Services/MetadataFilterMatcher.cs
index 451df8d915..9d22850128 100644
--- a/TUnit.Engine/Services/MetadataFilterMatcher.cs
+++ b/TUnit.Engine/Services/MetadataFilterMatcher.cs
@@ -131,11 +131,11 @@ internal sealed partial class MetadataFilterMatcher : IMetadataFilterMatcher
     private static readonly ConcurrentDictionary<string, string> _strippedFilterCache = new();
 
     // Matches property-bag filters like [key=value]; used to strip them before path parsing.
-#if NET7_0_OR_GREATER
-    [GeneratedRegex(@"\[([^\]]*)\]")]
+#if NET8_0_OR_GREATER
+    [GeneratedRegex(@"\[[^\]]*\]")]
     private static partial Regex PropertyFilterRegex();
 #else
-    private static readonly Regex _propertyFilterRegex = new(@"\[([^\]]*)\]", RegexOptions.Compiled);
+    private static readonly Regex _propertyFilterRegex = new(@"\[[^\]]*\]", RegexOptions.Compiled);
 
     private static Regex PropertyFilterRegex() => _propertyFilterRegex;
 #endif
