83924890e4b90468369d22b7824cf7fe843d81ef
[mono.git] / mcs / class / System / Test / System.Text.RegularExpressions / RegexTest.cs
1 //
2 // assembly:    System_test
3 // namespace:   MonoTests.System.Text.RegularExpressions
4 // file:        RegexTest.cs
5 //
6 // Authors:     
7 //   Juraj Skripsky (juraj@hotfeet.ch)
8 //
9 // (c) 2003 Juraj Skripsky
10
11 using System;
12 using System.Text.RegularExpressions;
13
14 #if NET_2_0
15 using System.Collections.Generic;
16 #endif
17
18 using NUnit.Framework;
19
20 namespace MonoTests.System.Text.RegularExpressions
21 {
22         [TestFixture]
23         public class RegexTest
24         {
25 #if NET_2_0
26                 private int cache_initial_value;
27
28                 [TestFixtureSetUp]
29                 public void FixtureSetUp ()
30                 {
31                         cache_initial_value = Regex.CacheSize;
32                 }
33
34                 [TearDown]
35                 public void TearDown ()
36                 {
37                         Regex.CacheSize = cache_initial_value;
38                 }
39 #endif
40
41                 [Test]
42                 public void Simple ()
43                 {
44                         char[] c = { (char)32, (char)8212, (char)32 };
45                         string s = new String(c);
46                         Assert.IsTrue (Regex.IsMatch(s, s), "char");
47                 }
48
49                 [Test, ExpectedException (typeof (ArgumentNullException))]
50                 public void NullPattern1 ()
51                 {
52                         new Regex (null);
53                 }
54
55                 [Test, ExpectedException (typeof (ArgumentNullException))]
56                 public void NullPattern2 ()
57                 {
58                         new Regex (null, RegexOptions.None);
59                 }
60
61                 [Test, ExpectedException (typeof (ArgumentOutOfRangeException))]
62                 public void InvalidOptions1 ()
63                 {
64                         new Regex ("foo", (RegexOptions) Int32.MaxValue);
65                 }
66
67                 [Test, ExpectedException (typeof (ArgumentOutOfRangeException))]
68                 public void InvalidOptions2 ()
69                 {
70                         new Regex ("foo", RegexOptions.ECMAScript | RegexOptions.RightToLeft);
71                 }
72                 
73                 [Test]
74                 public void Unescape ()
75                 {
76                         string inString = @"\a\b\t\r\v\f\n\e\02400\x231\cC\ufffff\*";
77                         char [] c = { (char)7, (char)8, (char)9, (char)13, 
78                                       (char)11, (char)12, (char)10, (char)27, (char) 20,
79                                       (char)48, (char)48, (char)35, (char)49, 
80                                       (char)3, (char)65535, (char)102, (char)42
81                         };
82                         string expectedString = new String(c);
83                         string outString = Regex.Unescape(inString);
84
85                         Assert.AreEqual (outString, expectedString, "unescape");
86                 }
87
88                 [Test]
89                 public void Match1 ()
90                 {
91                         Regex email = new Regex ("(?<user>[^@]+)@(?<domain>.+)");
92                         Match m;
93
94                         m = email.Match ("mono@go-mono.com");
95
96                         Assert.IsTrue (m.Success, "#m01");
97                         Assert.AreEqual ("mono", m.Groups ["user"].Value, "#m02");
98                         Assert.AreEqual ("go-mono.com", m.Groups ["domain"].Value, "#m03");
99
100                         m = email.Match ("mono.bugs@go-mono.com");
101                         Assert.IsTrue (m.Success, "m04");
102                         Assert.AreEqual ("mono.bugs", m.Groups ["user"].Value, "#m05");
103                         Assert.AreEqual ("go-mono.com", m.Groups ["domain"].Value, "#m06");
104                 }
105
106                 [Test]
107                 public void Match2 ()
108                 {
109                         Regex regex = new Regex(@"(?<tab>\t)|(?<text>[^\t]*)");
110                         MatchCollection col = regex.Matches("\tjust a text");
111                         Assert.AreEqual(3, col.Count);
112                         Assert.AreEqual (col [0].Value, "\t");
113                         Assert.AreEqual (col [1].Value, "just a text");
114                         Assert.AreEqual(col[2].Value, string.Empty);
115                 }
116
117                 [Test, ExpectedException (typeof (ArgumentNullException))]
118                 public void Match_Null1 ()
119                 {
120                         new Regex (@"foo").Match (null);
121                 }
122
123                 [Test, ExpectedException (typeof (ArgumentOutOfRangeException))]
124                 public void Match_BadStart1 ()
125                 {
126                         new Regex (@"foo").Match ("foobar", -1);
127                 }
128
129                 [Test, ExpectedException (typeof (ArgumentOutOfRangeException))]
130                 public void Match_BadStart2 ()
131                 {
132                         new Regex (@"foo").Match ("foobar", -1, 0);
133                 }
134
135                 [Test, ExpectedException (typeof (ArgumentOutOfRangeException))]
136                 public void Match_BadStart3 ()
137                 {
138                         new Regex (@"foo").Match ("foobar", 7);
139                 }
140
141                 [Test, ExpectedException (typeof (ArgumentOutOfRangeException))]
142                 public void Match_BadStart4 ()
143                 {
144                         new Regex (@"foo").Match ("foobar", 7, 0);
145                 }
146
147                 [Test, ExpectedException (typeof (ArgumentOutOfRangeException))]
148                 public void Match_BadLength1 ()
149                 {
150                         new Regex (@"foo").Match ("foobar", 5, -1);
151                 }
152
153                 [Test, ExpectedException (typeof (ArgumentOutOfRangeException))]
154                 public void Match_BadLength2 ()
155                 {
156                         new Regex (@"foo").Match ("foobar", 5, 3);
157                 }
158
159                 [Test, ExpectedException (typeof (ArgumentNullException))]
160                 public void Matches_Null1 ()
161                 {
162                         new Regex (@"foo").Matches (null);
163                 }
164
165                 [Test, ExpectedException (typeof (ArgumentNullException))]
166                 public void Matches_Null2 ()
167                 {
168                         new Regex (@"foo").Matches (null, 0);
169                 }
170
171                 [Test, ExpectedException (typeof (ArgumentNullException))]
172                 public void Matches_Null3 ()
173                 {
174                         new Regex (@"foo", RegexOptions.RightToLeft).Matches (null);
175                 }
176
177                 [Test, ExpectedException (typeof (ArgumentNullException))]
178                 public void Replace_InputNull ()
179                 {
180                         Regex r = new Regex ("^.*$");
181                         MatchEvaluator m = delegate (Match match) {return null;};
182                         r.Replace (null, m, 0, 0);
183                 }
184
185                 [Test, ExpectedException (typeof (ArgumentNullException))]
186                 public void Replace_InputNull2 ()
187                 {
188                         Regex r = new Regex ("^.*$");
189                         r.Replace (null, "abc", 0, 0);
190                 }
191
192                 [Test, ExpectedException (typeof (ArgumentNullException))]
193                 public void Replace_InputNull3 ()
194                 {
195                         Regex r = new Regex ("^.*$", RegexOptions.RightToLeft);
196                         MatchEvaluator m = delegate (Match match) {return null;};
197                         r.Replace (null, m);
198                 }
199
200                 [Test, ExpectedException (typeof (ArgumentNullException))]
201                 public void Replace_InputNull4 ()
202                 {
203                         Regex r = new Regex ("^.*$", RegexOptions.RightToLeft);
204                         r.Replace (null, "abc");
205                 }
206
207                 [Test, ExpectedException (typeof (ArgumentNullException))]
208                 public void Replace_ReplacementNull ()
209                 {
210                         Regex r = new Regex ("^.*$");
211                         r.Replace ("string", (string) null, 0, 0);
212                 }
213
214                 [Test, ExpectedException (typeof (ArgumentNullException))]
215                 public void Replace_EvaluatorNull ()
216                 {
217                         Regex r = new Regex ("^.*$");
218                         MatchEvaluator m = null;
219                         r.Replace ("string", m, 0, 0);
220                 }
221
222                 [Test, ExpectedException (typeof (ArgumentOutOfRangeException))]
223                 public void Replace_InvalidCount ()
224                 {
225                         Regex r = new Regex ("foo|bar");
226                         r.Replace ("foo",  "baz", -4);
227                 }
228
229                 [Test, ExpectedException (typeof (ArgumentOutOfRangeException))]
230                 public void Replace_InvalidStart ()
231                 {
232                         Regex r = new Regex ("foo|bar");
233                         r.Replace ("foo", "baz", 1, -4);
234                 }
235
236                 [Test, ExpectedException (typeof (ArgumentNullException))]
237                 public void Split_InputNull1 ()
238                 {
239                         Regex.Split (null, "^.*$");
240                 }
241
242                 [Test, ExpectedException (typeof (ArgumentNullException))]
243                 public void Split_InputNull2 ()
244                 {
245                         Regex.Split (null, "^.*$", RegexOptions.RightToLeft);
246                 }
247
248                 [Test, ExpectedException (typeof (ArgumentOutOfRangeException))]
249                 public void Split_InvalidCount ()
250                 {
251                         Regex r = new Regex ("^.*$");
252                         r.Split ("foo", -4);
253                 }
254
255                 [Test, ExpectedException (typeof (ArgumentOutOfRangeException))]
256                 public void Split_InvalidCount2 ()
257                 {
258                         Regex r = new Regex ("^.*$");
259                         r.Split ("foo", 1, -4);
260                 }
261
262                 [Test, ExpectedException (typeof (ArgumentNullException))]
263                 public void Escape_Null ()
264                 {
265                         Regex.Escape (null);
266                 }
267
268                 [Test, ExpectedException (typeof (ArgumentNullException))]
269                 public void Unescape_Null ()
270                 {
271                         Regex.Unescape (null);
272                 }
273
274                 static string story =
275                         "Two little dragons lived in the forest\n" +
276                         "They spent their days collecting honey suckle,\n" +
277                         "And eating curds and whey\n" +
278                         "Until an evil sorcer came along\n" +
279                         "And chased my dragon friends away";
280
281                 struct MatchCollectionTrial {
282                         public readonly string name;
283                         public readonly string text;
284                         public readonly string regex;
285                         public readonly string [] matches;
286                         public MatchCollectionTrial (string name, string text, string regex, string [] matches)
287                         {
288                                 this.name = name;
289                                 this.text = text;
290                                 this.regex = regex;
291                                 this.matches = matches;
292                         }
293                 }
294
295                 static readonly MatchCollectionTrial [] trials = {
296                         new MatchCollectionTrial ("word", "the fat cat ate the rat", "(?<word>\\w+)", 
297                                 new string [] { "the", "fat", "cat", "ate", "the", "rat" }),
298                         new MatchCollectionTrial ("digit", "0 1 2 3 4 5 6a7b8c9d10", "(?<digit>\\d+)", 
299                                 new string [] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" }),
300                         new MatchCollectionTrial ("line", story, "(?<line>.+)", 
301                                 new string [] { "Two little dragons lived in the forest",
302                                                 "They spent their days collecting honey suckle,",
303                                                 "And eating curds and whey",
304                                                 "Until an evil sorcer came along",
305                                                 "And chased my dragon friends away" }),
306                         new MatchCollectionTrial ("nonwhite", "ab 12 cde 456 fghi .,\niou", "(?<nonwhite>\\S+)",
307                                 new string [] { "ab", "12", "cde", "456", "fghi", ".,", "iou" }),
308                         new MatchCollectionTrial ("nondigit", "ab0cd1ef2", "(?<nondigit>\\D+)",
309                                 new string [] { "ab", "cd", "ef" })
310                 };
311
312                 static void runTrial (MatchCollectionTrial t)
313                 {
314                         runTrial (t, false);
315                         runTrial (t, true);
316                 }
317
318                 static void runTrial (MatchCollectionTrial t, bool rtl)
319                 {
320                         int i;
321                         MatchCollection mc;
322
323                         string name = t.name;
324                         if (rtl)
325                                 name += "-rtl";
326
327                         int len = t.matches.Length;
328                         Regex r = new Regex (t.regex, rtl ? RegexOptions.RightToLeft : RegexOptions.None);
329
330                         // Incremental mode -- this access
331                         mc = r.Matches (t.text);
332                         for (i = 0; i < len; ++i)
333                                 Assert.AreEqual (mc [i].Value, t.matches [rtl ? len - i - 1 : i], "{0}:this:{1}", name, i);
334                         Assert.AreEqual (i, mc.Count, "{0}:this:count", name);
335
336                         // Incremental mode -- enumerator
337                         mc = r.Matches (t.text);
338                         i = 0;
339                         foreach (Match m in mc) {
340                                 Assert.AreEqual (m.Value, t.matches [rtl ? len - i - 1 : i], "{0}:enum:{1}", name, i);
341                                 ++i;
342                         }
343                         Assert.AreEqual (i, len, "{0}:enum:count", name);
344
345                         // random mode
346                         Random rng = new Random ();
347                         for (int j = 0; j < len * 5; ++j) {
348                                 i = rng.Next (len);
349                                 Assert.AreEqual (mc [i].Value, t.matches [rtl ? len - i - 1 : i], "{0}:random{1}:{2}", name, j, i);
350                         }
351
352                         // Non-incremental mode
353                         mc = r.Matches (t.text);
354                         Assert.AreEqual (mc.Count, len);
355                         i = 0;
356                         foreach (Match m in mc) {
357                                 Assert.AreEqual (m.Value, t.matches [rtl ? len - i - 1 : i], "{0}:nienum:{1}", name, i);
358                                 ++i;
359                         }
360                         for (i = 0; i < len; ++i)
361                                 Assert.AreEqual (mc [i].Value, t.matches [rtl ? len - i - 1 : i], "{0}:nithis:{1}", name, i);
362                 }
363
364                 [Test]
365                 public void Matches ()
366                 {
367                         foreach (MatchCollectionTrial t in trials)
368                                 runTrial (t);
369                 }
370 #if NET_2_0
371                 [Test]
372                 public void CacheSize ()
373                 {
374                         Assert.AreEqual (15, Regex.CacheSize, "CacheSize");
375                         Regex.CacheSize = 0;
376                         Regex.CacheSize = Int32.MaxValue;
377                 }
378
379                 [Test]
380                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
381                 public void CacheSize_Negative ()
382                 {
383                         Regex.CacheSize = -1;
384                 }
385
386                 [Test]
387                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
388                 public void CacheSize_Min ()
389                 {
390                         Regex.CacheSize = Int32.MinValue;
391                 }
392
393                 static IEnumerable<uint> Primes (uint m)
394                 {
395                         if (m < 2)
396                                 yield break;
397
398                         yield return 2;
399
400                         Dictionary<uint, uint> w = new Dictionary<uint, uint> ();
401                         uint p2, n1;
402
403                         for (uint n = 3; n < m; n += 2) {
404                                 if (w.TryGetValue (n, out p2)) {
405                                         w.Remove (n);
406                                         n1 = n + p2;
407                                 } else {
408                                         yield return n;
409                                         n1 = n * n;
410                                         p2 = n + n;
411
412                                         // if there's an overflow, don't bother
413                                         if (n1 / n != n || n1 >= m)
414                                                 continue;
415                                 }
416
417                                 while (w.ContainsKey (n1))
418                                         n1 += p2;
419                                 w [n1] = p2;
420                         }
421                 }
422
423                 [Test]
424                 public void PrimeRegex ()
425                 {
426                         // Perl regex oneliner by: abigail@fnx.com (Abigail)
427                         // from: http://www.mit.edu:8008/bloom-picayune.mit.edu/perl/10138
428                         // perl -wle 'print "Prime" if (1 x shift) !~ /^1?$|^(11+?)\1+$/'
429
430                         // This is a backtracking torture test
431
432                         Regex composite = new Regex (@"^1?$|^(11+?)\1+$");
433
434                         uint i = 0;
435                         string x = "";
436
437                         foreach (uint p in Primes (3333)) {
438                                 while (i < p) {
439                                         Assert.IsTrue (composite.IsMatch (x));
440                                         ++i;
441                                         x += "1";
442                                 }
443                                 // i == p
444                                 Assert.IsFalse (composite.IsMatch (x));
445                                 ++i;
446                                 x += "1";
447                         }
448                 }
449 #endif
450         }
451 }