d7e79011b7aa2b4dcaf63fcfd2e8dbfbc60876ec
[mono.git] / mcs / class / System.Core / Test / System.Linq / EnumerableFixture.cs
1 #region License, Terms and Author(s)
2 //
3 // BackLINQ
4 // Copyright (c) 2008 Atif Aziz. All rights reserved.
5 //
6 //  Author(s):
7 //
8 //      Dominik Hug, http://www.dominikhug.ch
9 //
10 // This library is free software; you can redistribute it and/or modify it
11 // under the terms of the New BSD License, a copy of which should have
12 // been delivered along with this distribution.
13 //
14 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
17 // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 //
26 #endregion
27
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Globalization;
32 using System.Text;
33 using System.Threading;
34 using NUnit.Framework;
35 using System.Linq;
36 using NUnit.Framework.SyntaxHelpers;
37 using NUnit.Framework.Constraints;
38 using System.Diagnostics;
39
40 namespace MonoTests.System.Linq {
41         [TestFixture]
42         public sealed class EnumerableFixture {
43                 private CultureInfo initialCulture; // Thread culture saved during Setup to be undone in TearDown.
44                 private AssertionHandler tearDownAssertions;
45
46                 private delegate void AssertionHandler ();
47
48                 [SetUp]
49                 public void SetUp ()
50                 {
51                         tearDownAssertions = null;
52                         initialCulture = Thread.CurrentThread.CurrentCulture;
53                         Thread.CurrentThread.CurrentCulture = new CultureInfo ("de-CH");
54                 }
55
56                 [TearDown]
57                 public void TearDown ()
58                 {
59                         if (tearDownAssertions != null)
60                                 tearDownAssertions ();
61                         Thread.CurrentThread.CurrentCulture = initialCulture;
62                 }
63
64                 [Test]
65                 [ExpectedException (typeof (InvalidOperationException))]
66                 public void Aggregate_EmptySource_ThrowsInvalidOperationException ()
67                 {
68                         var source = Read<object> ();
69                         source.Aggregate ((a, b) => { throw new NotImplementedException (); });
70                 }
71
72                 [Test]
73                 public void Aggregate_AddFuncOnIntegers_ReturnsTotal ()
74                 {
75                         var source = Read (new [] { 12, 34, 56, 78, 910, 1112, 1314, 1516, 1718, 1920 });
76                         var result = source.Aggregate ((a, b) => a + b);
77                         Assert.That (result, Is.EqualTo (8670));
78                 }
79
80                 [Test]
81                 public void Aggregate_AddFuncOnIntegersWithSeed_ReturnsTotal ()
82                 {
83                         var source = Read (new [] { 12, 34, 56, 78, 910, 1112, 1314, 1516, 1718, 1920 });
84                         var result = source.Aggregate (100, (a, b) => a + b);
85                         Assert.That (result, Is.EqualTo (8770));
86                 }
87
88                 [Test]
89                 [ExpectedException (typeof (ArgumentNullException))]
90                 public void Aggregate_NullSource_ThrowsArgumentNullException ()
91                 {
92                         Enumerable.Aggregate<object> (null, (a, e) => { throw new NotImplementedException (); });
93                 }
94
95                 [Test]
96                 [ExpectedException (typeof (ArgumentNullException))]
97                 public void Aggregate_NullFunc_ThrowsArgumentNullException ()
98                 {
99                         Read<object> ().Aggregate (null);
100                 }
101
102                 [Test]
103                 public void Empty_YieldsEmptySource ()
104                 {
105                         var source = Enumerable.Empty<String> ();
106                         Assert.That (source, Is.Not.Null);
107                         var e = source.GetEnumerator ();
108                         Assert.That (e, Is.Not.Null);
109                         Assert.That (e.MoveNext (), Is.False);
110                 }
111
112                 [Test]
113                 [ExpectedException (typeof (ArgumentNullException))]
114                 public void Cast_NullSource_ThrowsArgumentNullException ()
115                 {
116                         Enumerable.Cast<object> (null);
117                 }
118
119                 [Test]
120                 [ExpectedException (typeof (InvalidCastException))]
121                 public void Cast_InvalidSource_ThrowsInvalidCastException ()
122                 {
123                         var source = Read (new object [] { 1000, "hello", new object () });
124                         var target = source.Cast<byte> ();
125                         // do something with the results so Cast will really be executed (deferred execution)
126                         var sb = new StringBuilder ();
127                         foreach (var b in target) {
128                                 sb.Append (b.ToString ());
129                         }
130                 }
131
132                 [Test]
133                 public void Cast_ObjectSourceContainingIntegers_YieldsDowncastedIntegers ()
134                 {
135                         var source = Read (new object [] { 1, 10, 100 });
136                         source.Cast<int> ().AssertEquals (1, 10, 100);
137                 }
138
139                 [Test]
140                 public void Cast_Integers_YieldsUpcastedObjects ()
141                 {
142                         Read (new [] { 1, 10, 100 }).Cast<object> ().AssertEquals (1, 10, 100);
143                 }
144
145                 [Test]
146                 [ExpectedException (typeof (ArgumentNullException))]
147                 public void All_NullSource_ThrowsArgumentNullException ()
148                 {
149                         Enumerable.All (null, (int i) => { throw new NotImplementedException (); });
150                 }
151
152                 [Test]
153                 public void All_SomeSourceElementsNotSatifyingPredicate_ReturnsFalse ()
154                 {
155                         var source = Read (new [] { -100, -1, 0, 1, 100 });
156                         Assert.That (source.All (i => i >= 0), Is.False);
157                 }
158
159                 [Test]
160                 public void All_SourceElementsSatisfyingPredicate_ReturnsTrue ()
161                 {
162                         var source = Read (new [] { -100, -1, 0, 1, 100 });
163                         Assert.That (source.All (i => i >= -100), Is.True);
164                 }
165
166                 [Test]
167                 [ExpectedException (typeof (ArgumentNullException))]
168                 public void Any_NullSource_ThrowsArgumentNullException ()
169                 {
170                         Enumerable.Any<object> (null);
171                 }
172
173                 [Test]
174                 public void Any_EmptySource_ReturnsFalse ()
175                 {
176                         var source = Read<object> ();
177                         Assert.That (source.Any (), Is.False);
178                 }
179
180                 [Test]
181                 public void Any_NonEmptySource_ReturnsTrue ()
182                 {
183                         var source = Read (new [] { new object () });
184                         Assert.That (source.Any (), Is.True);
185                 }
186
187                 [Test]
188                 public void Any_PredicateArg_EmptySource_ReturnsFalse ()
189                 {
190                         var source = Read (new int [0]);
191                         Assert.That (source.Any (i => { throw new NotImplementedException (); }), Is.False);
192                 }
193
194                 [Test]
195                 public void Any_PredicateArg_NonEmptySource_ReturnsTrue ()
196                 {
197                         Assert.That (Read (new [] { 100 }).Any (i => i > 0), Is.True);
198                 }
199
200                 [Test]
201                 public void Average_Longs_ReturnsAverage ()
202                 {
203                         Assert.That (Read (new [] { 25L, 75L }).Average (), Is.EqualTo (50));
204                 }
205
206                 [Test]
207                 public void Average_NullableLongs_ReturnsAverage ()
208                 {
209                         Assert.That (Read (new long? [] { 12L, 34L, null, 56L }).Average (), Is.EqualTo (34.0));
210                 }
211
212                 [Test]
213                 public void Average_NullableInts_ReturnsAverage ()
214                 {
215                         Assert.That (Read (new int? [] { 12, 34, null, 56 }).Average (), Is.EqualTo (34.0));
216                 }
217
218                 [Test]
219                 public void Average_Decimals_ReturnsToleratableAverage ()
220                 {
221                         var source = Read (new [] { -10000m, 2.0001m, 50m });
222                         Assert.That (source.Average (), Is.EqualTo (-3315.999966).Within (0.00001));
223                 }
224
225                 [Test]
226                 [ExpectedException (typeof (InvalidOperationException))]
227                 public void Average_EmptySource_ThrowsInvalidOperationException ()
228                 {
229                         Read<int> ().Average ();
230                 }
231
232                 [Test]
233                 public void Average_EmptyArrayOfNullableIntegers_ReturnsNull ()
234                 {
235                         Assert.That (Read<int?> ().Average (), Is.Null);
236                 }
237
238                 [Test]
239                 public void Average_Selector_ArrayOfPersons_AverageAge ()
240                 {
241                         var source = Read (Person.CreatePersons ());
242                         Assert.That (source.Average (p => p.Age).Equals (22.5));
243                 }
244
245                 [Test]
246                 public void Average_ArrayOfDoubles_ReturnsAverage ()
247                 {
248                         var source = Read (new [] { -3.45, 9.001, 10000.01 });
249                         Assert.That (source.Average (), Is.EqualTo (3335.187).Within (0.01));
250                 }
251
252                 [Test]
253                 public void Average_ArrayOfFloats_ReturnsAverage ()
254                 {
255                         var source = Read (new [] { -3.45F, 9.001F, 10000.01F });
256                         Assert.That (source.Average (), Is.EqualTo (3335.187).Within (0.01));
257                 }
258
259                 [Test]
260                 public void Average_ArrayOfNullableFloats_ReturnsAverage ()
261                 {
262                         var source = Read (new float? [] { -3.45F, 9.001F, 10000.01F, null });
263                         Assert.That (source.Average (), Is.EqualTo (3335.187).Within (0.01));
264                 }
265
266                 [Test]
267                 public void Average_NullableDoubles_ReturnsAverage ()
268                 {
269                         var source = Read (new double? [] { -3.45, 9.001, 10000.01, null });
270                         Assert.That (source.Average (), Is.EqualTo (3335.187).Within (0.01));
271                 }
272
273                 [Test]
274                 public void Average_NullableDecimals_ReturnsAverage ()
275                 {
276                         var source = Read (new decimal? [] { -3.45m, 9.001m, 10000.01m, null });
277                         Assert.That (source.Average (), Is.EqualTo (3335.187).Within (0.01));
278                 }
279
280                 [Test]
281                 [ExpectedException (typeof (ArgumentNullException))]
282                 public void Concat_FirstSourceNull_ThrowsArgumentNullException ()
283                 {
284                         Enumerable.Concat (null, new object [0]);
285                 }
286
287                 [Test]
288                 [ExpectedException (typeof (ArgumentNullException))]
289                 public void Concat_SecondSourceNull_ThrowsArgumentNullException ()
290                 {
291                         new object [0].Concat (null);
292                 }
293
294                 [Test]
295                 public void Concat_TwoLists_CorrectOrder ()
296                 {
297                         var first = Read (new [] { 12, 34, 56 });
298                         var second = Read (new [] { 78, 910, 1112 });
299                         first.Concat (second).AssertEquals (12, 34, 56, 78, 910, 1112);
300                 }
301
302                 [Test]
303                 public void Contains_IntsContainingPassedValue_ReturnsTrue ()
304                 {
305                         var source = Read (new [] { 12, -15, 21 });
306                         Assert.That (source.Contains (21), Is.True);
307                 }
308
309                 [Test]
310                 public void Contains_IntsThatDoNotContainPassedValue_ReturnsFalse ()
311                 {
312                         var source = Read (new [] { -2, 4, 8 });
313                         Assert.That (source.Contains (9), Is.False);
314                 }
315
316                 [Test]
317                 public void Contains_ListOfIntsContainingPassedValue_ReturnsTrue ()
318                 {
319                         var source = new List<int> { 1, 2, 3 };
320                         Assert.That (source.Contains (3), Is.True);
321                 }
322
323                 [Test]
324                 public void Count_Ints_ReturnsNumberOfElements ()
325                 {
326                         Assert.That (Read (new [] { 12, 34, 56 }).Count (), Is.EqualTo (3));
327                 }
328
329                 [Test]
330                 public void Count_PredicateArg_Strings_CountsOnlyStringsWithEvenLength ()
331                 {
332                         var source = new [] { "A", "AB", "ABC", "ABCD" };
333                         Assert.That (source.Count (s => s.Length % 2 == 0), Is.EqualTo (2));
334                 }
335
336                 [Test]
337                 public void DefaultIfEmpty_Inegers_YieldsIntegersInOrder ()
338                 {
339                         var source = Read (new [] { 12, 34, 56 });
340                         source.DefaultIfEmpty (1).AssertEquals (12, 34, 56);
341                 }
342
343                 [Test]
344                 public void DefaultIfEmpty_EmptyIntegersSource_ReturnsZero ()
345                 {
346                         var source = Read (new int [0]);
347                         source.DefaultIfEmpty ().AssertEquals (0);
348                 }
349
350                 [Test]
351                 public void DefaultIfEmpty_EmptyIntegersSourceWithNonZeroDefault_ReturnNonZeroDefault ()
352                 {
353                         var source = Read (new int [0]);
354                         source.DefaultIfEmpty (5).AssertEquals (5);
355                 }
356
357                 [Test]
358                 public void DefaultIfEmpty_DefaultValueArg_Integers_YieldsIntegersInOrder ()
359                 {
360                         var source = Read (new [] { 12, 34, 56 });
361                         source.DefaultIfEmpty (5).AssertEquals (12, 34, 56);
362                 }
363
364                 [Test]
365                 [ExpectedException (typeof (ArgumentNullException))]
366                 public void Distinct_NullSource_ThrowsArgumentNullException ()
367                 {
368                         Enumerable.Distinct<object> (null);
369                 }
370
371                 [Test]
372                 public void Distinct_IntegersWithSomeDuplicates_YieldsIntegersInSourceOrderWithoutDuplicates ()
373                 {
374                         var source = Read (new [] { 12, 34, 34, 56, 78, 78, 78, 910, 78 });
375                         source.Distinct ().AssertEquals (12, 34, 56, 78, 910);
376                 }
377
378                 [Test]
379                 public void Distinct_MixedSourceStringsWithCaseIgnoringComparer_YieldsFirstCaseOfEachDistinctStringInSourceOrder ()
380                 {
381                         var source = Read ("Foo Bar BAZ BaR baz FOo".Split ());
382                         source.Distinct (StringComparer.InvariantCultureIgnoreCase).AssertEquals ("Foo", "Bar", "BAZ");
383                 }
384
385                 [Test]
386                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
387                 public void ElementAt_IndexOutOfRange_ThrowsArgumentOutOfRangeException ()
388                 {
389                         var source = Read (new [] { 3, 5, 7 });
390                         source.ElementAt (3);
391                 }
392
393                 [Test]
394                 public void ElementAt_Integers_ReturnsCorrectValues ()
395                 {
396                         var source = new [] { 15, 2, 7 };
397                         Assert.That (Read (source).ElementAt (0), Is.EqualTo (15));
398                         Assert.That (Read (source).ElementAt (1), Is.EqualTo (2));
399                         Assert.That (Read (source).ElementAt (2), Is.EqualTo (7));
400                 }
401
402                 [Test]
403                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
404                 public void ElementAt_NegativeIndex_ThrowsArgumentOutOfRangeException ()
405                 {
406                         var source = new [] { 1, 2, 3 };
407                         source.ElementAt (-1);
408                 }
409
410                 [Test]
411                 public void ElementAtOrDefault_Integers_ReturnsZeroIfIndexOutOfRange ()
412                 {
413                         var source = Read (new [] { 3, 6, 8 });
414                         Assert.That (source.ElementAtOrDefault (3), Is.EqualTo (0));
415                 }
416
417                 [Test]
418                 public void ElementAtOrDefault_IntArray_ReturnsCorrectValue ()
419                 {
420                         var source = Read (new [] { 3, 6, 9 });
421                         Assert.That (source.ElementAtOrDefault (2), Is.EqualTo (9));
422                 }
423
424                 [Test]
425                 public void ElementAtOrDefault_ListOfInts_ReturnsCorrectElement ()
426                 {
427                         var source = new List<int> { 1, 2, 3, 4, 5, 6 };
428                         Assert.That (source.ElementAtOrDefault (2), Is.EqualTo (3));
429                 }
430
431                 [Test]
432                 public void ElementAtOrDefault_NegativeIndex_ReturnsDefault ()
433                 {
434                         var source = new [] { true, false, true, false };
435                         Assert.That (source.ElementAtOrDefault (-3), Is.False);
436                 }
437
438                 [Test]
439                 public void ElementAtOrDefault_ObjectArray_ReturnsNullIfIndexOutOfRange ()
440                 {
441                         var source = Read (new [] { new object (), new object () });
442                         Assert.That (source.ElementAtOrDefault (2), Is.EqualTo (null));
443                 }
444
445                 [Test]
446                 public void ElementAtOrDefault_ObjectArray_ReturnsCorrectValue ()
447                 {
448                         var first = new object ();
449                         var source = Read (new [] { first, new object () });
450                         Assert.That (source.ElementAt (0), Is.EqualTo (first));
451                 }
452
453                 [Test]
454                 [ExpectedException (typeof (ArgumentNullException))]
455                 public void Except_secondArg_ArgumentNull_ThrowsArgumentNullException ()
456                 {
457                         Read<object> ().Except (null);
458                 }
459
460                 [Test]
461                 public void Except_SecondArg_ValidArgument_ReturnsCorrectEnumerable () // TODO Improve test name
462                 {
463                         var source = Read (new [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
464                         var argument = Read (new [] { 1, 3, 5, 7, 9 });
465                         source.Except (argument).AssertEquals (2, 4, 6, 8, 10);
466                 }
467
468                 [Test]
469                 public void Except_SecondArgComparerArg_ComparerIsUsed ()
470                 {
471                         var source = Read (new [] { "albert", "john", "simon" });
472                         var argument = Read (new [] { "ALBERT" });
473                         source.Except (argument, StringComparer.CurrentCultureIgnoreCase).AssertEquals ("john", "simon");
474                 }
475
476                 [Test]
477                 [ExpectedException (typeof (InvalidOperationException))]
478                 public void First_EmptySource_ThrowsInvalidOperationException ()
479                 {
480                         Read<int> ().First ();
481                 }
482
483                 [Test]
484                 public void First_Integers_ReturnsFirst ()
485                 {
486                         var source = Read (new [] { 12, 34, 56 });
487                         Assert.That (source.First (), Is.EqualTo (12));
488                 }
489
490                 [Test]
491                 public void First_IntegersWithEvensPredicate_FirstEvenInteger ()
492                 {
493                         var source = Read (new [] { 15, 20, 25, 30 });
494                         Assert.That (source.First (i => i % 2 == 0), Is.EqualTo (20));
495                 }
496
497                 [Test]
498                 [ExpectedException (typeof (InvalidOperationException))]
499                 public void First_IntegersWithNonMatchingPredicate_ThrowsInvalidOperationException ()
500                 {
501                         var source = Read (new [] { 12, 34, 56, 78 });
502                         Assert.That (source.First (i => i > 100), Is.EqualTo (0));
503                 }
504
505                 [Test]
506                 public void FirstOrDefault_EmptyBooleanSource_ReturnsFalse ()
507                 {
508                         Assert.That (Read<bool> ().FirstOrDefault (), Is.False);
509                 }
510
511                 [Test]
512                 public void FirstOrDefault_Objects_ReturnsFirstReference ()
513                 {
514                         var first = new object ();
515                         var source = Read (new [] { first, new object () });
516                         Assert.That (source.FirstOrDefault (), Is.SameAs (first));
517                 }
518
519                 [Test]
520                 [ExpectedException (typeof (ArgumentNullException))]
521                 public void FirstOrDefault_PredicateArg_NullAsPredicate_ThrowsArgumentNullException ()
522                 {
523                         var source = new [] { 3, 5, 7 };
524                         source.FirstOrDefault (null);
525                 }
526
527                 [Test]
528                 public void FirstOrDefault_PredicateArg_ValidPredicate_ReturnsFirstMatchingItem ()
529                 {
530                         var source = Read (new [] { 1, 4, 8 });
531                         Assert.That (source.FirstOrDefault (i => i % 2 == 0), Is.EqualTo (4));
532                 }
533
534                 [Test]
535                 public void FirstOrDefault_PredicateArg_NoMatchesInArray_ReturnsDefaultValueOfType ()
536                 {
537                         var source = Read (new [] { 1, 4, 6 });
538                         Assert.That (source.FirstOrDefault (i => i > 10), Is.EqualTo (0));
539                 }
540
541                 private class Person {
542                         public string FirstName { get; set; }
543                         public string FamilyName { get; set; }
544                         public int Age { get; set; }
545                         public static Person [] CreatePersons ()
546                         {
547                                 return new []
548                            {
549                                new Person {FamilyName = "M\u00FCller", FirstName = "Peter", Age = 21},
550                                new Person {FamilyName = "M\u00FCller", FirstName = "Herbert", Age = 22},
551                                new Person {FamilyName = "Meier", FirstName = "Hubert", Age = 23},
552                                new Person {FamilyName = "Meier", FirstName = "Isidor", Age = 24}
553                            };
554                         }
555                 }
556
557                 [Test]
558                 [ExpectedException (typeof (ArgumentNullException))]
559                 public void GroupBy_KeySelectorArg_NullAsKeySelector_ThrowsArgumentNullException ()
560                 {
561                         Read<object> ().GroupBy<object, object> (null);
562                 }
563
564                 [Test]
565                 public void GroupBy_KeySelectorArg_ValidArguments_CorrectGrouping ()
566                 {
567                         var persons = Read (Person.CreatePersons ());
568                         var result = new Reader<IGrouping<string, Person>> (persons.GroupBy (person => person.FamilyName));
569
570                         var mueller = result.Read ();
571                         Assert.That (mueller.Key, Is.EqualTo ("M\u00FCller"));
572                         Assert.That (Array.ConvertAll (ToArray (mueller), p => p.FirstName),
573                                                 Is.EqualTo (new [] { "Peter", "Herbert" }));
574
575                         var meier = result.Read ();
576                         Assert.That (meier.Key, Is.EqualTo ("Meier"));
577                         Assert.That (Array.ConvertAll (ToArray (meier), p => p.FirstName),
578                                                 Is.EqualTo (new [] { "Hubert", "Isidor" }));
579
580                         result.AssertEnded ();
581                 }
582
583                 private static T [] ToArray<T> (IEnumerable<T> source)
584                 {
585                         return new List<T> (source).ToArray ();
586                 }
587
588                 [Test]
589                 // TODO: make better
590                 public void GroupBy_KeySelectorArg_ValidArguments_CorrectCaseSensitiveGrouping ()
591                 {
592                         var persons = Read (new []
593             {
594                 new Person {FamilyName = "M\u00FCller", FirstName = "Peter"},
595                 new Person {FamilyName = "m\u00FCller", FirstName = "Herbert"},
596                 new Person {FamilyName = "Meier", FirstName = "Hubert"},
597                 new Person {FamilyName = "meier", FirstName = "Isidor"}
598             });
599                         var result = persons.GroupBy (person => person.FamilyName);
600                         var enumerator = result.GetEnumerator ();
601                         enumerator.MoveNext ();
602                         Assert.That (enumerator.Current.Key, Is.EqualTo ("M\u00FCller"));
603                         Assert.That (enumerator.Current.ElementAt (0).FirstName, Is.EqualTo ("Peter"));
604                         enumerator.MoveNext ();
605                         Assert.That (enumerator.Current.Key, Is.EqualTo ("m\u00FCller"));
606                         Assert.That (enumerator.Current.ElementAt (0).FirstName, Is.EqualTo ("Herbert"));
607                         enumerator.MoveNext ();
608                         Assert.That (enumerator.Current.Key, Is.EqualTo ("Meier"));
609                         Assert.That (enumerator.Current.ElementAt (0).FirstName, Is.EqualTo ("Hubert"));
610                         enumerator.MoveNext ();
611                         Assert.That (enumerator.Current.Key, Is.EqualTo ("meier"));
612                         Assert.That (enumerator.Current.ElementAt (0).FirstName, Is.EqualTo ("Isidor"));
613
614                         Assert.That (enumerator.MoveNext (), Is.False);
615                 }
616
617                 [Test]
618                 public void GroupBy_KeySelectorArgComparerArg_KeysThatDifferInCasingNonCaseSensitiveStringComparer_CorrectGrouping ()
619                 {
620                         var persons = Read (new []
621             {
622                 new Person {FamilyName = "M\u00FCller", FirstName = "Peter"},
623                 new Person {FamilyName = "m\u00FCller", FirstName = "Herbert"},
624                 new Person {FamilyName = "Meier", FirstName = "Hubert"},
625                 new Person {FamilyName = "meier", FirstName = "Isidor"}
626             });
627                         var result = persons.GroupBy (person => person.FamilyName, StringComparer.InvariantCultureIgnoreCase);
628                         var enumerator = result.GetEnumerator ();
629                         enumerator.MoveNext ();
630                         Assert.That (enumerator.Current.Key, Is.EqualTo ("M\u00FCller"));
631                         Assert.That (enumerator.Current.ElementAt (0).FirstName, Is.EqualTo ("Peter"));
632                         Assert.That (enumerator.Current.ElementAt (1).FirstName, Is.EqualTo ("Herbert"));
633
634                         enumerator.MoveNext ();
635                         Assert.That (enumerator.Current.Key, Is.EqualTo ("Meier"));
636                         Assert.That (enumerator.Current.ElementAt (0).FirstName, Is.EqualTo ("Hubert"));
637                         Assert.That (enumerator.Current.ElementAt (1).FirstName, Is.EqualTo ("Isidor"));
638
639                         Assert.That (enumerator.MoveNext (), Is.False);
640                 }
641
642                 [Test]
643                 public void GroupBy_KeySelectorArgElementSelectorArg_ValidArguments_CorrectGroupingAndProjection ()
644                 {
645                         var enumerable = Read (Person.CreatePersons ());
646                         var result = enumerable.GroupBy (person => person.FamilyName, person => person.Age);
647                         var enumerator = result.GetEnumerator ();
648                         enumerator.MoveNext ();
649                         Assert.That (enumerator.Current.Key, Is.EqualTo ("M\u00FCller"));
650                         Assert.That (enumerator.Current.ElementAt (0), Is.EqualTo (21));
651                         Assert.That (enumerator.Current.ElementAt (1), Is.EqualTo (22));
652
653                         enumerator.MoveNext ();
654                         Assert.That (enumerator.Current.Key, Is.EqualTo ("Meier"));
655                         Assert.That (enumerator.Current.ElementAt (0), Is.EqualTo (23));
656                         Assert.That (enumerator.Current.ElementAt (1), Is.EqualTo (24));
657                 }
658
659                 [Test]
660                 public void GroupBy_KeySelectorArgResultSelectorArg_ValidArguments_CorrectGroupingProcessing ()
661                 {
662                         var persons = Read (Person.CreatePersons ());
663
664                         IEnumerable<int> result = persons.GroupBy (person => person.FamilyName,
665                                                                                                 (key, group) => {
666                                                                                                         int ageSum = 0;
667                                                                                                         foreach (Person p in group) {
668                                                                                                                 ageSum += p.Age;
669                                                                                                         }
670                                                                                                         return ageSum;
671                                                                                                 }
672                                                                                                 );
673                         result.AssertEquals (43, 47);
674                 }
675
676                 [Test]
677                 public void GroupByKey_KeySelectorArgElementSelectorArgComparerArg_ValidArguments_CorrectGroupingAndProcessing ()
678                 {
679                         var persons = Read (new []
680             {
681                 new Person {FamilyName = "M\u00FCller", FirstName = "Peter", Age = 21},
682                 new Person {FamilyName = "m\u00FCller", FirstName = "Herbert", Age = 22},
683                 new Person {FamilyName = "Meier", FirstName = "Hubert", Age= 23},
684                 new Person {FamilyName = "meier", FirstName = "Isidor", Age = 24}
685             });
686
687                         IEnumerable<IGrouping<string, int>> result = persons.GroupBy (person => person.FamilyName,
688                                                                                                 person => person.Age,
689                                                                                                 StringComparer.CurrentCultureIgnoreCase);
690                         IEnumerator<IGrouping<string, int>> enumerator = result.GetEnumerator ();
691                         enumerator.MoveNext ();
692                         Assert.That (enumerator.Current.ElementAt (0), Is.EqualTo (21));
693                         Assert.That (enumerator.Current.ElementAt (1), Is.EqualTo (22));
694                         enumerator.MoveNext ();
695                         Assert.That (enumerator.Current.ElementAt (0), Is.EqualTo (23));
696                         Assert.That (enumerator.Current.ElementAt (1), Is.EqualTo (24));
697                         Assert.That (enumerator.MoveNext (), Is.False);
698                 }
699
700                 [Test]
701                 public void GroupBy_KeySelectorArgElementSelectorArgResultSelectorArg_ValidArguments_CorrectGroupingAndTransforming ()
702                 {
703                         var persons = Read (Person.CreatePersons ());
704                         var result = persons.GroupBy (p => p.FamilyName, p => p.Age,
705                                                                                                                                           (name, enumerable2) => {
706                                                                                                                                                   int totalAge = 0;
707                                                                                                                                                   foreach (var i in enumerable2) {
708                                                                                                                                                           totalAge += i;
709                                                                                                                                                   }
710                                                                                                                                                   return totalAge;
711                                                                                                                                           });
712                         result.AssertEquals (43, 47);
713                 }
714
715                 [Test]
716                 public void GroupBy_KeySelectorArgResultSelectorArgComparerArg_ValidArguments_CorrectGroupingAndTransforming ()
717                 {
718                         var persons = Read (new []
719             {
720                 new Person {FamilyName = "M\u00FCller", FirstName = "Peter", Age = 21},
721                 new Person {FamilyName = "m\u00FCller", FirstName = "Herbert", Age = 22},
722                 new Person {FamilyName = "Meier", FirstName = "Hubert", Age= 23},
723                 new Person {FamilyName = "meier", FirstName = "Isidor", Age = 24}
724             });
725                         var result = persons.GroupBy (p => p.FamilyName,
726                                                                                                                                           (name, enumerable2) => {
727                                                                                                                                                   int totalAge = 0;
728                                                                                                                                                   foreach (var i in enumerable2) {
729                                                                                                                                                           totalAge += i.Age;
730                                                                                                                                                   }
731                                                                                                                                                   return totalAge;
732                                                                                                                                           },
733                                                                                                                                           StringComparer.CurrentCultureIgnoreCase);
734                         result.AssertEquals (43, 47);
735                 }
736
737                 [Test]
738                 public void GroupBy_KeySelectorArgElementSelectorArgResultSelectorArgComparerArg_ValidArguments_CorrectGroupingAndTransforming ()
739                 {
740                         var persons = Read (new []
741             {
742                 new Person {FamilyName = "M\u00FCller", FirstName = "Peter", Age = 21},
743                 new Person {FamilyName = "m\u00FCller", FirstName = "Herbert", Age = 22},
744                 new Person {FamilyName = "Meier", FirstName = "Hubert", Age= 23},
745                 new Person {FamilyName = "meier", FirstName = "Isidor", Age = 24}
746             });
747                         var result = persons.GroupBy (p => p.FamilyName, p => p.Age,
748                                                                                                                                           (name, enumerable2) => {
749                                                                                                                                                   int totalAge = 0;
750                                                                                                                                                   foreach (var i in enumerable2) {
751                                                                                                                                                           totalAge += i;
752                                                                                                                                                   }
753                                                                                                                                                   return totalAge;
754                                                                                                                                           }, StringComparer.CurrentCultureIgnoreCase);
755                         result.AssertEquals (43, 47);
756                 }
757
758                 class Pet {
759                         public string Name { get; set; }
760                         public string Owner { get; set; }
761                 }
762
763                 [Test]
764                 public void GroupJoin_InnerArgOuterKeySelectorArgInnerKeySelectorArgResultSelectorArg_ValidArguments_CorrectGroupingAndJoining ()
765                 {
766                         var persons = Read (new []
767             {
768                 new Person {FamilyName = "M\u00FCller", FirstName = "Peter", Age = 21},
769                 new Person {FamilyName = "m\u00FCller", FirstName = "Herbert", Age = 22},
770                 new Person {FamilyName = "Meier", FirstName = "Hubert", Age= 23},
771                 new Person {FamilyName = "meier", FirstName = "Isidor", Age = 24}
772             });
773
774                         var pets = Read (new []
775             {
776                 new Pet {Name = "Barley", Owner = "Peter"},
777                 new Pet {Name = "Boots", Owner = "Herbert"},
778                 new Pet {Name = "Whiskers", Owner = "Herbert"},
779                 new Pet {Name = "Daisy", Owner = "Isidor"}
780             });
781
782                         var result = persons.GroupJoin (pets, person => person.FirstName, pet => pet.Owner,
783                                                           (person, petCollection) =>
784                                                           new { OwnerName = person.FirstName, Pets = petCollection.Select (pet => pet.Name) });
785
786                         var enumerator = result.GetEnumerator ();
787                         enumerator.MoveNext (); Assert.That (enumerator.Current.OwnerName, Is.EqualTo ("Peter"));
788                         var petEnumerator = enumerator.Current.Pets.GetEnumerator ();
789                         petEnumerator.MoveNext (); Assert.That (petEnumerator.Current, Is.EqualTo ("Barley"));
790                         Assert.That (petEnumerator.MoveNext (), Is.False);
791                         enumerator.MoveNext (); Assert.That (enumerator.Current.OwnerName, Is.EqualTo ("Herbert"));
792                         petEnumerator = enumerator.Current.Pets.GetEnumerator ();
793                         petEnumerator.MoveNext (); Assert.That (petEnumerator.Current, Is.EqualTo ("Boots"));
794                         petEnumerator.MoveNext (); Assert.That (petEnumerator.Current, Is.EqualTo ("Whiskers"));
795                         Assert.That (petEnumerator.MoveNext (), Is.False);
796                         enumerator.MoveNext (); Assert.That (enumerator.Current.OwnerName, Is.EqualTo ("Hubert"));
797                         petEnumerator = enumerator.Current.Pets.GetEnumerator ();
798                         Assert.That (petEnumerator.MoveNext (), Is.False);
799                         enumerator.MoveNext (); Assert.That (enumerator.Current.OwnerName, Is.EqualTo ("Isidor"));
800                         petEnumerator = enumerator.Current.Pets.GetEnumerator ();
801                         petEnumerator.MoveNext (); Assert.That (petEnumerator.Current, Is.EqualTo ("Daisy"));
802                         Assert.That (petEnumerator.MoveNext (), Is.False);
803                         Assert.That (enumerator.MoveNext (), Is.False);
804
805                         //foreach (var owner in result) {
806                         //    Debug.WriteLine(owner.OwnerName);
807                         //    Debug.Indent();
808                         //    foreach (var petName in owner.Pets) {
809                         //        Debug.WriteLine("    " + petName);
810                         //    }
811                         //    Debug.Unindent();
812                         //}
813                 }
814
815                 [Test]
816                 public void GroupJoin_InnerArgOuterKeySelectorArgInnerKeySelectorArgResultSelectorArgComparerArg_ValidArguments_CorrectGroupingAndJoining ()
817                 {
818                         var persons = Read (new []
819             {
820                 new Person {FamilyName = "M\u00FCller", FirstName = "Peter", Age = 21},
821                 new Person {FamilyName = "m\u00FCller", FirstName = "Herbert", Age = 22},
822                 new Person {FamilyName = "Meier", FirstName = "Hubert", Age= 23},
823                 new Person {FamilyName = "meier", FirstName = "Isidor", Age = 24}
824             });
825
826                         var pets = Read (new []
827             {
828                 new Pet {Name = "Barley", Owner = "Peter"},
829                 new Pet {Name = "Boots", Owner = "Herbert"},
830                 new Pet {Name = "Whiskers", Owner = "herbert"}, // This pet is not associated to "Herbert"
831                 new Pet {Name = "Daisy", Owner = "Isidor"}
832             });
833
834                         var result = persons.GroupJoin (pets, person => person.FirstName, pet => pet.Owner,
835                                                           (person, petCollection) =>
836                                                           new { OwnerName = person.FirstName, Pets = petCollection.Select (pet => pet.Name) },
837                                                           StringComparer.CurrentCultureIgnoreCase);
838
839                         var enumerator = result.GetEnumerator ();
840                         enumerator.MoveNext (); Assert.That (enumerator.Current.OwnerName, Is.EqualTo ("Peter"));
841                         var petEnumerator = enumerator.Current.Pets.GetEnumerator ();
842                         petEnumerator.MoveNext (); Assert.That (petEnumerator.Current, Is.EqualTo ("Barley"));
843                         Assert.That (petEnumerator.MoveNext (), Is.False);
844                         enumerator.MoveNext (); Assert.That (enumerator.Current.OwnerName, Is.EqualTo ("Herbert"));
845                         petEnumerator = enumerator.Current.Pets.GetEnumerator ();
846                         petEnumerator.MoveNext (); Assert.That (petEnumerator.Current, Is.EqualTo ("Boots"));
847                         petEnumerator.MoveNext (); Assert.That (petEnumerator.Current, Is.EqualTo ("Whiskers"));
848                         Assert.That (petEnumerator.MoveNext (), Is.False);
849                         enumerator.MoveNext (); Assert.That (enumerator.Current.OwnerName, Is.EqualTo ("Hubert"));
850                         petEnumerator = enumerator.Current.Pets.GetEnumerator ();
851                         Assert.That (petEnumerator.MoveNext (), Is.False);
852                         enumerator.MoveNext (); Assert.That (enumerator.Current.OwnerName, Is.EqualTo ("Isidor"));
853                         petEnumerator = enumerator.Current.Pets.GetEnumerator ();
854                         petEnumerator.MoveNext (); Assert.That (petEnumerator.Current, Is.EqualTo ("Daisy"));
855                         Assert.That (petEnumerator.MoveNext (), Is.False);
856                         Assert.That (enumerator.MoveNext (), Is.False);
857                 }
858
859                 [Test]
860                 [ExpectedException (typeof (ArgumentNullException))]
861                 public void GroupJoin_InnerArgOuterKeySelectorArgInnerKeySelectorArgResultSelectorArg_PassNullAsOuterKeySelector_ThrowsArgumentNullException ()
862                 {
863                         var persons = Read (new []
864             {
865                 new Person {FamilyName = "M\u00FCller", FirstName = "Peter", Age = 21},
866                 new Person {FamilyName = "m\u00FCller", FirstName = "Herbert", Age = 22},
867                 new Person {FamilyName = "Meier", FirstName = "Hubert", Age= 23},
868                 new Person {FamilyName = "meier", FirstName = "Isidor", Age = 24}
869             });
870
871                         var pets = Read (new []
872             {
873                 new Pet {Name = "Barley", Owner = "Peter"},
874                 new Pet {Name = "Boots", Owner = "Herbert"},
875                 new Pet {Name = "Whiskers", Owner = "Herbert"},
876                 new Pet {Name = "Daisy", Owner = "Isidor"}
877             });
878
879                         persons.GroupJoin (pets, null, pet => pet.Owner,
880                                                           (person, petCollection) =>
881                                                           new { OwnerName = person.FirstName, Pets = petCollection.Select (pet => pet.Name) });
882                 }
883
884                 [Test]
885                 [ExpectedException (typeof (ArgumentNullException))]
886                 public void Intersect_NullSecondSource_ThrowsArgumentNullException ()
887                 {
888                         Read<object> ().Intersect (null);
889                 }
890
891                 [Test]
892                 public void Intersect_IntegerSources_YieldsCommonSet ()
893                 {
894                         var first = Read (new [] { 1, 2, 3 });
895                         var second = Read (new [] { 2, 3, 4 });
896                         first.Intersect (second).AssertEquals (2, 3);
897                 }
898
899                 [Test]
900                 public void Intersect_StringSourcesWithMixedCasingAndCaseInsensitiveComparer_YieldsCommonSetFromFirstSource ()
901                 {
902                         var first = Read (new [] { "Heinrich", "Hubert", "Thomas" });
903                         var second = Read (new [] { "Heinrich", "hubert", "Joseph" });
904                         var result = first.Intersect (second, StringComparer.CurrentCultureIgnoreCase);
905                         result.AssertEquals ("Heinrich", "Hubert");
906                 }
907
908                 [Test]
909                 [ExpectedException (typeof (ArgumentNullException))]
910                 public void Join_InnerArgOuterKeySelectorArgInnerKeySelectorArgResultSelectorArg_PassNullAsArgument_ThrowsArgumentNullException ()
911                 {
912                         Read<object> ().Join<object, object, object, object> (null, null, null, null);
913                 }
914
915                 [Test]
916                 public void Join_InnerArgOuterKeySelectorArgInnerKeySelectorArgResultSelectorArg_PassingPetsAndOwners_PetsAreCorrectlyAssignedToOwners ()
917                 {
918                         var persons = Read (Person.CreatePersons ());
919                         var pets = new Reader<Pet> (new []
920                            {
921                                new Pet {Name = "Barley", Owner = "Peter"},
922                                new Pet {Name = "Boots", Owner = "Herbert"},
923                                new Pet {Name = "Whiskers", Owner = "Herbert"},
924                                new Pet {Name = "Daisy", Owner = "Isidor"}
925                            });
926                         var result = persons.Join (pets, aPerson => aPerson.FirstName, aPet => aPet.Owner,
927                                                  (aPerson, aPet) => new { Owner = aPerson.FirstName, Pet = aPet.Name });
928
929                         var enumerator = result.GetEnumerator ();
930                         Assert.That (enumerator.MoveNext (), Is.True);
931                         Assert.That (enumerator.Current.Owner, Is.EqualTo ("Peter"));
932                         Assert.That (enumerator.Current.Pet, Is.EqualTo ("Barley"));
933
934                         Assert.That (enumerator.MoveNext (), Is.True);
935                         Assert.That (enumerator.Current.Owner, Is.EqualTo ("Herbert"));
936                         Assert.That (enumerator.Current.Pet, Is.EqualTo ("Boots"));
937
938                         Assert.That (enumerator.MoveNext (), Is.True);
939                         Assert.That (enumerator.Current.Owner, Is.EqualTo ("Herbert"));
940                         Assert.That (enumerator.Current.Pet, Is.EqualTo ("Whiskers"));
941
942                         Assert.That (enumerator.MoveNext (), Is.True);
943                         Assert.That (enumerator.Current.Owner, Is.EqualTo ("Isidor"));
944                         Assert.That (enumerator.Current.Pet, Is.EqualTo ("Daisy"));
945
946                         Assert.That (enumerator.MoveNext (), Is.False);
947                 }
948
949                 [Test]
950                 public void Join_InnerArgOuterKeySelectorArgInnerKeySelectorArgResultSelectorArgComparerArg_PetOwnersNamesCasingIsInconsistent_CaseInsensitiveJoinIsPerformed ()
951                 {
952                         var persons = Read (Person.CreatePersons ());
953                         var pets = new Reader<Pet> (new []
954                            {
955                                new Pet {Name = "Barley", Owner = "Peter"},
956                                new Pet {Name = "Boots", Owner = "Herbert"},
957                                new Pet {Name = "Whiskers", Owner = "herbert"},
958                                new Pet {Name = "Daisy", Owner = "Isidor"}
959                            });
960                         var result = persons.Join (pets, aPerson => aPerson.FirstName, aPet => aPet.Owner,
961                                                  (aPerson, aPet) => new { Owner = aPerson.FirstName, Pet = aPet.Name },
962                                                  StringComparer.CurrentCultureIgnoreCase);
963
964                         var enumerator = result.GetEnumerator ();
965                         Assert.That (enumerator.MoveNext (), Is.True);
966                         Assert.That (enumerator.Current.Owner, Is.EqualTo ("Peter"));
967                         Assert.That (enumerator.Current.Pet, Is.EqualTo ("Barley"));
968
969                         Assert.That (enumerator.MoveNext (), Is.True);
970                         Assert.That (enumerator.Current.Owner, Is.EqualTo ("Herbert"));
971                         Assert.That (enumerator.Current.Pet, Is.EqualTo ("Boots"));
972
973                         Assert.That (enumerator.MoveNext (), Is.True);
974                         Assert.That (enumerator.Current.Owner, Is.EqualTo ("Herbert"));
975                         Assert.That (enumerator.Current.Pet, Is.EqualTo ("Whiskers"));
976
977                         Assert.That (enumerator.MoveNext (), Is.True);
978                         Assert.That (enumerator.Current.Owner, Is.EqualTo ("Isidor"));
979                         Assert.That (enumerator.Current.Pet, Is.EqualTo ("Daisy"));
980
981                         Assert.That (enumerator.MoveNext (), Is.False);
982
983                         //foreach (var i in result) {
984                         //    Debug.WriteLine(String.Format("Owner = {0}; Pet = {1}", i.Owner, i.Pet));
985                         //}
986                 }
987
988                 [Test]
989                 public void Last_Integers_ReturnsLastElement ()
990                 {
991                         var source = Read (new [] { 1, 2, 3 });
992                         Assert.That (source.Last (), Is.EqualTo (3));
993                 }
994
995                 [Test]
996                 public void Last_IntegerListOptimization_ReturnsLastElementWithoutEnumerating ()
997                 {
998                         var source = new NonEnumerableList<int> (new [] { 1, 2, 3 });
999                         Assert.That (source.Last (), Is.EqualTo (3));
1000                 }
1001
1002                 [Test]
1003                 [ExpectedException (typeof (InvalidOperationException))]
1004                 public void Last_EmptyIntegerListOptimization_ThrowsInvalidOperationException ()
1005                 {
1006                         new NonEnumerableList<int> ().Last ();
1007                 }
1008
1009                 [Test]
1010                 [ExpectedException (typeof (ArgumentNullException))]
1011                 public void Last_PredicateArg_NullAsPredicate_ThrowsArgumentNullException ()
1012                 {
1013                         Read<object> ().Last (null);
1014                 }
1015
1016                 [Test]
1017                 [ExpectedException (typeof (InvalidOperationException))]
1018                 public void Last_PredicateArg_NoMatchingElement_ThrowsInvalidOperationException ()
1019                 {
1020                         var source = Read (new [] { 1, 2, 3, 4, 5 });
1021                         source.Last (i => i > 10);
1022                 }
1023
1024                 [Test]
1025                 public void Last_PredicateArg_ListOfInts_ReturnsLastMatchingElement ()
1026                 {
1027                         var source = Read (new [] { 1, 2, 3, 4, 5 });
1028                         Assert.That (source.Last (i => i % 2 == 0), Is.EqualTo (4));
1029                 }
1030
1031                 [Test]
1032                 public void LastOrDefault_EmptySource_ReturnsZero ()
1033                 {
1034                         var source = Read (new int [0]);
1035                         Assert.That (source.LastOrDefault (), Is.EqualTo (0));
1036                 }
1037
1038                 [Test]
1039                 public void LastOrDefault_NonEmptyList_ReturnsLastElement ()
1040                 {
1041                         var source = Read (new [] { 1, 2, 3, 4, 5 });
1042                         Assert.That (source.LastOrDefault (), Is.EqualTo (5));
1043                 }
1044
1045                 [Test]
1046                 public void LastOrDefault_PredicateArg_ValidArguments_RetunsLastMatchingElement ()
1047                 {
1048                         var source = Read (new [] { 1, 2, 3, 4, 5 });
1049                         Assert.That (source.LastOrDefault (i => i % 2 == 0), Is.EqualTo (4));
1050                 }
1051
1052                 [Test]
1053                 public void LastOrDefault_PredicateArg_NoMatchingElement_ReturnsZero ()
1054                 {
1055                         var source = Read (new [] { 1, 3, 5, 7 });
1056                         Assert.That (source.LastOrDefault (i => i % 2 == 0), Is.EqualTo (0));
1057                 }
1058
1059                 [Test]
1060                 public void LongCount_ValidArgument_ReturnsCorrectNumberOfElements ()
1061                 {
1062                         var source = Read (new [] { 1, 4, 7, 10 });
1063                         Assert.That (source.LongCount (), Is.EqualTo (4));
1064                 }
1065
1066                 [Test]
1067                 [ExpectedException (typeof (ArgumentNullException))]
1068                 public void LongCount_PredicateArg_NullAsPredicate_ThrowsArgumentNullException ()
1069                 {
1070                         Read<object> ().LongCount (null);
1071                 }
1072
1073                 [Test]
1074                 public void LongCount_PredicateArg_ValidArguments_ReturnsCorrectNumerOfMatchingElements ()
1075                 {
1076                         var source = Read (new [] { 1, 2, 3, 4, 5 });
1077                         Assert.That (source.LongCount (i => i % 2 == 0), Is.EqualTo (2));
1078                 }
1079
1080                 [Test]
1081                 [ExpectedException (typeof (InvalidOperationException))]
1082                 public void Max_EmptyList_ThrowsInvalidOperationException ()
1083                 {
1084                         var source = Read (new int [0]);
1085                         source.Max ();
1086                 }
1087
1088                 [Test]
1089                 public void Max_EmptyNullableIntegerArray_ReturnsNull ()
1090                 {
1091                         Assert.That (Read (new int? [0]).Max (), Is.Null);
1092                 }
1093
1094                 [Test]
1095                 public void Max_NullableIntegerArrayWithNullsOnly_ReturnsNull ()
1096                 {
1097                         Assert.That (Read (new int? [] { null, null, null }).Max (), Is.Null);
1098                 }
1099
1100                 [Test]
1101                 public void Max_Integers_ReturnsMaxValue ()
1102                 {
1103                         var source = Read (new [] { 1000, 203, -9999 });
1104                         Assert.That (source.Max (), Is.EqualTo (1000));
1105                 }
1106
1107                 [Test]
1108                 public void Max_NullableLongs_ReturnsMaxValue ()
1109                 {
1110                         Assert.That (Read (new long? [] { 1L, 2L, 3L, null }).Max (), Is.EqualTo (3));
1111                 }
1112
1113                 [Test]
1114                 public void Max_NullableDoubles_ReturnsMaxValue ()
1115                 {
1116                         Assert.That (Read (new double? [] { 1, 2, 3, null }).Max (), Is.EqualTo (3));
1117                 }
1118
1119                 [Test]
1120                 public void Max_NullableDecimals_ReturnsMaxValue ()
1121                 {
1122                         Assert.That (Read (new decimal? [] { 1m, 2m, 3m, null }).Max (), Is.EqualTo (3));
1123                 }
1124
1125                 [Test]
1126                 public void Max_NullableFloats_ReturnsMaxValue ()
1127                 {
1128                         Assert.That (Read (new float? [] { -1000, -100, -1, null }).Max (), Is.EqualTo (-1));
1129                 }
1130
1131                 [Test]
1132                 public void Max_ListWithNullableType_ReturnsMaximum ()
1133                 {
1134                         var source = Read (new int? [] { 1, 4, null, 10 });
1135                         Assert.That (source.Max (), Is.EqualTo (10));
1136                 }
1137
1138                 [Test]
1139                 public void Max_NullableList_ReturnsMaxNonNullValue ()
1140                 {
1141                         var source = Read (new int? [] { -5, -2, null });
1142                         Assert.That (source.Max (), Is.EqualTo (-2));
1143                 }
1144
1145                 [Test]
1146                 public void Max_SelectorArg_ListOfObjects_ReturnsMaxSelectedValue ()
1147                 {
1148                         var persons = Read (Person.CreatePersons ());
1149                         Assert.That (persons.Max (p => p.Age), Is.EqualTo (24));
1150                 }
1151
1152                 [Test]
1153                 [ExpectedException (typeof (InvalidOperationException))]
1154                 public void Min_EmptyList_ThrowsInvalidOperationException ()
1155                 {
1156                         var source = Read<int> ();
1157                         source.Min ();
1158                 }
1159
1160                 [Test]
1161                 public void Min_IntegersWithSomeNull_ReturnsMinimumNonNullValue ()
1162                 {
1163                         var source = Read (new int? [] { 199, 15, null, 30 });
1164                         Assert.That (source.Min (), Is.EqualTo (15));
1165                 }
1166
1167                 [Test]
1168                 public void Min_NullableLongs_ReturnsMinimumNonNullValue ()
1169                 {
1170                         var source = Read (new long? [] { 199, 15, null, 30 });
1171                         Assert.That (source.Min (), Is.EqualTo (15));
1172                 }
1173
1174                 [Test]
1175                 public void Min_NullableFloats_ReturnsMinimumNonNullValue ()
1176                 {
1177                         var source = Read (new float? [] { 1.111f, null, 2.222f });
1178                         Assert.That (source.Min (), Is.EqualTo (1.111f).Within (0.01));
1179                 }
1180
1181                 [Test]
1182                 public void Min_NullableDoubles_ReturnsMinimumNonNullValue ()
1183                 {
1184                         var source = Read (new double? [] { 1.111, null, 2.222 });
1185                         Assert.That (source.Min (), Is.EqualTo (1.111).Within (0.01));
1186                 }
1187
1188                 [Test]
1189                 public void Min_NullableDecimals_ReturnsMinimumNonNullValue ()
1190                 {
1191                         var source = Read (new decimal? [] { 1.111m, null, 2.222m });
1192                         Assert.That (source.Min (), Is.EqualTo (1.111m).Within (0.01));
1193                 }
1194
1195                 [Test]
1196                 public void Min_StringsWithLengthSelector_ReturnsMinimumNonNullStringLength ()
1197                 {
1198                         var strings = Read (new [] { "five", "four", null, "three", null, "two", "one", "zero" });
1199                         Assert.That (strings.Min (s => s != null ? s.Length : (int?) null), Is.EqualTo (3));
1200                 }
1201
1202                 [Test]
1203                 public void OfType_EnumerableWithElementsOfDifferentTypes_OnlyDecimalsAreReturned ()
1204                 {
1205                         // ...................V----V Needed for Mono (CS0029)
1206                         var source = Read (new object [] { 1, "Hello", 1.234m, new object () });
1207                         var result = source.OfType<decimal> ();
1208                         result.AssertEquals (1.234m);
1209                 }
1210
1211                 [Test]
1212                 [ExpectedException (typeof (ArgumentNullException))]
1213                 public void OrderBy_KeySelectorArg_NullAsKeySelector_ThrowsArgumentNullException ()
1214                 {
1215                         Read<object> ().OrderBy<object, object> (null);
1216                 }
1217
1218                 [Test]
1219                 public void OrderBy_KeySelector_ArrayOfPersons_PersonsAreOrderedByAge ()
1220                 {
1221                         var persons = Person.CreatePersons ();
1222                         var reversePersons = (Person []) persons.Clone ();
1223                         Array.Reverse (reversePersons);
1224                         var source = Read (reversePersons);
1225                         var result = source.OrderBy (p => p.Age);
1226
1227                         var age = 21;
1228                         foreach (var person in result)
1229                                 Assert.That (person.Age, Is.EqualTo (age++));
1230
1231                         Assert.That (age, Is.EqualTo (25));
1232                 }
1233
1234                 [Test]
1235                 [Category ("NotWorking")]
1236                 public void OrderBy_KeySelector_DataWithDuplicateKeys_YieldsStablySortedData ()
1237                 {
1238                         var data = new []
1239             {
1240                 new { Number = 4, Text = "four" },
1241                 new { Number = 4, Text = "quatre" },
1242                 new { Number = 4, Text = "vier" },
1243                 new { Number = 4, Text = "quattro" },
1244                 new { Number = 1, Text = "one" },
1245                 new { Number = 2, Text = "two" },
1246                 new { Number = 2, Text = "deux" },
1247                 new { Number = 3, Text = "three" },
1248                 new { Number = 3, Text = "trois" },
1249                 new { Number = 3, Text = "drei" },
1250             };
1251
1252                         var result = Read (data).OrderBy (e => e.Number);
1253                         using (var e = result.GetEnumerator ()) {
1254                                 e.MoveNext (); Assert.That (e.Current.Text, Is.EqualTo ("one"));
1255                                 e.MoveNext (); Assert.That (e.Current.Text, Is.EqualTo ("two"));
1256                                 e.MoveNext (); Assert.That (e.Current.Text, Is.EqualTo ("deux"));
1257                                 e.MoveNext (); Assert.That (e.Current.Text, Is.EqualTo ("three"));
1258                                 e.MoveNext (); Assert.That (e.Current.Text, Is.EqualTo ("trois"));
1259                                 e.MoveNext (); Assert.That (e.Current.Text, Is.EqualTo ("drei"));
1260                                 e.MoveNext (); Assert.That (e.Current.Text, Is.EqualTo ("four"));
1261                                 e.MoveNext (); Assert.That (e.Current.Text, Is.EqualTo ("quatre"));
1262                                 e.MoveNext (); Assert.That (e.Current.Text, Is.EqualTo ("vier"));
1263                                 e.MoveNext (); Assert.That (e.Current.Text, Is.EqualTo ("quattro"));
1264                                 Assert.That (e.MoveNext (), Is.False);
1265                         }
1266                 }
1267
1268                 [Test]
1269                 [Category ("NotWorking")]
1270                 public void ThenBy_KeySelector_DataWithDuplicateKeys_YieldsStablySortedData ()
1271                 {
1272                         var data = new []
1273             {
1274                 new { Position = 1, LastName = "Smith", FirstName = "John" },
1275                 new { Position = 2, LastName = "Smith", FirstName = "Jack" },
1276                 new { Position = 3, LastName = "Smith", FirstName = "John" },
1277                 new { Position = 4, LastName = "Smith", FirstName = "Jack" },
1278                 new { Position = 5, LastName = "Smith", FirstName = "John" },
1279                 new { Position = 6, LastName = "Smith", FirstName = "Jack" },
1280             };
1281
1282                         var result = Read (data).OrderBy (e => e.LastName).ThenBy (e => e.FirstName);
1283                         using (var e = result.GetEnumerator ()) {
1284                                 e.MoveNext (); Assert.That (e.Current.Position, Is.EqualTo (2));
1285                                 e.MoveNext (); Assert.That (e.Current.Position, Is.EqualTo (4));
1286                                 e.MoveNext (); Assert.That (e.Current.Position, Is.EqualTo (6));
1287                                 e.MoveNext (); Assert.That (e.Current.Position, Is.EqualTo (1));
1288                                 e.MoveNext (); Assert.That (e.Current.Position, Is.EqualTo (3));
1289                                 e.MoveNext (); Assert.That (e.Current.Position, Is.EqualTo (5));
1290                                 Assert.That (e.MoveNext (), Is.False);
1291                         }
1292                 }
1293
1294                 [Test]
1295                 [ExpectedException (typeof (ArgumentNullException))]
1296                 public void ThenBy_NullSource_ThrowsArgumentNullException ()
1297                 {
1298                         Enumerable.ThenBy<object, object> (null, e => { throw new NotImplementedException (); });
1299                 }
1300
1301                 [Test]
1302                 [ExpectedException (typeof (ArgumentNullException))]
1303                 public void ThenBy_NullKeySelector_ThrowsArgumentNullException ()
1304                 {
1305                         Read<object> ().OrderBy<object, object> (e => { throw new NotImplementedException (); }).ThenBy<object, object> (null);
1306                 }
1307                 /// <summary>
1308                 /// To sort ints in descending order.
1309                 /// </summary>
1310                 class ReverseComparer : IComparer<int> {
1311                         public int Compare (int x, int y)
1312                         {
1313                                 return y.CompareTo (x);
1314                         }
1315                 }
1316
1317                 [Test]
1318                 public void ThenByDescending_KeySelectorArgComparerArg_StringArray_CorrectOrdering ()
1319                 {
1320                         var source = Read (new [] { "AA", "AB", "AC", "-BA", "-BB", "-BC" });
1321                         var result = source.OrderBy (s => s.ToCharArray () [s.ToCharArray ().Length - 1]).ThenByDescending (s => s.Length); /*.AssertEquals("butterfly", "elephant", "dog", "snake", "ape"); */
1322                         result.AssertEquals ("-BA", "AA", "-BB", "AB", "-BC", "AC");
1323                 }
1324
1325                 [Test]
1326                 public void OrderBy_KeySelectorArgComparerArg_ArrayOfPersonsAndReversecomparer_PersonsAreOrderedByAgeUsingReversecomparer ()
1327                 {
1328                         var persons = Read (Person.CreatePersons ());
1329                         var result = persons.OrderBy (p => p.Age, new ReverseComparer ());
1330                         var age = 25;
1331                         foreach (var person in result) {
1332                                 age--;
1333                                 Assert.That (person.Age, Is.EqualTo (age));
1334                         }
1335                         Assert.That (age, Is.EqualTo (21));
1336
1337                 }
1338
1339                 [Test]
1340                 public void OrderByDescending_KeySelectorArg_ArrayOfPersons_PersonsAreOrderedByAgeDescending ()
1341                 {
1342                         var persons = Read (Person.CreatePersons ());
1343                         var result = persons.OrderByDescending (p => p.Age);
1344                         int age = 25;
1345                         foreach (var person in result) {
1346                                 age--;
1347                                 Assert.That (person.Age, Is.EqualTo (age));
1348                         }
1349                         Assert.That (age, Is.EqualTo (21));
1350                 }
1351
1352                 [Test]
1353                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
1354                 public void Range_ProduceRangeThatLeadsToOverflow_ThrowsArgumentOutOfRangeException ()
1355                 {
1356                         Enumerable.Range (int.MaxValue - 3, 5);
1357                 }
1358
1359                 [Test]
1360                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
1361                 public void Range_NegativeCount_ThrowsArgumentOutOfRangeException ()
1362                 {
1363                         Enumerable.Range (0, -1);
1364                 }
1365
1366                 [Test]
1367                 public void Range_Start10Count5_IntsFrom10To14 ()
1368                 {
1369                         var result = Enumerable.Range (10, 5);
1370                         result.AssertEquals (10, 11, 12, 13, 14);
1371                 }
1372
1373                 [Test]
1374                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
1375                 public void Repeat_PassNegativeCount_ThrowsArgumentOutOfRangeException ()
1376                 {
1377                         Enumerable.Repeat ("Hello World", -2);
1378                 }
1379
1380                 [Test]
1381                 public void Repeat_StringArgumentCount2_ReturnValueContainsStringArgumentTwice ()
1382                 {
1383                         var result = Enumerable.Repeat ("Hello World", 2);
1384                         result.AssertEquals ("Hello World", "Hello World");
1385                 }
1386
1387                 [Test]
1388                 public void Reverse_SeriesOfInts_IntsAreCorrectlyReversed ()
1389                 {
1390                         var source = Read (new [] { 1, 2, 3, 4, 5 });
1391                         source.Reverse ().AssertEquals (5, 4, 3, 2, 1);
1392                 }
1393
1394                 [Test]
1395                 public void Select_ArrayOfPersons_AgeOfPersonsIsSelectedAccordingToPassedLambdaExpression ()
1396                 {
1397                         var persons = Read (Person.CreatePersons ());
1398                         persons.Select (p => p.Age).AssertEquals (21, 22, 23, 24);
1399                 }
1400
1401                 [Test]
1402                 public void Select_SelectorArg_LambdaThatTakesIndexAsArgument_ReturnValueContainsElementsMultipliedByIndex ()
1403                 {
1404                         var source = Read (new [] { 0, 1, 2, 3 });
1405                         source.Select ((i, index) => i * index).AssertEquals (0, 1, 4, 9);
1406                 }
1407
1408                 [Test]
1409                 public void SelectMany_SelectorArg_ArrayOfPersons_ReturnsASequenceWithAllLettersOfFirstnames ()
1410                 {
1411                         var persons = Read (Person.CreatePersons ());
1412                         var result = persons.SelectMany (p => p.FirstName.ToCharArray ());
1413                         var check = "PeterHerbertHubertIsidor".ToCharArray ();
1414                         int count = 0;
1415                         foreach (var c in result) {
1416                                 Assert.That (c, Is.EqualTo (check [count]));
1417                                 count++;
1418                         }
1419                 }
1420
1421                 class PetOwner {
1422                         public string Name { get; set; }
1423                         public List<string> Pets { get; set; }
1424                 }
1425
1426                 [Test]
1427                 public void SelectMany_Selector3Arg_ArrayOfPetOwners_SelectorUsesElementIndexArgument ()
1428                 {
1429                         var petOwners = Read (new []
1430                 { new PetOwner { Name="Higa, Sidney",
1431                       Pets = new List<string>{ "Scruffy", "Sam" } },
1432                   new PetOwner { Name="Ashkenazi, Ronen",
1433                       Pets = new List<string>{ "Walker", "Sugar" } },
1434                   new PetOwner { Name="Price, Vernette",
1435                       Pets = new List<string>{ "Scratches", "Diesel" } },
1436                   new PetOwner { Name="Hines, Patrick",
1437                       Pets = new List<string>{ "Dusty" } } });
1438                         IEnumerable<string> result =
1439                                 petOwners.SelectMany ((petOwner, index) =>
1440                                                          petOwner.Pets.Select (pet => index + pet));
1441                         result.AssertEquals ("0Scruffy", "0Sam", "1Walker", "1Sugar", "2Scratches", "2Diesel", "3Dusty");
1442                 }
1443
1444                 [Test]
1445                 [Category ("NotWorking")]
1446                 public void SelectMany_CollectionSelectorArgResultSelectorArg_ArrayOfPetOwner_ResultContainsElementForEachPetAPetOwnerHas ()
1447                 {
1448                         var petOwners = Read (new []
1449                 { new PetOwner { Name="Higa",
1450                       Pets = new List<string>{ "Scruffy", "Sam" } },
1451                   new PetOwner { Name="Ashkenazi",
1452                       Pets = new List<string>{ "Walker", "Sugar" } },
1453                   new PetOwner { Name="Price",
1454                       Pets = new List<string>{ "Scratches", "Diesel" } },
1455                   new PetOwner { Name="Hines",
1456                       Pets = new List<string>{ "Dusty" } } });
1457                         var result = petOwners.SelectMany (petOwner => petOwner.Pets, (petOwner, petName) => new { petOwner.Name, petName });
1458
1459                         // compare result with result from Microsoft implementation
1460                         var sb = new StringBuilder ();
1461                         foreach (var s in result) {
1462                                 sb.Append (s.ToString ());
1463                         }
1464                         Assert.That (sb.ToString (), Is.EqualTo ("{ Name = Higa, petName = Scruffy }{ Name = Higa, petName = Sam }{ Name = Ashkenazi, petName = Walker }{ Name = Ashkenazi, petName = Sugar }{ Name = Price, petName = Scratches }{ Name = Price, petName = Diesel }{ Name = Hines, petName = Dusty }"));
1465                 }
1466
1467                 [Test]
1468                 [ExpectedException (typeof (ArgumentNullException))]
1469                 public void SequenceEqual_NullFirstSequence_ThrowsArgumentNullException ()
1470                 {
1471                         Enumerable.SequenceEqual (null, Read<object> ());
1472                 }
1473
1474                 [Test]
1475                 [ExpectedException (typeof (ArgumentNullException))]
1476                 public void SequenceEqual_NullSecondSequence_ThrowsArgumentNullException ()
1477                 {
1478                         Read<object> ().SequenceEqual (null);
1479                 }
1480
1481                 [Test]
1482                 public void SequenceEqual_EqualSequences_ReturnsTrue ()
1483                 {
1484                         var source = Read (new [] { 1, 2, 3 });
1485                         var argument = Read (new [] { 1, 2, 3 });
1486                         Assert.That (source.SequenceEqual (argument), Is.True);
1487                 }
1488
1489                 [Test]
1490                 public void SequenceEqual_DifferentSequences_ReturnsFalse ()
1491                 {
1492                         var source = Read (new [] { 1, 2, 3 });
1493                         var argument = Read (new [] { 1, 3, 2 });
1494                         Assert.That (source.SequenceEqual (argument), Is.False);
1495                 }
1496
1497                 [Test]
1498                 public void SequenceEqual_LongerSecondSequence_ReturnsFalse ()
1499                 {
1500                         var source = Read (new [] { 1, 2, 3 });
1501                         var argument = Read (new [] { 1, 2, 3, 4 });
1502                         Assert.That (source.SequenceEqual (argument), Is.False);
1503                 }
1504
1505                 [Test]
1506                 public void SequenceEqual_ShorterSecondSequence_ReturnsFalse ()
1507                 {
1508                         var first = Read (new [] { 1, 2, 3, 4 });
1509                         var second = Read (new [] { 1, 2, 3 });
1510                         Assert.That (first.SequenceEqual (second), Is.False);
1511                 }
1512
1513                 [Test]
1514                 public void SequenceEqual_FloatsWithTolerantComparer_ComparerIsUsed ()
1515                 {
1516                         var source = Read (new [] { 1f, 2f, 3f });
1517                         var argument = Read (new [] { 1.03f, 1.99f, 3.02f });
1518                         Assert.That (source.SequenceEqual (argument, new FloatComparer ()), Is.True);
1519                 }
1520
1521                 private sealed class FloatComparer : IEqualityComparer<float> {
1522                         public bool Equals (float x, float y)
1523                         {
1524                                 return Math.Abs (x - y) < 0.1f;
1525                         }
1526                         public int GetHashCode (float x)
1527                         {
1528                                 throw new NotImplementedException ();
1529                         }
1530                 }
1531
1532                 [Test]
1533                 [ExpectedException (typeof (InvalidOperationException))]
1534                 public void Single_EmptySource_ThrowsInvalidOperationException ()
1535                 {
1536                         var source = Read<int> ();
1537                         source.Single ();
1538                 }
1539
1540                 [Test]
1541                 [ExpectedException (typeof (InvalidOperationException))]
1542                 public void Single_SourceWithMoreThanOneElement_ThrowsInvalidOperationException ()
1543                 {
1544                         var source = Read (new [] { 3, 6 });
1545                         source.Single ();
1546                 }
1547
1548                 [Test]
1549                 public void Single_SourceWithOneElement_ReturnsSingleElement ()
1550                 {
1551                         var source = Read (new [] { 1 });
1552                         Assert.That (source.Single (), Is.EqualTo (1));
1553                 }
1554
1555                 [Test]
1556                 [ExpectedException (typeof (ArgumentNullException))]
1557                 public void Single_PredicateArg_PassNullAsPredicate_ThrowsArgumentNullException ()
1558                 {
1559                         Read<object> ().Single (null);
1560                 }
1561
1562                 [Test]
1563                 [ExpectedException (typeof (InvalidOperationException))]
1564                 public void Single_PredicateArg_NoElementSatisfiesCondition_ThrowsInvalidOperationException ()
1565                 {
1566                         var source = Read (new [] { 1, 3, 5 });
1567                         source.Single (i => i % 2 == 0);
1568                 }
1569
1570                 [Test]
1571                 [ExpectedException (typeof (InvalidOperationException))]
1572                 public void Single_PredicateArg_MoreThanOneElementSatisfiedCondition_ThrowsInvalidOperationException ()
1573                 {
1574                         var source = Read (new [] { 1, 2, 3, 4 });
1575                         source.Single (i => i % 2 == 0);
1576                 }
1577
1578                 [Test]
1579                 [ExpectedException (typeof (InvalidOperationException))]
1580                 public void Single_PredicateArg_SourceIsEmpty_ThrowsInvalidOperationException ()
1581                 {
1582                         var source = Read<int> ();
1583                         source.Single (i => i % 2 == 0);
1584                 }
1585
1586                 [Test]
1587                 public void Single_PredicateArg_ArrayOfIntWithOnlyOneElementSatisfyingCondition_ReturnsOnlyThisElement ()
1588                 {
1589                         var source = Read (new [] { 1, 2, 3 });
1590                         Assert.That (source.Single (i => i % 2 == 0), Is.EqualTo (2));
1591                 }
1592
1593                 [Test]
1594                 [ExpectedException (typeof (InvalidOperationException))]
1595                 public void SingleOrDefault_MoreThanOneElementInSource_ThrowsInvalidOperationException ()
1596                 {
1597                         var source = Read (new [] { 1, 2, 3 });
1598                         source.SingleOrDefault ();
1599                 }
1600
1601                 [Test]
1602                 public void SingleOrDefault_EmptySource_ReturnsZero ()
1603                 {
1604                         var source = Read<int> ();
1605                         Assert.That (source.SingleOrDefault (), Is.EqualTo (0));
1606                 }
1607
1608                 [Test]
1609                 public void SingleOrDefault_SourceWithOneElement_ReturnsSingleElement ()
1610                 {
1611                         var source = Read (new [] { 5 });
1612                         Assert.That (source.SingleOrDefault (), Is.EqualTo (5));
1613                 }
1614
1615                 [Test]
1616                 [ExpectedException (typeof (ArgumentNullException))]
1617                 public void SingleOrDefault_PredicateArg_PassNullAsPredicate_ThrowsArgumentNullException ()
1618                 {
1619                         Read<object> ().SingleOrDefault (null);
1620                 }
1621
1622                 [Test]
1623                 public void SingleOrDefault_PredicateArg_EmptySource_ReturnsZero ()
1624                 {
1625                         var source = Read<int> ();
1626                         Assert.That (source.SingleOrDefault (i => i % 2 == 0), Is.EqualTo (0));
1627                 }
1628
1629                 [Test]
1630                 [ExpectedException (typeof (InvalidOperationException))]
1631                 public void SingleOrDefault_PredicateArg_MoreThanOneElementSatisfiesCondition_ThrowsInvalidOperationException ()
1632                 {
1633                         var source = Read (new [] { 1, 2, 3, 4, 5 });
1634                         source.SingleOrDefault (i => i % 2 == 0);
1635                 }
1636
1637                 [Test]
1638                 public void SingleOrDefault_PredicateArg_NoElementSatisfiesCondition_ReturnsZero ()
1639                 {
1640                         var source = Read (new [] { 1, 3, 5 });
1641                         Assert.That (source.SingleOrDefault (i => i % 2 == 0), Is.EqualTo (0));
1642                 }
1643
1644                 [Test]
1645                 public void SingleOrDefault_PredicateArg_OneElementSatisfiesCondition_ReturnsCorrectElement ()
1646                 {
1647                         var source = Read (new [] { 1, 2, 3 });
1648                         Assert.That (source.SingleOrDefault (i => i % 2 == 0), Is.EqualTo (2));
1649                 }
1650
1651                 [Test]
1652                 public void Skip_IntsFromOneToTenAndFifeAsSecondArg_IntsFromSixToTen ()
1653                 {
1654                         var source = Read (new [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
1655                         source.Skip (5).AssertEquals (6, 7, 8, 9, 10);
1656                 }
1657
1658                 [Test]
1659                 public void Skip_PassNegativeValueAsCount_SameBehaviorAsMicrosoftImplementation ()
1660                 {
1661                         var source = Read (new [] { 1, 2, 3, 4, 5 });
1662                         source.Skip (-5).AssertEquals (1, 2, 3, 4, 5);
1663                 }
1664
1665                 [Test]
1666                 [ExpectedException (typeof (ArgumentNullException))]
1667                 public void SkipWhile_PredicateArg_PassNullAsPredicate_ThrowsArgumentNullException ()
1668                 {
1669                         Read<object> ().SkipWhile ((Func<object, bool>) null);
1670                 }
1671
1672                 [Test]
1673                 public void SkipWhile_PredicateArg_IntsFromOneToFive_ElementsAreSkippedAsLongAsConditionIsSatisfied ()
1674                 {
1675                         var source = Read (new [] { 1, 2, 3, 4, 5 });
1676                         source.SkipWhile (i => i < 3).AssertEquals (3, 4, 5);
1677                 }
1678
1679                 [Test]
1680                 public void SkipWhile_PredicateArg_ArrayOfIntsWithElementsNotSatisfyingConditionAtTheEnd_IntsAtTheEndArePartOfResult ()
1681                 {
1682                         var source = Read (new [] { 1, 2, 3, 4, 5, 1, 2, 3 });
1683                         source.SkipWhile (i => i < 3).AssertEquals (3, 4, 5, 1, 2, 3);
1684                 }
1685
1686                 [Test]
1687                 public void SkipWhile_PredicateArg_PredicateAlwaysTrue_EmptyResult ()
1688                 {
1689                         var source = Read (new [] { 1, 2, 3 });
1690                         var result = source.SkipWhile (i => true);
1691                         Assert.That (result.GetEnumerator ().MoveNext (), Is.False);
1692                 }
1693
1694                 [Test]
1695                 public void SkipWhile_Predicate3Arg_IntsFromOneToNine_ElementsAreSkippedWhileIndexLessThanFive ()
1696                 {
1697                         var source = Read (new [] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
1698                         source.SkipWhile ((i, index) => index < 5).AssertEquals (6, 7, 8, 9);
1699                 }
1700
1701                 [Test]
1702                 [ExpectedException (typeof (OverflowException))]
1703                 [Category ("NotWorking")]
1704                 public void Sum_SumOfArgumentsCausesOverflow_ThrowsOverflowException ()
1705                 {
1706                         var source = Read (new [] { int.MaxValue - 1, 2 });
1707                         source.Sum ();
1708                 }
1709
1710                 [Test]
1711                 public void Sum_IntsFromOneToTen_ResultIsFiftyFive ()
1712                 {
1713                         var source = Read (new [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
1714                         Assert.That (source.Sum (), Is.EqualTo (55));
1715                 }
1716
1717                 [Test]
1718                 public void Sum_Longs_ReturnsSum ()
1719                 {
1720                         Assert.That (Read (new [] { 1L, 2L, 3L }).Sum (), Is.EqualTo (6));
1721                 }
1722
1723                 [Test]
1724                 public void Sum_Floats_ReturnsSum ()
1725                 {
1726                         Assert.That (Read (new [] { 1F, 2F, 3F }).Sum (), Is.EqualTo (6));
1727                 }
1728
1729                 [Test]
1730                 [Category ("NotWorking")]
1731                 public void Sum_NullableFloats_ReturnsSum ()
1732                 {
1733                         Assert.That (Read (new float? [] { 1F, 2F, 3F, null }).Sum (), Is.EqualTo (6));
1734                 }
1735
1736                 [Test]
1737                 public void Sum_Doubles_ReturnsSum ()
1738                 {
1739                         Assert.That (Read (new double [] { 1, 2, 3 }).Sum (), Is.EqualTo (6));
1740                 }
1741
1742                 [Test]
1743                 [Category ("NotWorking")]
1744                 public void Sum_NullableDoubles_ReturnsSum ()
1745                 {
1746                         Assert.That (Read (new double? [] { 1, 2, 3, null }).Sum (), Is.EqualTo (6));
1747                 }
1748
1749                 [Test]
1750                 public void Sum_Decimals_ReturnsSum ()
1751                 {
1752                         Assert.That (Read (new [] { 1m, 2m, 3m }).Sum (), Is.EqualTo (6));
1753                 }
1754
1755                 [Test]
1756                 [Category ("NotWorking")]
1757                 public void Sum_NullableDecimals_ReturnsSum ()
1758                 {
1759                         Assert.That (Read (new decimal? [] { 1m, 2m, 3m, null }).Sum (), Is.EqualTo (6));
1760                 }
1761
1762                 [Test]
1763                 [Category ("NotWorking")]
1764                 public void Sum_NullableLongs_ReturnsSum ()
1765                 {
1766                         Assert.That (Read (new long? [] { 1L, 2L, 3L, null }).Sum (), Is.EqualTo (6));
1767                 }
1768
1769                 [Test]
1770                 [Category ("NotWorking")]
1771                 public void Sum_NullableIntsAsArguments_ReturnsCorrectSum ()
1772                 {
1773                         var source = Read (new int? [] { 1, 2, null });
1774                         Assert.That (source.Sum (), Is.EqualTo (3));
1775                 }
1776
1777                 [Test]
1778                 public void Sum_SelectorArg_StringArray_ResultIsSumOfStringLengths ()
1779                 {
1780                         var source = Read (new [] { "dog", "cat", "eagle" });
1781                         Assert.That (source.Sum (s => s.Length), Is.EqualTo (11));
1782                 }
1783
1784                 [Test]
1785                 public void Take_IntsFromOneToSixAndThreeAsCount_IntsFromOneToThreeAreReturned ()
1786                 {
1787                         var source = Read (new [] { 1, 2, 3, 4, 5, 6 });
1788                         source.Take (3).AssertEquals (1, 2, 3);
1789                 }
1790
1791                 [Test]
1792                 public void Take_CountBiggerThanList_ReturnsAllElements ()
1793                 {
1794                         var source = Read (new [] { 1, 2, 3, 4, 5 });
1795                         source.Take (10).AssertEquals (1, 2, 3, 4, 5);
1796                 }
1797
1798                 [Test]
1799                 [ExpectedException (typeof (ArgumentNullException))]
1800                 public void TakeWhile_PassNullAsPredicate_ThrowsArgumentNullException ()
1801                 {
1802                         new object [0].TakeWhile ((Func<object, bool>) null);
1803                 }
1804
1805                 [Test]
1806                 public void TakeWhile_IntsFromOneToTenAndConditionThatSquareIsSmallerThan50_IntsFromOneToSeven ()
1807                 {
1808                         var source = Read (new [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
1809                         source.TakeWhile (i => i * i < 50).AssertEquals (1, 2, 3, 4, 5, 6, 7);
1810                 }
1811
1812                 [Test]
1813                 public void ToArray_IntsFromOneToTen_ResultIsIntArrayContainingAllElements ()
1814                 {
1815                         var source = Read (new [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
1816                         var result = source.ToArray ();
1817                         Assert.That (result, Is.TypeOf (typeof (int [])));
1818                         result.AssertEquals (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
1819                 }
1820
1821                 [Test]
1822                 [ExpectedException (typeof (ArgumentNullException))]
1823                 public void ToDictionary_KeySelectorArg_KeySelectorYieldsNull_ThrowsArgumentNullException ()
1824                 {
1825                         var source = new [] { "eagle", "deer" };
1826                         source.ToDictionary<string, string> (s => null);
1827                 }
1828
1829                 [Test]
1830                 [ExpectedException (typeof (ArgumentException))]
1831                 public void ToDictionary_KeySelectorArg_DuplicateKeys_ThrowsArgumentException ()
1832                 {
1833                         var source = new [] { "eagle", "deer", "cat", "dog" };
1834                         source.ToDictionary (s => s.Length);
1835                 }
1836
1837                 [Test]
1838                 public void ToDictionary_KeySelectorArg_ValidArguments_KeySelectorIsUsedForKeysInDictionary ()
1839                 {
1840                         var source = Read (new [] { "1", "2", "3" });
1841                         var result = source.ToDictionary (s => int.Parse (s));
1842                         int check = 1;
1843                         foreach (var pair in result) {
1844                                 Assert.That (pair.Key, Is.EqualTo (check));
1845                                 Assert.That (pair.Value, Is.EqualTo (check.ToString ()));
1846                                 check++;
1847                         }
1848                         Assert.That (check, Is.EqualTo (4));
1849                 }
1850
1851                 [Test]
1852                 public void ToDictionary_KeySelectorArgElementSelectorArg_IntsFromOneToTen_KeySelectorAndElementSelectorAreUsedForDictionaryElements ()
1853                 {
1854                         var source = Read (new [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
1855                         var result = source.ToDictionary (i => i.ToString (), i => Math.Sqrt (double.Parse (i.ToString ())));
1856                         int check = 1;
1857                         foreach (var pair in result) {
1858                                 Assert.That (pair.Key, Is.EqualTo (check.ToString ()));
1859                                 Assert.That (pair.Value, Is.EqualTo (Math.Sqrt (double.Parse (check.ToString ()))).Within (0.00001));
1860                                 check++;
1861                         }
1862                 }
1863
1864                 [Test]
1865                 public void ToList_IntsFromOneToTen_ReturnsListOfIntsContainingAllElements ()
1866                 {
1867                         var source = Read (new [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
1868                         var result = source.ToList ();
1869                         Assert.That (result, Is.TypeOf (typeof (List<int>)));
1870                         result.AssertEquals (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
1871                 }
1872
1873                 [Test]
1874                 public void ToLookup_KeySelectorArg_Strings_ReturnsLookupArrayWithStringLengthAsKey ()
1875                 {
1876                         var source = Read (new [] { "eagle", "dog", "cat", "bird", "camel" });
1877                         var result = source.ToLookup (s => s.Length);
1878
1879                         result [3].AssertEquals ("dog", "cat");
1880                         result [4].AssertEquals ("bird");
1881                         result [5].AssertEquals ("eagle", "camel");
1882                 }
1883
1884                 [Test]
1885                 public void ToLookup_KeySelectorArgElementSelectorArg_Strings_ElementSelectorIsUsed ()
1886                 {
1887                         var source = Read (new [] { "eagle", "dog", "cat", "bird", "camel" });
1888                         var result = source.ToLookup (s => s.Length, str => str.ToCharArray ().Reverse ());
1889                         var enumerator = result [3].GetEnumerator ();
1890                         enumerator.MoveNext (); Assert.That (enumerator.Current.ToString (), Is.EqualTo ("dog".ToCharArray ().Reverse ().ToString ()));
1891                         enumerator.MoveNext (); Assert.That (enumerator.Current.ToString (), Is.EqualTo ("cat".ToCharArray ().Reverse ().ToString ()));
1892                         Assert.That (enumerator.MoveNext (), Is.False);
1893
1894                         enumerator = result [4].GetEnumerator ();
1895                         enumerator.MoveNext (); Assert.That (enumerator.Current.ToString (), Is.EqualTo ("bird".ToCharArray ().Reverse ().ToString ()));
1896                         Assert.That (enumerator.MoveNext (), Is.False);
1897
1898                         enumerator = result [5].GetEnumerator ();
1899                         enumerator.MoveNext (); Assert.That (enumerator.Current.ToString (), Is.EqualTo ("eagle".ToCharArray ().Reverse ().ToString ()));
1900                         enumerator.MoveNext (); Assert.That (enumerator.Current.ToString (), Is.EqualTo ("camel".ToCharArray ().Reverse ().ToString ()));
1901                         Assert.That (enumerator.MoveNext (), Is.False);
1902                 }
1903
1904                 [Test]
1905                 [ExpectedException (typeof (ArgumentNullException))]
1906                 public void Union_SecondArg_PassNullAsArgument_ThrowsArgumentNullException ()
1907                 {
1908                         Read<object> ().Union (null);
1909                 }
1910
1911                 [Test]
1912                 public void Union_SecondArg_ValidIntArguments_NoDuplicatesAndInSourceOrder ()
1913                 {
1914                         var source = Read (new [] { 5, 3, 9, 7, 5, 9, 3, 7 });
1915                         var argument = Read (new [] { 8, 3, 6, 4, 4, 9, 1, 0 });
1916                         source.Union (argument).AssertEquals (5, 3, 9, 7, 8, 6, 4, 1, 0);
1917                 }
1918
1919                 [Test]
1920                 public void Union_SecondArgComparerArg_UpperCaseAndLowerCaseStrings_PassedComparerIsUsed ()
1921                 {
1922                         var source = Read (new [] { "A", "B", "C", "D", "E", "F" });
1923                         var argument = Read (new [] { "a", "b", "c", "d", "e", "f" });
1924                         source.Union (argument, StringComparer.CurrentCultureIgnoreCase).AssertEquals ("A", "B", "C", "D", "E", "F");
1925                 }
1926
1927                 [Test]
1928                 [ExpectedException (typeof (ArgumentNullException))]
1929                 public void Where_NullPredicate_ThrowsArgumentNullException ()
1930                 {
1931                         Read<object> ().Where ((Func<object, bool>) null);
1932                 }
1933
1934                 [Test]
1935                 public void Where_IntegersWithEvensPredicate_YieldsEvenIntegers ()
1936                 {
1937                         var source = Read (new [] { 1, 2, 3, 4, 5 });
1938                         source.Where (i => i % 2 == 0).AssertEquals (2, 4);
1939                 }
1940
1941                 [Test]
1942                 public void Where_StringsWithEvenIndexPredicate_YieldsElementsWithEvenIndex ()
1943                 {
1944                         var source = Read (new [] { "Camel", "Marlboro", "Parisienne", "Lucky Strike" });
1945                         source.Where ((s, i) => i % 2 == 0).AssertEquals ("Camel", "Parisienne");
1946                 }
1947
1948                 [Test]
1949                 public void AsEnumerable_NonNullSource_ReturnsSourceReference ()
1950                 {
1951                         var source = new object [0];
1952                         Assert.That (Enumerable.AsEnumerable (source), Is.SameAs (source));
1953                 }
1954
1955                 [Test]
1956                 public void AsEnumerable_NullSource_ReturnsNull ()
1957                 {
1958                         Assert.That (Enumerable.AsEnumerable<object> (null), Is.Null);
1959                 }
1960
1961                 private Reader<T> Read<T> (params T [] source)
1962                 {
1963                         Debug.Assert (source != null);
1964
1965                         var reader = new Reader<T> (source);
1966
1967                         //
1968                         // If the calling test method is not expecting an exception
1969                         // then check that the source enumerator will be disposed
1970                         // by the time the test is torn.
1971                         //
1972
1973                         var disposed = false;
1974                         var enumerated = false;
1975                         reader.Disposed += delegate { disposed = true; };
1976                         reader.Enumerated += delegate { enumerated = true; };
1977                         AssertionHandler assertion = () => Assert.That (!enumerated || disposed, Is.True, "Enumerator not disposed.");
1978                         tearDownAssertions = (AssertionHandler) Delegate.Combine (tearDownAssertions, assertion);
1979
1980                         return reader;
1981                 }
1982         }
1983
1984         [Serializable]
1985         internal sealed class NonEnumerableList<T> : List<T>, IEnumerable<T> {
1986                 public NonEnumerableList () { }
1987
1988                 public NonEnumerableList (IEnumerable<T> collection) :
1989                         base (collection) { }
1990
1991                 // Re-implement GetEnumerator to be undefined.
1992
1993                 IEnumerator<T> IEnumerable<T>.GetEnumerator ()
1994                 {
1995                         throw new NotImplementedException ();
1996                 }
1997
1998                 IEnumerator IEnumerable.GetEnumerator ()
1999                 {
2000                         return ((IEnumerable<T>) this).GetEnumerator ();
2001                 }
2002         }
2003
2004         internal sealed class Reader<T> : IEnumerable<T>, IEnumerator<T> {
2005                 public event EventHandler Disposed;
2006                 public event EventHandler Enumerated;
2007
2008                 private IEnumerable<T> source;
2009                 private IEnumerator<T> cursor;
2010
2011                 public Reader (IEnumerable<T> values)
2012                 {
2013                         Debug.Assert (values != null);
2014                         source = values;
2015                 }
2016
2017                 private IEnumerator<T> Enumerator
2018                 {
2019                         get
2020                         {
2021                                 if (cursor == null)
2022                                         GetEnumerator ();
2023                                 return this;
2024                         }
2025                 }
2026
2027                 public object EOF
2028                 {
2029                         get { return Enumerator.MoveNext (); }
2030                 }
2031
2032                 public IEnumerator<T> GetEnumerator ()
2033                 {
2034                         if (source == null) throw new Exception ("A LINQ Operator called GetEnumerator() twice.");
2035                         cursor = source.GetEnumerator ();
2036                         source = null;
2037
2038                         var handler = Enumerated;
2039                         if (handler != null)
2040                                 handler (this, EventArgs.Empty);
2041
2042                         return this;
2043                 }
2044
2045                 IEnumerator IEnumerable.GetEnumerator ()
2046                 {
2047                         return GetEnumerator ();
2048                 }
2049
2050                 public T Read ()
2051                 {
2052                         if (!Enumerator.MoveNext ())
2053                                 throw new InvalidOperationException ("No more elements in the source sequence.");
2054                         return Enumerator.Current;
2055                 }
2056
2057                 void IDisposable.Dispose ()
2058                 {
2059                         source = null;
2060                         var e = cursor;
2061                         cursor = null;
2062
2063                         if (e != null) {
2064                                 e.Dispose ();
2065
2066                                 var handler = Disposed;
2067                                 if (handler != null)
2068                                         handler (this, EventArgs.Empty);
2069                         }
2070                 }
2071
2072                 private IEnumerator<T> GetSourceEnumerator ()
2073                 {
2074                         if (source != null && cursor == null)
2075                                 throw new InvalidOperationException (/* GetEnumerator not called yet */);
2076                         if (source == null && cursor == null)
2077                                 throw new ObjectDisposedException (GetType ().FullName);
2078
2079                         return cursor;
2080                 }
2081
2082                 bool IEnumerator.MoveNext ()
2083                 {
2084                         return GetSourceEnumerator ().MoveNext ();
2085                 }
2086
2087                 void IEnumerator.Reset ()
2088                 {
2089                         GetSourceEnumerator ().Reset ();
2090                 }
2091
2092                 T IEnumerator<T>.Current
2093                 {
2094                         get { return GetSourceEnumerator ().Current; }
2095                 }
2096
2097                 object IEnumerator.Current
2098                 {
2099                         get { return ((IEnumerator<T>) this).Current; }
2100                 }
2101         }
2102
2103         internal static class ReaderTestExtensions {
2104                 public static void AssertEnded<T> (this Reader<T> reader)
2105                 {
2106                         Debug.Assert (reader != null);
2107
2108                         Assert.That (reader.EOF, Is.False, "Too many elements in source.");
2109                 }
2110
2111                 public static Reader<T> AssertNext<T> (this Reader<T> reader, Constraint constraint)
2112                 {
2113                         Debug.Assert (reader != null);
2114                         Debug.Assert (constraint != null);
2115
2116                         Assert.That (reader.Read (), constraint);
2117                         return reader;
2118                 }
2119         }
2120
2121         internal static class Tester {
2122                 public static void AssertEquals<T> (this IEnumerable<T> actuals, params T [] expectations)
2123                 {
2124                         using (var e = actuals.GetEnumerator ()) {
2125                                 foreach (var expected in expectations) {
2126                                         e.MoveNext ();
2127                                         Assert.That (e.Current, Is.EqualTo (expected));
2128                                 }
2129
2130                                 Assert.That (e.MoveNext (), Is.False);
2131                         }
2132                 }
2133         }
2134 }