1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Collections.Generic;
6 using System.Collections.Immutable;
7 using Xunit;
8 
9 namespace System.Linq.Parallel.Tests
10 {
11     public static class AggregateTests
12     {
13         private const int ResultFuncModifier = 17;
14 
15         [Theory]
16         [InlineData(1)]
17         [InlineData(2)]
18         [InlineData(16)]
Aggregate_Sum(int count)19         public static void Aggregate_Sum(int count)
20         {
21             // The operation will overflow for long-running sizes, but that's okay:
22             // The helper is overflowing too!
23             Assert.Equal(Functions.SumRange(0, count), UnorderedSources.Default(count).Aggregate((x, y) => unchecked(x + y)));
24         }
25 
26         [Fact]
27         [OuterLoop]
Aggregate_Sum_Longrunning()28         public static void Aggregate_Sum_Longrunning()
29         {
30             Aggregate_Sum(Sources.OuterLoopCount);
31         }
32 
33         [Theory]
34         [InlineData(0)]
35         [InlineData(1)]
36         [InlineData(2)]
37         [InlineData(16)]
Aggregate_Sum_Seed(int count)38         public static void Aggregate_Sum_Seed(int count)
39         {
40             Assert.Equal(Functions.SumRange(0, count), UnorderedSources.Default(count).Aggregate(0, (x, y) => unchecked(x + y)));
41         }
42 
43         [Fact]
44         [OuterLoop]
Aggregate_Sum_Seed_Longrunning()45         public static void Aggregate_Sum_Seed_Longrunning()
46         {
47             Aggregate_Sum_Seed(Sources.OuterLoopCount);
48         }
49 
50         [Theory]
51         [InlineData(0)]
52         [InlineData(1)]
53         [InlineData(2)]
54         [InlineData(16)]
Aggregate_Product_Seed(int count)55         public static void Aggregate_Product_Seed(int count)
56         {
57             // The operation will overflow for long-running sizes, but that's okay:
58             // The helper is overflowing too!
59             Assert.Equal(Functions.ProductRange(1, count), ParallelEnumerable.Range(1, count).Aggregate(1L, (x, y) => unchecked(x * y)));
60         }
61 
62         [Fact]
63         [OuterLoop]
Aggregate_Product_Seed_Longrunning()64         public static void Aggregate_Product_Seed_Longrunning()
65         {
66             Aggregate_Product_Seed(Sources.OuterLoopCount);
67         }
68 
69         [Theory]
70         [InlineData(0)]
71         [InlineData(1)]
72         [InlineData(2)]
73         [InlineData(16)]
Aggregate_Collection_Seed(int count)74         public static void Aggregate_Collection_Seed(int count)
75         {
76             Assert.Equal(Enumerable.Range(0, count), UnorderedSources.Default(count).Aggregate(ImmutableList<int>.Empty, (l, x) => l.Add(x)).OrderBy(x => x));
77         }
78 
79         [Fact]
80         [OuterLoop]
Aggregate_Collection_Seed_Longrunning()81         public static void Aggregate_Collection_Seed_Longrunning()
82         {
83             // Given the cost of using an object, reduce count.
84             Aggregate_Collection_Seed(Sources.OuterLoopCount / 2);
85         }
86 
87         [Theory]
88         [InlineData(0)]
89         [InlineData(1)]
90         [InlineData(2)]
91         [InlineData(16)]
Aggregate_Sum_Result(int count)92         public static void Aggregate_Sum_Result(int count)
93         {
94             Assert.Equal(Functions.SumRange(0, count) + ResultFuncModifier,
95                          UnorderedSources.Default(count).Aggregate(0, (x, y) => unchecked(x + y), result => result + ResultFuncModifier));
96         }
97 
98         [Fact]
99         [OuterLoop]
Aggregate_Sum_Result_Longrunning()100         public static void Aggregate_Sum_Result_Longrunning()
101         {
102             Aggregate_Sum_Result(Sources.OuterLoopCount);
103         }
104 
105         [Theory]
106         [InlineData(0)]
107         [InlineData(1)]
108         [InlineData(2)]
109         [InlineData(16)]
Aggregate_Product_Result(int count)110         public static void Aggregate_Product_Result(int count)
111         {
112             Assert.Equal(Functions.ProductRange(1, count) + ResultFuncModifier,
113                          ParallelEnumerable.Range(1, count).Aggregate(1L, (x, y) => unchecked(x * y), result => result + ResultFuncModifier));
114         }
115 
116         [Fact]
117         [OuterLoop]
Aggregate_Product_Results_Longrunning()118         public static void Aggregate_Product_Results_Longrunning()
119         {
120             Aggregate_Product_Result(Sources.OuterLoopCount);
121         }
122 
123         [Theory]
124         [InlineData(0)]
125         [InlineData(1)]
126         [InlineData(2)]
127         [InlineData(16)]
Aggregate_Collection_Results(int count)128         public static void Aggregate_Collection_Results(int count)
129         {
130             Assert.Equal(Enumerable.Range(0, count), UnorderedSources.Default(count).Aggregate(ImmutableList<int>.Empty, (l, x) => l.Add(x), l => l.OrderBy(x => x)));
131         }
132 
133         [Fact]
134         [OuterLoop]
Aggregate_Collection_Results_Longrunning()135         public static void Aggregate_Collection_Results_Longrunning()
136         {
137             Aggregate_Collection_Results(Sources.OuterLoopCount / 2);
138         }
139 
140         [Theory]
141         [InlineData(0)]
142         [InlineData(1)]
143         [InlineData(2)]
144         [InlineData(16)]
Aggregate_Sum_Accumulator(int count)145         public static void Aggregate_Sum_Accumulator(int count)
146         {
147             ParallelQuery<int> query = UnorderedSources.Default(count);
148             int actual = query.Aggregate(
149                 0,
150                 (accumulator, x) => accumulator + x,
151                 (left, right) => unchecked(left + right),
152                 result => result + ResultFuncModifier);
153             Assert.Equal(Functions.SumRange(0, count) + ResultFuncModifier, actual);
154         }
155 
156         [Fact]
157         [OuterLoop]
Aggregate_Sum_Accumulator_Longrunning()158         public static void Aggregate_Sum_Accumulator_Longrunning()
159         {
160             Aggregate_Sum_Accumulator(Sources.OuterLoopCount);
161         }
162 
163         [Theory]
164         [InlineData(0)]
165         [InlineData(1)]
166         [InlineData(2)]
167         [InlineData(16)]
Aggregate_Product_Accumulator(int count)168         public static void Aggregate_Product_Accumulator(int count)
169         {
170             ParallelQuery<int> query = ParallelEnumerable.Range(1, count);
171             long actual = query.Aggregate(
172                 1L,
173                 (accumulator, x) => unchecked(accumulator * x),
174                 (left, right) => left * right,
175                 result => result + ResultFuncModifier);
176             Assert.Equal(Functions.ProductRange(1, count) + ResultFuncModifier, actual);
177         }
178 
179         [Fact]
180         [OuterLoop]
Aggregate_Product_Accumulator_Longrunning()181         public static void Aggregate_Product_Accumulator_Longrunning()
182         {
183             Aggregate_Product_Accumulator(Sources.OuterLoopCount);
184         }
185 
186         [Theory]
187         [InlineData(0)]
188         [InlineData(1)]
189         [InlineData(2)]
190         [InlineData(16)]
Aggregate_Collection_Accumulator(int count)191         public static void Aggregate_Collection_Accumulator(int count)
192         {
193             ParallelQuery<int> query = UnorderedSources.Default(count);
194             IList<int> actual = query.Aggregate(
195                 ImmutableList<int>.Empty,
196                 (accumulator, x) => accumulator.Add(x),
197                 (left, right) => left.AddRange(right),
198                 result => result.OrderBy(x => x).ToList());
199             Assert.Equal(Enumerable.Range(0, count), actual);
200         }
201 
202         [Fact]
203         [OuterLoop]
Aggregate_Collection_Accumulator_Longrunning()204         public static void Aggregate_Collection_Accumulator_Longrunning()
205         {
206             Aggregate_Collection_Accumulator(Sources.OuterLoopCount / 2);
207         }
208 
209         [Theory]
210         [InlineData(0)]
211         [InlineData(1)]
212         [InlineData(2)]
213         [InlineData(16)]
Aggregate_Sum_SeedFunction(int count)214         public static void Aggregate_Sum_SeedFunction(int count)
215         {
216             ParallelQuery<int> query = UnorderedSources.Default(count);
217             int actual = query.Aggregate(
218                 () => 0,
219                 (accumulator, x) => accumulator + x,
220                 (left, right) => unchecked(left + right),
221                 result => result + ResultFuncModifier);
222             Assert.Equal(Functions.SumRange(0, count) + ResultFuncModifier, actual);
223         }
224 
225         [Fact]
226         [OuterLoop]
Aggregate_Sum_SeedFunction_Longrunning()227         public static void Aggregate_Sum_SeedFunction_Longrunning()
228         {
229             Aggregate_Sum_SeedFunction(Sources.OuterLoopCount);
230         }
231 
232         [Theory]
233         [InlineData(0)]
234         [InlineData(1)]
235         [InlineData(2)]
236         [InlineData(16)]
Aggregate_Product_SeedFunction(int count)237         public static void Aggregate_Product_SeedFunction(int count)
238         {
239             ParallelQuery<int> query = ParallelEnumerable.Range(1, count);
240             long actual = query.Aggregate(
241                 () => 1L,
242                 (accumulator, x) => unchecked(accumulator * x),
243                 (left, right) => left * right,
244                 result => result + ResultFuncModifier);
245             Assert.Equal(Functions.ProductRange(1, count) + ResultFuncModifier, actual);
246         }
247 
248         [Fact]
249         [OuterLoop]
Aggregate_Product_SeedFunction_Longrunning()250         public static void Aggregate_Product_SeedFunction_Longrunning()
251         {
252             Aggregate_Product_SeedFunction(Sources.OuterLoopCount);
253         }
254 
255         [Theory]
256         [InlineData(0)]
257         [InlineData(1)]
258         [InlineData(2)]
259         [InlineData(16)]
Aggregate_Collection_SeedFunction(int count)260         public static void Aggregate_Collection_SeedFunction(int count)
261         {
262             ParallelQuery<int> query = UnorderedSources.Default(count);
263             IList<int> actual = query.Aggregate(
264                 () => ImmutableList<int>.Empty,
265                 (accumulator, x) => accumulator.Add(x),
266                 (left, right) => left.AddRange(right),
267                 result => result.OrderBy(x => x).ToList());
268             Assert.Equal(Enumerable.Range(0, count), actual);
269         }
270 
271         [Fact]
272         [OuterLoop]
Aggregate_Collection_SeedFunction_Longrunning()273         public static void Aggregate_Collection_SeedFunction_Longrunning()
274         {
275             Aggregate_Collection_SeedFunction(Sources.OuterLoopCount / 2);
276         }
277 
278         [Fact]
Aggregate_InvalidOperationException()279         public static void Aggregate_InvalidOperationException()
280         {
281             Assert.Throws<InvalidOperationException>(() => ParallelEnumerable.Empty<int>().Aggregate((i, j) => i));
282             // All other invocations return the seed value.
283             Assert.Equal(-1, ParallelEnumerable.Empty<int>().Aggregate(-1, (i, j) => i + j));
284             Assert.Equal(-1, ParallelEnumerable.Empty<int>().Aggregate(-1, (i, j) => i + j, i => i));
285             Assert.Equal(-1, ParallelEnumerable.Empty<int>().Aggregate(-1, (i, j) => i + j, (i, j) => i + j, i => i));
286             Assert.Equal(-1, ParallelEnumerable.Empty<int>().Aggregate(() => -1, (i, j) => i + j, (i, j) => i + j, i => i));
287         }
288 
289         [Fact]
Aggregate_OperationCanceledException()290         public static void Aggregate_OperationCanceledException()
291         {
292             AssertThrows.EventuallyCanceled((source, canceler) => source.Aggregate((i, j) => { canceler(); return j; }));
293             AssertThrows.EventuallyCanceled((source, canceler) => source.Aggregate(0, (i, j) => { canceler(); return j; }));
294             AssertThrows.EventuallyCanceled((source, canceler) => source.Aggregate(0, (i, j) => { canceler(); return j; }, i => i));
295             AssertThrows.EventuallyCanceled((source, canceler) => source.Aggregate(0, (i, j) => { canceler(); return j; }, (i, j) => i, i => i));
296             AssertThrows.EventuallyCanceled((source, canceler) => source.Aggregate(() => 0, (i, j) => { canceler(); ; return j; }, (i, j) => i, i => i));
297         }
298 
299         [Fact]
Aggregate_AggregateException_Wraps_OperationCanceledException()300         public static void Aggregate_AggregateException_Wraps_OperationCanceledException()
301         {
302             AssertThrows.OtherTokenCanceled((source, canceler) => source.Aggregate((i, j) => { canceler(); return j; }));
303             AssertThrows.OtherTokenCanceled((source, canceler) => source.Aggregate(0, (i, j) => { canceler(); return j; }));
304             AssertThrows.OtherTokenCanceled((source, canceler) => source.Aggregate(0, (i, j) => { canceler(); return j; }, i => i));
305             AssertThrows.OtherTokenCanceled((source, canceler) => source.Aggregate(0, (i, j) => { canceler(); return j; }, (i, j) => i, i => i));
306             AssertThrows.OtherTokenCanceled((source, canceler) => source.Aggregate(() => 0, (i, j) => { canceler(); ; return j; }, (i, j) => i, i => i));
307             AssertThrows.SameTokenNotCanceled((source, canceler) => source.Aggregate((i, j) => { canceler(); return j; }));
308             AssertThrows.SameTokenNotCanceled((source, canceler) => source.Aggregate(0, (i, j) => { canceler(); return j; }));
309             AssertThrows.SameTokenNotCanceled((source, canceler) => source.Aggregate(0, (i, j) => { canceler(); return j; }, i => i));
310             AssertThrows.SameTokenNotCanceled((source, canceler) => source.Aggregate(0, (i, j) => { canceler(); return j; }, (i, j) => i, i => i));
311             AssertThrows.SameTokenNotCanceled((source, canceler) => source.Aggregate(() => 0, (i, j) => { canceler(); ; return j; }, (i, j) => i, i => i));
312         }
313 
314         [Fact]
Aggregate_OperationCanceledException_PreCanceled()315         public static void Aggregate_OperationCanceledException_PreCanceled()
316         {
317             AssertThrows.AlreadyCanceled(source => source.Aggregate((i, j) => i));
318             AssertThrows.AlreadyCanceled(source => source.Aggregate(0, (i, j) => i));
319             AssertThrows.AlreadyCanceled(source => source.Aggregate(0, (i, j) => i, i => i));
320             AssertThrows.AlreadyCanceled(source => source.Aggregate(0, (i, j) => i, (i, j) => i, i => i));
321             AssertThrows.AlreadyCanceled(source => source.Aggregate(() => 0, (i, j) => i, (i, j) => i, i => i));
322         }
323 
324         [Fact]
Aggregate_AggregateException()325         public static void Aggregate_AggregateException()
326         {
327             AssertThrows.Wrapped<DeliberateTestException>(() => UnorderedSources.Default(2).Aggregate((i, j) => { throw new DeliberateTestException(); }));
328             AssertThrows.Wrapped<DeliberateTestException>(() => UnorderedSources.Default(2).Aggregate(0, (i, j) => { throw new DeliberateTestException(); }));
329             AssertThrows.Wrapped<DeliberateTestException>(() => UnorderedSources.Default(2).Aggregate(0, (i, j) => { throw new DeliberateTestException(); }, i => i));
330             AssertThrows.Wrapped<DeliberateTestException>(() => UnorderedSources.Default(2).Aggregate<int, int, int>(0, (i, j) => i, i => { throw new DeliberateTestException(); }));
331             AssertThrows.Wrapped<DeliberateTestException>(() => UnorderedSources.Default(2).Aggregate(0, (i, j) => { throw new DeliberateTestException(); }, (i, j) => i, i => i));
332             AssertThrows.Wrapped<DeliberateTestException>(() => UnorderedSources.Default(2).Aggregate<int, int, int>(0, (i, j) => i, (i, j) => i, i => { throw new DeliberateTestException(); }));
333             AssertThrows.Wrapped<DeliberateTestException>(() => UnorderedSources.Default(2).Aggregate<int, int, int>(() => { throw new DeliberateTestException(); }, (i, j) => i, (i, j) => i, i => i));
334             AssertThrows.Wrapped<DeliberateTestException>(() => UnorderedSources.Default(2).Aggregate(() => 0, (i, j) => { throw new DeliberateTestException(); }, (i, j) => i, i => i));
335             AssertThrows.Wrapped<DeliberateTestException>(() => UnorderedSources.Default(2).Aggregate<int, int, int>(() => 0, (i, j) => i, (i, j) => i, i => { throw new DeliberateTestException(); }));
336             if (Environment.ProcessorCount >= 2)
337             {
338                 AssertThrows.Wrapped<DeliberateTestException>(() => UnorderedSources.Default(2).Aggregate(0, (i, j) => i, (i, j) => { throw new DeliberateTestException(); }, i => i));
339                 AssertThrows.Wrapped<DeliberateTestException>(() => UnorderedSources.Default(2).Aggregate(() => 0, (i, j) => i, (i, j) => { throw new DeliberateTestException(); }, i => i));
340             }
341         }
342 
343         [Fact]
Aggregate_ArgumentNullException()344         public static void Aggregate_ArgumentNullException()
345         {
346             AssertExtensions.Throws<ArgumentNullException>("source", () => ((ParallelQuery<int>)null).Aggregate((i, j) => i));
347             AssertExtensions.Throws<ArgumentNullException>("func", () => UnorderedSources.Default(1).Aggregate(null));
348 
349             AssertExtensions.Throws<ArgumentNullException>("source", () => ((ParallelQuery<int>)null).Aggregate(0, (i, j) => i));
350             AssertExtensions.Throws<ArgumentNullException>("func", () => UnorderedSources.Default(1).Aggregate(0, null));
351 
352             AssertExtensions.Throws<ArgumentNullException>("source", () => ((ParallelQuery<int>)null).Aggregate(0, (i, j) => i, i => i));
353             AssertExtensions.Throws<ArgumentNullException>("func", () => UnorderedSources.Default(1).Aggregate(0, null, i => i));
354             AssertExtensions.Throws<ArgumentNullException>("resultSelector", () => UnorderedSources.Default(1).Aggregate<int, int, int>(0, (i, j) => i, null));
355 
356             AssertExtensions.Throws<ArgumentNullException>("source", () => ((ParallelQuery<int>)null).Aggregate(0, (i, j) => i, (i, j) => i, i => i));
357             AssertExtensions.Throws<ArgumentNullException>("updateAccumulatorFunc", () => UnorderedSources.Default(1).Aggregate(0, null, (i, j) => i, i => i));
358             AssertExtensions.Throws<ArgumentNullException>("combineAccumulatorsFunc", () => UnorderedSources.Default(1).Aggregate(0, (i, j) => i, null, i => i));
359             AssertExtensions.Throws<ArgumentNullException>("resultSelector", () => UnorderedSources.Default(1).Aggregate<int, int, int>(0, (i, j) => i, (i, j) => i, null));
360 
361             AssertExtensions.Throws<ArgumentNullException>("source", () => ((ParallelQuery<int>)null).Aggregate(() => 0, (i, j) => i, (i, j) => i, i => i));
362             AssertExtensions.Throws<ArgumentNullException>("seedFactory", () => UnorderedSources.Default(1).Aggregate<int, int, int>(null, (i, j) => i, (i, j) => i, i => i));
363             AssertExtensions.Throws<ArgumentNullException>("updateAccumulatorFunc", () => UnorderedSources.Default(1).Aggregate(() => 0, null, (i, j) => i, i => i));
364             AssertExtensions.Throws<ArgumentNullException>("combineAccumulatorsFunc", () => UnorderedSources.Default(1).Aggregate(() => 0, (i, j) => i, null, i => i));
365             AssertExtensions.Throws<ArgumentNullException>("resultSelector", () => UnorderedSources.Default(1).Aggregate<int, int, int>(() => 0, (i, j) => i, (i, j) => i, null));
366         }
367     }
368 }
369