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