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 SingleSingleOrDefaultTests
11     {
SingleSpecificData(int[] counts)12         public static IEnumerable<object[]> SingleSpecificData(int[] counts)
13         {
14             foreach (int count in counts.DefaultIfEmpty(Sources.OuterLoopCount))
15             {
16                 foreach (int position in new[] { 0, count / 2, Math.Max(0, count - 1) }.Distinct())
17                 {
18                     yield return new object[] { count, position };
19                 }
20             }
21         }
22 
23         //
24         // Single and SingleOrDefault
25         //
26         [Theory]
27         [InlineData(1)]
28         [InlineData("string")]
29         [InlineData((object)null)]
Single(T element)30         public static void Single<T>(T element)
31         {
32             Assert.Equal(element, ParallelEnumerable.Repeat(element, 1).Single());
33             Assert.Equal(element, ParallelEnumerable.Repeat(element, 1).Single(x => true));
34         }
35 
36         [Theory]
37         [InlineData(1, 0)]
38         [InlineData("string", 0)]
39         [InlineData((object)null, 0)]
40         [InlineData(1, 1)]
41         [InlineData("string", 1)]
42         [InlineData((object)null, 1)]
SingleOrDefault(T element, int count)43         public static void SingleOrDefault<T>(T element, int count)
44         {
45             Assert.Equal(count >= 1 ? element : default(T), ParallelEnumerable.Repeat(element, count).SingleOrDefault());
46             Assert.Equal(count >= 1 ? element : default(T), ParallelEnumerable.Repeat(element, count).SingleOrDefault(x => true));
47         }
48 
49         [Fact]
Single_Empty()50         public static void Single_Empty()
51         {
52             Assert.Throws<InvalidOperationException>(() => ParallelEnumerable.Empty<int>().Single());
53             Assert.Throws<InvalidOperationException>(() => ParallelEnumerable.Empty<int>().Single(x => true));
54         }
55 
56         [Theory]
57         [InlineData(1)]
58         [InlineData(2)]
59         [InlineData(16)]
Single_NoMatch(int count)60         public static void Single_NoMatch(int count)
61         {
62             IntegerRangeSet seen = new IntegerRangeSet(0, count);
63             Assert.Throws<InvalidOperationException>(() => ParallelEnumerable.Range(0, count).Single(x => !seen.Add(x)));
64             seen.AssertComplete();
65         }
66 
67         [Fact]
68         [OuterLoop]
Single_NoMatch_Longrunning()69         public static void Single_NoMatch_Longrunning()
70         {
71             Single_NoMatch(Sources.OuterLoopCount);
72         }
73 
74         [Theory]
75         [InlineData(0)]
76         [InlineData(1)]
77         [InlineData(2)]
78         [InlineData(16)]
SingleOrDefault_NoMatch(int count)79         public static void SingleOrDefault_NoMatch(int count)
80         {
81             IntegerRangeSet seen = new IntegerRangeSet(0, count);
82             Assert.Equal(default(int), ParallelEnumerable.Range(0, count).SingleOrDefault(x => !seen.Add(x)));
83             seen.AssertComplete();
84         }
85 
86         [Fact]
87         [OuterLoop]
SingleOrDefault_NoMatch_Longrunning()88         public static void SingleOrDefault_NoMatch_Longrunning()
89         {
90             SingleOrDefault_NoMatch(Sources.OuterLoopCount);
91         }
92 
93         [Theory]
94         [InlineData(2)]
95         [InlineData(16)]
Single_AllMatch(int count)96         public static void Single_AllMatch(int count)
97         {
98             Assert.Throws<InvalidOperationException>(() => ParallelEnumerable.Range(0, count).Single(x => true));
99         }
100 
101         [Fact]
102         [OuterLoop]
Single_AllMatch_Longrunning()103         public static void Single_AllMatch_Longrunning()
104         {
105             Single_AllMatch(Sources.OuterLoopCount);
106         }
107 
108         [Theory]
109         [InlineData(2)]
110         [InlineData(16)]
SingleOrDefault_AllMatch(int count)111         public static void SingleOrDefault_AllMatch(int count)
112         {
113             Assert.Throws<InvalidOperationException>(() => ParallelEnumerable.Range(0, count).SingleOrDefault(x => true));
114         }
115 
116         [Fact]
117         [OuterLoop]
SingleOrDefault_AllMatch_Longrunning()118         public static void SingleOrDefault_AllMatch_Longrunning()
119         {
120             SingleOrDefault_AllMatch(Sources.OuterLoopCount);
121         }
122 
123         [Theory]
124         [MemberData(nameof(SingleSpecificData), new[] { 1, 2, 16 })]
Single_OneMatch(int count, int element)125         public static void Single_OneMatch(int count, int element)
126         {
127             IntegerRangeSet seen = new IntegerRangeSet(0, count);
128             Assert.Equal(element, ParallelEnumerable.Range(0, count).Single(x => seen.Add(x) && x == element));
129             seen.AssertComplete();
130         }
131 
132         [Theory]
133         [OuterLoop]
134         [MemberData(nameof(SingleSpecificData), new int[] { /* Sources.OuterLoopCount */ })]
Single_OneMatch_Longrunning(int count, int element)135         public static void Single_OneMatch_Longrunning(int count, int element)
136         {
137             Single_OneMatch(count, element);
138         }
139 
140         [Theory]
141         [MemberData(nameof(SingleSpecificData), new[] { 0, 1, 2, 16 })]
SingleOrDefault_OneMatch(int count, int element)142         public static void SingleOrDefault_OneMatch(int count, int element)
143         {
144             IntegerRangeSet seen = new IntegerRangeSet(0, count);
145             Assert.Equal(element, ParallelEnumerable.Range(0, count).SingleOrDefault(x => seen.Add(x) && x == element));
146             seen.AssertComplete();
147         }
148 
149         [Theory]
150         [OuterLoop]
151         [MemberData(nameof(SingleSpecificData), new int[] { /* Sources.OuterLoopCount */ })]
SingleOrDefault_OneMatch_Longrunning(int count, int element)152         public static void SingleOrDefault_OneMatch_Longrunning(int count, int element)
153         {
154             SingleOrDefault_OneMatch(count, element);
155         }
156 
157         [Fact]
Single_OperationCanceledException()158         public static void Single_OperationCanceledException()
159         {
160             AssertThrows.EventuallyCanceled((source, canceler) => source.Single(x => { canceler(); return false; }));
161         }
162 
163         [Fact]
SingleOrDefault_OperationCanceledException()164         public static void SingleOrDefault_OperationCanceledException()
165         {
166             AssertThrows.EventuallyCanceled((source, canceler) => source.SingleOrDefault(x => { canceler(); return false; }));
167         }
168 
169         [Fact]
Single_AggregateException_Wraps_OperationCanceledException()170         public static void Single_AggregateException_Wraps_OperationCanceledException()
171         {
172             AssertThrows.OtherTokenCanceled((source, canceler) => source.Single(x => { canceler(); return false; }));
173             AssertThrows.SameTokenNotCanceled((source, canceler) => source.Single(x => { canceler(); return false; }));
174         }
175 
176         [Fact]
SingleOrDefault_AggregateException_Wraps_OperationCanceledException()177         public static void SingleOrDefault_AggregateException_Wraps_OperationCanceledException()
178         {
179             AssertThrows.OtherTokenCanceled((source, canceler) => source.SingleOrDefault(x => { canceler(); return false; }));
180             AssertThrows.SameTokenNotCanceled((source, canceler) => source.SingleOrDefault(x => { canceler(); return false; }));
181         }
182 
183         [Fact]
Single_OperationCanceledException_PreCanceled()184         public static void Single_OperationCanceledException_PreCanceled()
185         {
186             AssertThrows.AlreadyCanceled(source => source.Single());
187             AssertThrows.AlreadyCanceled(source => source.Single(x => true));
188         }
189 
190         [Fact]
SingleOrDefault_OperationCanceledException_PreCanceled()191         public static void SingleOrDefault_OperationCanceledException_PreCanceled()
192         {
193             AssertThrows.AlreadyCanceled(source => source.SingleOrDefault());
194             AssertThrows.AlreadyCanceled(source => source.SingleOrDefault(x => true));
195         }
196 
197         [Fact]
Single_AggregateException()198         public static void Single_AggregateException()
199         {
200             AssertThrows.Wrapped<DeliberateTestException>(() => ParallelEnumerable.Range(0, 1).Single(x => { throw new DeliberateTestException(); }));
201             AssertThrows.Wrapped<DeliberateTestException>(() => ParallelEnumerable.Range(0, 1).SingleOrDefault(x => { throw new DeliberateTestException(); }));
202         }
203 
204         [Fact]
Single_ArgumentNullException()205         public static void Single_ArgumentNullException()
206         {
207             AssertExtensions.Throws<ArgumentNullException>("source", () => ((ParallelQuery<bool>)null).Single());
208             AssertExtensions.Throws<ArgumentNullException>("source", () => ((ParallelQuery<bool>)null).SingleOrDefault());
209 
210             AssertExtensions.Throws<ArgumentNullException>("predicate", () => ParallelEnumerable.Empty<int>().Single(null));
211             AssertExtensions.Throws<ArgumentNullException>("predicate", () => ParallelEnumerable.Empty<int>().SingleOrDefault(null));
212         }
213     }
214 }
215