diff --git a/src/libraries/System.Text.RegularExpressions/System.Text.RegularExpressions.sln b/src/libraries/System.Text.RegularExpressions/System.Text.RegularExpressions.sln
index 2bde91c3efe702..188f97b70acf5a 100644
--- a/src/libraries/System.Text.RegularExpressions/System.Text.RegularExpressions.sln
+++ b/src/libraries/System.Text.RegularExpressions/System.Text.RegularExpressions.sln
@@ -11,9 +11,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Text.RegularExpressi
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Text.RegularExpressions", "src\System.Text.RegularExpressions.csproj", "{0409C086-D7CC-43F8-9762-C94FB1E47F5B}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Text.RegularExpressions.Generators.Tests", "tests\System.Text.RegularExpressions.Generators.Tests\System.Text.RegularExpressions.Generators.Tests.csproj", "{32ABFCDA-10FD-4A98-A429-145C28021EBE}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Text.RegularExpressions.Tests", "tests\FunctionalTests\System.Text.RegularExpressions.Tests.csproj", "{8EE1A7C4-3630-4900-8976-9B3ADAFF10DC}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Text.RegularExpressions.Tests", "tests\System.Text.RegularExpressions.Tests.csproj", "{8EE1A7C4-3630-4900-8976-9B3ADAFF10DC}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Text.RegularExpressions.UnitTests", "tests\UnitTests\System.Text.RegularExpressions.UnitTests.csproj", "{A86931EC-34DC-40A8-BD8C-F5E13BDBA903}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{2ACCCAAB-F0CE-4839-82BD-F174861DEA78}"
EndProject
@@ -53,22 +53,22 @@ Global
{0409C086-D7CC-43F8-9762-C94FB1E47F5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0409C086-D7CC-43F8-9762-C94FB1E47F5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0409C086-D7CC-43F8-9762-C94FB1E47F5B}.Release|Any CPU.Build.0 = Release|Any CPU
- {32ABFCDA-10FD-4A98-A429-145C28021EBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {32ABFCDA-10FD-4A98-A429-145C28021EBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {32ABFCDA-10FD-4A98-A429-145C28021EBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {32ABFCDA-10FD-4A98-A429-145C28021EBE}.Release|Any CPU.Build.0 = Release|Any CPU
{8EE1A7C4-3630-4900-8976-9B3ADAFF10DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8EE1A7C4-3630-4900-8976-9B3ADAFF10DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8EE1A7C4-3630-4900-8976-9B3ADAFF10DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8EE1A7C4-3630-4900-8976-9B3ADAFF10DC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A86931EC-34DC-40A8-BD8C-F5E13BDBA903}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A86931EC-34DC-40A8-BD8C-F5E13BDBA903}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A86931EC-34DC-40A8-BD8C-F5E13BDBA903}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A86931EC-34DC-40A8-BD8C-F5E13BDBA903}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{63551298-BFD4-43FC-8465-AC454228B83C} = {2ACCCAAB-F0CE-4839-82BD-F174861DEA78}
- {32ABFCDA-10FD-4A98-A429-145C28021EBE} = {2ACCCAAB-F0CE-4839-82BD-F174861DEA78}
{8EE1A7C4-3630-4900-8976-9B3ADAFF10DC} = {2ACCCAAB-F0CE-4839-82BD-F174861DEA78}
+ {A86931EC-34DC-40A8-BD8C-F5E13BDBA903} = {2ACCCAAB-F0CE-4839-82BD-F174861DEA78}
{08F0E5F4-BBD5-45CC-BB12-BA37A83AD7B6} = {0D20E771-24BD-4F9E-BBD0-60156E8C44FC}
{77CDA838-6489-4816-8847-DE2C7F5E1DCE} = {0D20E771-24BD-4F9E-BBD0-60156E8C44FC}
{3699C8E2-C354-4AED-81DC-ECBAC3EFEB4B} = {0D20E771-24BD-4F9E-BBD0-60156E8C44FC}
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs
index 135202e770bc1f..e8d727582de52d 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs
@@ -127,25 +127,17 @@ public RegexFindOptimizations(RegexTree tree, CultureInfo culture)
// The set contains one and only one character, meaning every match starts
// with the same literal value (potentially case-insensitive). Search for that.
FixedDistanceLiteral = (chars[0], 0);
- FindMode = (_rightToLeft, set.CaseInsensitive) switch
- {
- (false, false) => FindNextStartingPositionMode.FixedLiteral_LeftToRight_CaseSensitive,
- (false, true) => FindNextStartingPositionMode.FixedLiteral_LeftToRight_CaseInsensitive,
- (true, false) => FindNextStartingPositionMode.LeadingLiteral_RightToLeft_CaseSensitive,
- (true, true) => FindNextStartingPositionMode.LeadingLiteral_RightToLeft_CaseInsensitive,
- };
+ FindMode = set.CaseInsensitive ?
+ FindNextStartingPositionMode.LeadingLiteral_RightToLeft_CaseInsensitive :
+ FindNextStartingPositionMode.LeadingLiteral_RightToLeft_CaseSensitive;
}
else
{
// The set may match multiple characters. Search for that.
FixedDistanceSets = new() { (chars, set.CharClass, 0, set.CaseInsensitive) };
- FindMode = (_rightToLeft, set.CaseInsensitive) switch
- {
- (false, false) => FindNextStartingPositionMode.LeadingSet_LeftToRight_CaseSensitive,
- (false, true) => FindNextStartingPositionMode.LeadingSet_LeftToRight_CaseInsensitive,
- (true, false) => FindNextStartingPositionMode.LeadingSet_RightToLeft_CaseSensitive,
- (true, true) => FindNextStartingPositionMode.LeadingSet_RightToLeft_CaseInsensitive,
- };
+ FindMode = set.CaseInsensitive ?
+ FindNextStartingPositionMode.LeadingSet_RightToLeft_CaseInsensitive :
+ FindNextStartingPositionMode.LeadingSet_RightToLeft_CaseSensitive;
_asciiLookups = new uint[1][];
}
}
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexTreeAnalyzer.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexTreeAnalyzer.cs
index 7845cf455b9745..990456b3aff89c 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexTreeAnalyzer.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexTreeAnalyzer.cs
@@ -13,17 +13,17 @@ internal static class RegexTreeAnalyzer
public static AnalysisResults Analyze(RegexCode code)
{
var results = new AnalysisResults(code);
- results._complete = TryAnalyze(code.Tree.Root, results, isAtomicBySelfOrParent: true);
+ results._complete = TryAnalyze(code.Tree.Root, results, isAtomicByAncestor: true);
return results;
- static bool TryAnalyze(RegexNode node, AnalysisResults results, bool isAtomicBySelfOrParent)
+ static bool TryAnalyze(RegexNode node, AnalysisResults results, bool isAtomicByAncestor)
{
if (!StackHelper.TryEnsureSufficientExecutionStack())
{
return false;
}
- if (isAtomicBySelfOrParent)
+ if (isAtomicByAncestor)
{
// We've been told by our parent that we should be considered atomic, so add ourselves
// to the atomic collection.
@@ -45,6 +45,7 @@ static bool TryAnalyze(RegexNode node, AnalysisResults results, bool isAtomicByS
}
// Update state for certain node types.
+ bool isAtomicBySelf = false;
switch (node.Kind)
{
// Some node types add atomicity around what they wrap. Set isAtomicBySelfOrParent to true for such nodes
@@ -52,7 +53,7 @@ static bool TryAnalyze(RegexNode node, AnalysisResults results, bool isAtomicByS
case RegexNodeKind.Atomic:
case RegexNodeKind.NegativeLookaround:
case RegexNodeKind.PositiveLookaround:
- isAtomicBySelfOrParent = true;
+ isAtomicBySelf = true;
break;
// Track any nodes that are themselves captures.
@@ -70,7 +71,7 @@ static bool TryAnalyze(RegexNode node, AnalysisResults results, bool isAtomicByS
// Determine whether the child should be treated as atomic (whether anything
// can backtrack into it), which is influenced by whether this node (the child's
// parent) is considered atomic by itself or by its parent.
- bool treatChildAsAtomic = isAtomicBySelfOrParent && node.Kind switch
+ bool treatChildAsAtomic = (isAtomicByAncestor | isAtomicBySelf) && node.Kind switch
{
// If the parent is atomic, so is the child. That's the whole purpose
// of the Atomic node, and lookarounds are also implicitly atomic.
@@ -104,14 +105,16 @@ static bool TryAnalyze(RegexNode node, AnalysisResults results, bool isAtomicByS
}
// If the child contains captures, so too does this parent.
- if (results.MayContainCapture(child))
+ if (results._containsCapture.Contains(child))
{
results._containsCapture.Add(node);
}
// If the child might require backtracking into it, so too might the parent,
- // unless the parent is itself considered atomic.
- if (!isAtomicBySelfOrParent && results.MayBacktrack(child))
+ // unless the parent is itself considered atomic. Here we don't consider parental
+ // atomicity, as we need to surface upwards to the parent whether any backtracking
+ // will be visible from this node to it.
+ if (!isAtomicBySelf && (results._mayBacktrack?.Contains(child) == true))
{
(results._mayBacktrack ??= new()).Add(node);
}
@@ -149,7 +152,7 @@ internal sealed class AnalysisResults
/// Gets the code that was analyzed.
public RegexCode Code { get; }
- /// Gets whether a node is considered atomic based on itself or its ancestry.
+ /// Gets whether a node is considered atomic based on its ancestry.
public bool IsAtomicByAncestor(RegexNode node) => _isAtomicByAncestor.Contains(node);
/// Gets whether a node directly or indirectly contains captures.
diff --git a/src/libraries/System.Text.RegularExpressions/tests/AttRegexTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/AttRegexTests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/AttRegexTests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/AttRegexTests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/CaptureCollectionTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/CaptureCollectionTests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/CaptureCollectionTests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/CaptureCollectionTests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/CaptureCollectionTests2.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/CaptureCollectionTests2.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/CaptureCollectionTests2.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/CaptureCollectionTests2.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/CustomDerivedRegexScenarioTest.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/CustomDerivedRegexScenarioTest.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/CustomDerivedRegexScenarioTest.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/CustomDerivedRegexScenarioTest.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/GroupCollectionReadOnlyDictionaryTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/GroupCollectionReadOnlyDictionaryTests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/GroupCollectionReadOnlyDictionaryTests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/GroupCollectionReadOnlyDictionaryTests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/GroupCollectionTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/GroupCollectionTests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/GroupCollectionTests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/GroupCollectionTests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/GroupCollectionTests2.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/GroupCollectionTests2.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/GroupCollectionTests2.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/GroupCollectionTests2.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/MatchCollectionTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/MatchCollectionTests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/MatchCollectionTests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/MatchCollectionTests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/MatchCollectionTests2.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/MatchCollectionTests2.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/MatchCollectionTests2.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/MatchCollectionTests2.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/MonoRegexTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/MonoRegexTests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/MonoRegexTests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/MonoRegexTests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/PrecompiledRegexScenarioTest.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/PrecompiledRegexScenarioTest.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/PrecompiledRegexScenarioTest.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/PrecompiledRegexScenarioTest.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Cache.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Cache.Tests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/Regex.Cache.Tests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Cache.Tests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.CompileToAssembly.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.CompileToAssembly.Tests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/Regex.CompileToAssembly.Tests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.CompileToAssembly.Tests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Count.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Count.Tests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/Regex.Count.Tests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Count.Tests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Ctor.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Ctor.Tests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/Regex.Ctor.Tests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Ctor.Tests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.EscapeUnescape.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.EscapeUnescape.Tests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/Regex.EscapeUnescape.Tests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.EscapeUnescape.Tests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.GetGroupNames.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.GetGroupNames.Tests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/Regex.GetGroupNames.Tests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.GetGroupNames.Tests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Groups.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Groups.Tests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/Regex.Groups.Tests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Groups.Tests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.KnownPattern.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.KnownPattern.Tests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/Regex.KnownPattern.Tests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.KnownPattern.Tests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.MultipleMatches.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.MultipleMatches.Tests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/Regex.MultipleMatches.Tests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.MultipleMatches.Tests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Replace.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Replace.Tests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/Regex.Replace.Tests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Replace.Tests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Split.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Split.Tests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/Regex.Split.Tests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Split.Tests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Tests.Common.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Tests.Common.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/Regex.Tests.Common.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Tests.Common.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.UnicodeChar.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.UnicodeChar.Tests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/Regex.UnicodeChar.Tests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.UnicodeChar.Tests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexAssert.netcoreapp.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexAssert.netcoreapp.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/RegexAssert.netcoreapp.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexAssert.netcoreapp.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexAssert.netfx.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexAssert.netfx.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/RegexAssert.netfx.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexAssert.netfx.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexCharacterSetTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexCharacterSetTests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/RegexCharacterSetTests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexCharacterSetTests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexCompilationInfoTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexCompilationInfoTests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/RegexCompilationInfoTests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexCompilationInfoTests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexCultureTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexCultureTests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/RegexCultureTests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexCultureTests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexExperiment.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexExperiment.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/RegexExperiment.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexExperiment.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexGeneratorAttributeTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorAttributeTests.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/RegexGeneratorAttributeTests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorAttributeTests.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexGeneratorHelper.netcoreapp.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs
similarity index 75%
rename from src/libraries/System.Text.RegularExpressions/tests/RegexGeneratorHelper.netcoreapp.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs
index f4904dc9c73247..c2d30702339e46 100644
--- a/src/libraries/System.Text.RegularExpressions/tests/RegexGeneratorHelper.netcoreapp.cs
+++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs
@@ -24,11 +24,12 @@ namespace System.Text.RegularExpressions.Tests
public static class RegexGeneratorHelper
{
private static readonly CSharpParseOptions s_previewParseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview);
- private static readonly MetadataReference[] s_refs = CreateReferences();
private static readonly EmitOptions s_emitOptions = new EmitOptions(debugInformationFormat: DebugInformationFormat.Embedded);
private static readonly CSharpGeneratorDriver s_generatorDriver = CSharpGeneratorDriver.Create(new[] { new RegexGenerator().AsSourceGenerator() }, parseOptions: s_previewParseOptions);
private static Compilation? s_compilation;
+ internal static MetadataReference[] References { get; } = CreateReferences();
+
private static MetadataReference[] CreateReferences()
{
if (PlatformDetection.IsBrowser)
@@ -49,6 +50,61 @@ private static MetadataReference[] CreateReferences()
};
}
+ internal static byte[] CreateAssemblyImage(string source, string assemblyName)
+ {
+ CSharpCompilation compilation = CSharpCompilation.Create(
+ assemblyName,
+ new[] { CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview)) },
+ References,
+ new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
+
+ var ms = new MemoryStream();
+ if (compilation.Emit(ms).Success)
+ {
+ return ms.ToArray();
+ }
+
+ throw new InvalidOperationException();
+ }
+
+ internal static async Task> RunGenerator(
+ string code, bool compile = false, LanguageVersion langVersion = LanguageVersion.Preview, MetadataReference[]? additionalRefs = null, bool allowUnsafe = false, CancellationToken cancellationToken = default)
+ {
+ var proj = new AdhocWorkspace()
+ .AddSolution(SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Create()))
+ .AddProject("RegexGeneratorTest", "RegexGeneratorTest.dll", "C#")
+ .WithMetadataReferences(additionalRefs is not null ? References.Concat(additionalRefs) : References)
+ .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: allowUnsafe)
+ .WithNullableContextOptions(NullableContextOptions.Enable))
+ .WithParseOptions(new CSharpParseOptions(langVersion))
+ .AddDocument("RegexGenerator.g.cs", SourceText.From(code, Encoding.UTF8)).Project;
+
+ Assert.True(proj.Solution.Workspace.TryApplyChanges(proj.Solution));
+
+ Compilation? comp = await proj!.GetCompilationAsync(CancellationToken.None).ConfigureAwait(false);
+ Debug.Assert(comp is not null);
+
+ var generator = new RegexGenerator();
+ CSharpGeneratorDriver cgd = CSharpGeneratorDriver.Create(new[] { generator.AsSourceGenerator() }, parseOptions: CSharpParseOptions.Default.WithLanguageVersion(langVersion));
+ GeneratorDriver gd = cgd.RunGenerators(comp!, cancellationToken);
+ GeneratorDriverRunResult generatorResults = gd.GetRunResult();
+ if (!compile)
+ {
+ return generatorResults.Diagnostics;
+ }
+
+ comp = comp.AddSyntaxTrees(generatorResults.GeneratedTrees.ToArray());
+ EmitResult results = comp.Emit(Stream.Null, cancellationToken: cancellationToken);
+ if (!results.Success || results.Diagnostics.Length != 0 || generatorResults.Diagnostics.Length != 0)
+ {
+ throw new ArgumentException(
+ string.Join(Environment.NewLine, results.Diagnostics.Concat(generatorResults.Diagnostics)) + Environment.NewLine +
+ string.Join(Environment.NewLine, generatorResults.GeneratedTrees.Select(t => t.ToString())));
+ }
+
+ return generatorResults.Diagnostics.Concat(results.Diagnostics).Where(d => d.Severity != DiagnosticSeverity.Hidden).ToArray();
+ }
+
internal static async Task SourceGenRegexAsync(
string pattern, RegexOptions? options = null, TimeSpan? matchTimeout = null, CancellationToken cancellationToken = default)
{
@@ -109,7 +165,7 @@ internal static async Task SourceGenRegexAsync(
var proj = new AdhocWorkspace()
.AddSolution(SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Create()))
.AddProject("Test", "test.dll", "C#")
- .WithMetadataReferences(s_refs)
+ .WithMetadataReferences(References)
.WithCompilationOptions(
new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexGeneratorHelper.netfx.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netfx.cs
similarity index 100%
rename from src/libraries/System.Text.RegularExpressions/tests/RegexGeneratorHelper.netfx.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netfx.cs
diff --git a/src/libraries/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Generators.Tests/RegexGeneratorParserTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorParserTests.cs
similarity index 76%
rename from src/libraries/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Generators.Tests/RegexGeneratorParserTests.cs
rename to src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorParserTests.cs
index d78f6801341be6..c84f2455c8c689 100644
--- a/src/libraries/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Generators.Tests/RegexGeneratorParserTests.cs
+++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorParserTests.cs
@@ -3,19 +3,12 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.Emit;
-using Microsoft.CodeAnalysis.Text;
using System.Collections.Generic;
-using System.Diagnostics;
using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Threading;
using System.Threading.Tasks;
using Xunit;
-namespace System.Text.RegularExpressions.Generator.Tests
+namespace System.Text.RegularExpressions.Tests
{
// Tests don't actually use reflection emit, but they do generate assembly via Roslyn in-memory at run time and expect it to be JIT'd.
// The tests also use typeof(object).Assembly.Location, which returns an empty string on wasm.
@@ -25,7 +18,7 @@ public class RegexGeneratorParserTests
[Fact]
public async Task Diagnostic_MultipleAttributes()
{
- IReadOnlyList diagnostics = await RunGenerator(@"
+ IReadOnlyList diagnostics = await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
partial class C
{
@@ -62,7 +55,7 @@ public async Task Diagnostic_MalformedCtor(string attribute)
{
// Validate the generator doesn't crash with an incomplete attribute
- IReadOnlyList diagnostics = await RunGenerator($@"
+ IReadOnlyList diagnostics = await RegexGeneratorHelper.RunGenerator($@"
using System.Text.RegularExpressions;
partial class C
{{
@@ -82,7 +75,7 @@ partial class C
[InlineData("\"ab[]\"")]
public async Task Diagnostic_InvalidRegexPattern(string pattern)
{
- IReadOnlyList diagnostics = await RunGenerator($@"
+ IReadOnlyList diagnostics = await RegexGeneratorHelper.RunGenerator($@"
using System.Text.RegularExpressions;
partial class C
{{
@@ -98,7 +91,7 @@ partial class C
[InlineData(0x800)]
public async Task Diagnostic_InvalidRegexOptions(int options)
{
- IReadOnlyList diagnostics = await RunGenerator(@$"
+ IReadOnlyList diagnostics = await RegexGeneratorHelper.RunGenerator(@$"
using System.Text.RegularExpressions;
partial class C
{{
@@ -115,7 +108,7 @@ partial class C
[InlineData(0)]
public async Task Diagnostic_InvalidRegexTimeout(int matchTimeout)
{
- IReadOnlyList diagnostics = await RunGenerator(@$"
+ IReadOnlyList diagnostics = await RegexGeneratorHelper.RunGenerator(@$"
using System.Text.RegularExpressions;
partial class C
{{
@@ -130,7 +123,7 @@ partial class C
[Fact]
public async Task Diagnostic_MethodMustReturnRegex()
{
- IReadOnlyList diagnostics = await RunGenerator(@"
+ IReadOnlyList diagnostics = await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
partial class C
{
@@ -145,7 +138,7 @@ partial class C
[Fact]
public async Task Diagnostic_MethodMustNotBeGeneric()
{
- IReadOnlyList diagnostics = await RunGenerator(@"
+ IReadOnlyList diagnostics = await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
partial class C
{
@@ -160,7 +153,7 @@ partial class C
[Fact]
public async Task Diagnostic_MethodMustBeParameterless()
{
- IReadOnlyList diagnostics = await RunGenerator(@"
+ IReadOnlyList diagnostics = await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
partial class C
{
@@ -175,7 +168,7 @@ partial class C
[Fact]
public async Task Diagnostic_MethodMustBePartial()
{
- IReadOnlyList diagnostics = await RunGenerator(@"
+ IReadOnlyList diagnostics = await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
partial class C
{
@@ -191,7 +184,7 @@ partial class C
[Fact]
public async Task Diagnostic_InvalidLangVersion()
{
- IReadOnlyList diagnostics = await RunGenerator(@"
+ IReadOnlyList diagnostics = await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
partial class C
{
@@ -206,7 +199,7 @@ partial class C
[Fact]
public async Task Diagnostic_RightToLeft_LimitedSupport()
{
- IReadOnlyList diagnostics = await RunGenerator(@"
+ IReadOnlyList diagnostics = await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
partial class C
{
@@ -221,7 +214,7 @@ partial class C
[Fact]
public async Task Diagnostic_NonBacktracking_LimitedSupport()
{
- IReadOnlyList diagnostics = await RunGenerator(@"
+ IReadOnlyList diagnostics = await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
partial class C
{
@@ -236,7 +229,7 @@ partial class C
[Fact]
public async Task Diagnostic_PositiveLookbehind_LimitedSupport()
{
- IReadOnlyList diagnostics = await RunGenerator(@"
+ IReadOnlyList diagnostics = await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
partial class C
{
@@ -251,7 +244,7 @@ partial class C
[Fact]
public async Task Diagnostic_NegativeLookbehind_LimitedSupport()
{
- IReadOnlyList diagnostics = await RunGenerator(@"
+ IReadOnlyList diagnostics = await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
partial class C
{
@@ -266,7 +259,7 @@ partial class C
[Fact]
public async Task Valid_ClassWithoutNamespace()
{
- Assert.Empty(await RunGenerator(@"
+ Assert.Empty(await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
partial class C
{
@@ -282,7 +275,7 @@ partial class C
[InlineData("RegexOptions.IgnoreCase | RegexOptions.CultureInvariant")]
public async Task Valid_PatternOptions(string options)
{
- Assert.Empty(await RunGenerator($@"
+ Assert.Empty(await RegexGeneratorHelper.RunGenerator($@"
using System.Text.RegularExpressions;
partial class C
{{
@@ -298,7 +291,7 @@ partial class C
[InlineData("1_000")]
public async Task Valid_PatternOptionsTimeout(string timeout)
{
- Assert.Empty(await RunGenerator($@"
+ Assert.Empty(await RegexGeneratorHelper.RunGenerator($@"
using System.Text.RegularExpressions;
partial class C
{{
@@ -311,7 +304,7 @@ partial class C
[Fact]
public async Task Valid_NamedArguments()
{
- Assert.Empty(await RunGenerator($@"
+ Assert.Empty(await RegexGeneratorHelper.RunGenerator($@"
using System.Text.RegularExpressions;
partial class C
{{
@@ -324,7 +317,7 @@ partial class C
[Fact]
public async Task Valid_ReorderedNamedArguments()
{
- Assert.Empty(await RunGenerator($@"
+ Assert.Empty(await RegexGeneratorHelper.RunGenerator($@"
using System.Text.RegularExpressions;
partial class C
{{
@@ -342,7 +335,7 @@ partial class C
[InlineData(true)]
public async Task Valid_ClassWithNamespace(bool allowUnsafe)
{
- Assert.Empty(await RunGenerator(@"
+ Assert.Empty(await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
namespace A
{
@@ -358,7 +351,7 @@ partial class C
[Fact]
public async Task Valid_ClassWithFileScopedNamespace()
{
- Assert.Empty(await RunGenerator(@"
+ Assert.Empty(await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
namespace A;
partial class C
@@ -372,7 +365,7 @@ partial class C
[Fact]
public async Task Valid_ClassWithNestedNamespaces()
{
- Assert.Empty(await RunGenerator(@"
+ Assert.Empty(await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
namespace A
{
@@ -391,7 +384,7 @@ partial class C
[Fact]
public async Task Valid_NestedClassWithoutNamespace()
{
- Assert.Empty(await RunGenerator(@"
+ Assert.Empty(await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
partial class B
{
@@ -407,7 +400,7 @@ partial class C
[Fact]
public async Task Valid_NestedClassWithNamespace()
{
- Assert.Empty(await RunGenerator(@"
+ Assert.Empty(await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
namespace A
{
@@ -426,7 +419,7 @@ partial class C
[Fact]
public async Task Valid_NestedClassWithFileScopedNamespace()
{
- Assert.Empty(await RunGenerator(@"
+ Assert.Empty(await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
namespace A;
partial class B
@@ -443,7 +436,7 @@ partial class C
[Fact]
public async Task Valid_NestedClassesWithNamespace()
{
- Assert.Empty(await RunGenerator(@"
+ Assert.Empty(await RegexGeneratorHelper.RunGenerator(@"
using System.Text.RegularExpressions;
namespace A
{
@@ -471,7 +464,7 @@ private partial class F
[Fact]
public async Task Valid_NullableRegex()
{
- Assert.Empty(await RunGenerator(@"
+ Assert.Empty(await RegexGeneratorHelper.RunGenerator(@"
#nullable enable
using System.Text.RegularExpressions;
partial class C
@@ -485,7 +478,7 @@ partial class C
[Fact]
public async Task Valid_ClassWithGenericConstraints()
{
- Assert.Empty(await RunGenerator(@"
+ Assert.Empty(await RegexGeneratorHelper.RunGenerator(@"
using D;
using System.Text.RegularExpressions;
namespace A
@@ -539,7 +532,7 @@ public static IEnumerable