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