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 Xunit;
7 
8 namespace System.Linq.Parallel.Tests
9 {
10     public static class TakeTakeWhileTests
11     {
12         private static readonly Func<int, IEnumerable<int>> TakePosition = x => new[] { -x, -1, 0, 1, x / 2, x, x * 2 }.Distinct();
13 
14         //
15         // Take
16         //
17 
TakeUnorderedData(int[] counts)18         public static IEnumerable<object[]> TakeUnorderedData(int[] counts)
19         {
20             foreach (int count in counts.DefaultIfEmpty(Sources.OuterLoopCount / 4))
21             {
22                 foreach (int position in TakePosition(count))
23                 {
24                     yield return new object[] { count, position };
25                 }
26             }
27         }
28 
TakeData(int[] counts)29         public static IEnumerable<object[]> TakeData(int[] counts)
30         {
31             foreach (object[] results in Sources.Ranges(counts.DefaultIfEmpty(Sources.OuterLoopCount / 4), TakePosition)) yield return results;
32         }
33 
34         [Theory]
35         [MemberData(nameof(TakeUnorderedData), new[] { 0, 1, 2, 16 })]
Take_Unordered(int count, int take)36         public static void Take_Unordered(int count, int take)
37         {
38             // For unordered collections, which elements (if any) are taken isn't actually guaranteed, but an effect of the implementation.
39             // If this test starts failing it should be updated, and possibly mentioned in release notes.
40             IntegerRangeSet seen = new IntegerRangeSet(0, Math.Min(count, Math.Max(0, take)));
41             foreach (int i in UnorderedSources.Default(count).Take(take))
42             {
43                 seen.Add(i);
44             }
45             seen.AssertComplete();
46         }
47 
48         [Theory]
49         [OuterLoop]
50         [MemberData(nameof(TakeUnorderedData), new int[] { /* Sources.OuterLoopCount */ })]
Take_Unordered_Longrunning(int count, int take)51         public static void Take_Unordered_Longrunning(int count, int take)
52         {
53             Take_Unordered(count, take);
54         }
55 
56         [Theory]
57         [MemberData(nameof(TakeData), new[] { 0, 1, 2, 16 })]
Take(Labeled<ParallelQuery<int>> labeled, int count, int take)58         public static void Take(Labeled<ParallelQuery<int>> labeled, int count, int take)
59         {
60             ParallelQuery<int> query = labeled.Item;
61             int seen = 0;
62             foreach (int i in query.Take(take))
63             {
64                 Assert.Equal(seen++, i);
65             }
66             Assert.Equal(Math.Min(count, Math.Max(0, take)), seen);
67         }
68 
69         [Theory]
70         [OuterLoop]
71         [MemberData(nameof(TakeData), new int[] { /* Sources.OuterLoopCount */ })]
Take_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int take)72         public static void Take_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int take)
73         {
74             Take(labeled, count, take);
75         }
76 
77         [Theory]
78         [MemberData(nameof(TakeUnorderedData), new[] { 0, 1, 2, 16 })]
Take_Unordered_NotPipelined(int count, int take)79         public static void Take_Unordered_NotPipelined(int count, int take)
80         {
81             // For unordered collections, which elements (if any) are taken isn't actually guaranteed, but an effect of the implementation.
82             // If this test starts failing it should be updated, and possibly mentioned in release notes.
83             IntegerRangeSet seen = new IntegerRangeSet(0, Math.Min(count, Math.Max(0, take)));
84             Assert.All(UnorderedSources.Default(count).Take(take).ToList(), x => seen.Add(x));
85             seen.AssertComplete();
86         }
87 
88         [Theory]
89         [OuterLoop]
90         [MemberData(nameof(TakeUnorderedData), new int[] { /* Sources.OuterLoopCount */ })]
Take_Unordered_NotPipelined_Longrunning(int count, int take)91         public static void Take_Unordered_NotPipelined_Longrunning(int count, int take)
92         {
93             Take_Unordered_NotPipelined(count, take);
94         }
95 
96         [Theory]
97         [MemberData(nameof(TakeData), new[] { 0, 1, 2, 16 })]
Take_NotPipelined(Labeled<ParallelQuery<int>> labeled, int count, int take)98         public static void Take_NotPipelined(Labeled<ParallelQuery<int>> labeled, int count, int take)
99         {
100             ParallelQuery<int> query = labeled.Item;
101             int seen = 0;
102             Assert.All(query.Take(take).ToList(), x => Assert.Equal(seen++, x));
103             Assert.Equal(Math.Min(count, Math.Max(0, take)), seen);
104         }
105 
106         [Theory]
107         [OuterLoop]
108         [MemberData(nameof(TakeData), new int[] { /* Sources.OuterLoopCount */ })]
Take_NotPipelined_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int take)109         public static void Take_NotPipelined_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int take)
110         {
111             Take_NotPipelined(labeled, count, take);
112         }
113 
114         [Fact]
Take_ArgumentNullException()115         public static void Take_ArgumentNullException()
116         {
117             AssertExtensions.Throws<ArgumentNullException>("source", () => ((ParallelQuery<bool>)null).Take(0));
118         }
119 
120         //
121         // TakeWhile
122         //
TakeWhileData(int[] counts)123         public static IEnumerable<object[]> TakeWhileData(int[] counts)
124         {
125             foreach (object[] results in Sources.Ranges(counts.DefaultIfEmpty(Sources.OuterLoopCount / 4)))
126             {
127                 yield return new[] { results[0], results[1], new[] { 0 } };
128                 yield return new[] { results[0], results[1], Enumerable.Range((int)results[1] / 2, ((int)results[1] - 1) / 2 + 1).ToArray() };
129                 yield return new[] { results[0], results[1], new[] { (int)results[1] - 1 } };
130             }
131         }
132 
133         [Theory]
134         [MemberData(nameof(TakeUnorderedData), new[] { 0, 1, 2, 16 })]
TakeWhile_Unordered(int count, int take)135         public static void TakeWhile_Unordered(int count, int take)
136         {
137             // For unordered collections, which elements (if any) are taken isn't actually guaranteed, but an effect of the implementation.
138             // If this test starts failing it should be updated, and possibly mentioned in release notes.
139             IntegerRangeSet seen = new IntegerRangeSet(0, Math.Min(count, Math.Max(0, take)));
140             foreach (int i in UnorderedSources.Default(count).TakeWhile(x => x < take))
141             {
142                 seen.Add(i);
143             }
144             seen.AssertComplete();
145         }
146 
147         [Theory]
148         [OuterLoop]
149         [MemberData(nameof(TakeUnorderedData), new int[] { /* Sources.OuterLoopCount */ })]
TakeWhile_Unordered_Longrunning(int count, int take)150         public static void TakeWhile_Unordered_Longrunning(int count, int take)
151         {
152             TakeWhile_Unordered(count, take);
153         }
154 
155         [Theory]
156         [MemberData(nameof(TakeData), new[] { 0, 1, 2, 16 })]
TakeWhile(Labeled<ParallelQuery<int>> labeled, int count, int take)157         public static void TakeWhile(Labeled<ParallelQuery<int>> labeled, int count, int take)
158         {
159             ParallelQuery<int> query = labeled.Item;
160             int seen = 0;
161             foreach (int i in query.TakeWhile(x => x < take))
162             {
163                 Assert.Equal(seen++, i);
164             }
165             Assert.Equal(Math.Min(count, Math.Max(0, take)), seen);
166         }
167 
168         [Theory]
169         [OuterLoop]
170         [MemberData(nameof(TakeData), new int[] { /* Sources.OuterLoopCount */ })]
TakeWhile_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int take)171         public static void TakeWhile_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int take)
172         {
173             TakeWhile(labeled, count, take);
174         }
175 
176         [Theory]
177         [MemberData(nameof(TakeUnorderedData), new[] { 0, 1, 2, 16 })]
TakeWhile_Unordered_NotPipelined(int count, int take)178         public static void TakeWhile_Unordered_NotPipelined(int count, int take)
179         {
180             // For unordered collections, which elements (if any) are taken isn't actually guaranteed, but an effect of the implementation.
181             // If this test starts failing it should be updated, and possibly mentioned in release notes.
182             IntegerRangeSet seen = new IntegerRangeSet(0, Math.Min(count, Math.Max(0, take)));
183             Assert.All(UnorderedSources.Default(count).TakeWhile(x => x < take).ToList(), x => seen.Add(x));
184             seen.AssertComplete();
185         }
186 
187         [Theory]
188         [OuterLoop]
189         [MemberData(nameof(TakeUnorderedData), new int[] { /* Sources.OuterLoopCount */ })]
TakeWhile_Unordered_NotPipelined_Longrunning(int count, int take)190         public static void TakeWhile_Unordered_NotPipelined_Longrunning(int count, int take)
191         {
192             TakeWhile_Unordered_NotPipelined(count, take);
193         }
194 
195         [Theory]
196         [MemberData(nameof(TakeData), new[] { 0, 1, 2, 16 })]
TakeWhile_NotPipelined(Labeled<ParallelQuery<int>> labeled, int count, int take)197         public static void TakeWhile_NotPipelined(Labeled<ParallelQuery<int>> labeled, int count, int take)
198         {
199             ParallelQuery<int> query = labeled.Item;
200             int seen = 0;
201             Assert.All(query.TakeWhile(x => x < take).ToList(), x => Assert.Equal(seen++, x));
202             Assert.Equal(Math.Min(count, Math.Max(0, take)), seen);
203         }
204 
205         [Theory]
206         [OuterLoop]
207         [MemberData(nameof(TakeData), new int[] { /* Sources.OuterLoopCount */ })]
TakeWhile_NotPipelined_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int take)208         public static void TakeWhile_NotPipelined_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int take)
209         {
210             TakeWhile_NotPipelined(labeled, count, take);
211         }
212 
213         [Theory]
214         [MemberData(nameof(TakeUnorderedData), new[] { 0, 1, 2, 16 })]
TakeWhile_Indexed_Unordered(int count, int take)215         public static void TakeWhile_Indexed_Unordered(int count, int take)
216         {
217             // For unordered collections, which elements (if any) are taken isn't actually guaranteed, but an effect of the implementation.
218             // If this test starts failing it should be updated, and possibly mentioned in release notes.
219             IntegerRangeSet seen = new IntegerRangeSet(0, Math.Min(count, Math.Max(0, take)));
220             foreach (int i in UnorderedSources.Default(count).TakeWhile((x, index) => index < take))
221             {
222                 seen.Add(i);
223             }
224             seen.AssertComplete();
225         }
226 
227         [Theory]
228         [OuterLoop]
229         [MemberData(nameof(TakeUnorderedData), new int[] { /* Sources.OuterLoopCount */ })]
TakeWhile_Indexed_Unordered_Longrunning(int count, int take)230         public static void TakeWhile_Indexed_Unordered_Longrunning(int count, int take)
231         {
232             TakeWhile_Indexed_Unordered(count, take);
233         }
234 
235         [Theory]
236         [MemberData(nameof(TakeData), new[] { 0, 1, 2, 16 })]
TakeWhile_Indexed(Labeled<ParallelQuery<int>> labeled, int count, int take)237         public static void TakeWhile_Indexed(Labeled<ParallelQuery<int>> labeled, int count, int take)
238         {
239             ParallelQuery<int> query = labeled.Item;
240             int seen = 0;
241             foreach (int i in query.TakeWhile((x, index) => index < take))
242             {
243                 Assert.Equal(seen++, i);
244             }
245             Assert.Equal(Math.Min(count, Math.Max(0, take)), seen);
246         }
247 
248         [Theory]
249         [OuterLoop]
250         [MemberData(nameof(TakeData), new int[] { /* Sources.OuterLoopCount */ })]
TakeWhile_Indexed_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int take)251         public static void TakeWhile_Indexed_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int take)
252         {
253             TakeWhile_Indexed(labeled, count, take);
254         }
255 
256         [Theory]
257         [MemberData(nameof(TakeUnorderedData), new[] { 0, 1, 2, 16 })]
TakeWhile_Indexed_Unordered_NotPipelined(int count, int take)258         public static void TakeWhile_Indexed_Unordered_NotPipelined(int count, int take)
259         {
260             // For unordered collections, which elements (if any) are taken isn't actually guaranteed, but an effect of the implementation.
261             // If this test starts failing it should be updated, and possibly mentioned in release notes.
262             IntegerRangeSet seen = new IntegerRangeSet(0, Math.Min(count, Math.Max(0, take)));
263             Assert.All(UnorderedSources.Default(count).TakeWhile((x, index) => index < take).ToList(), x => seen.Add(x));
264             seen.AssertComplete();
265         }
266 
267         [Theory]
268         [OuterLoop]
269         [MemberData(nameof(TakeUnorderedData), new int[] { /* Sources.OuterLoopCount */ })]
TakeWhile_Indexed_Unordered_NotPipelined_Longrunning(int count, int take)270         public static void TakeWhile_Indexed_Unordered_NotPipelined_Longrunning(int count, int take)
271         {
272             TakeWhile_Indexed_Unordered_NotPipelined(count, take);
273         }
274 
275         [Theory]
276         [MemberData(nameof(TakeData), new[] { 0, 1, 2, 16 })]
TakeWhile_Indexed_NotPipelined(Labeled<ParallelQuery<int>> labeled, int count, int take)277         public static void TakeWhile_Indexed_NotPipelined(Labeled<ParallelQuery<int>> labeled, int count, int take)
278         {
279             ParallelQuery<int> query = labeled.Item;
280             int seen = 0;
281             Assert.All(query.TakeWhile((x, index) => index < take).ToList(), x => Assert.Equal(seen++, x));
282             Assert.Equal(Math.Min(count, Math.Max(0, take)), seen);
283         }
284 
285         [Theory]
286         [OuterLoop]
287         [MemberData(nameof(TakeData), new int[] { /* Sources.OuterLoopCount */ })]
TakeWhile_Indexed_NotPipelined_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int take)288         public static void TakeWhile_Indexed_NotPipelined_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int take)
289         {
290             TakeWhile_Indexed_NotPipelined(labeled, count, take);
291         }
292 
293         [Theory]
294         [MemberData(nameof(TakeUnorderedData), new[] { 0, 1, 2, 16 })]
TakeWhile_AllFalse(int count, int take)295         public static void TakeWhile_AllFalse(int count, int take)
296         {
297             Assert.Empty(UnorderedSources.Default(count).TakeWhile(x => false));
298         }
299 
300         [Theory]
301         [OuterLoop]
302         [MemberData(nameof(TakeUnorderedData), new int[] { /* Sources.OuterLoopCount */ })]
TakeWhile_AllFalse_Longrunning(int count, int take)303         public static void TakeWhile_AllFalse_Longrunning(int count, int take)
304         {
305             TakeWhile_AllFalse(count, take);
306         }
307 
308         [Theory]
309         [MemberData(nameof(TakeData), new[] { 0, 1, 2, 16 })]
TakeWhile_AllTrue(Labeled<ParallelQuery<int>> labeled, int count, int take)310         public static void TakeWhile_AllTrue(Labeled<ParallelQuery<int>> labeled, int count, int take)
311         {
312             ParallelQuery<int> query = labeled.Item;
313             int seen = 0;
314             Assert.All(query.TakeWhile(x => true), x => Assert.Equal(seen++, x));
315             Assert.Equal(count, seen);
316         }
317 
318         [Theory]
319         [OuterLoop]
320         [MemberData(nameof(TakeData), new int[] { /* Sources.OuterLoopCount */ })]
TakeWhile_AllTrue_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int take)321         public static void TakeWhile_AllTrue_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int take)
322         {
323             TakeWhile_AllTrue(labeled, count, take);
324         }
325 
326         [Theory]
327         [MemberData(nameof(TakeWhileData), new[] { 2, 16 })]
TakeWhile_SomeTrue(Labeled<ParallelQuery<int>> labeled, int count, int[] take)328         public static void TakeWhile_SomeTrue(Labeled<ParallelQuery<int>> labeled, int count, int[] take)
329         {
330             ParallelQuery<int> query = labeled.Item;
331             int seen = 0;
332             Assert.All(query.TakeWhile(x => take.Contains(x)), x => Assert.Equal(seen++, x));
333             Assert.Equal(take.Min() > 0 ? 0 : take.Max() + 1, seen);
334         }
335 
336         [Theory]
337         [OuterLoop]
338         [MemberData(nameof(TakeWhileData), new int[] { /* Sources.OuterLoopCount */ })]
TakeWhile_SomeTrue_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int[] take)339         public static void TakeWhile_SomeTrue_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int[] take)
340         {
341             TakeWhile_SomeTrue(labeled, count, take);
342         }
343 
344         [Theory]
345         [MemberData(nameof(TakeWhileData), new[] { 2, 16 })]
TakeWhile_SomeFalse(Labeled<ParallelQuery<int>> labeled, int count, int[] take)346         public static void TakeWhile_SomeFalse(Labeled<ParallelQuery<int>> labeled, int count, int[] take)
347         {
348             ParallelQuery<int> query = labeled.Item;
349             int seen = 0;
350             Assert.All(query.TakeWhile(x => !take.Contains(x)), x => Assert.Equal(seen++, x));
351             Assert.Equal(take.Min(), seen);
352         }
353 
354         [Theory]
355         [OuterLoop]
356         [MemberData(nameof(TakeWhileData), new int[] { /* Sources.OuterLoopCount */ })]
TakeWhile_SomeFalse_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int[] take)357         public static void TakeWhile_SomeFalse_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int[] take)
358         {
359             TakeWhile_SomeFalse(labeled, count, take);
360         }
361 
362         [Fact]
TakeWhile_ArgumentNullException()363         public static void TakeWhile_ArgumentNullException()
364         {
365             AssertExtensions.Throws<ArgumentNullException>("source", () => ((ParallelQuery<bool>)null).TakeWhile(x => true));
366             AssertExtensions.Throws<ArgumentNullException>("predicate", () => ParallelEnumerable.Empty<bool>().TakeWhile((Func<bool, bool>)null));
367             AssertExtensions.Throws<ArgumentNullException>("predicate", () => ParallelEnumerable.Empty<bool>().TakeWhile((Func<bool, int, bool>)null));
368         }
369     }
370 }
371