public async Task Count_Timeout_ThrowsAfterTooLongExecution(RegexEngine engine) { if (RegexHelpers.IsNonBacktracking(engine)) { // Test relies on backtracking taking a long time return; } const string Pattern = @"^(\w+\s?)*$"; const string Input = "An input string that takes a very very very very very very very very very very very long time!"; Regex r = await RegexHelpers.GetRegexAsync(engine, Pattern, RegexOptions.None, TimeSpan.FromMilliseconds(1)); Stopwatch sw = Stopwatch.StartNew(); Assert.Throws <RegexMatchTimeoutException>(() => r.Count(Input)); Assert.Throws <RegexMatchTimeoutException>(() => r.Count(Input.AsSpan())); Assert.InRange(sw.Elapsed.TotalSeconds, 0, 10); // arbitrary upper bound that should be well above what's needed with a 1ms timeout switch (engine) { case RegexEngine.Interpreter: case RegexEngine.Compiled: sw = Stopwatch.StartNew(); Assert.Throws <RegexMatchTimeoutException>(() => Regex.Count(Input, Pattern, RegexHelpers.OptionsFromEngine(engine), TimeSpan.FromMilliseconds(1))); Assert.Throws <RegexMatchTimeoutException>(() => Regex.Count(Input.AsSpan(), Pattern, RegexHelpers.OptionsFromEngine(engine), TimeSpan.FromMilliseconds(1))); Assert.InRange(sw.Elapsed.TotalSeconds, 0, 10); // arbitrary upper bound that should be well above what's needed with a 1ms timeout break; } }
public async Task CharactersComparedOneByOne_Invariant(RegexEngine engine, RegexOptions options) { // Regex compares characters one by one. If that changes, it could impact the behavior of // a case like this, where these characters are not the same, but the strings compare // as equal with the invariant culture (and some other cultures as well). const string S1 = "\u00D6\u200D"; const string S2 = "\u004F\u0308"; // Validate the chosen strings to make sure they compare the way we want to test via Regex Assert.False(S1[0] == S2[0]); Assert.False(S1[1] == S2[1]); Assert.StartsWith(S1, S2, StringComparison.InvariantCulture); Assert.True(S1.Equals(S2, StringComparison.InvariantCulture)); // Test varying lengths of strings to validate codegen changes that kick in at longer lengths foreach (int multiple in new[] { 1, 10, 100 }) { string pattern = string.Concat(Enumerable.Repeat(S1, multiple)); string input = string.Concat(Enumerable.Repeat(S2, multiple)); Regex r; // Validate when the string is at the beginning of the pattern, as it impacts prefix matching. r = await RegexHelpers.GetRegexAsync(engine, pattern, options); Assert.False(r.IsMatch(input)); Assert.True(r.IsMatch(pattern)); // Validate when it's not at the beginning of the pattern, as it impacts "multi" matching. r = await RegexHelpers.GetRegexAsync(engine, "[abc]" + pattern, options); Assert.False(r.IsMatch("a" + input)); Assert.True(r.IsMatch("a" + pattern)); } }
public async Task Replace(RegexEngine engine, string pattern, string input, string replacement, RegexOptions options, int count, int start, string expected) { // A few tests exceed the 1000 limit, they reach 6003 RegexHelpers.SetSafeSizeThreshold(6005); Regex r; try { r = await RegexHelpers.GetRegexAsync(engine, pattern, options); } finally { RegexHelpers.RestoreSafeSizeThresholdToDefault(); } bool isDefaultStart = RegexHelpers.IsDefaultStart(input, options, start); bool isDefaultCount = RegexHelpers.IsDefaultCount(input, options, count); if (isDefaultStart) { if (isDefaultCount) { Assert.Equal(expected, r.Replace(input, replacement)); Assert.Equal(expected, Regex.Replace(input, pattern, replacement, options)); } Assert.Equal(expected, r.Replace(input, replacement, count)); } Assert.Equal(expected, r.Replace(input, replacement, count, start)); }
public async Task Count_ReturnsExpectedCount(RegexEngine engine, string pattern, string input, RegexOptions options, int expectedCount) { Regex r = await RegexHelpers.GetRegexAsync(engine, pattern, options); Assert.Equal(expectedCount, r.Count(input)); Assert.Equal(expectedCount, r.Count(input.AsSpan())); Assert.Equal(r.Count(input), r.Matches(input).Count); Assert.Equal(r.Count(input.AsSpan()), r.Matches(input).Count); if (options == RegexOptions.None && engine == RegexEngine.Interpreter) { Assert.Equal(expectedCount, Regex.Count(input, pattern)); Assert.Equal(expectedCount, Regex.Count(input.AsSpan(), pattern)); } switch (engine) { case RegexEngine.Interpreter: case RegexEngine.Compiled: case RegexEngine.NonBacktracking: RegexOptions engineOptions = RegexHelpers.OptionsFromEngine(engine); Assert.Equal(expectedCount, Regex.Count(input, pattern, options | engineOptions)); Assert.Equal(expectedCount, Regex.Count(input.AsSpan(), pattern, options | engineOptions)); Assert.Equal(expectedCount, Regex.Count(input, pattern, options | engineOptions, Regex.InfiniteMatchTimeout)); Assert.Equal(expectedCount, Regex.Count(input.AsSpan(), pattern, options | engineOptions, Regex.InfiniteMatchTimeout)); break; } }
public void TurkishI_Is_Differently_LowerUpperCased_In_Turkish_Culture_NonBacktracking() { var turkish = new CultureInfo("tr-TR"); string input = "I\u0131\u0130i"; // Use the input as the regex also // Ignore the Compiled option here because it is a noop in combination with NonBacktracking Regex cultInvariantRegex = RegexHelpers.CreateRegexInCulture(input, RegexHelpers.RegexOptionNonBacktracking | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant, CultureInfo.InvariantCulture); Regex turkishRegex = RegexHelpers.CreateRegexInCulture(input, RegexHelpers.RegexOptionNonBacktracking | RegexOptions.IgnoreCase, turkish); Assert.True(cultInvariantRegex.IsMatch(input)); Assert.True(turkishRegex.IsMatch(input)); // <---------- This result differs from the result in the previous test!!! // As above and no surprises here // The regexes recognize different lowercase variants of different versions of i differently Assert.True(cultInvariantRegex.IsMatch(input.ToLowerInvariant())); Assert.False(cultInvariantRegex.IsMatch(input.ToLower(turkish))); Assert.False(turkishRegex.IsMatch(input.ToLowerInvariant())); Assert.True(turkishRegex.IsMatch(input.ToLower(turkish))); // The same holds symmetrically for ToUpper Assert.True(cultInvariantRegex.IsMatch(input.ToUpperInvariant())); Assert.False(cultInvariantRegex.IsMatch(input.ToUpper(turkish))); Assert.False(turkishRegex.IsMatch(input.ToUpperInvariant())); Assert.True(turkishRegex.IsMatch(input.ToUpper(turkish))); }
public async Task SingleExpected(RegexEngine engine, char c) { string s = $@"\u{(int)c:X4}"; var set = new HashSet <char>() { c }; // One await ValidateSetAsync(engine, $"{s}", RegexOptions.None, set, null); await ValidateSetAsync(engine, $"[{s}]", RegexOptions.None, set, null); await ValidateSetAsync(engine, $"[^{s}]", RegexOptions.None, null, set); if (!RegexHelpers.IsNonBacktracking(engine)) { // Positive lookahead await ValidateSetAsync(engine, $"(?={s}){s}", RegexOptions.None, set, null); await ValidateSetAsync(engine, $"(?=[^{s}])[^{s}]", RegexOptions.None, null, set); // Negative lookahead await ValidateSetAsync(engine, $"(?![^{s}]){s}", RegexOptions.None, set, null); await ValidateSetAsync(engine, $"(?![{s}])[^{s}]", RegexOptions.None, null, set); } // Concatenation await ValidateSetAsync(engine, $"[{s}{s}]", RegexOptions.None, set, null); await ValidateSetAsync(engine, $"[^{s}{s}{s}]", RegexOptions.None, null, set); // Alternation await ValidateSetAsync(engine, $"{s}|{s}", RegexOptions.None, set, null); await ValidateSetAsync(engine, $"[^{s}]|[^{s}]|[^{s}]", RegexOptions.None, null, set); await ValidateSetAsync(engine, $"{s}|[^{s}]", RegexOptions.None, null, new HashSet <char>()); }
public async Task Matches(RegexEngine engine, string pattern, string input, RegexOptions options, CaptureData[] expected) { Regex regexAdvanced = await RegexHelpers.GetRegexAsync(engine, pattern, options); VerifyMatches(regexAdvanced.Matches(input), expected); VerifyMatches(regexAdvanced.Match(input), expected); }
public void Match_In_Different_Cultures_CriticalCases(string pattern, RegexOptions options, CultureInfo culture, string input, string match_expected) { Regex r = RegexHelpers.CreateRegexInCulture(pattern, options, culture); Match match = r.Match(input); Assert.Equal(match_expected, match.Value); }
public void Replace(string pattern, string input, MatchEvaluator evaluator, RegexOptions options, int count, int start, string expected) { bool isDefaultStart = RegexHelpers.IsDefaultStart(input, options, start); bool isDefaultCount = RegexHelpers.IsDefaultCount(input, options, count); if (options == RegexOptions.None) { if (isDefaultStart && isDefaultCount) { // Use Replace(string, MatchEvaluator) or Replace(string, string, MatchEvaluator) Assert.Equal(expected, new Regex(pattern).Replace(input, evaluator)); Assert.Equal(expected, Regex.Replace(input, pattern, evaluator)); } if (isDefaultStart) { // Use Replace(string, MatchEvaluator, string, int) Assert.Equal(expected, new Regex(pattern).Replace(input, evaluator, count)); } // Use Replace(string, MatchEvaluator, int, int) Assert.Equal(expected, new Regex(pattern).Replace(input, evaluator, count, start)); } if (isDefaultStart && isDefaultCount) { // Use Replace(string, MatchEvaluator) or Replace(string, MatchEvaluator, RegexOptions) Assert.Equal(expected, new Regex(pattern, options).Replace(input, evaluator)); Assert.Equal(expected, Regex.Replace(input, pattern, evaluator, options)); } if (isDefaultStart) { // Use Replace(string, MatchEvaluator, string, int) Assert.Equal(expected, new Regex(pattern, options).Replace(input, evaluator, count)); } // Use Replace(string, MatchEvaluator, int, int) Assert.Equal(expected, new Regex(pattern, options).Replace(input, evaluator, count, start)); }
public void Split(string pattern, string input, RegexOptions options, int count, int start, string[] expected) { bool isDefaultStart = RegexHelpers.IsDefaultStart(input, options, start); bool isDefaultCount = RegexHelpers.IsDefaultStart(input, options, count); if (options == RegexOptions.None) { // Use Split(string), Split(string, string), Split(string, int) or Split(string, int, int) if (isDefaultStart && isDefaultCount) { // Use Split(string) or Split(string, string) Assert.Equal(expected, new Regex(pattern).Split(input)); Assert.Equal(expected, Regex.Split(input, pattern)); } if (isDefaultStart) { // Use Split(string, int) Assert.Equal(expected, new Regex(pattern).Split(input, count)); } // Use Split(string, int, int) Assert.Equal(expected, new Regex(pattern).Split(input, count, start)); } if (isDefaultStart && isDefaultCount) { // Use Split(string, string, RegexOptions) Assert.Equal(expected, Regex.Split(input, pattern, options)); } if (isDefaultStart) { // Use Split(string, int) Assert.Equal(expected, new Regex(pattern, options).Split(input, count)); } // Use Split(string, int, int, int) Assert.Equal(expected, new Regex(pattern, options).Split(input, count, start)); }
public async Task Match_In_Different_Cultures_CriticalCases(string pattern, RegexOptions options, RegexEngine engine, CultureInfo culture, string input, string match_expected) { Regex r = await RegexHelpers.GetRegexAsync(engine, pattern, options, culture); Match match = r.Match(input); Assert.Equal(match_expected, match.Value); }
public async Task Test(RegexEngine engine, RegexOptions options, string pattern, string input, string captures, string nonBacktrackingCaptures = null) { if (input == "NULL") { input = ""; } bool nonBacktracking = engine == RegexEngine.NonBacktracking; string expected = nonBacktracking && nonBacktrackingCaptures != null ? nonBacktrackingCaptures : // nonBacktrackingCaptures value overrides the expected result in NonBacktracking mode captures; if (expected == "BADBR") { await Assert.ThrowsAnyAsync <ArgumentException>(async() => await RegexHelpers.GetRegexAsync(engine, pattern, options)); return; } if (nonBacktracking && nonBacktrackingCaptures == "NONBACKTRACKINGINCOMPATIBLE") { // In particular: backreferences are not supported in NonBacktracking mode await Assert.ThrowsAnyAsync <NotSupportedException>(() => RegexHelpers.GetRegexAsync(engine, pattern, options)); return; } Regex r = await RegexHelpers.GetRegexAsync(engine, pattern, options); if (expected == "NOMATCH") { Assert.False(r.IsMatch(input)); return; } Match match = r.Match(input); Assert.True(match.Success); var expectedSet = new HashSet <(int start, int end)>( expected .Split(new[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries) .Select(s => s.Split(',')) .Select(s => (start: int.Parse(s[0]), end: int.Parse(s[1])))); var actualSet = new HashSet <(int start, int end)>( match.Groups .Cast <Group>() .Select(g => (start: g.Index, end: g.Index + g.Length))); // NonBacktracking mode only provides the top-level match. // The .NET implementation sometimes has extra captures beyond what the original data specifies, so we assert a subset. if (nonBacktracking ? !actualSet.IsSubsetOf(expectedSet) : !expectedSet.IsSubsetOf(actualSet)) { throw new Xunit.Sdk.XunitException($"Actual: {string.Join(", ", actualSet)}{Environment.NewLine}Expected: {string.Join(", ", expected)}"); } }
public async Task TurkishCulture_MatchesWordChar(RegexEngine engine, string input, RegexOptions options, string expectedResult) { using (new ThreadCultureChange(new CultureInfo("tr-TR"))) { Regex regex = await RegexHelpers.GetRegexAsync(engine, @"\w*", options); Assert.Equal(expectedResult, regex.Match(input).Value); } }
public static IEnumerable <object[]> Count_ReturnsExpectedCount_TestData() { foreach (RegexEngine engine in RegexHelpers.AvailableEngines) { yield return(new object[] { engine, @"", "", 0, RegexOptions.None, 1 }); yield return(new object[] { engine, @"", "a", 0, RegexOptions.None, 2 }); yield return(new object[] { engine, @"", "ab", 0, RegexOptions.None, 3 }); yield return(new object[] { engine, @"", "ab", 1, RegexOptions.None, 2 }); yield return(new object[] { engine, @"\w", "", 0, RegexOptions.None, 0 }); yield return(new object[] { engine, @"\w", "a", 0, RegexOptions.None, 1 }); yield return(new object[] { engine, @"\w", "ab", 0, RegexOptions.None, 2 }); yield return(new object[] { engine, @"\w", "ab", 1, RegexOptions.None, 1 }); yield return(new object[] { engine, @"\w", "ab", 2, RegexOptions.None, 0 }); yield return(new object[] { engine, @"\b\w+\b", "abc def ghi jkl", 0, RegexOptions.None, 4 }); yield return(new object[] { engine, @"\b\w+\b", "abc def ghi jkl", 7, RegexOptions.None, 2 }); yield return(new object[] { engine, @"A", "", 0, RegexOptions.IgnoreCase, 0 }); yield return(new object[] { engine, @"A", "a", 0, RegexOptions.IgnoreCase, 1 }); yield return(new object[] { engine, @"A", "aAaA", 0, RegexOptions.IgnoreCase, 4 }); yield return(new object[] { engine, @".", "\n\n\n", 0, RegexOptions.None, 0 }); yield return(new object[] { engine, @".", "\n\n\n", 0, RegexOptions.Singleline, 3 }); yield return(new object[] { engine, @"[а-я-[аeиоуыэюя]]", "спокойной ночи", 0, RegexOptions.None, 8 }); if (!RegexHelpers.IsNonBacktracking(engine)) { // Lookbehinds yield return(new object[] { engine, @"(?<=abc)\w", "abcxabcy", 7, RegexOptions.None, 1 }); // Starting anchors yield return(new object[] { engine, @"\Gdef", "abcdef", 0, RegexOptions.None, 0 }); yield return(new object[] { engine, @"\Gdef", "abcdef", 3, RegexOptions.None, 1 }); // RightToLeft yield return(new object[] { engine, @"\b\w+\b", "abc def ghi jkl", 15, RegexOptions.RightToLeft, 4 }); yield return(new object[] { RegexEngine.Interpreter, @"(?<=abc)\w", "abcxabcy", 8, RegexOptions.RightToLeft, 2 }); yield return(new object[] { engine, @"(?<=abc)\w", "abcxabcy", 7, RegexOptions.RightToLeft, 1 }); } } }
public async Task CharactersLowercasedOneByOne(RegexEngine engine) { using (new ThreadCultureChange("en-US")) { Assert.True((await RegexHelpers.GetRegexAsync(engine, "\uD801\uDC00", RegexOptions.IgnoreCase)).IsMatch("\uD801\uDC00")); Assert.True((await RegexHelpers.GetRegexAsync(engine, "\uD801\uDC00", RegexOptions.IgnoreCase)).IsMatch("abcdefg\uD801\uDC00")); Assert.True((await RegexHelpers.GetRegexAsync(engine, "\uD801", RegexOptions.IgnoreCase)).IsMatch("\uD801\uDC00")); Assert.True((await RegexHelpers.GetRegexAsync(engine, "\uDC00", RegexOptions.IgnoreCase)).IsMatch("\uD801\uDC00")); } }
public void EnumerateMatches_Count(RegexEngine engine, string pattern, string input, int expectedCount) { Regex r = RegexHelpers.GetRegexAsync(engine, pattern).GetAwaiter().GetResult(); int count = 0; foreach (ValueMatch _ in r.EnumerateMatches(input)) { count++; } Assert.Equal(expectedCount, count); }
public void TurkishCulture_Handling_Of_IgnoreCase_NonBacktracking() { var turkish = new CultureInfo("tr-TR"); string input = "I\u0131\u0130i"; string pattern = "[H-J][\u0131-\u0140][\u0120-\u0130][h-j]"; Regex regex = RegexHelpers.CreateRegexInCulture(pattern, RegexOptions.IgnoreCase | RegexHelpers.RegexOptionNonBacktracking, turkish); // The pattern must trivially match the input because all of the letters fall in the given intervals // Ignoring case can only add more letters here -- not REMOVE letters Assert.True(regex.IsMatch(input)); }
public async Task TurkishCulture_Handling_Of_IgnoreCase(RegexEngine engine) { var turkish = new CultureInfo("tr-TR"); string input = "I\u0131\u0130i"; string pattern = "[H-J][\u0131-\u0140][\u0120-\u0130][h-j]"; Regex regex = await RegexHelpers.GetRegexAsync(engine, pattern, RegexOptions.IgnoreCase, turkish); // The pattern must trivially match the input because all of the letters fall in the given intervals // Ignoring case can only add more letters here -- not REMOVE letters Assert.True(regex.IsMatch(input)); }
public async Task CharactersComparedOneByOne_AnchoredPattern(RegexEngine engine, string pattern, string input, string culture, RegexOptions options, bool expected) { // Regex compares characters one by one. If that changes, it could impact the behavior of // a case like this, where these characters are not the same, but the strings compare // as equal with the invariant culture (and some other cultures as well). using (new ThreadCultureChange(culture)) { Regex r = await RegexHelpers.GetRegexAsync(engine, pattern, options); Assert.Equal(expected, r.IsMatch(input)); } }
public void EnumerateMatches_ReturnsExpectedCount(RegexEngine engine, string pattern, string input, int startat, RegexOptions options, int expectedCount) { Regex r = RegexHelpers.GetRegexAsync(engine, pattern, options).GetAwaiter().GetResult(); int count; count = 0; foreach (ValueMatch _ in r.EnumerateMatches(input, startat)) { count++; } Assert.Equal(expectedCount, count); bool isDefaultStartAt = startat == ((options & RegexOptions.RightToLeft) != 0 ? input.Length : 0); if (!isDefaultStartAt) { return; } if (options == RegexOptions.None && engine == RegexEngine.Interpreter) { count = 0; foreach (ValueMatch _ in Regex.EnumerateMatches(input, pattern)) { count++; } Assert.Equal(expectedCount, count); } switch (engine) { case RegexEngine.Interpreter: case RegexEngine.Compiled: case RegexEngine.NonBacktracking: RegexOptions engineOptions = RegexHelpers.OptionsFromEngine(engine); count = 0; foreach (ValueMatch _ in Regex.EnumerateMatches(input, pattern, options | engineOptions)) { count++; } Assert.Equal(expectedCount, count); count = 0; foreach (ValueMatch _ in Regex.EnumerateMatches(input, pattern, options | engineOptions, Regex.InfiniteMatchTimeout)) { count++; } Assert.Equal(expectedCount, count); break; } }
public async Task Test(string pattern, string input, string captures) { if (input == "NULL") { input = ""; } foreach (RegexEngine engine in RegexHelpers.AvailableEngines) { if (captures == "BADBR") { await Assert.ThrowsAnyAsync <ArgumentException>(async() => (await RegexHelpers.GetRegexAsync(engine, pattern)).IsMatch(input)); return; } Regex r = await RegexHelpers.GetRegexAsync(engine, pattern); if (captures == "NOMATCH") { Assert.False(r.IsMatch(input)); return; } Match match = r.Match(input); Assert.True(match.Success); var expected = new HashSet <(int start, int end)>( captures .Split(new[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries) .Select(s => s.Split(',')) .Select(s => (start: int.Parse(s[0]), end: int.Parse(s[1]))) .Distinct() .OrderBy(c => c.start) .ThenBy(c => c.end)); var actual = new HashSet <(int start, int end)>( match.Groups .Cast <Group>() .Select(g => (start: g.Index, end: g.Index + g.Length)) .Distinct() .OrderBy(g => g.start) .ThenBy(g => g.end)); // The .NET implementation sometimes has extra captures beyond what the original data specifies, so we assert a subset. if (!expected.IsSubsetOf(actual)) { throw new Xunit.Sdk.XunitException($"Actual: {string.Join(", ", actual)}{Environment.NewLine}Expected: {string.Join(", ", expected)}"); } } }
public static IEnumerable <object[]> TurkishCulture_MatchesWordChar_MemberData() { foreach (RegexEngine engine in RegexHelpers.AvailableEngines) { yield return(new object[] { engine, "I\u0131\u0130i", RegexOptions.None, "I\u0131\u0130i" }); yield return(new object[] { engine, "I\u0131\u0130i", RegexOptions.IgnoreCase, "I\u0131\u0130i" }); if (!RegexHelpers.IsNonBacktracking(engine)) { yield return(new object[] { engine, "I\u0131\u0130i", RegexOptions.IgnoreCase | RegexOptions.ECMAScript, "" }); } } }
public static IEnumerable <object[]> Replace_MatchEvaluator_TestData() { foreach (RegexEngine engine in RegexHelpers.AvailableEngines) { yield return(new object[] { engine, "a", "bbbb", new MatchEvaluator(match => "uhoh"), RegexOptions.None, 4, 0, "bbbb" }); yield return(new object[] { engine, "(Big|Small)", "Big mountain", new MatchEvaluator(MatchEvaluator1), RegexOptions.None, 12, 0, "Huge mountain" }); yield return(new object[] { engine, "(Big|Small)", "Small village", new MatchEvaluator(MatchEvaluator1), RegexOptions.None, 13, 0, "Tiny village" }); if ("i".ToUpper() == "I") { yield return(new object[] { engine, "(Big|Small)", "bIG horse", new MatchEvaluator(MatchEvaluator1), RegexOptions.IgnoreCase, 9, 0, "Huge horse" }); } yield return(new object[] { engine, "(Big|Small)", "sMaLl dog", new MatchEvaluator(MatchEvaluator1), RegexOptions.IgnoreCase, 9, 0, "Tiny dog" }); yield return(new object[] { engine, ".+", "XSP_TEST_FAILURE", new MatchEvaluator(MatchEvaluator2), RegexOptions.None, 16, 0, "SUCCESS" }); yield return(new object[] { engine, "[abcabc]", "abcabc", new MatchEvaluator(MatchEvaluator3), RegexOptions.None, 6, 0, "ABCABC" }); yield return(new object[] { engine, "[abcabc]", "abcabc", new MatchEvaluator(MatchEvaluator3), RegexOptions.None, 3, 0, "ABCabc" }); yield return(new object[] { engine, "[abcabc]", "abcabc", new MatchEvaluator(MatchEvaluator3), RegexOptions.None, 3, 2, "abCABc" }); if (!RegexHelpers.IsNonBacktracking(engine)) { // Regression test: // Regex treating Devanagari matra characters as matching "\b" // Unicode characters in the "Mark, NonSpacing" Category, U+0902=Devanagari sign anusvara, U+0947=Devanagri vowel sign E string boldInput = "\u092f\u0939 \u0915\u0930 \u0935\u0939 \u0915\u0930\u0947\u0902 \u0939\u0948\u0964"; string boldExpected = "\u092f\u0939 <b>\u0915\u0930</b> \u0935\u0939 <b>\u0915\u0930\u0947\u0902</b> \u0939\u0948\u0964"; yield return(new object[] { engine, @"\u0915\u0930.*?\b", boldInput, new MatchEvaluator(MatchEvaluatorBold), RegexOptions.CultureInvariant | RegexOptions.Singleline, boldInput.Length, 0, boldExpected }); // RighToLeft yield return(new object[] { engine, "a", "bbbb", new MatchEvaluator(match => "uhoh"), RegexOptions.RightToLeft, 4, 3, "bbbb" }); yield return(new object[] { engine, @"foo\s+", "0123456789foo4567890foo ", new MatchEvaluator(MatchEvaluatorBar), RegexOptions.RightToLeft, 32, 32, "0123456789foo4567890bar" }); yield return(new object[] { engine, @"\d", "0123456789foo4567890foo ", new MatchEvaluator(MatchEvaluatorPoundSign), RegexOptions.RightToLeft, 17, 32, "##########foo#######foo " }); yield return(new object[] { engine, @"\d", "0123456789foo4567890foo ", new MatchEvaluator(MatchEvaluatorPoundSign), RegexOptions.RightToLeft, 7, 32, "0123456789foo#######foo " }); yield return(new object[] { engine, @"\d", "0123456789foo4567890foo ", new MatchEvaluator(MatchEvaluatorPoundSign), RegexOptions.RightToLeft, 0, 32, "0123456789foo4567890foo " }); yield return(new object[] { engine, @"\d", "0123456789foo4567890foo ", new MatchEvaluator(MatchEvaluatorPoundSign), RegexOptions.RightToLeft, -1, 32, "##########foo#######foo " }); } } }
public void EnumerateMatches(RegexEngine engine, string pattern, string input, RegexOptions options, CaptureData[] expected) { Regex regexAdvanced = RegexHelpers.GetRegexAsync(engine, pattern, options).GetAwaiter().GetResult(); int count = 0; ReadOnlySpan <char> span = input.AsSpan(); foreach (ValueMatch match in regexAdvanced.EnumerateMatches(span)) { Assert.Equal(expected[count].Index, match.Index); Assert.Equal(expected[count].Length, match.Length); Assert.Equal(expected[count].Value, span.Slice(match.Index, match.Length).ToString()); count++; } Assert.Equal(expected.Length, count); }
public void Match(string pattern, string input, RegexOptions options, int beginning, int length, CaptureData[] expected) { bool isDefaultStart = RegexHelpers.IsDefaultStart(input, options, beginning); bool isDefaultCount = RegexHelpers.IsDefaultStart(input, options, length); if (options == RegexOptions.None) { if (isDefaultStart && isDefaultCount) { // Use Match(string) or Match(string, string) VerifyMatch(new Regex(pattern).Match(input), true, expected); VerifyMatch(Regex.Match(input, pattern), true, expected); Assert.True(new Regex(pattern).IsMatch(input)); Assert.True(Regex.IsMatch(input, pattern)); } if (beginning + length == input.Length) { // Use Match(string, int) VerifyMatch(new Regex(pattern).Match(input, beginning), true, expected); Assert.True(new Regex(pattern).IsMatch(input, beginning)); } else { // Use Match(string, int, int) VerifyMatch(new Regex(pattern).Match(input, beginning, length), true, expected); } } if (isDefaultStart && isDefaultCount) { // Use Match(string) or Match(string, string, RegexOptions) VerifyMatch(new Regex(pattern, options).Match(input), true, expected); VerifyMatch(Regex.Match(input, pattern, options), true, expected); Assert.True(Regex.IsMatch(input, pattern, options)); } if (beginning + length == input.Length) { // Use Match(string, int) VerifyMatch(new Regex(pattern, options).Match(input, beginning), true, expected); } if ((options & RegexOptions.RightToLeft) == 0) { // Use Match(string, int, int) VerifyMatch(new Regex(pattern, options).Match(input, beginning, length), true, expected); } }
public async Task UnicodeCategoriesInclusionsExpected(RegexEngine engine, string generalCategory, UnicodeCategory unicodeCategory) { Regex r; char[] allChars = Enumerable.Range(0, char.MaxValue + 1).Select(i => (char)i).ToArray(); int expectedInCategory = allChars.Count(c => char.GetUnicodeCategory(c) == unicodeCategory); int expectedNotInCategory = allChars.Length - expectedInCategory; r = await RegexHelpers.GetRegexAsync(engine, @$ "\p{{{generalCategory}}}"); Assert.Equal(expectedInCategory, r.Matches(string.Concat(allChars)).Count); r = await RegexHelpers.GetRegexAsync(engine, (@$ "\P{{{generalCategory}}}")); Assert.Equal(expectedNotInCategory, r.Matches(string.Concat(allChars)).Count); }
private static async Task ValidateSetAsync(string regex, RegexOptions options, HashSet <char> included, HashSet <char> excluded, bool validateEveryChar = false) { Assert.True((included != null) ^ (excluded != null)); foreach (RegexEngine engine in RegexHelpers.AvailableEngines) { Regex r = await RegexHelpers.GetRegexAsync(engine, regex, options); if (validateEveryChar) { for (int i = 0; i <= char.MaxValue; i++) { bool actual = r.IsMatch(((char)i).ToString()); bool expected = included != null?included.Contains((char)i) : !excluded.Contains((char)i); if (actual != expected) { Fail(i); } } } else if (included != null) { foreach (char c in included) { if (!r.IsMatch(c.ToString())) { Fail(c); } } } else { foreach (char c in excluded) { if (r.IsMatch(c.ToString())) { Fail(c); } } } } void Fail(int c) => throw new XunitException($"Set=\"{regex}\", Options=\"{options}\", {c:X4} => '{(char)c}'"); }
public void EnumerateMatches_CheckIndex(RegexEngine engine) { const string Pattern = @"e{2}\w\b"; const string Input = "needing a reed"; Regex r = RegexHelpers.GetRegexAsync(engine, Pattern).GetAwaiter().GetResult(); int count = 0; string[] expectedMatches = new[] { "eed" }; int[] expectedIndex = new[] { 11 }; ReadOnlySpan <char> span = Input.AsSpan(); foreach (ValueMatch match in r.EnumerateMatches(span)) { Assert.Equal(expectedMatches[count], span.Slice(match.Index, match.Length).ToString()); Assert.Equal(expectedIndex[count++], match.Index); } }
public async Task Replace_MatchEvaluator_Test(RegexEngine engine, string pattern, string input, MatchEvaluator evaluator, RegexOptions options, int count, int start, string expected) { bool isDefaultStart = RegexHelpers.IsDefaultStart(input, options, start); bool isDefaultCount = RegexHelpers.IsDefaultCount(input, options, count); Regex r = await RegexHelpers.GetRegexAsync(engine, pattern, options); if (isDefaultStart && isDefaultCount) { Assert.Equal(expected, r.Replace(input, evaluator)); } if (isDefaultStart) { Assert.Equal(expected, r.Replace(input, evaluator, count)); } Assert.Equal(expected, r.Replace(input, evaluator, count, start)); }
public async Task Split(RegexEngine engine, string pattern, string input, RegexOptions options, int count, int start, string[] expected) { bool isDefaultStart = RegexHelpers.IsDefaultStart(input, options, start); bool isDefaultCount = RegexHelpers.IsDefaultCount(input, options, count); Regex r = await RegexHelpers.GetRegexAsync(engine, pattern, options); if (isDefaultStart && isDefaultCount) { Assert.Equal(expected, r.Split(input)); } if (isDefaultStart) { Assert.Equal(expected, r.Split(input, count)); } Assert.Equal(expected, r.Split(input, count, start)); }