diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexNimTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexNimTests.cs
new file mode 100644
index 00000000000000..825be310511cbd
--- /dev/null
+++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexNimTests.cs
@@ -0,0 +1,202 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Xunit;
+
+namespace System.Text.RegularExpressions.Tests
+{
+ ///
+ /// These tests were ported from https://github.com/nitely/nim-regex/blob/master/tests/tests.nim
+ /// in order to increase .NET's test coverage. You can find the relevant repo license in this folder's THIRD-PARTY-NOTICES.TXT file.
+ ///
+ public class RegexNimTests
+ {
+ public static IEnumerable NimTestData()
+ {
+ foreach (RegexEngine engine in RegexHelpers.AvailableEngines)
+ {
+ (string pattern, RegexOptions options, string input, bool expectedSuccess)[] cases = NimTestData_Cases(engine).ToArray();
+ Regex[] regexes = RegexHelpers.GetRegexes(engine, cases.Select(c => (c.pattern, (CultureInfo?)null, (RegexOptions?)c.options, (TimeSpan?)null)).ToArray());
+ for (int i = 0; i < regexes.Length; i++)
+ {
+ yield return new object[] { regexes[i], cases[i].input, cases[i].expectedSuccess };
+ }
+ }
+ }
+
+ public static IEnumerable<(string Pattern, RegexOptions options, string Input, bool ExpectedSuccess)> NimTestData_Cases(RegexEngine engine)
+ {
+ yield return ("", RegexOptions.None, "", true);
+ yield return ("((a)*b)", RegexOptions.None, "aab", true);
+ yield return ("a(b|c)*d", RegexOptions.None, "abbbbccccd", true);
+ yield return ("((a)*(b)*)", RegexOptions.None, "abbb", true);
+ yield return ("((a(b)*)*(b)*)", RegexOptions.None, "abbb", true);
+ yield return ("a(b|c)*d", RegexOptions.None, "ab", false);
+ yield return ("\\s\".*\"\\s", RegexOptions.None, " \"word\" ", true);
+ yield return ("\\**", RegexOptions.None, "**", true);
+ yield return ("\\++", RegexOptions.None, "++", true);
+ yield return ("\\?+", RegexOptions.None, "??", true);
+ yield return ("\\?*", RegexOptions.None, "??", true);
+ yield return ("\\??", RegexOptions.None, "?", true);
+ yield return ("\\???", RegexOptions.None, "?", true);
+ yield return ("\\**?", RegexOptions.None, "**", true);
+ yield return ("\\++?", RegexOptions.None, "++", true);
+ yield return ("\\?+?", RegexOptions.None, "??", true);
+ yield return ("\\?*?", RegexOptions.None, "??", true);
+ yield return ("(a*)*", RegexOptions.None, "aaa", true);
+ yield return ("((a*|b*))*", RegexOptions.None, "aaabbbaaa", true);
+ yield return ("(a?)*", RegexOptions.None, "aaa", true);
+ yield return ("((a)*(a)*)*", RegexOptions.None, "aaaa", true);
+ yield return ("(a|b)*", RegexOptions.None, "abab", true);
+ yield return ("(a|b)+", RegexOptions.None, "abab", true);
+ yield return ("(a|b|c)*", RegexOptions.None, "abcabc", true);
+ yield return ("(a|b|c)+", RegexOptions.None, "abcabc", true);
+ yield return ("(a|b)*c", RegexOptions.None, "ababc", true);
+ yield return ("a(a|b)*c", RegexOptions.None, "aababc", true);
+ yield return ("a(a|b)+c", RegexOptions.None, "aababc", true);
+ yield return ("a|b*", RegexOptions.None, "a", true);
+ yield return ("a|b*", RegexOptions.None, "b", true);
+ yield return ("a|b*", RegexOptions.None, "bb", true);
+ yield return ("a*a*", RegexOptions.None, "aaa", true);
+ yield return ("a*b*", RegexOptions.None, "aabb", true);
+ yield return ("(a*)*b", RegexOptions.None, "aaab", true);
+ yield return ("a*b*c*", RegexOptions.None, "aabbcc", true);
+ yield return ("a*b*", RegexOptions.None, "ab", true);
+ yield return ("a*b*", RegexOptions.None, "a", true);
+ yield return ("a*b*", RegexOptions.None, "b", true);
+ yield return ("a*b*", RegexOptions.None, "", true);
+ yield return ("a+", RegexOptions.None, "a", true);
+ yield return ("ab+", RegexOptions.None, "abb", true);
+ yield return ("aba+", RegexOptions.None, "abaa", true);
+ yield return ("a+a+", RegexOptions.None, "aa", true);
+ yield return ("a+a+", RegexOptions.None, "aaa", true);
+ yield return ("a+b+", RegexOptions.None, "ab", true);
+ yield return ("a+b+", RegexOptions.None, "aabb", true);
+ yield return ("(a+|b)+", RegexOptions.None, "aabb", true);
+ yield return ("(a+|b+)*", RegexOptions.None, "aabb", true);
+ yield return ("ab?", RegexOptions.None, "a", true);
+ yield return ("ab?", RegexOptions.None, "ab", true);
+ yield return ("ab?a", RegexOptions.None, "aba", true);
+ yield return ("ab?a", RegexOptions.None, "aa", true);
+ yield return ("a?b?", RegexOptions.None, "ab", true);
+ yield return ("a?b?", RegexOptions.None, "a", true);
+ yield return ("a?b?", RegexOptions.None, "b", true);
+ yield return ("a?b?", RegexOptions.None, "", true);
+ yield return ("a??b??", RegexOptions.None, "ab", true);
+ yield return ("a??b??", RegexOptions.None, "a", true);
+ yield return ("a??b??", RegexOptions.None, "b", true);
+ yield return ("a??b??", RegexOptions.None, "", true);
+ yield return ("\\(a\\)", RegexOptions.None, "(a)", true);
+ yield return ("a\\*b", RegexOptions.None, "a*b", true);
+ yield return ("a\\*b*", RegexOptions.None, "a*bbb", true);
+ yield return ("\\\\", RegexOptions.None, "\\", true);
+ yield return ("\\\\\\\\", RegexOptions.None, "\\\\", true);
+ yield return ("\\w", RegexOptions.None, "a", true);
+ yield return ("\\w*", RegexOptions.None, "abc123", true);
+ yield return ("\\w+", RegexOptions.None, "abc123", true);
+ yield return ("\\w+", RegexOptions.None, "abc_123", true);
+ yield return ("\\d", RegexOptions.None, "1", true);
+ yield return ("\\d*", RegexOptions.None, "123", true);
+ yield return ("\\d+", RegexOptions.None, "123", true);
+ yield return ("\\d+", RegexOptions.None, "123abc", true);
+ yield return ("\\d", RegexOptions.None, "۲", true);
+ yield return ("\\s", RegexOptions.None, " ", true);
+ yield return ("\\s*", RegexOptions.None, " ", true);
+ yield return ("\\s*", RegexOptions.None, " \t\r", true);
+ yield return ("\\s+", RegexOptions.None, " ", true);
+ yield return ("\\s+", RegexOptions.None, " \t\n", true);
+ yield return ("\\s", RegexOptions.None, "\u0020", true);
+ yield return ("\\s", RegexOptions.None, "\u2028", true);
+ yield return ("\\W", RegexOptions.None, "!", true);
+ yield return ("\\W+", RegexOptions.None, "!@#", true);
+ yield return ("\\D", RegexOptions.None, "a", true);
+ yield return ("\\D", RegexOptions.None, "⅕", true);
+ yield return ("\\D+", RegexOptions.None, "abc", true);
+ yield return ("\\D+", RegexOptions.None, "!@#", true);
+ yield return ("\\S", RegexOptions.None, "a", true);
+ yield return ("\\S+", RegexOptions.None, "abc", true);
+ yield return ("[abc]", RegexOptions.None, "a", true);
+ yield return ("[abc]", RegexOptions.None, "b", true);
+ yield return ("[abc]", RegexOptions.None, "c", true);
+ yield return ("[abc]", RegexOptions.None, "d", false);
+ yield return ("[a-z]", RegexOptions.None, "a", true);
+ yield return ("[a-z]", RegexOptions.None, "z", true);
+ yield return ("[a-z]", RegexOptions.None, "A", false);
+ yield return ("[a-z]+", RegexOptions.None, "abc", true);
+ yield return ("[0-9]+", RegexOptions.None, "123", true);
+ yield return ("[^abc]", RegexOptions.None, "d", true);
+ yield return ("[^abc]", RegexOptions.None, "a", false);
+ yield return ("[^a-z]", RegexOptions.None, "1", true);
+ yield return ("a{3}", RegexOptions.None, "aaa", true);
+ yield return ("a{3}", RegexOptions.None, "aa", false);
+ yield return ("a{3}", RegexOptions.None, "aaaa", true);
+ yield return ("a{2,4}", RegexOptions.None, "aa", true);
+ yield return ("a{2,4}", RegexOptions.None, "aaa", true);
+ yield return ("a{2,4}", RegexOptions.None, "aaaa", true);
+ yield return ("a{2,4}", RegexOptions.None, "a", false);
+ yield return ("a{2,4}", RegexOptions.None, "aaaaa", true);
+ yield return ("a{2,}", RegexOptions.None, "aa", true);
+ yield return ("a{2,}", RegexOptions.None, "aaa", true);
+ yield return ("a{2,}", RegexOptions.None, "aaaa", true);
+ yield return ("a{2,}", RegexOptions.None, "a", false);
+ yield return ("(?:ab)+", RegexOptions.None, "ab", true);
+ yield return ("(?:ab)+", RegexOptions.None, "abab", true);
+ yield return ("(?:ab)+", RegexOptions.None, "ababab", true);
+ yield return ("(?:ab)+", RegexOptions.None, "a", false);
+ yield return ("a*?", RegexOptions.None, "aaa", true);
+ yield return ("a??", RegexOptions.None, "aaa", true);
+ yield return ("a{2,4}?", RegexOptions.None, "aaa", true);
+ yield return ("(a*)*?b", RegexOptions.None, "aaab", true);
+ yield return ("(a*?)*b", RegexOptions.None, "aaab", true);
+ yield return ("abc$", RegexOptions.None, "abcz", false);
+ yield return ("^abc$", RegexOptions.None, "abcz", false);
+ yield return ("^abc$", RegexOptions.None, "zabc", false);
+ yield return ("\\b", RegexOptions.None, "a", true);
+ yield return ("\\b", RegexOptions.None, " a", true);
+ yield return ("\\b", RegexOptions.None, "a ", true);
+ yield return ("\\B", RegexOptions.None, "ab", true);
+ yield return (".+", RegexOptions.None, "abc", true);
+ yield return ("(?a)", RegexOptions.None, "a", true);
+ yield return ("(?a)(?b)", RegexOptions.None, "ab", true);
+
+ // Lookahead and lookbehind are not supported by NonBacktracking engine
+ if (engine != RegexEngine.NonBacktracking)
+ {
+ yield return ("a(?=b)\\w", RegexOptions.None, "ab", true);
+ yield return ("a(?=c)\\w", RegexOptions.None, "ab", false);
+ yield return ("\\w(?<=a)b", RegexOptions.None, "ab", true);
+ yield return ("\\w(?<=c)b", RegexOptions.None, "ab", false);
+ yield return ("a(?!c)\\w", RegexOptions.None, "ab", true);
+ yield return ("a(?!b)\\w", RegexOptions.None, "ab", false);
+ yield return ("\\w(?
+