1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Collections.Generic;
6 using System.Diagnostics;
7 using System.Globalization;
8 using System.Linq;
9 using Xunit;
10 
11 namespace System.Text.RegularExpressions.Tests
12 {
13     public class RegexMatchTests : RemoteExecutorTestBase
14     {
Match_Basic_TestData()15         public static IEnumerable<object[]> Match_Basic_TestData()
16         {
17             // Testing octal sequence matches: "\\060(\\061)?\\061"
18             // Octal \061 is ASCII 49 ('1')
19             yield return new object[] { @"\060(\061)?\061", "011", RegexOptions.None, 0, 3, true, "011" };
20 
21             // Testing hexadecimal sequence matches: "(\\x30\\x31\\x32)"
22             // Hex \x31 is ASCII 49 ('1')
23             yield return new object[] { @"(\x30\x31\x32)", "012", RegexOptions.None, 0, 3, true, "012" };
24 
25             // Testing control character escapes???: "2", "(\u0032)"
26             yield return new object[] { "(\u0034)", "4", RegexOptions.None, 0, 1, true, "4", };
27 
28             // Using *, +, ?, {}: Actual - "a+\\.?b*\\.?c{2}"
29             yield return new object[] { @"a+\.?b*\.+c{2}", "ab.cc", RegexOptions.None, 0, 5, true, "ab.cc" };
30 
31             // Using [a-z], \s, \w: Actual - "([a-zA-Z]+)\\s(\\w+)"
32             yield return new object[] { @"([a-zA-Z]+)\s(\w+)", "David Bau", RegexOptions.None, 0, 9, true, "David Bau" };
33 
34             // \\S, \\d, \\D, \\W: Actual - "(\\S+):\\W(\\d+)\\s(\\D+)"
35             yield return new object[] { @"(\S+):\W(\d+)\s(\D+)", "Price: 5 dollars", RegexOptions.None, 0, 16, true, "Price: 5 dollars" };
36 
37             // \\S, \\d, \\D, \\W: Actual - "[^0-9]+(\\d+)"
38             yield return new object[] { @"[^0-9]+(\d+)", "Price: 30 dollars", RegexOptions.None, 0, 17, true, "Price: 30" };
39 
40             // Zero-width negative lookahead assertion: Actual - "abc(?!XXX)\\w+"
41             yield return new object[] { @"abc(?!XXX)\w+", "abcXXXdef", RegexOptions.None, 0, 9, false, string.Empty };
42 
43             // Zero-width positive lookbehind assertion: Actual - "(\\w){6}(?<=XXX)def"
44             yield return new object[] { @"(\w){6}(?<=XXX)def", "abcXXXdef", RegexOptions.None, 0, 9, true, "abcXXXdef" };
45 
46             // Zero-width negative lookbehind assertion: Actual - "(\\w){6}(?<!XXX)def"
47             yield return new object[] { @"(\w){6}(?<!XXX)def", "XXXabcdef", RegexOptions.None, 0, 9, true, "XXXabcdef" };
48 
49             // Nonbacktracking subexpression: Actual - "[^0-9]+(?>[0-9]+)3"
50             // The last 3 causes the match to fail, since the non backtracking subexpression does not give up the last digit it matched
51             // for it to be a success. For a correct match, remove the last character, '3' from the pattern
52             yield return new object[] { "[^0-9]+(?>[0-9]+)3", "abc123", RegexOptions.None, 0, 6, false, string.Empty };
53 
54             // Using beginning/end of string chars \A, \Z: Actual - "\\Aaaa\\w+zzz\\Z"
55             yield return new object[] { @"\Aaaa\w+zzz\Z", "aaaasdfajsdlfjzzz", RegexOptions.None, 0, 17, true, "aaaasdfajsdlfjzzz" };
56 
57             // Using beginning/end of string chars \A, \Z: Actual - "\\Aaaa\\w+zzz\\Z"
58             yield return new object[] { @"\Aaaa\w+zzz\Z", "aaaasdfajsdlfjzzza", RegexOptions.None, 0, 18, false, string.Empty };
59 
60             // Using beginning/end of string chars \A, \Z: Actual - "\\Aaaa\\w+zzz\\Z"
61             yield return new object[] { @"\A(line2\n)line3\Z", "line2\nline3\n", RegexOptions.Multiline, 0, 12, true, "line2\nline3" };
62 
63             // Using beginning/end of string chars ^: Actual - "^b"
64             yield return new object[] { "^b", "ab", RegexOptions.None, 0, 2, false, string.Empty };
65 
66             // Actual - "(?<char>\\w)\\<char>"
67             yield return new object[] { @"(?<char>\w)\<char>", "aa", RegexOptions.None, 0, 2, true, "aa" };
68 
69             // Actual - "(?<43>\\w)\\43"
70             yield return new object[] { @"(?<43>\w)\43", "aa", RegexOptions.None, 0, 2, true, "aa" };
71 
72             // Actual - "abc(?(1)111|222)"
73             yield return new object[] { "(abbc)(?(1)111|222)", "abbc222", RegexOptions.None, 0, 7, false, string.Empty };
74 
75             // "x" option. Removes unescaped whitespace from the pattern: Actual - " ([^/]+) ","x"
76             yield return new object[] { "            ((.)+)      ", "abc", RegexOptions.IgnorePatternWhitespace, 0, 3, true, "abc" };
77 
78             // "x" option. Removes unescaped whitespace from the pattern. : Actual - "\x20([^/]+)\x20","x"
79             yield return new object[] { "\x20([^/]+)\x20\x20\x20\x20\x20\x20\x20", " abc       ", RegexOptions.IgnorePatternWhitespace, 0, 10, true, " abc      " };
80 
81             // Turning on case insensitive option in mid-pattern : Actual - "aaa(?i:match this)bbb"
82             if ("i".ToUpper() == "I")
83             {
84                 yield return new object[] { "aaa(?i:match this)bbb", "aaaMaTcH ThIsbbb", RegexOptions.None, 0, 16, true, "aaaMaTcH ThIsbbb" };
85             }
86 
87             // Turning off case insensitive option in mid-pattern : Actual - "aaa(?-i:match this)bbb", "i"
88             yield return new object[] { "aaa(?-i:match this)bbb", "AaAmatch thisBBb", RegexOptions.IgnoreCase, 0, 16, true, "AaAmatch thisBBb" };
89 
90             // Turning on/off all the options at once : Actual - "aaa(?imnsx-imnsx:match this)bbb", "i"
91             yield return new object[] { "aaa(?-i:match this)bbb", "AaAmatcH thisBBb", RegexOptions.IgnoreCase, 0, 16, false, string.Empty };
92 
93             // Actual - "aaa(?#ignore this completely)bbb"
94             yield return new object[] { "aaa(?#ignore this completely)bbb", "aaabbb", RegexOptions.None, 0, 6, true, "aaabbb" };
95 
96             // Trying empty string: Actual "[a-z0-9]+", ""
97             yield return new object[] { "[a-z0-9]+", "", RegexOptions.None, 0, 0, false, string.Empty };
98 
99             // Numbering pattern slots: "(?<1>\\d{3})(?<2>\\d{3})(?<3>\\d{4})"
100             yield return new object[] { @"(?<1>\d{3})(?<2>\d{3})(?<3>\d{4})", "8885551111", RegexOptions.None, 0, 10, true, "8885551111" };
101             yield return new object[] { @"(?<1>\d{3})(?<2>\d{3})(?<3>\d{4})", "Invalid string", RegexOptions.None, 0, 14, false, string.Empty };
102 
103             // Not naming pattern slots at all: "^(cat|chat)"
104             yield return new object[] { "^(cat|chat)", "cats are bad", RegexOptions.None, 0, 12, true, "cat" };
105 
106             yield return new object[] { "abc", "abc", RegexOptions.None, 0, 3, true, "abc" };
107             yield return new object[] { "abc", "aBc", RegexOptions.None, 0, 3, false, string.Empty };
108             yield return new object[] { "abc", "aBc", RegexOptions.IgnoreCase, 0, 3, true, "aBc" };
109 
110             // Using *, +, ?, {}: Actual - "a+\\.?b*\\.?c{2}"
111             yield return new object[] { @"a+\.?b*\.+c{2}", "ab.cc", RegexOptions.None, 0, 5, true, "ab.cc" };
112 
113             // RightToLeft
114             yield return new object[] { @"\s+\d+", "sdf 12sad", RegexOptions.RightToLeft, 0, 9, true, " 12" };
115             yield return new object[] { @"\s+\d+", " asdf12 ", RegexOptions.RightToLeft, 0, 6, false, string.Empty };
116             yield return new object[] { "aaa", "aaabbb", RegexOptions.None, 3, 3, false, string.Empty };
117 
118             yield return new object[] { @"foo\d+", "0123456789foo4567890foo         ", RegexOptions.RightToLeft, 10, 3, false, string.Empty };
119             yield return new object[] { @"foo\d+", "0123456789foo4567890foo         ", RegexOptions.RightToLeft, 11, 21, false, string.Empty };
120 
121             // IgnoreCase
122             yield return new object[] { "AAA", "aaabbb", RegexOptions.IgnoreCase, 0, 6, true, "aaa" };
123             yield return new object[] { @"\p{Lu}", "1bc", RegexOptions.IgnoreCase, 0, 3, true, "b" };
124             yield return new object[] { @"\p{Ll}", "1bc", RegexOptions.IgnoreCase, 0, 3, true, "b" };
125             yield return new object[] { @"\p{Lt}", "1bc", RegexOptions.IgnoreCase, 0, 3, true, "b" };
126             yield return new object[] { @"\p{Lo}", "1bc", RegexOptions.IgnoreCase, 0, 3, false, string.Empty };
127 
128             // "\D+"
129             yield return new object[] { @"\D+", "12321", RegexOptions.None, 0, 5, false, string.Empty };
130 
131             // Groups
132             yield return new object[] { "(?<first_name>\\S+)\\s(?<last_name>\\S+)", "David Bau", RegexOptions.None, 0, 9, true, "David Bau" };
133 
134             // "^b"
135             yield return new object[] { "^b", "abc", RegexOptions.None, 0, 3, false, string.Empty };
136 
137             // RightToLeft
138             yield return new object[] { @"foo\d+", "0123456789foo4567890foo         ", RegexOptions.RightToLeft, 0, 32, true, "foo4567890" };
139             yield return new object[] { @"foo\d+", "0123456789foo4567890foo         ", RegexOptions.RightToLeft, 10, 22, true, "foo4567890" };
140             yield return new object[] { @"foo\d+", "0123456789foo4567890foo         ", RegexOptions.RightToLeft, 10, 4, true, "foo4" };
141 
142             // Trim leading and trailing whitespace
143             yield return new object[] { @"\s*(.*?)\s*$", " Hello World ", RegexOptions.None, 0, 13, true, " Hello World " };
144 
145             // < in group
146             yield return new object[] { @"(?<cat>cat)\w+(?<dog-0>dog)", "cat_Hello_World_dog", RegexOptions.None, 0, 19, false, string.Empty };
147 
148             // Atomic Zero-Width Assertions \A \Z \z \G \b \B
149             yield return new object[] { @"\A(cat)\s+(dog)", "cat   \n\n\ncat     dog", RegexOptions.None, 0, 20, false, string.Empty };
150             yield return new object[] { @"\A(cat)\s+(dog)", "cat   \n\n\ncat     dog", RegexOptions.Multiline, 0, 20, false, string.Empty };
151             yield return new object[] { @"\A(cat)\s+(dog)", "cat   \n\n\ncat     dog", RegexOptions.ECMAScript, 0, 20, false, string.Empty };
152 
153             yield return new object[] { @"(cat)\s+(dog)\Z", "cat   dog\n\n\ncat", RegexOptions.None, 0, 15, false, string.Empty };
154             yield return new object[] { @"(cat)\s+(dog)\Z", "cat   dog\n\n\ncat     ", RegexOptions.Multiline, 0, 20, false, string.Empty };
155             yield return new object[] { @"(cat)\s+(dog)\Z", "cat   dog\n\n\ncat     ", RegexOptions.ECMAScript, 0, 20, false, string.Empty };
156 
157             yield return new object[] { @"(cat)\s+(dog)\z", "cat   dog\n\n\ncat", RegexOptions.None, 0, 15, false, string.Empty };
158             yield return new object[] { @"(cat)\s+(dog)\z", "cat   dog\n\n\ncat     ", RegexOptions.Multiline, 0, 20, false, string.Empty };
159             yield return new object[] { @"(cat)\s+(dog)\z", "cat   dog\n\n\ncat     ", RegexOptions.ECMAScript, 0, 20, false, string.Empty };
160             yield return new object[] { @"(cat)\s+(dog)\z", "cat   \n\n\n   dog\n", RegexOptions.None, 0, 16, false, string.Empty };
161             yield return new object[] { @"(cat)\s+(dog)\z", "cat   \n\n\n   dog\n", RegexOptions.Multiline, 0, 16, false, string.Empty };
162             yield return new object[] { @"(cat)\s+(dog)\z", "cat   \n\n\n   dog\n", RegexOptions.ECMAScript, 0, 16, false, string.Empty };
163 
164             yield return new object[] { @"\b@cat", "123START123;@catEND", RegexOptions.None, 0, 19, false, string.Empty };
165             yield return new object[] { @"\b<cat", "123START123'<catEND", RegexOptions.None, 0, 19, false, string.Empty };
166             yield return new object[] { @"\b,cat", "satwe,,,START',catEND", RegexOptions.None, 0, 21, false, string.Empty };
167             yield return new object[] { @"\b\[cat", "`12START123'[catEND", RegexOptions.None, 0, 19, false, string.Empty };
168 
169             yield return new object[] { @"\B@cat", "123START123@catEND", RegexOptions.None, 0, 18, false, string.Empty };
170             yield return new object[] { @"\B<cat", "123START123<catEND", RegexOptions.None, 0, 18, false, string.Empty };
171             yield return new object[] { @"\B,cat", "satwe,,,START,catEND", RegexOptions.None, 0, 20, false, string.Empty };
172             yield return new object[] { @"\B\[cat", "`12START123[catEND", RegexOptions.None, 0, 18, false, string.Empty };
173 
174             // Lazy operator Backtracking
175             yield return new object[] { @"http://([a-zA-z0-9\-]*\.?)*?(:[0-9]*)??/", "http://www.msn.com", RegexOptions.IgnoreCase, 0, 18, false, string.Empty };
176 
177             // Grouping Constructs Invalid Regular Expressions
178             yield return new object[] { "(?!)", "(?!)cat", RegexOptions.None, 0, 7, false, string.Empty };
179             yield return new object[] { "(?<!)", "(?<!)cat", RegexOptions.None, 0, 8, false, string.Empty };
180 
181             // Alternation construct
182             yield return new object[] { "(?(cat)|dog)", "cat", RegexOptions.None, 0, 3, true, string.Empty };
183             yield return new object[] { "(?(cat)|dog)", "catdog", RegexOptions.None, 0, 6, true, string.Empty };
184             yield return new object[] { "(?(cat)dog1|dog2)", "catdog1", RegexOptions.None, 0, 7, false, string.Empty };
185             yield return new object[] { "(?(cat)dog1|dog2)", "catdog2", RegexOptions.None, 0, 7, true, "dog2" };
186             yield return new object[] { "(?(cat)dog1|dog2)", "catdog1dog2", RegexOptions.None, 0, 11, true, "dog2" };
187             yield return new object[] { "(?(dog2))", "dog2", RegexOptions.None, 0, 4, true, string.Empty };
188             yield return new object[] { "(?(cat)|dog)", "oof", RegexOptions.None, 0, 3, false, string.Empty };
189             yield return new object[] { "(?(a:b))", "a", RegexOptions.None, 0, 1, true, string.Empty };
190             yield return new object[] { "(?(a:))", "a", RegexOptions.None, 0, 1, true, string.Empty };
191 
192             // No Negation
193             yield return new object[] { "[abcd-[abcd]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
194             yield return new object[] { "[1234-[1234]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
195 
196             // All Negation
197             yield return new object[] { "[^abcd-[^abcd]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
198             yield return new object[] { "[^1234-[^1234]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
199 
200             // No Negation
201             yield return new object[] { "[a-z-[a-z]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
202             yield return new object[] { "[0-9-[0-9]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
203 
204             // All Negation
205             yield return new object[] { "[^a-z-[^a-z]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
206             yield return new object[] { "[^0-9-[^0-9]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
207 
208             // No Negation
209             yield return new object[] { @"[\w-[\w]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
210             yield return new object[] { @"[\W-[\W]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
211             yield return new object[] { @"[\s-[\s]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
212             yield return new object[] { @"[\S-[\S]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
213             yield return new object[] { @"[\d-[\d]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
214             yield return new object[] { @"[\D-[\D]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
215 
216             // All Negation
217             yield return new object[] { @"[^\w-[^\w]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
218             yield return new object[] { @"[^\W-[^\W]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
219             yield return new object[] { @"[^\s-[^\s]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
220             yield return new object[] { @"[^\S-[^\S]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
221             yield return new object[] { @"[^\d-[^\d]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
222             yield return new object[] { @"[^\D-[^\D]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
223 
224             // MixedNegation
225             yield return new object[] { @"[^\w-[\W]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
226             yield return new object[] { @"[\w-[^\W]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
227             yield return new object[] { @"[^\s-[\S]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
228             yield return new object[] { @"[\s-[^\S]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
229             yield return new object[] { @"[^\d-[\D]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
230             yield return new object[] { @"[\d-[^\D]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
231 
232             // No Negation
233             yield return new object[] { @"[\p{Ll}-[\p{Ll}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
234             yield return new object[] { @"[\P{Ll}-[\P{Ll}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
235             yield return new object[] { @"[\p{Lu}-[\p{Lu}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
236             yield return new object[] { @"[\P{Lu}-[\P{Lu}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
237             yield return new object[] { @"[\p{Nd}-[\p{Nd}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
238             yield return new object[] { @"[\P{Nd}-[\P{Nd}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
239 
240             // All Negation
241             yield return new object[] { @"[^\p{Ll}-[^\p{Ll}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
242             yield return new object[] { @"[^\P{Ll}-[^\P{Ll}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
243             yield return new object[] { @"[^\p{Lu}-[^\p{Lu}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
244             yield return new object[] { @"[^\P{Lu}-[^\P{Lu}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
245             yield return new object[] { @"[^\p{Nd}-[^\p{Nd}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
246             yield return new object[] { @"[^\P{Nd}-[^\P{Nd}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
247 
248             // MixedNegation
249             yield return new object[] { @"[^\p{Ll}-[\P{Ll}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
250             yield return new object[] { @"[\p{Ll}-[^\P{Ll}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
251             yield return new object[] { @"[^\p{Lu}-[\P{Lu}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
252             yield return new object[] { @"[\p{Lu}-[^\P{Lu}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
253             yield return new object[] { @"[^\p{Nd}-[\P{Nd}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
254             yield return new object[] { @"[\p{Nd}-[^\P{Nd}]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty };
255 
256             // Character Class Substraction
257             yield return new object[] { @"[ab\-\[cd-[-[]]]]", "[]]", RegexOptions.None, 0, 3, false, string.Empty };
258             yield return new object[] { @"[ab\-\[cd-[-[]]]]", "-]]", RegexOptions.None, 0, 3, false, string.Empty };
259             yield return new object[] { @"[ab\-\[cd-[-[]]]]", "`]]", RegexOptions.None, 0, 3, false, string.Empty };
260             yield return new object[] { @"[ab\-\[cd-[-[]]]]", "e]]", RegexOptions.None, 0, 3, false, string.Empty };
261 
262             yield return new object[] { @"[ab\-\[cd-[[]]]]", "']]", RegexOptions.None, 0, 3, false, string.Empty };
263             yield return new object[] { @"[ab\-\[cd-[[]]]]", "e]]", RegexOptions.None, 0, 3, false, string.Empty };
264 
265             yield return new object[] { @"[a-[a-f]]", "abcdefghijklmnopqrstuvwxyz", RegexOptions.None, 0, 26, false, string.Empty };
266         }
267 
268         [Theory]
269         [MemberData(nameof(Match_Basic_TestData))]
270         [MemberData(nameof(RegexCompilationHelper.TransformRegexOptions), nameof(Match_Basic_TestData), 2, MemberType = typeof(RegexCompilationHelper))]
Match(string pattern, string input, RegexOptions options, int beginning, int length, bool expectedSuccess, string expectedValue)271         public void Match(string pattern, string input, RegexOptions options, int beginning, int length, bool expectedSuccess, string expectedValue)
272         {
273             bool isDefaultStart = RegexHelpers.IsDefaultStart(input, options, beginning);
274             bool isDefaultCount = RegexHelpers.IsDefaultCount(input, options, length);
275             if (options == RegexOptions.None)
276             {
277                 if (isDefaultStart && isDefaultCount)
278                 {
279                     // Use Match(string) or Match(string, string)
280                     VerifyMatch(new Regex(pattern).Match(input), expectedSuccess, expectedValue);
281                     VerifyMatch(Regex.Match(input, pattern), expectedSuccess, expectedValue);
282 
283                     Assert.Equal(expectedSuccess, new Regex(pattern).IsMatch(input));
284                     Assert.Equal(expectedSuccess, Regex.IsMatch(input, pattern));
285                 }
286                 if (beginning + length == input.Length)
287                 {
288                     // Use Match(string, int)
289                     VerifyMatch(new Regex(pattern).Match(input, beginning), expectedSuccess, expectedValue);
290 
291                     Assert.Equal(expectedSuccess, new Regex(pattern).IsMatch(input, beginning));
292                 }
293                 // Use Match(string, int, int)
294                 VerifyMatch(new Regex(pattern).Match(input, beginning, length), expectedSuccess, expectedValue);
295             }
296             if (isDefaultStart && isDefaultCount)
297             {
298                 // Use Match(string) or Match(string, string, RegexOptions)
299                 VerifyMatch(new Regex(pattern, options).Match(input), expectedSuccess, expectedValue);
300                 VerifyMatch(Regex.Match(input, pattern, options), expectedSuccess, expectedValue);
301 
302                 Assert.Equal(expectedSuccess, Regex.IsMatch(input, pattern, options));
303             }
304             if (beginning + length == input.Length && (options & RegexOptions.RightToLeft) == 0)
305             {
306                 // Use Match(string, int)
307                 VerifyMatch(new Regex(pattern, options).Match(input, beginning), expectedSuccess, expectedValue);
308             }
309             // Use Match(string, int, int)
310             VerifyMatch(new Regex(pattern, options).Match(input, beginning, length), expectedSuccess, expectedValue);
311         }
312 
VerifyMatch(Match match, bool expectedSuccess, string expectedValue)313         public static void VerifyMatch(Match match, bool expectedSuccess, string expectedValue)
314         {
315             Assert.Equal(expectedSuccess, match.Success);
316             Assert.Equal(expectedValue, match.Value);
317 
318             // Groups can never be empty
319             Assert.True(match.Groups.Count >= 1);
320             Assert.Equal(expectedSuccess, match.Groups[0].Success);
321             Assert.Equal(expectedValue, match.Groups[0].Value);
322         }
323 
324         [Fact]
Match_Timeout()325         public void Match_Timeout()
326         {
327             Regex regex = new Regex(@"\p{Lu}", RegexOptions.IgnoreCase, TimeSpan.FromHours(1));
328             Match match = regex.Match("abc");
329             Assert.True(match.Success);
330             Assert.Equal("a", match.Value);
331         }
332 
333         [Fact]
Match_Timeout_Throws()334         public void Match_Timeout_Throws()
335         {
336             RemoteInvoke(() =>
337             {
338                 const string Pattern = @"^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@(([0-9a-zA-Z])+([-\w]*[0-9a-zA-Z])*\.)+[a-zA-Z]{2,9})$";
339                 string input = new string('a', 50) + "@a.a";
340 
341                 AppDomain.CurrentDomain.SetData(RegexHelpers.DefaultMatchTimeout_ConfigKeyName, TimeSpan.FromMilliseconds(100));
342                 Assert.Throws<RegexMatchTimeoutException>(() => new Regex(Pattern).Match(input));
343 
344                 return SuccessExitCode;
345             });
346         }
347 
Match_Advanced_TestData()348         public static IEnumerable<object[]> Match_Advanced_TestData()
349         {
350             // \B special character escape: ".*\\B(SUCCESS)\\B.*"
351             yield return new object[]
352             {
353                 @".*\B(SUCCESS)\B.*", "adfadsfSUCCESSadsfadsf", RegexOptions.None, 0, 22,
354                 new CaptureData[]
355                 {
356                     new CaptureData("adfadsfSUCCESSadsfadsf", 0, 22),
357                     new CaptureData("SUCCESS", 7, 7)
358                 }
359             };
360 
361             // Using |, (), ^, $, .: Actual - "^aaa(bb.+)(d|c)$"
362             yield return new object[]
363             {
364                 "^aaa(bb.+)(d|c)$", "aaabb.cc", RegexOptions.None, 0, 8,
365                 new CaptureData[]
366                 {
367                     new CaptureData("aaabb.cc", 0, 8),
368                     new CaptureData("bb.c", 3, 4),
369                     new CaptureData("c", 7, 1)
370                 }
371             };
372 
373             // Using greedy quantifiers: Actual - "(a+)(b*)(c?)"
374             yield return new object[]
375             {
376                 "(a+)(b*)(c?)", "aaabbbccc", RegexOptions.None, 0, 9,
377                 new CaptureData[]
378                 {
379                     new CaptureData("aaabbbc", 0, 7),
380                     new CaptureData("aaa", 0, 3),
381                     new CaptureData("bbb", 3, 3),
382                     new CaptureData("c", 6, 1)
383                 }
384             };
385 
386             // Using lazy quantifiers: Actual - "(d+?)(e*?)(f??)"
387             // Interesting match from this pattern and input. If needed to go to the end of the string change the ? to + in the last lazy quantifier
388             yield return new object[]
389             {
390                 "(d+?)(e*?)(f??)", "dddeeefff", RegexOptions.None, 0, 9,
391                 new CaptureData[]
392                 {
393                     new CaptureData("d", 0, 1),
394                     new CaptureData("d", 0, 1),
395                     new CaptureData(string.Empty, 1, 0),
396                     new CaptureData(string.Empty, 1, 0)
397                 }
398             };
399 
400             // Noncapturing group : Actual - "(a+)(?:b*)(ccc)"
401             yield return new object[]
402             {
403                 "(a+)(?:b*)(ccc)", "aaabbbccc", RegexOptions.None, 0, 9,
404                 new CaptureData[]
405                 {
406                     new CaptureData("aaabbbccc", 0, 9),
407                     new CaptureData("aaa", 0, 3),
408                     new CaptureData("ccc", 6, 3),
409                 }
410             };
411 
412             // Zero-width positive lookahead assertion: Actual - "abc(?=XXX)\\w+"
413             yield return new object[]
414             {
415                 @"abc(?=XXX)\w+", "abcXXXdef", RegexOptions.None, 0, 9,
416                 new CaptureData[]
417                 {
418                     new CaptureData("abcXXXdef", 0, 9)
419                 }
420             };
421 
422             // Backreferences : Actual - "(\\w)\\1"
423             yield return new object[]
424             {
425                 @"(\w)\1", "aa", RegexOptions.None, 0, 2,
426                 new CaptureData[]
427                 {
428                     new CaptureData("aa", 0, 2),
429                     new CaptureData("a", 0, 1),
430                 }
431             };
432 
433             // Alternation constructs: Actual - "(111|aaa)"
434             yield return new object[]
435             {
436                 "(111|aaa)", "aaa", RegexOptions.None, 0, 3,
437                 new CaptureData[]
438                 {
439                     new CaptureData("aaa", 0, 3),
440                     new CaptureData("aaa", 0, 3)
441                 }
442             };
443 
444             // Actual - "(?<1>\\d+)abc(?(1)222|111)"
445             yield return new object[]
446             {
447                 @"(?<MyDigits>\d+)abc(?(MyDigits)222|111)", "111abc222", RegexOptions.None, 0, 9,
448                 new CaptureData[]
449                 {
450                     new CaptureData("111abc222", 0, 9),
451                     new CaptureData("111", 0, 3)
452                 }
453             };
454 
455             // Using "n" Regex option. Only explicitly named groups should be captured: Actual - "([0-9]*)\\s(?<s>[a-z_A-Z]+)", "n"
456             yield return new object[]
457             {
458                 @"([0-9]*)\s(?<s>[a-z_A-Z]+)", "200 dollars", RegexOptions.ExplicitCapture, 0, 11,
459                 new CaptureData[]
460                 {
461                     new CaptureData("200 dollars", 0, 11),
462                     new CaptureData("dollars", 4, 7)
463                 }
464             };
465 
466             // Single line mode "s". Includes new line character: Actual - "([^/]+)","s"
467             yield return new object[]
468             {
469                 "(.*)", "abc\nsfc", RegexOptions.Singleline, 0, 7,
470                 new CaptureData[]
471                 {
472                     new CaptureData("abc\nsfc", 0, 7),
473                     new CaptureData("abc\nsfc", 0, 7),
474                 }
475             };
476 
477             // "([0-9]+(\\.[0-9]+){3})"
478             yield return new object[]
479             {
480                 @"([0-9]+(\.[0-9]+){3})", "209.25.0.111", RegexOptions.None, 0, 12,
481                 new CaptureData[]
482                 {
483                     new CaptureData("209.25.0.111", 0, 12),
484                     new CaptureData("209.25.0.111", 0, 12),
485                     new CaptureData(".111", 8, 4, new CaptureData[]
486                     {
487                         new CaptureData(".25", 3, 3),
488                         new CaptureData(".0", 6, 2),
489                         new CaptureData(".111", 8, 4),
490                     }),
491                 }
492             };
493 
494             // Groups and captures
495             yield return new object[]
496             {
497                 @"(?<A1>a*)(?<A2>b*)(?<A3>c*)", "aaabbccccccccccaaaabc", RegexOptions.None, 0, 21,
498                 new CaptureData[]
499                 {
500                     new CaptureData("aaabbcccccccccc", 0, 15),
501                     new CaptureData("aaa", 0, 3),
502                     new CaptureData("bb", 3, 2),
503                     new CaptureData("cccccccccc", 5, 10)
504                 }
505             };
506 
507             yield return new object[]
508             {
509                 @"(?<A1>A*)(?<A2>B*)(?<A3>C*)", "aaabbccccccccccaaaabc", RegexOptions.IgnoreCase, 0, 21,
510                 new CaptureData[]
511                 {
512                     new CaptureData("aaabbcccccccccc", 0, 15),
513                     new CaptureData("aaa", 0, 3),
514                     new CaptureData("bb", 3, 2),
515                     new CaptureData("cccccccccc", 5, 10)
516                 }
517             };
518 
519             // Using |, (), ^, $, .: Actual - "^aaa(bb.+)(d|c)$"
520             yield return new object[]
521             {
522                 "^aaa(bb.+)(d|c)$", "aaabb.cc", RegexOptions.None, 0, 8,
523                 new CaptureData[]
524                 {
525                     new CaptureData("aaabb.cc", 0, 8),
526                     new CaptureData("bb.c", 3, 4),
527                     new CaptureData("c", 7, 1)
528                 }
529             };
530 
531             // Actual - ".*\\b(\\w+)\\b"
532             yield return new object[]
533             {
534                 @".*\b(\w+)\b", "XSP_TEST_FAILURE SUCCESS", RegexOptions.None, 0, 24,
535                 new CaptureData[]
536                 {
537                     new CaptureData("XSP_TEST_FAILURE SUCCESS", 0, 24),
538                     new CaptureData("SUCCESS", 17, 7)
539                 }
540             };
541 
542             // Mutliline
543             yield return new object[]
544             {
545                 "(line2$\n)line3", "line1\nline2\nline3\n\nline4", RegexOptions.Multiline, 0, 24,
546                 new CaptureData[]
547                 {
548                     new CaptureData("line2\nline3", 6, 11),
549                     new CaptureData("line2\n", 6, 6)
550                 }
551             };
552 
553             // Mutliline
554             yield return new object[]
555             {
556                 "(line2\n^)line3", "line1\nline2\nline3\n\nline4", RegexOptions.Multiline, 0, 24,
557                 new CaptureData[]
558                 {
559                     new CaptureData("line2\nline3", 6, 11),
560                     new CaptureData("line2\n", 6, 6)
561                 }
562             };
563 
564             // Mutliline
565             yield return new object[]
566             {
567                 "(line3\n$\n)line4", "line1\nline2\nline3\n\nline4", RegexOptions.Multiline, 0, 24,
568                 new CaptureData[]
569                 {
570                     new CaptureData("line3\n\nline4", 12, 12),
571                     new CaptureData("line3\n\n", 12, 7)
572                 }
573             };
574 
575             // Mutliline
576             yield return new object[]
577             {
578                 "(line3\n^\n)line4", "line1\nline2\nline3\n\nline4", RegexOptions.Multiline, 0, 24,
579                 new CaptureData[]
580                 {
581                     new CaptureData("line3\n\nline4", 12, 12),
582                     new CaptureData("line3\n\n", 12, 7)
583                 }
584             };
585 
586             // Mutliline
587             yield return new object[]
588             {
589                 "(line2$\n^)line3", "line1\nline2\nline3\n\nline4", RegexOptions.Multiline, 0, 24,
590                 new CaptureData[]
591                 {
592                     new CaptureData("line2\nline3", 6, 11),
593                     new CaptureData("line2\n", 6, 6)
594                 }
595             };
596 
597             // RightToLeft
598             yield return new object[]
599             {
600                 "aaa", "aaabbb", RegexOptions.RightToLeft, 3, 3,
601                 new CaptureData[]
602                 {
603                     new CaptureData("aaa", 0, 3)
604                 }
605             };
606         }
607 
608         [Theory]
609         [MemberData(nameof(Match_Advanced_TestData))]
Match(string pattern, string input, RegexOptions options, int beginning, int length, CaptureData[] expected)610         public void Match(string pattern, string input, RegexOptions options, int beginning, int length, CaptureData[] expected)
611         {
612             bool isDefaultStart = RegexHelpers.IsDefaultStart(input, options, beginning);
613             bool isDefaultCount = RegexHelpers.IsDefaultStart(input, options, length);
614             if (options == RegexOptions.None)
615             {
616                 if (isDefaultStart && isDefaultCount)
617                 {
618                     // Use Match(string) or Match(string, string)
619                     VerifyMatch(new Regex(pattern).Match(input), true, expected);
620                     VerifyMatch(Regex.Match(input, pattern), true, expected);
621 
622                     Assert.True(new Regex(pattern).IsMatch(input));
623                     Assert.True(Regex.IsMatch(input, pattern));
624                 }
625                 if (beginning + length == input.Length)
626                 {
627                     // Use Match(string, int)
628                     VerifyMatch(new Regex(pattern).Match(input, beginning), true, expected);
629 
630                     Assert.True(new Regex(pattern).IsMatch(input, beginning));
631                 }
632                 else
633                 {
634                     // Use Match(string, int, int)
635                     VerifyMatch(new Regex(pattern).Match(input, beginning, length), true, expected);
636                 }
637             }
638             if (isDefaultStart && isDefaultCount)
639             {
640                 // Use Match(string) or Match(string, string, RegexOptions)
641                 VerifyMatch(new Regex(pattern, options).Match(input), true, expected);
642                 VerifyMatch(Regex.Match(input, pattern, options), true, expected);
643 
644                 Assert.True(Regex.IsMatch(input, pattern, options));
645             }
646             if (beginning + length == input.Length)
647             {
648                 // Use Match(string, int)
649                 VerifyMatch(new Regex(pattern, options).Match(input, beginning), true, expected);
650             }
651             if ((options & RegexOptions.RightToLeft) == 0)
652             {
653                 // Use Match(string, int, int)
654                 VerifyMatch(new Regex(pattern, options).Match(input, beginning, length), true, expected);
655             }
656         }
657 
VerifyMatch(Match match, bool expectedSuccess, CaptureData[] expected)658         public static void VerifyMatch(Match match, bool expectedSuccess, CaptureData[] expected)
659         {
660             Assert.Equal(expectedSuccess, match.Success);
661 
662             Assert.Equal(expected[0].Value, match.Value);
663             Assert.Equal(expected[0].Index, match.Index);
664             Assert.Equal(expected[0].Length, match.Length);
665 
666             Assert.Equal(1, match.Captures.Count);
667             Assert.Equal(expected[0].Value, match.Captures[0].Value);
668             Assert.Equal(expected[0].Index, match.Captures[0].Index);
669             Assert.Equal(expected[0].Length, match.Captures[0].Length);
670 
671             Assert.Equal(expected.Length, match.Groups.Count);
672             for (int i = 0; i < match.Groups.Count; i++)
673             {
674                 Assert.Equal(expectedSuccess, match.Groups[i].Success);
675 
676                 Assert.Equal(expected[i].Value, match.Groups[i].Value);
677                 Assert.Equal(expected[i].Index, match.Groups[i].Index);
678                 Assert.Equal(expected[i].Length, match.Groups[i].Length);
679 
680                 Assert.Equal(expected[i].Captures.Length, match.Groups[i].Captures.Count);
681                 for (int j = 0; j < match.Groups[i].Captures.Count; j++)
682                 {
683                     Assert.Equal(expected[i].Captures[j].Value, match.Groups[i].Captures[j].Value);
684                     Assert.Equal(expected[i].Captures[j].Index, match.Groups[i].Captures[j].Index);
685                     Assert.Equal(expected[i].Captures[j].Length, match.Groups[i].Captures[j].Length);
686                 }
687             }
688         }
689 
690         [Theory]
691         [InlineData(@"(?<1>\d{1,2})/(?<2>\d{1,2})/(?<3>\d{2,4})\s(?<time>\S+)", "08/10/99 16:00", "${time}", "16:00")]
692         [InlineData(@"(?<1>\d{1,2})/(?<2>\d{1,2})/(?<3>\d{2,4})\s(?<time>\S+)", "08/10/99 16:00", "${1}", "08")]
693         [InlineData(@"(?<1>\d{1,2})/(?<2>\d{1,2})/(?<3>\d{2,4})\s(?<time>\S+)", "08/10/99 16:00", "${2}", "10")]
694         [InlineData(@"(?<1>\d{1,2})/(?<2>\d{1,2})/(?<3>\d{2,4})\s(?<time>\S+)", "08/10/99 16:00", "${3}", "99")]
695         [InlineData("abc", "abc", "abc", "abc")]
Result(string pattern, string input, string replacement, string expected)696         public void Result(string pattern, string input, string replacement, string expected)
697         {
698             Assert.Equal(expected, new Regex(pattern).Match(input).Result(replacement));
699         }
700 
701         [Fact]
Result_Invalid()702         public void Result_Invalid()
703         {
704             Match match = Regex.Match("foo", "foo");
705             AssertExtensions.Throws<ArgumentNullException>("replacement", () => match.Result(null));
706 
707             Assert.Throws<NotSupportedException>(() => RegularExpressions.Match.Empty.Result("any"));
708         }
709 
710         [Fact]
Match_SpecialUnicodeCharacters_enUS()711         public void Match_SpecialUnicodeCharacters_enUS()
712         {
713             RemoteInvoke(() =>
714             {
715                 CultureInfo.CurrentCulture = new CultureInfo("en-US");
716                 Match("\u0131", "\u0049", RegexOptions.IgnoreCase, 0, 1, false, string.Empty);
717                 Match("\u0131", "\u0069", RegexOptions.IgnoreCase, 0, 1, false, string.Empty);
718 
719                 return SuccessExitCode;
720             }).Dispose();
721         }
722 
723         [Fact]
Match_SpecialUnicodeCharacters_Invariant()724         public void Match_SpecialUnicodeCharacters_Invariant()
725         {
726             RemoteInvoke(() =>
727             {
728                 CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
729                 Match("\u0131", "\u0049", RegexOptions.IgnoreCase, 0, 1, false, string.Empty);
730                 Match("\u0131", "\u0069", RegexOptions.IgnoreCase, 0, 1, false, string.Empty);
731                 Match("\u0130", "\u0049", RegexOptions.IgnoreCase, 0, 1, false, string.Empty);
732                 Match("\u0130", "\u0069", RegexOptions.IgnoreCase, 0, 1, false, string.Empty);
733 
734                 return SuccessExitCode;
735             }).Dispose();
736         }
737 
738         [Fact]
Match_Invalid()739         public void Match_Invalid()
740         {
741             // Input is null
742             AssertExtensions.Throws<ArgumentNullException>("input", () => Regex.Match(null, "pattern"));
743             AssertExtensions.Throws<ArgumentNullException>("input", () => Regex.Match(null, "pattern", RegexOptions.None));
744             AssertExtensions.Throws<ArgumentNullException>("input", () => Regex.Match(null, "pattern", RegexOptions.None, TimeSpan.FromSeconds(1)));
745 
746             AssertExtensions.Throws<ArgumentNullException>("input", () => new Regex("pattern").Match(null));
747             AssertExtensions.Throws<ArgumentNullException>("input", () => new Regex("pattern").Match(null, 0));
748             AssertExtensions.Throws<ArgumentNullException>("input", () => new Regex("pattern").Match(null, 0, 0));
749 
750             // Pattern is null
751             AssertExtensions.Throws<ArgumentNullException>("pattern", () => Regex.Match("input", null));
752             AssertExtensions.Throws<ArgumentNullException>("pattern", () => Regex.Match("input", null, RegexOptions.None));
753             AssertExtensions.Throws<ArgumentNullException>("pattern", () => Regex.Match("input", null, RegexOptions.None, TimeSpan.FromSeconds(1)));
754 
755             // Start is invalid
756             Assert.Throws<ArgumentOutOfRangeException>(() => new Regex("pattern").Match("input", -1));
757             Assert.Throws<ArgumentOutOfRangeException>(() => new Regex("pattern").Match("input", -1, 0));
758             Assert.Throws<ArgumentOutOfRangeException>(() => new Regex("pattern").Match("input", 6));
759             Assert.Throws<ArgumentOutOfRangeException>(() => new Regex("pattern").Match("input", 6, 0));
760 
761             // Length is invalid
762             AssertExtensions.Throws<ArgumentOutOfRangeException>("length", () => new Regex("pattern").Match("input", 0, -1));
763             AssertExtensions.Throws<ArgumentOutOfRangeException>("length", () => new Regex("pattern").Match("input", 0, 6));
764         }
765 
766         [Theory]
767         [InlineData(")")]
768         [InlineData("())")]
769         [InlineData("[a-z-[aeiuo]")]
770         [InlineData("[a-z-[aeiuo")]
771         [InlineData("[a-z-[b]")]
772         [InlineData("[a-z-[b")]
773         [InlineData("[b-a]")]
774         [InlineData(@"[a-c]{2,1}")]
775         [InlineData(@"\d{2147483648}")]
776         [InlineData("[a-z-[b][")]
777         [InlineData(@"\")]
778         [InlineData("(?()|||||)")]
Match_InvalidPattern(string pattern)779         public void Match_InvalidPattern(string pattern)
780         {
781             AssertExtensions.Throws<ArgumentException>(null, () => Regex.Match("input", pattern));
782         }
783 
784         [Fact]
IsMatch_Invalid()785         public void IsMatch_Invalid()
786         {
787             // Input is null
788             AssertExtensions.Throws<ArgumentNullException>("input", () => Regex.IsMatch(null, "pattern"));
789             AssertExtensions.Throws<ArgumentNullException>("input", () => Regex.IsMatch(null, "pattern", RegexOptions.None));
790             AssertExtensions.Throws<ArgumentNullException>("input", () => Regex.IsMatch(null, "pattern", RegexOptions.None, TimeSpan.FromSeconds(1)));
791 
792             AssertExtensions.Throws<ArgumentNullException>("input", () => new Regex("pattern").IsMatch(null));
793             AssertExtensions.Throws<ArgumentNullException>("input", () => new Regex("pattern").IsMatch(null, 0));
794 
795             // Pattern is null
796             AssertExtensions.Throws<ArgumentNullException>("pattern", () => Regex.IsMatch("input", null));
797             AssertExtensions.Throws<ArgumentNullException>("pattern", () => Regex.IsMatch("input", null, RegexOptions.None));
798             AssertExtensions.Throws<ArgumentNullException>("pattern", () => Regex.IsMatch("input", null, RegexOptions.None, TimeSpan.FromSeconds(1)));
799 
800             // Start is invalid
801             Assert.Throws<ArgumentOutOfRangeException>(() => new Regex("pattern").IsMatch("input", -1));
802             Assert.Throws<ArgumentOutOfRangeException>(() => new Regex("pattern").IsMatch("input", 6));
803         }
804     }
805 }
806