1 // ParallelEnumerableTests.cs
3 // Copyright (c) 2008 Jérémie "Garuma" Laval
5 // Based on Enumerable test suite by Jb Evain (jbevain@novell.com)
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30 using System.Threading;
33 using System.Collections;
34 using System.Collections.Generic;
36 using NUnit.Framework;
38 namespace MonoTests.System.Linq
40 internal static class AsParallelHelper
42 internal static ParallelQuery<T> AsReallyParallel<T> (this IEnumerable<T> source)
44 return source.AsParallel ().WithExecutionMode (ParallelExecutionMode.ForceParallelism);
48 [TestFixtureAttribute]
49 public class ParallelEnumerableTests
51 IEnumerable<int> baseEnumerable;
56 baseEnumerable = Enumerable.Range(1, 10000);
59 void AreEquivalent (IEnumerable<int> syncEnumerable, IEnumerable<int> asyncEnumerable, int count)
61 int[] sync = Enumerable.ToArray(syncEnumerable);
62 int[] async = Enumerable.ToArray(asyncEnumerable);
64 // This is not AreEquals because ParallelQuery is non-deterministic (IParallelOrderedEnumerable is)
65 // thus the order of the initial Enumerable might not be preserved
66 CollectionAssert.AreEquivalent(sync, async, "#" + count);
69 void AreEquivalent<T> (IEnumerable<T> syncEnumerable, IEnumerable<T> asyncEnumerable, int count)
71 T[] sync = Enumerable.ToArray(syncEnumerable);
72 T[] async = Enumerable.ToArray(asyncEnumerable);
74 // This is not AreEquals because ParallelQuery is non-deterministic (IParallelOrderedEnumerable is)
75 // thus the order of the initial Enumerable might not be preserved
76 CollectionAssert.AreEquivalent(sync, async, "#" + count);
79 static void AssertAreSame<T> (IEnumerable<T> expected, IEnumerable<T> actual)
81 if (expected == null) {
82 Assert.IsNull (actual);
86 Assert.IsNotNull (actual);
89 IEnumerator<T> ee = expected.GetEnumerator ();
90 IEnumerator<T> ea = actual.GetEnumerator ();
92 while (ee.MoveNext ()) {
93 Assert.IsTrue (ea.MoveNext (), "'" + ee.Current + "' expected at index '"+ ++index + "'.");
94 Assert.AreEqual (ee.Current, ea.Current, "at index '" + index + "'");
98 Assert.Fail ("Unexpected element: " + ea.Current);
101 public static void AssertException<T> (Action action) where T : Exception
109 Assert.Fail ("Expected: " + typeof (T).Name);
112 static void AssertAreSame<K, V> (K expectedKey, IEnumerable<V> expectedValues, IGrouping<K, V> actual)
114 if (expectedValues == null) {
115 Assert.IsNull (actual);
119 Assert.IsNotNull (actual);
121 Assert.AreEqual (expectedKey, actual.Key);
123 var ee = expectedValues.GetEnumerator ();
124 var ea = actual.GetEnumerator ();
126 while (ee.MoveNext ()) {
127 Assert.IsTrue (ea.MoveNext (), "'" + ee.Current + "' expected.");
128 Assert.AreEqual (ee.Current, ea.Current);
132 Assert.Fail ("Unexpected element: " + ee.Current);
135 static void AssertAreSame<K, V> (IDictionary<K, IEnumerable<V>> expected, IEnumerable<IGrouping<K, V>> actual)
137 if (expected == null) {
138 Assert.IsNull (actual);
142 Assert.IsNotNull (actual);
144 var ee = expected.GetEnumerator ();
145 var ea = actual.GetEnumerator ();
147 while (ee.MoveNext ()) {
148 Assert.IsTrue (ea.MoveNext (), "'" + ee.Current.Key + "' expected.");
149 AssertAreSame (ee.Current.Key, ee.Current.Value, ea.Current);
153 Assert.Fail ("Unexpected element: " + ee.Current.Key);
156 static void AssertAreSame<K, V> (IDictionary<K, IEnumerable<V>> expected, ILookup<K, V> actual)
158 if (expected == null) {
159 Assert.IsNull (actual);
163 Assert.IsNotNull (actual);
165 var ee = expected.GetEnumerator ();
166 var ea = actual.GetEnumerator ();
168 while (ee.MoveNext ()) {
169 Assert.IsTrue (ea.MoveNext (), "'" + ee.Current.Key + "' expected.");
170 AssertAreSame (ee.Current.Key, ee.Current.Value, ea.Current);
174 Assert.Fail ("Unexpected element: " + ee.Current.Key);
177 static void AssertAreSame<K, V> (IDictionary<K, V> expected, IDictionary<K, V> actual)
179 if (expected == null) {
180 Assert.IsNull (actual);
184 Assert.IsNotNull (actual);
186 var ee = expected.GetEnumerator ();
187 var ea = actual.GetEnumerator ();
189 while (ee.MoveNext ()) {
190 Assert.IsTrue (ea.MoveNext (), "'" + ee.Current.Key + ", " + ee.Current.Value + "' expected.");
191 Assert.AreEqual (ee.Current.Key, ea.Current.Key);
192 Assert.AreEqual (ee.Current.Value, ea.Current.Value);
196 Assert.Fail ("Unexpected element: " + ee.Current.Key + ", " + ee.Current.Value);
200 public void SelectTestCase ()
202 ParallelTestHelper.Repeat (() => {
203 IEnumerable<int> sync = baseEnumerable.Select (i => i * i);
204 IEnumerable<int> async = baseEnumerable.AsParallel ().Select (i => i * i);
206 AreEquivalent(sync, async, 1);
211 public void WhereTestCase ()
213 ParallelTestHelper.Repeat (() => {
214 IEnumerable<int> sync = baseEnumerable.Where(i => i % 2 == 0);
215 IEnumerable<int> async = baseEnumerable.AsParallel().Where(i => i % 2 == 0);
217 AreEquivalent(sync, async, 1);
222 public void CountTestCase ()
224 ParallelTestHelper.Repeat (() => {
225 int sync = baseEnumerable.Count();
226 int async = baseEnumerable.AsParallel().Count();
228 Assert.AreEqual(sync, async, "#1");
233 public void AggregateTestCase ()
235 ParallelTestHelper.Repeat (() => {
236 ParallelQuery<int> range = ParallelEnumerable.Repeat (5, 2643);
237 double average = range.Aggregate(() => new double[2],
238 (acc, elem) => { acc[0] += elem; acc[1]++; return acc; },
239 (acc1, acc2) => { acc1[0] += acc2[0]; acc1[1] += acc2[1]; return acc1; },
240 acc => acc[0] / acc[1]);
242 Assert.AreEqual(5.0, average, "#1");
247 public void TestSimpleExcept ()
249 ParallelTestHelper.Repeat (() => {
250 int [] first = {0, 1, 2, 3, 4, 5};
251 int [] second = {2, 4, 6};
252 int [] result = {0, 1, 3, 5};
254 AreEquivalent (result, first.AsReallyParallel ().Except (second.AsParallel ()), 1);
259 public void TestSimpleIntersect ()
261 ParallelTestHelper.Repeat (() => {
262 int [] first = {0, 1, 2, 3, 4, 5};
263 int [] second = {2, 4, 6};
264 int [] result = {2, 4};
266 AreEquivalent (result, first.AsReallyParallel ().Intersect (second.AsParallel ()), 1);
271 public void TestSimpleUnion ()
273 ParallelTestHelper.Repeat (() => {
274 int [] first = {0, 1, 2, 3, 4, 5};
275 int [] second = {2, 4, 6};
276 int [] result = {0, 1, 2, 3, 4, 5, 6};
278 AreEquivalent (result, first.AsReallyParallel ().Union (second.AsParallel ()), 1);
283 public void TestBigUnion ()
285 ParallelTestHelper.Repeat (() => {
286 int [] first = Enumerable.Range (1, 10000).ToArray ();
287 int [] second = Enumerable.Range (323, 757).ToArray ();
289 AreEquivalent (first, first.AsReallyParallel ().Union (second.AsParallel ()), 1);
294 public void TestBigIntersect ()
296 ParallelTestHelper.Repeat (() => {
297 int [] first = Enumerable.Range (1, 10000).ToArray ();
298 int [] second = Enumerable.Range (323, 757).ToArray ();
300 AreEquivalent (second, first.AsReallyParallel ().Intersect (second.AsParallel ()), 1);
308 public void TestCast ()
314 Foo [] foos = new Foo [] {a, b, c};
315 Bar [] result = new Bar [] {a, b, c};
317 AreEquivalent (result, foos.AsReallyParallel ().Cast<Bar> (), 1);
321 public void TestSkip ()
323 int [] data = {0, 1, 2, 3, 4, 5};
324 int [] result = {3, 4, 5};
326 AssertAreSame (result, data.AsReallyParallel ().AsOrdered ().Skip (3).ToArray ());
330 public void TestSkipIterating ()
332 int [] data = {0, 1, 2, 3, 4, 5};
333 int [] result = {3, 4, 5};
335 AssertAreSame (result, data.AsReallyParallel ().AsOrdered ().Skip (3));
339 public void TestSkipWhile ()
341 int [] data = {0, 1, 2, 3, 4, 5};
342 int [] result = {3, 4, 5};
344 AssertAreSame (result, data.AsReallyParallel ().AsOrdered ().SkipWhile (i => i < 3));
348 public void TestTake ()
350 int [] data = {0, 1, 2, 3, 4, 5};
351 int [] result = {0, 1, 2};
353 AssertAreSame (result, data.AsReallyParallel ().AsOrdered ().Take (3));
357 public void TestTakeWhile ()
359 int [] data = {0, 1, 2, 3, 4, 5};
360 int [] result = {0, 1, 2};
362 AssertAreSame (result, data.AsReallyParallel ().AsOrdered ().TakeWhile (i => i < 3));
366 public void SelectManyTest ()
368 IEnumerable<int> initial = Enumerable.Range (1, 50);
369 IEnumerable<int> expected = initial.SelectMany ((i) => Enumerable.Range (1, i));
371 ParallelTestHelper.Repeat (() => {
372 var actual = initial.AsReallyParallel ().SelectMany ((i) => Enumerable.Range (1, i));
373 AreEquivalent (expected, actual, 1);
378 public void SelectManyOrderedTest ()
380 IEnumerable<int> initial = Enumerable.Range (1, 50);
381 IEnumerable<int> expected = initial.SelectMany ((i) => Enumerable.Range (1, i));
383 ParallelTestHelper.Repeat (() => {
384 var actual = initial.AsReallyParallel ().AsOrdered ().SelectMany ((i) => Enumerable.Range (1, i));
385 AssertAreSame (expected, actual);
390 public void TestLast ()
392 int [] data = {1, 2, 3};
394 Assert.AreEqual (3, data.AsReallyParallel ().AsOrdered ().Last ());
398 public void TestLastOrDefault ()
402 Assert.AreEqual (default (int), data.AsReallyParallel ().AsOrdered ().LastOrDefault ());
406 public void TestFirst ()
408 int [] data = {1, 2, 3};
410 Assert.AreEqual (1, data.AsReallyParallel ().AsOrdered ().First ());
414 public void TestFirstOrDefault ()
418 Assert.AreEqual (default (int), data.AsReallyParallel ().AsOrdered ().FirstOrDefault ());
422 public void TestReverse ()
424 int [] data = {0, 1, 2, 3, 4};
425 int [] result = {4, 3, 2, 1, 0};
427 AssertAreSame (result, ((IEnumerable<int>)data).Select ((i) => i).AsReallyParallel ().AsOrdered ().Reverse ());
428 AssertAreSame (result, ParallelEnumerable.Range (0, 5).WithExecutionMode (ParallelExecutionMode.ForceParallelism).AsOrdered ().Reverse ());
432 public void TestOrderBy ()
434 ParallelTestHelper.Repeat (() => {
435 int [] array = { 14, 53, 3, 9, 11, 14, 5, 32, 2 };
437 var q = array.AsReallyParallel ().OrderBy ((i) => i);
438 AssertIsOrdered (q, array.Length);
449 if (string.IsNullOrEmpty (name))
450 return Age.ToString ();
452 return name + " (" + Age + ")";
458 get { return age + 1; }
461 public Baz (string name, int age)
467 public override int GetHashCode ()
469 return this.Age ^ this.Name.GetHashCode ();
472 public override bool Equals (object obj)
478 return b.Age == this.Age && b.Name == this.Name;
481 public override string ToString ()
487 static IEnumerable<Baz> CreateBazCollection ()
499 public void TestOrderByAgeAscendingTheByNameDescending ()
501 ParallelTestHelper.Repeat (() => {
502 var q = from b in CreateBazCollection ().AsReallyParallel ()
503 orderby b.Age ascending, b.Name descending
506 var expected = new [] {
514 AssertAreSame (expected, q);
519 public int ID { get; set; }
520 public string Name { get; set; }
522 public override string ToString ()
524 return ID + " " + Name;
528 IEnumerable<Data> CreateData ()
531 new Data { ID = 10, Name = "bcd" },
532 new Data { ID = 20, Name = "Abcd" },
533 new Data { ID = 20, Name = "Ab" },
534 new Data { ID = 10, Name = "Zyx" },
539 public void TestOrderByIdDescendingThenByNameAscending ()
541 ParallelTestHelper.Repeat (() => {
542 var q = from d in CreateData ().AsReallyParallel ()
543 orderby d.ID descending, d.Name ascending
546 var list = new List<Data> (q);
548 Assert.AreEqual ("Ab", list [0].Name);
549 Assert.AreEqual ("Abcd", list [1].Name);
550 Assert.AreEqual ("bcd", list [2].Name);
551 Assert.AreEqual ("Zyx", list [3].Name);
555 static void AssertIsOrdered (IEnumerable<int> e, int count)
557 int f = int.MinValue;
560 foreach (int i in e) {
561 Assert.IsTrue (f <= i, string.Format ("{0} <= {1}", f, i));
566 Assert.AreEqual (count, c);
571 public void ElementAtTestCase()
573 //ParallelTestHelper.Repeat (() => {
574 Assert.AreEqual(1, baseEnumerable.AsReallyParallel ().AsOrdered ().ElementAt(0), "#1");
575 Assert.AreEqual(51, baseEnumerable.AsReallyParallel ().AsOrdered ().ElementAt(50), "#2");
576 Assert.AreEqual(489, baseEnumerable.AsReallyParallel ().AsOrdered ().ElementAt(488), "#3");
581 public void TestJoin ()
584 Tuple<int, int>[] outer = Enumerable.Range (1, 50).Select ((i) => Tuple.Create (i, num - 2 * i)).ToArray ();
585 Tuple<int, int>[] inner = Enumerable.Range (1, 50).Reverse ().Select ((i) => Tuple.Create (i, 2 * i)).ToArray ();
587 IEnumerable<int> expected = outer.Join (inner, (e) => e.Item1, (e) => e.Item1, (e1, e2) => e1.Item2 + e2.Item2, EqualityComparer<int>.Default);
589 ParallelTestHelper.Repeat (() => {
590 ParallelQuery<int> actual = outer.AsReallyParallel ().Join (inner.AsParallel (), (e) => e.Item1, (e) => e.Item1, (e1, e2) => e1.Item2 + e2.Item2, EqualityComparer<int>.Default);
592 AreEquivalent (expected, actual, 1);
597 public void TestGroupBy ()
600 Tuple<int, int>[] source = Enumerable.Range (0, num).Select ((i) => Tuple.Create (i / 10, i)).ToArray ();
602 ParallelTestHelper.Repeat (() => {
603 ParallelQuery<IGrouping<int, int>> actual = source.AsReallyParallel ().GroupBy ((e) => e.Item1, (e) => e.Item2, EqualityComparer<int>.Default);
605 foreach (var group in actual) {
606 Assert.GreaterOrEqual (group.Key, 0);
607 Assert.Less (group.Key, num / 10);
610 foreach (var e in group) {
612 Assert.GreaterOrEqual (e, group.Key * 10);
613 Assert.Less (e, (group.Key + 1) * 10);
616 Assert.AreEqual (10, count, "count");
622 public void TakeTestCase()
624 ParallelTestHelper.Repeat (() => {
625 ParallelQuery<int> async = baseEnumerable.AsReallyParallel ().AsOrdered ().Take(2000);
626 IEnumerable<int> sync = baseEnumerable.Take(2000);
628 AreEquivalent(sync, async, 1);
630 async = baseEnumerable.AsReallyParallel ().AsOrdered ().Take(100);
631 sync = baseEnumerable.Take(100);
633 AreEquivalent(sync, async, 2);
638 public void UnorderedTakeTestCase()
640 ParallelTestHelper.Repeat (() => {
641 ParallelQuery<int> async = baseEnumerable.AsReallyParallel ().Take(2000);
642 IEnumerable<int> sync = baseEnumerable.Take (2000);
644 Assert.AreEqual (sync.Count (), async.Count (), "#1");
646 async = baseEnumerable.AsReallyParallel ().Take(100);
647 sync = baseEnumerable.Take(100);
649 Assert.AreEqual (sync.Count (), async.Count (), "#2");
654 public void SkipTestCase()
656 ParallelTestHelper.Repeat (() => {
657 ParallelQuery<int> async = baseEnumerable.AsReallyParallel ().AsOrdered().Skip(2000);
658 IEnumerable<int> sync = baseEnumerable.Skip(2000);
660 AreEquivalent(sync, async, 1);
665 public void SkipTestCaseSmall ()
667 ParallelTestHelper.Repeat (() => {
668 var async = baseEnumerable.AsReallyParallel ().Skip(100);
669 var sync = baseEnumerable.Skip(100);
671 Assert.AreEqual (sync.Count (), async.Count ());
676 public void ZipTestCase()
678 ParallelTestHelper.Repeat (() => {
679 ParallelQuery<int> async1 = ParallelEnumerable.Range(0, 10000);
680 ParallelQuery<int> async2 = ParallelEnumerable.Repeat(1, 10000).Zip(async1, (e1, e2) => e1 + e2);
682 int[] expected = Enumerable.Range (1, 10000).ToArray ();
683 CollectionAssert.AreEquivalent(expected, Enumerable.ToArray (async2), "#1");
688 public void RangeTestCase ()
690 ParallelTestHelper.Repeat (() => {
691 IEnumerable<int> sync = Enumerable.Range(1, 1000);
692 IEnumerable<int> async = ParallelEnumerable.Range(1, 1000);
694 AreEquivalent (sync, async, 1);
699 public void RepeatTestCase ()
701 ParallelTestHelper.Repeat (() => {
702 IEnumerable<int> sync = Enumerable.Repeat(1, 1000);
703 IEnumerable<int> async = ParallelEnumerable.Repeat(1, 1000);
705 AreEquivalent (sync, async, 1);
710 public void TestSum ()
712 int [] data = {1, 2, 3, 4};
714 Assert.AreEqual (10, data.AsReallyParallel ().Sum ());
718 public void SumOnEmpty ()
722 Assert.AreEqual (0, data.AsReallyParallel ().Sum ());
726 public void TestMax ()
728 int [] data = {1, 3, 5, 2};
730 Assert.AreEqual (5, data.AsReallyParallel ().Max ());
734 public void TestMin ()
736 int [] data = {3, 5, 2, 6, 1, 7};
738 Assert.AreEqual (1, data.AsReallyParallel ().Min ());
742 public void TestToListOrdered ()
744 int [] data = { 2, 3, 5 };
746 var list = data.AsParallel().AsOrdered().WithExecutionMode (ParallelExecutionMode.ForceParallelism).ToList ();
748 AssertAreSame (data, list);
749 AssertIsOrdered (list, data.Length);
751 Assert.AreEqual (typeof (List<int>), list.GetType ());
755 public void TestToArrayOrdered ()
757 ICollection<int> coll = new List<int> ();
762 int [] result = {0, 1, 2};
764 var array = coll.AsReallyParallel ().AsOrdered().ToArray ();
766 AssertAreSame (result, array);
767 AssertIsOrdered (array, result.Length);
769 Assert.AreEqual (typeof (int []), array.GetType ());
771 array = Enumerable.Range (1, 100).Select ((i) => i).AsReallyParallel ().AsOrdered().ToArray ();
772 result = Enumerable.Range (1, 100).ToArray ();
774 AssertAreSame (result, array);
775 AssertIsOrdered (array, result.Length);
777 Assert.AreEqual (typeof (int []), array.GetType ());
782 public void TestToList ()
784 int [] data = {3, 5, 2};
786 var list = data.AsReallyParallel ().ToList ();
788 CollectionAssert.AreEquivalent (data, list);
790 Assert.AreEqual (typeof (List<int>), list.GetType ());
794 public void TestToArray ()
796 ICollection<int> coll = new List<int> ();
801 int [] result = {0, 1, 2};
803 var array = coll.AsReallyParallel ().ToArray ();
805 CollectionAssert.AreEquivalent (result, array);
807 Assert.AreEqual (typeof (int []), array.GetType ());
812 public void TestAverageOnInt32 ()
814 Assert.AreEqual (23.25, (new int [] { 24, 7, 28, 34 }).Average ());
818 public void TestAverageOnInt64 ()
820 Assert.AreEqual (23.25, (new long [] { 24, 7, 28, 34 }).Average ());
825 public void AnyArgumentNullTest ()
827 string [] data = { "2", "1", "5", "3", "4" };
831 AssertException<ArgumentNullException> (delegate () { ((IEnumerable<string>) null).AsReallyParallel ().Any (); });
833 // Any<TSource> (Func<TSource, bool>)
834 AssertException<ArgumentNullException> (delegate () { ((IEnumerable<string>) null).AsReallyParallel ().Any (x => true); });
835 AssertException<ArgumentNullException> (delegate () { data.AsReallyParallel ().Any ((Func<string, bool>) null); });
839 public void AnyTest ()
841 int [] data = { 5, 2, 3, 1, 6 };
846 Assert.IsTrue (data.AsReallyParallel ().Any ());
847 Assert.IsFalse (empty.AsReallyParallel ().Any ());
849 // Any<TSource> (Func<TSource, bool>)
850 Assert.IsTrue (data.AsReallyParallel ().Any (x => x == 5));
851 Assert.IsFalse (data.AsReallyParallel ().Any (x => x == 9));
852 Assert.IsFalse (empty.AsReallyParallel ().Any (x => true));
857 public void AllArgumentNullTest ()
859 string [] data = { "2", "1", "5", "3", "4" };
861 AssertException<ArgumentNullException> (delegate () { ((IEnumerable<string>) null).AsReallyParallel ().All (x => true); });
862 AssertException<ArgumentNullException> (delegate () { data.AsReallyParallel ().All ((Func<string, bool>) null); });
866 public void AllTest ()
868 int [] data = { 5, 2, 3, 1, 6 };
871 Assert.IsTrue (data.AsReallyParallel ().All (x => true));
872 Assert.IsFalse (data.AsReallyParallel ().All (x => x != 1));
873 Assert.IsTrue (empty.AsReallyParallel ().All (x => false));