Merge pull request #890 from xoofx/master
[mono.git] / mcs / class / System.Core / Test / System.Linq / EnumerableTest.cs
1 //
2 // EnumerableTest.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@novell.com)
6 //
7 // (C) 2007 Novell, Inc. (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30 using System.IO;
31 using System.Collections;
32 using System.Collections.Generic;
33 using System.Linq;
34 using System.Linq.Expressions;
35
36 using NUnit.Framework;
37
38 namespace MonoTests.System.Linq {
39
40         [TestFixture]
41         public class EnumerableTest {
42
43                 [Test]
44                 public void TestSimpleExcept ()
45                 {
46                         int [] first = {0, 1, 2, 3, 4, 5};
47                         int [] second = {2, 4, 6};
48                         int [] result = {0, 1, 3, 5};
49
50                         AssertAreSame (result, first.Except (second));
51                 }
52
53                 [Test]
54                 public void TestSimpleIntersect ()
55                 {
56                         int [] first = {0, 1, 2, 3, 4, 5};
57                         int [] second = {2, 4, 6};
58                         int [] result = {2, 4};
59
60                         AssertAreSame (result, first.Intersect (second));
61                 }
62
63                 [Test]
64                 public void TestSimpleUnion ()
65                 {
66                         int [] first = {0, 1, 2, 3, 4, 5};
67                         int [] second = {2, 4, 6};
68                         int [] result = {0, 1, 2, 3, 4, 5, 6};
69
70                         AssertAreSame (result, first.Union (second));
71                 }
72
73                 class Foo {}
74                 class Bar : Foo {}
75
76                 [Test]
77                 public void TestCast ()
78                 {
79                         Bar a = new Bar ();
80                         Bar b = new Bar ();
81                         Bar c = new Bar ();
82
83                         Foo [] foos = new Foo [] {a, b, c};
84                         Bar [] result = new Bar [] {a, b, c};
85
86                         AssertAreSame (result, foos.Cast<Bar> ());
87                 }
88
89                 class Bingo : IEnumerable<int>, IEnumerable<string> {
90
91                         IEnumerator<int> IEnumerable<int>.GetEnumerator ()
92                         {
93                                 yield return 42;
94                                 yield return 12;
95                         }
96
97                         IEnumerator<string> IEnumerable<string>.GetEnumerator ()
98                         {
99                                 yield return "foo";
100                                 yield return "bar";
101                         }
102
103                         public IEnumerator GetEnumerator ()
104                         {
105                                 return (this as IEnumerable<int>).GetEnumerator ();
106                         }
107                 }
108
109                 [Test]
110                 public void TestCastToImplementedType ()
111                 {
112                         var ints = new int [] { 42, 12 };
113                         var strs = new string [] { "foo", "bar" };
114
115                         var bingo = new Bingo ();
116
117                         AssertAreSame (ints, bingo.Cast<int> ());
118                         AssertAreSame (strs, bingo.Cast<string> ());
119                 }
120
121                 [Test]
122                 public void TestLast ()
123                 {
124                         int [] data = {1, 2, 3};
125
126                         Assert.AreEqual (3, data.Last ());
127                 }
128
129                 [Test]
130                 public void TestLastOrDefault ()
131                 {
132                         int [] data = {};
133
134                         Assert.AreEqual (default (int), data.LastOrDefault ());
135                 }
136
137                 [Test]
138                 public void TestFirst ()
139                 {
140                         int [] data = {1, 2, 3};
141
142                         Assert.AreEqual (1, data.First ());
143                 }
144
145                 [Test]
146                 public void TestFirstOrDefault ()
147                 {
148                         int [] data = {};
149
150                         Assert.AreEqual (default (int), data.FirstOrDefault ());
151                 }
152
153                 [Test]
154                 public void TestSequenceEqual ()
155                 {
156                         int [] first = {0, 1, 2, 3, 4, 5};
157                         int [] second = {0, 1, 2};
158                         int [] third = {0, 1, 2, 3, 4, 5};
159
160                         Assert.IsFalse (first.SequenceEqual (second));
161                         Assert.IsTrue (first.SequenceEqual (third));
162                 }
163
164                 [Test]
165                 public void TestSkip ()
166                 {
167                         int [] data = {0, 1, 2, 3, 4, 5};
168                         int [] result = {3, 4, 5};
169
170                         AssertAreSame (result, data.Skip (3));
171                 }
172
173                 [Test]
174                 public void TestSkipWhile ()
175                 {
176                         int [] data = {0, 1, 2, 3, 4, 5};
177                         int [] result = {3, 4, 5};
178
179                         AssertAreSame (result, data.SkipWhile (i => i < 3));
180                 }
181
182                 [Test]
183                 public void TestTake ()
184                 {
185                         int [] data = {0, 1, 2, 3, 4, 5};
186                         int [] result = {0, 1, 2};
187
188                         AssertAreSame (result, data.Take (3));
189                 }
190
191                 [Test]
192                 public void TestTakeWhile ()
193                 {
194                         int [] data = {0, 1, 2, 3, 4, 5};
195                         int [] result = {0, 1, 2};
196
197                         AssertAreSame (result, data.TakeWhile (i => i < 3));
198                 }
199
200                 [Test]
201                 public void TestSelect ()
202                 {
203                         int [] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
204                         int [] result = {1, 3, 5, 7, 9};
205
206                         AssertAreSame (result, data.Where (i => i % 2 != 0));
207                 }
208
209                 [Test]
210                 public void TestReverse ()
211                 {
212                         int [] data = {0, 1, 2, 3, 4};
213                         int [] result = {4, 3, 2, 1, 0};
214
215                         AssertAreSame (result, data.Reverse ());
216                         AssertAreSame (result, Enumerable.Range (0, 5).Reverse ());
217                 }
218
219                 [Test]
220                 public void ReverseArrays ()
221                 {
222                         int[] source = { 1, 2, 3 };
223
224                         var query = source.Reverse ();
225                         using (var enumerator = query.GetEnumerator ()) {
226                                 enumerator.MoveNext ();
227                                 Assert.AreEqual (3, enumerator.Current);
228
229                                 source [1] = 42;
230                                 enumerator.MoveNext ();
231                                 Assert.AreEqual (2, enumerator.Current);
232
233                                 enumerator.MoveNext ();
234                                 Assert.AreEqual (1, enumerator.Current);
235                         }
236                 }
237
238                 [Test]
239                 public void TestSum ()
240                 {
241                         int [] data = {1, 2, 3, 4};
242
243                         Assert.AreEqual (10, data.Sum ());
244                 }
245
246                 [Test]
247                 public void SumOnEmpty ()
248                 {
249                         int [] data = {};
250
251                         Assert.AreEqual (0, data.Sum ());
252                 }
253
254                 [Test]
255                 public void TestMax ()
256                 {
257                         int [] data = {1, 3, 5, 2};
258
259                         Assert.AreEqual (5, data.Max ());
260                 }
261
262                 [Test]
263                 public void TestMaxNullableInt32 ()
264                 {
265                         int? [] data = { null, null, null };
266
267                         Assert.IsNull (data.Max (x => -x));
268
269                         data = new int? [] { null, 1, 2 };
270
271                         Assert.AreEqual (-1, data.Max (x => -x));
272                 }
273
274                 [Test]
275                 public void TestMin ()
276                 {
277                         int [] data = {3, 5, 2, 6, 1, 7};
278
279                         Assert.AreEqual (1, data.Min ());
280                 }
281
282                 [Test]
283                 public void TestMinNullableInt32 ()
284                 {
285                         int? [] data = { null, null, null };
286
287                         Assert.IsNull (data.Min(x => -x));
288
289                         data = new int? [] { null, 1, 2 };
290
291                         Assert.AreEqual (-2, data.Min (x => -x));
292                 }
293
294                 [Test]
295                 public void TestMinStringEmpty ()
296                 {
297                         Assert.IsNull ((new string [0]).Min ());
298                 }
299
300                 [Test]
301                 public void TestMaxStringEmpty ()
302                 {
303                         Assert.IsNull ((new string [0]).Max ());
304                 }
305
306                 [Test]
307                 public void TestToList ()
308                 {
309                         int [] data = {3, 5, 2};
310
311                         var list = data.ToList ();
312
313                         AssertAreSame (data, list);
314
315                         Assert.AreEqual (typeof (List<int>), list.GetType ());
316                 }
317
318                 [Test]
319                 public void TestToArray ()
320                 {
321                         ICollection<int> coll = new List<int> ();
322                         coll.Add (0);
323                         coll.Add (1);
324                         coll.Add (2);
325
326                         int [] result = {0, 1, 2};
327
328                         var array = coll.ToArray ();
329
330                         AssertAreSame (result, array);
331
332                         Assert.AreEqual (typeof (int []), array.GetType ());
333                 }
334
335                 [Test]
336                 public void TestIntersect ()
337                 {
338                         int [] left = { 1, 1 }, right = { 1, 1 };
339                         int [] result = { 1 };
340
341                         AssertAreSame (result, left.Intersect (right));
342                 }
343
344                 [Test]
345                 public void TestAverageOnInt32 ()
346                 {
347                         Assert.AreEqual (23.25, (new int [] { 24, 7, 28, 34 }).Average ());
348                 }
349
350                 [Test]
351                 public void TestAverageOnInt64 ()
352                 {
353                         Assert.AreEqual (23.25, (new long [] { 24, 7, 28, 34 }).Average ());
354                 }
355
356                 [Test]
357                 public void TestAverageInt32 ()
358                 {
359                         // This does not overflow, computation is done with longs
360                         var x = new int [] { Int32.MaxValue, Int32.MaxValue };
361                         Assert.AreEqual ((double) Int32.MaxValue, x.Average ());
362                 }
363                 
364                 [Test]
365                 public void TestAverageOverflowOnInt64 ()
366                 {
367                         var x = new long [] { Int64.MaxValue, Int64.MaxValue };
368                         x.Average ();
369                 }
370
371                 [Test]
372                 public void TestAverageOnLongNullable ()
373                 {
374                         List<long?> list = new List<long?> ();
375                         list.Add (2);
376                         list.Add (3);
377                         Assert.AreEqual (2.5d, list.Average ());
378                 }
379
380                 [Test]
381                 public void TestRange ()
382                 {
383                         AssertAreSame (new [] {1, 2, 3, 4}, Enumerable.Range (1, 4));
384                         AssertAreSame (new [] {0, 1, 2, 3}, Enumerable.Range (0, 4));
385                 }
386
387                 [Test]
388                 public void SingleValueOfMaxInt32 ()
389                 {
390                         AssertAreSame (new [] { int.MaxValue }, Enumerable.Range(int.MaxValue, 1));
391                 }
392
393                 [Test]
394                 public void EmptyRangeStartingAtMinInt32 ()
395                 {
396                         AssertAreSame (new int [0], Enumerable.Range(int.MinValue, 0));
397                 }
398
399                 static void AssertThrows<T> (Action action) where T : Exception
400                 {
401                         try {
402                                 action ();
403                                 Assert.Fail ();
404                         } catch (T) {
405                         } catch {
406                                 Assert.Fail ();
407                         }
408                 }
409
410                 [Test]
411                 public void TestTakeTakesProperNumberOfItems ()
412                 {
413                         var stream = new MemoryStream (new byte [] { 1, 2, 3, 4, 0 });
414
415                         Assert.AreEqual (0, stream.Position);
416
417                         foreach (byte b in AsEnumerable (stream).Take (2))
418                                 ;
419
420                         Assert.AreEqual (2, stream.Position);
421                 }
422
423                 static IEnumerable<byte> AsEnumerable (Stream stream)
424                 {
425                         byte b;
426                         while ((b = (byte) stream.ReadByte ()) >= 0)
427                                 yield return b;
428                 }
429
430                 [Test]
431                 public void TestOrderBy ()
432                 {
433                                 int [] array = { 14, 53, 3, 9, 11, 14, 5, 32, 2 };
434                                 var q = from i in array
435                                                 orderby i
436                                                 select i;
437                                 AssertIsOrdered (q);
438                 }
439
440                 class Baz {
441                         string name;
442                         int age;
443
444                         public string Name
445                         {
446                                 get {
447                                         if (string.IsNullOrEmpty (name))
448                                                 return Age.ToString ();
449
450                                         return name + " (" + Age + ")";
451                                 }
452                         }
453
454                         public int Age
455                         {
456                                 get { return age + 1; }
457                         }
458
459                         public Baz (string name, int age)
460                         {
461                                 this.name = name;
462                                 this.age = age;
463                         }
464
465                         public override int GetHashCode ()
466                         {
467                                 return this.Age ^ this.Name.GetHashCode ();
468                         }
469
470                         public override bool Equals (object obj)
471                         {
472                                 Baz b = obj as Baz;
473                                 if (b == null)
474                                         return false;
475
476                                 return b.Age == this.Age && b.Name == this.Name;
477                         }
478
479                         public override string ToString ()
480                         {
481                                 return this.Name;
482                         }
483                 }
484
485                 static IEnumerable<Baz> CreateBazCollection ()
486                 {
487                         return new [] {
488                                 new Baz ("jb", 25),
489                                 new Baz ("ana", 20),
490                                 new Baz ("reg", 28),
491                                 new Baz ("ro", 25),
492                                 new Baz ("jb", 7),
493                         };
494                 }
495
496                 [Test]
497                 public void TestOrderByAgeAscendingTheByNameDescending ()
498                 {
499                         var q = from b in CreateBazCollection ()
500                                         orderby b.Age ascending, b.Name descending
501                                         select b;
502
503                         var expected = new [] {
504                                 new Baz ("jb", 7),
505                                 new Baz ("ana", 20),
506                                 new Baz ("ro", 25),
507                                 new Baz ("jb", 25),
508                                 new Baz ("reg", 28),
509                         };
510
511                         AssertAreSame (expected, q);
512                 }
513
514                 class Data {
515                         public int ID { get; set; }
516                         public string Name { get; set; }
517
518                         public override string ToString ()
519                         {
520                                 return ID + " " + Name;
521                         }
522                 }
523
524                 IEnumerable<Data> CreateData ()
525                 {
526                         return new [] {
527                                 new Data { ID = 10, Name = "bcd" },
528                                 new Data { ID = 20, Name = "Abcd" },
529                                 new Data { ID = 20, Name = "Ab" },
530                                 new Data { ID = 10, Name = "Zyx" },
531                         };
532                 }
533
534                 [Test]
535                 public void TestOrderByIdDescendingThenByNameAscending ()
536                 {
537                         var q = from d in CreateData ()
538                                         orderby d.ID descending, d.Name ascending
539                                         select d;
540
541                         var list = new List<Data> (q);
542
543                         Assert.AreEqual ("Ab", list [0].Name);
544                         Assert.AreEqual ("Abcd", list [1].Name);
545                         Assert.AreEqual ("bcd", list [2].Name);
546                         Assert.AreEqual ("Zyx", list [3].Name);
547                 }
548
549                 [Test]
550                 public void TestOrderByDescendingStability ()
551                 {
552                         var data = new [] {
553                                 new { Key = true, Value = 1 },
554                                 new { Key = false, Value = 2},
555                                 new { Key = true, Value = 3},
556                                 new { Key = false, Value = 4},
557                                 new { Key = true, Value = 5},
558                                 new { Key = false, Value = 6},
559                                 new { Key = true, Value = 7},
560                                 new { Key = false, Value = 8},
561                                 new { Key = true, Value = 9},
562                                 new { Key = false, Value = 10},
563                         };
564
565                         var expected = new [] {
566                                 new { Key = true, Value = 1 },
567                                 new { Key = true, Value = 3},
568                                 new { Key = true, Value = 5},
569                                 new { Key = true, Value = 7},
570                                 new { Key = true, Value = 9},
571                                 new { Key = false, Value = 2},
572                                 new { Key = false, Value = 4},
573                                 new { Key = false, Value = 6},
574                                 new { Key = false, Value = 8},
575                                 new { Key = false, Value = 10},
576                         };
577
578                         AssertAreSame (expected, data.OrderByDescending (x => x.Key));
579                 }
580
581                 static void AssertIsOrdered (IEnumerable<int> e)
582                 {
583                                 int f = int.MinValue;
584                                 foreach(int i in e) {
585                                                 Assert.IsTrue (f <= i);
586                                                 f = i;
587                                 }
588                 }
589
590                 static void AssertAreSame<T> (IEnumerable<T> expected, IEnumerable<T> actual)
591                 {
592                         if (expected == null) {
593                                 Assert.IsNull (actual);
594                                 return;
595                         }
596
597                         Assert.IsNotNull (actual);
598
599                         IEnumerator<T> ee = expected.GetEnumerator ();
600                         IEnumerator<T> ea = actual.GetEnumerator ();
601
602                         while (ee.MoveNext ()) {
603                                 Assert.IsTrue (ea.MoveNext (), "'" + ee.Current + "' expected.");
604                                 Assert.AreEqual (ee.Current, ea.Current);
605                         }
606
607                         if (ea.MoveNext ())
608                                 Assert.Fail ("Unexpected element: " + ea.Current);
609                 }
610         }
611 }