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