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, 1000);
59 void AreEquivalent (IEnumerable<int> syncEnumerable, IEnumerable<int> async_resEnumerable, int count)
61 int[] sync = Enumerable.ToArray(syncEnumerable);
62 int[] async_res = Enumerable.ToArray(async_resEnumerable);
64 // This is not AreEquals because ParallelQuery is non-deterministic (IParallelOrderedEnumerable is)
65 // thus the order of the initial Enumerable might not be preserved
68 if (sync.Length != async_res.Length)
69 error = string.Format ("Expected size {0} but got {1} #{2}", sync.Length, async_res.Length, count);
72 Array.Sort (async_res);
74 for (i = j = 0; i < sync.Length && j < async_res.Length; ++i) {
75 if (sync [i] != async_res [j])
76 error += "missing " + sync [i] + "";
84 void AreEquivalent<T> (IEnumerable<T> syncEnumerable, IEnumerable<T> async_resEnumerable, int count)
86 T[] sync = Enumerable.ToArray(syncEnumerable);
87 T[] async_res = Enumerable.ToArray(async_resEnumerable);
89 // This is not AreEquals because ParallelQuery is non-deterministic (IParallelOrderedEnumerable is)
90 // thus the order of the initial Enumerable might not be preserved
91 CollectionAssert.AreEquivalent(sync, async_res, "#" + count);
94 static void AssertAreSame<T> (IEnumerable<T> expected, IEnumerable<T> actual)
96 if (expected == null) {
97 Assert.IsNull (actual);
101 Assert.IsNotNull (actual);
104 IEnumerator<T> ee = expected.GetEnumerator ();
105 IEnumerator<T> ea = actual.GetEnumerator ();
107 while (ee.MoveNext ()) {
108 Assert.IsTrue (ea.MoveNext (), "'" + ee.Current + "' expected at index '"+ ++index + "'.");
109 Assert.AreEqual (ee.Current, ea.Current, "at index '" + index + "'");
113 Assert.Fail ("Unexpected element: " + ea.Current);
116 public static void AssertException<T> (Action action) where T : Exception
124 Assert.Fail ("Expected: " + typeof (T).Name);
127 static void AssertAreSame<K, V> (K expectedKey, IEnumerable<V> expectedValues, IGrouping<K, V> actual)
129 if (expectedValues == null) {
130 Assert.IsNull (actual);
134 Assert.IsNotNull (actual);
136 Assert.AreEqual (expectedKey, actual.Key);
138 var ee = expectedValues.GetEnumerator ();
139 var ea = actual.GetEnumerator ();
141 while (ee.MoveNext ()) {
142 Assert.IsTrue (ea.MoveNext (), "'" + ee.Current + "' expected.");
143 Assert.AreEqual (ee.Current, ea.Current);
147 Assert.Fail ("Unexpected element: " + ee.Current);
150 static void AssertAreSame<K, V> (IDictionary<K, IEnumerable<V>> expected, IEnumerable<IGrouping<K, V>> actual)
152 if (expected == null) {
153 Assert.IsNull (actual);
157 Assert.IsNotNull (actual);
159 var ee = expected.GetEnumerator ();
160 var ea = actual.GetEnumerator ();
162 while (ee.MoveNext ()) {
163 Assert.IsTrue (ea.MoveNext (), "'" + ee.Current.Key + "' expected.");
164 AssertAreSame (ee.Current.Key, ee.Current.Value, ea.Current);
168 Assert.Fail ("Unexpected element: " + ee.Current.Key);
171 static void AssertAreSame<K, V> (IDictionary<K, IEnumerable<V>> expected, ILookup<K, V> actual)
173 if (expected == null) {
174 Assert.IsNull (actual);
178 Assert.IsNotNull (actual);
180 var ee = expected.GetEnumerator ();
181 var ea = actual.GetEnumerator ();
183 while (ee.MoveNext ()) {
184 Assert.IsTrue (ea.MoveNext (), "'" + ee.Current.Key + "' expected.");
185 AssertAreSame (ee.Current.Key, ee.Current.Value, ea.Current);
189 Assert.Fail ("Unexpected element: " + ee.Current.Key);
192 static void AssertAreSame<K, V> (IDictionary<K, V> expected, IDictionary<K, V> actual)
194 if (expected == null) {
195 Assert.IsNull (actual);
199 Assert.IsNotNull (actual);
201 var ee = expected.GetEnumerator ();
202 var ea = actual.GetEnumerator ();
204 while (ee.MoveNext ()) {
205 Assert.IsTrue (ea.MoveNext (), "'" + ee.Current.Key + ", " + ee.Current.Value + "' expected.");
206 Assert.AreEqual (ee.Current.Key, ea.Current.Key);
207 Assert.AreEqual (ee.Current.Value, ea.Current.Value);
211 Assert.Fail ("Unexpected element: " + ee.Current.Key + ", " + ee.Current.Value);
215 public void SelectTestCase ()
217 ParallelTestHelper.Repeat (() => {
218 IEnumerable<int> sync = baseEnumerable.Select (i => i * i);
219 IEnumerable<int> async_res = baseEnumerable.AsParallel ().Select (i => i * i);
221 AreEquivalent(sync, async_res, 1);
226 public void WhereTestCase ()
228 ParallelTestHelper.Repeat (() => {
229 IEnumerable<int> sync = baseEnumerable.Where(i => i % 2 == 0);
230 IEnumerable<int> async_res = baseEnumerable.AsParallel().Where(i => i % 2 == 0);
232 AreEquivalent(sync, async_res, 1);
237 public void CountTestCase ()
239 ParallelTestHelper.Repeat (() => {
240 int sync = baseEnumerable.Count();
241 int async_res = baseEnumerable.AsParallel().Count();
243 Assert.AreEqual(sync, async_res, "#1");
248 public void AggregateTestCase ()
250 ParallelTestHelper.Repeat (() => {
251 ParallelQuery<int> range = ParallelEnumerable.Repeat (5, 2643);
252 double average = range.Aggregate(() => new double[2],
253 (acc, elem) => { acc[0] += elem; acc[1]++; return acc; },
254 (acc1, acc2) => { acc1[0] += acc2[0]; acc1[1] += acc2[1]; return acc1; },
255 acc => acc[0] / acc[1]);
257 Assert.AreEqual(5.0, average, "#1");
262 public void TestSimpleExcept ()
264 ParallelTestHelper.Repeat (() => {
265 int [] first = {0, 1, 2, 3, 4, 5};
266 int [] second = {2, 4, 6};
267 int [] result = {0, 1, 3, 5};
269 AreEquivalent (result, first.AsReallyParallel ().Except (second.AsParallel ()), 1);
274 public void TestSimpleIntersect ()
276 ParallelTestHelper.Repeat (() => {
277 int [] first = {0, 1, 2, 3, 4, 5};
278 int [] second = {2, 4, 6};
279 int [] result = {2, 4};
281 AreEquivalent (result, first.AsReallyParallel ().Intersect (second.AsParallel ()), 1);
286 public void TestSimpleUnion ()
288 ParallelTestHelper.Repeat (() => {
289 int [] first = {0, 1, 2, 3, 4, 5};
290 int [] second = {2, 4, 6};
291 int [] result = {0, 1, 2, 3, 4, 5, 6};
293 AreEquivalent (result, first.AsReallyParallel ().Union (second.AsParallel ()), 1);
298 public void TestBigUnion ()
300 ParallelTestHelper.Repeat (() => {
301 int [] first = Enumerable.Range (1, 10000).ToArray ();
302 int [] second = Enumerable.Range (323, 757).ToArray ();
304 AreEquivalent (first, first.AsReallyParallel ().Union (second.AsParallel ()), 1);
309 public void TestBigIntersect ()
311 ParallelTestHelper.Repeat (() => {
312 int [] first = Enumerable.Range (1, 10000).ToArray ();
313 int [] second = Enumerable.Range (323, 757).ToArray ();
315 AreEquivalent (second, first.AsReallyParallel ().Intersect (second.AsParallel ()), 1);
323 public void TestCast ()
329 Foo [] foos = new Foo [] {a, b, c};
330 Bar [] result = new Bar [] {a, b, c};
332 AreEquivalent (result, foos.AsReallyParallel ().Cast<Bar> (), 1);
336 public void TestSkip ()
338 int [] data = {0, 1, 2, 3, 4, 5};
339 int [] result = {3, 4, 5};
341 AssertAreSame (result, data.AsReallyParallel ().AsOrdered ().Skip (3).ToArray ());
345 public void TestSkipIterating ()
347 int [] data = {0, 1, 2, 3, 4, 5};
348 int [] result = {3, 4, 5};
350 AssertAreSame (result, data.AsReallyParallel ().AsOrdered ().Skip (3));
354 public void TestSkipWhile ()
356 int [] data = {0, 1, 2, 3, 4, 5};
357 int [] result = {3, 4, 5};
359 AssertAreSame (result, data.AsReallyParallel ().AsOrdered ().SkipWhile (i => i < 3));
363 public void TestTake ()
365 int [] data = {0, 1, 2, 3, 4, 5};
366 int [] result = {0, 1, 2};
368 AssertAreSame (result, data.AsReallyParallel ().AsOrdered ().Take (3));
372 public void TestTakeWhile ()
374 int [] data = {0, 1, 2, 3, 4, 5};
375 int [] result = {0, 1, 2};
377 AssertAreSame (result, data.AsReallyParallel ().AsOrdered ().TakeWhile (i => i < 3));
381 public void SelectManyTest ()
383 IEnumerable<int> initial = Enumerable.Range (1, 50);
384 IEnumerable<int> expected = initial.SelectMany ((i) => Enumerable.Range (1, i));
386 ParallelTestHelper.Repeat (() => {
387 var actual = initial.AsReallyParallel ().SelectMany ((i) => Enumerable.Range (1, i));
388 AreEquivalent (expected, actual, 1);
393 public void SelectManyOrderedTest ()
395 IEnumerable<int> initial = Enumerable.Range (1, 50);
396 IEnumerable<int> expected = initial.SelectMany ((i) => Enumerable.Range (1, i));
398 ParallelTestHelper.Repeat (() => {
399 var actual = initial.AsReallyParallel ().AsOrdered ().SelectMany ((i) => Enumerable.Range (1, i));
400 AssertAreSame (expected, actual);
405 public void TestLast ()
407 int [] data = {1, 2, 3};
409 Assert.AreEqual (3, data.AsReallyParallel ().AsOrdered ().Last ());
413 public void TestLastOrDefault ()
417 Assert.AreEqual (default (int), data.AsReallyParallel ().AsOrdered ().LastOrDefault ());
421 public void TestFirst ()
423 int [] data = {1, 2, 3};
425 Assert.AreEqual (1, data.AsReallyParallel ().AsOrdered ().First ());
429 public void TestFirstOrDefault ()
433 Assert.AreEqual (default (int), data.AsReallyParallel ().AsOrdered ().FirstOrDefault ());
437 public void TestReverse ()
439 int [] data = {0, 1, 2, 3, 4};
440 int [] result = {4, 3, 2, 1, 0};
442 AssertAreSame (result, ((IEnumerable<int>)data).Select ((i) => i).AsReallyParallel ().AsOrdered ().Reverse ());
443 AssertAreSame (result, ParallelEnumerable.Range (0, 5).AsReallyParallel ().AsOrdered ().Reverse ());
447 public void TestOrderBy ()
449 ParallelTestHelper.Repeat (() => {
450 int [] array = { 14, 53, 3, 9, 11, 14, 5, 32, 2 };
452 var q = array.AsReallyParallel ().OrderBy ((i) => i);
453 AssertIsOrdered (q, array.Length);
464 if (string.IsNullOrEmpty (name))
465 return Age.ToString ();
467 return name + " (" + Age + ")";
473 get { return age + 1; }
476 public Baz (string name, int age)
482 public override int GetHashCode ()
484 return this.Age ^ this.Name.GetHashCode ();
487 public override bool Equals (object obj)
493 return b.Age == this.Age && b.Name == this.Name;
496 public override string ToString ()
502 static IEnumerable<Baz> CreateBazCollection ()
514 public void TestOrderByAgeAscendingTheByNameDescending ()
516 ParallelTestHelper.Repeat (() => {
517 var q = from b in CreateBazCollection ().AsReallyParallel ()
518 orderby b.Age ascending, b.Name descending
521 var expected = new [] {
529 AssertAreSame (expected, q);
534 public int ID { get; set; }
535 public string Name { get; set; }
537 public override string ToString ()
539 return ID + " " + Name;
543 IEnumerable<Data> CreateData ()
546 new Data { ID = 10, Name = "bcd" },
547 new Data { ID = 20, Name = "Abcd" },
548 new Data { ID = 20, Name = "Ab" },
549 new Data { ID = 10, Name = "Zyx" },
554 public void TestOrderByIdDescendingThenByNameAscending ()
556 ParallelTestHelper.Repeat (() => {
557 var q = from d in CreateData ().AsReallyParallel ()
558 orderby d.ID descending, d.Name ascending
561 var list = new List<Data> (q);
563 Assert.AreEqual ("Ab", list [0].Name);
564 Assert.AreEqual ("Abcd", list [1].Name);
565 Assert.AreEqual ("bcd", list [2].Name);
566 Assert.AreEqual ("Zyx", list [3].Name);
570 static void AssertIsOrdered (IEnumerable<int> e, int count)
572 int f = int.MinValue;
575 foreach (int i in e) {
576 Assert.IsTrue (f <= i, string.Format ("{0} <= {1}", f, i));
581 Assert.AreEqual (count, c);
586 public void ElementAtTestCase()
588 //ParallelTestHelper.Repeat (() => {
589 Assert.AreEqual(1, baseEnumerable.AsReallyParallel ().AsOrdered ().ElementAt(0), "#1");
590 Assert.AreEqual(51, baseEnumerable.AsReallyParallel ().AsOrdered ().ElementAt(50), "#2");
591 Assert.AreEqual(489, baseEnumerable.AsReallyParallel ().AsOrdered ().ElementAt(488), "#3");
596 public void TestJoin ()
599 Tuple<int, int>[] outer = Enumerable.Range (1, 50).Select ((i) => Tuple.Create (i, num - 2 * i)).ToArray ();
600 Tuple<int, int>[] inner = Enumerable.Range (1, 50).Reverse ().Select ((i) => Tuple.Create (i, 2 * i)).ToArray ();
602 IEnumerable<int> expected = outer.Join (inner, (e) => e.Item1, (e) => e.Item1, (e1, e2) => e1.Item2 + e2.Item2, EqualityComparer<int>.Default);
604 ParallelTestHelper.Repeat (() => {
605 ParallelQuery<int> actual = outer.AsReallyParallel ().Join (inner.AsParallel (),
608 (e1, e2) => e1.Item2 + e2.Item2,
609 EqualityComparer<int>.Default);
610 AreEquivalent (expected, actual, 1);
615 [Category ("NotWorking")] // Deadlocks randomly
616 public void TestGroupBy ()
619 Tuple<int, int>[] source = Enumerable.Range (0, num).Select ((i) => Tuple.Create (i / 10, i)).ToArray ();
621 ParallelTestHelper.Repeat (() => {
622 ParallelQuery<IGrouping<int, int>> actual = source.AsReallyParallel ().GroupBy ((e) => e.Item1, (e) => e.Item2, EqualityComparer<int>.Default);
623 foreach (var group in actual) {
624 Assert.GreaterOrEqual (group.Key, 0);
625 Assert.Less (group.Key, num / 10);
628 foreach (var e in group) {
630 Assert.GreaterOrEqual (e, group.Key * 10);
631 Assert.Less (e, (group.Key + 1) * 10);
634 Assert.AreEqual (10, count, "count");
640 public void TakeTestCase()
642 ParallelTestHelper.Repeat (() => {
643 ParallelQuery<int> async_res = baseEnumerable.AsReallyParallel ().AsOrdered ().Take(800);
644 IEnumerable<int> sync = baseEnumerable.Take(800);
646 AreEquivalent(sync, async_res, 1);
648 async_res = baseEnumerable.AsReallyParallel ().AsOrdered ().Take(100);
649 sync = baseEnumerable.Take(100);
651 AreEquivalent(sync, async_res, 2);
656 public void UnorderedTakeTestCase()
658 ParallelTestHelper.Repeat (() => {
659 ParallelQuery<int> async_res = baseEnumerable.AsReallyParallel ().Take(800);
660 IEnumerable<int> sync = baseEnumerable.Take (800);
662 Assert.AreEqual (sync.Count (), async_res.Count (), "#1");
664 async_res = baseEnumerable.AsReallyParallel ().Take(100);
665 sync = baseEnumerable.Take(100);
667 Assert.AreEqual (sync.Count (), async_res.Count (), "#2");
672 public void SkipTestCase()
674 ParallelTestHelper.Repeat (() => {
675 ParallelQuery<int> async_res = baseEnumerable.AsReallyParallel ().AsOrdered().Skip (800);
676 IEnumerable<int> sync = baseEnumerable.Skip (800);
678 AreEquivalent (sync, async_res, 1);
683 public void SkipTestCaseSmall ()
685 ParallelTestHelper.Repeat (() => {
686 var async_res = baseEnumerable.AsReallyParallel ().Skip(100);
687 var sync = baseEnumerable.Skip(100);
689 Assert.AreEqual (sync.Count (), async_res.Count ());
694 public void ZipTestCase()
696 ParallelTestHelper.Repeat (() => {
697 ParallelQuery<int> async_res1 = ParallelEnumerable.Range(0, 10000);
698 ParallelQuery<int> async_res2 = ParallelEnumerable.Repeat(1, 10000).Zip(async_res1, (e1, e2) => e1 + e2);
700 int[] expected = Enumerable.Range (1, 10000).ToArray ();
701 CollectionAssert.AreEquivalent(expected, Enumerable.ToArray (async_res2), "#1");
706 public void RangeTestCase ()
708 ParallelTestHelper.Repeat (() => {
709 IEnumerable<int> sync = Enumerable.Range(1, 1000);
710 IEnumerable<int> async_res = ParallelEnumerable.Range(1, 1000);
712 AreEquivalent (sync, async_res, 1);
717 public void RepeatTestCase ()
719 ParallelTestHelper.Repeat (() => {
720 IEnumerable<int> sync = Enumerable.Repeat(1, 1000);
721 IEnumerable<int> async_res = ParallelEnumerable.Repeat(1, 1000);
723 AreEquivalent (sync, async_res, 1);
728 public void TestSum ()
730 int [] data = {1, 2, 3, 4};
732 Assert.AreEqual (10, data.AsReallyParallel ().Sum ());
736 public void SumOnEmpty ()
740 Assert.AreEqual (0, data.AsReallyParallel ().Sum ());
744 public void TestMax ()
746 int [] data = {1, 3, 5, 2};
748 Assert.AreEqual (5, data.AsReallyParallel ().Max ());
752 public void TestMin ()
754 int [] data = {3, 5, 2, 6, 1, 7};
756 Assert.AreEqual (1, data.AsReallyParallel ().Min ());
760 public void TestToListOrdered ()
762 int [] data = { 2, 3, 5 };
764 var list = data.AsParallel().AsOrdered().WithExecutionMode (ParallelExecutionMode.ForceParallelism).ToList ();
766 AssertAreSame (data, list);
767 AssertIsOrdered (list, data.Length);
769 Assert.AreEqual (typeof (List<int>), list.GetType ());
773 public void TestToArrayOrdered ()
775 ICollection<int> coll = new List<int> ();
780 int [] result = {0, 1, 2};
782 var array = coll.AsReallyParallel ().AsOrdered().ToArray ();
784 AssertAreSame (result, array);
785 AssertIsOrdered (array, result.Length);
787 Assert.AreEqual (typeof (int []), array.GetType ());
789 array = Enumerable.Range (1, 100).Select ((i) => i).AsReallyParallel ().AsOrdered().ToArray ();
790 result = Enumerable.Range (1, 100).ToArray ();
792 AssertAreSame (result, array);
793 AssertIsOrdered (array, result.Length);
795 Assert.AreEqual (typeof (int []), array.GetType ());
800 public void TestToList ()
802 int [] data = {3, 5, 2};
804 var list = data.AsReallyParallel ().ToList ();
806 CollectionAssert.AreEquivalent (data, list);
808 Assert.AreEqual (typeof (List<int>), list.GetType ());
812 public void TestToArray ()
814 ICollection<int> coll = new List<int> ();
819 int [] result = {0, 1, 2};
821 var array = coll.AsReallyParallel ().ToArray ();
823 CollectionAssert.AreEquivalent (result, array);
825 Assert.AreEqual (typeof (int []), array.GetType ());
830 public void TestAverageOnInt32 ()
832 Assert.AreEqual (23.25, (new int [] { 24, 7, 28, 34 }).Average ());
836 public void TestAverageOnInt64 ()
838 Assert.AreEqual (23.25, (new long [] { 24, 7, 28, 34 }).Average ());
843 public void AnyArgumentNullTest ()
845 string [] data = { "2", "1", "5", "3", "4" };
849 AssertException<ArgumentNullException> (delegate () { ((IEnumerable<string>) null).AsReallyParallel ().Any (); });
851 // Any<TSource> (Func<TSource, bool>)
852 AssertException<ArgumentNullException> (delegate () { ((IEnumerable<string>) null).AsReallyParallel ().Any (x => true); });
853 AssertException<ArgumentNullException> (delegate () { data.AsReallyParallel ().Any ((Func<string, bool>) null); });
857 public void AnyTest ()
859 int [] data = { 5, 2, 3, 1, 6 };
864 Assert.IsTrue (data.AsReallyParallel ().Any ());
865 Assert.IsFalse (empty.AsReallyParallel ().Any ());
867 // Any<TSource> (Func<TSource, bool>)
868 Assert.IsTrue (data.AsReallyParallel ().Any (x => x == 5));
869 Assert.IsFalse (data.AsReallyParallel ().Any (x => x == 9));
870 Assert.IsFalse (empty.AsReallyParallel ().Any (x => true));
875 public void AllArgumentNullTest ()
877 string [] data = { "2", "1", "5", "3", "4" };
879 AssertException<ArgumentNullException> (delegate () { ((IEnumerable<string>) null).AsReallyParallel ().All (x => true); });
880 AssertException<ArgumentNullException> (delegate () { data.AsReallyParallel ().All ((Func<string, bool>) null); });
884 public void AllTest ()
886 int [] data = { 5, 2, 3, 1, 6 };
889 Assert.IsTrue (data.AsReallyParallel ().All (x => true));
890 Assert.IsFalse (data.AsReallyParallel ().All (x => x != 1));
891 Assert.IsTrue (empty.AsReallyParallel ().All (x => false));