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; 6 using System.Collections.Generic; 7 using System.Threading; 8 using Xunit; 9 10 namespace System.Linq.Parallel.Tests 11 { 12 public static class SequenceEqualTests 13 { 14 private const int DuplicateFactor = 8; 15 16 // 17 // SequenceEqual 18 // SequenceEqualData(int[] counts)19 public static IEnumerable<object[]> SequenceEqualData(int[] counts) 20 { 21 foreach (object[] left in Sources.Ranges(counts.DefaultIfEmpty(Sources.OuterLoopCount / 4))) 22 { 23 foreach (object[] right in Sources.Ranges(new[] { (int)left[1] })) 24 { 25 yield return new object[] { left[0], right[0], right[1] }; 26 } 27 } 28 } 29 SequenceEqualUnequalSizeData(int[] counts)30 public static IEnumerable<object[]> SequenceEqualUnequalSizeData(int[] counts) 31 { 32 foreach (object[] left in Sources.Ranges(counts.DefaultIfEmpty(Sources.OuterLoopCount / 4))) 33 { 34 foreach (object[] right in Sources.Ranges(new[] { 1, ((int)left[1] - 1) / 2 + 1, (int)left[1] * 2 + 1 }.Distinct())) 35 { 36 yield return new object[] { left[0], left[1], right[0], right[1] }; 37 } 38 } 39 } 40 SequenceEqualUnequalData(int[] counts)41 public static IEnumerable<object[]> SequenceEqualUnequalData(int[] counts) 42 { 43 foreach (object[] left in Sources.Ranges(counts.DefaultIfEmpty(Sources.OuterLoopCount / 4))) 44 { 45 Func<int, IEnumerable<int>> items = x => new[] { 0, x / 8, x / 2, x * 7 / 8, x - 1 }.Distinct(); 46 foreach (object[] right in Sources.Ranges(new[] { (int)left[1] }, items)) 47 { 48 yield return new object[] { left[0], right[0], right[1], right[2] }; 49 } 50 } 51 } 52 53 [Theory] 54 [MemberData(nameof(SequenceEqualData), new[] { 0, 1, 2, 16 })] SequenceEqual(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count)55 public static void SequenceEqual(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count) 56 { 57 ParallelQuery<int> leftQuery = left.Item; 58 ParallelQuery<int> rightQuery = right.Item; 59 Assert.True(leftQuery.SequenceEqual(rightQuery)); 60 Assert.True(rightQuery.SequenceEqual(leftQuery)); 61 Assert.True(leftQuery.SequenceEqual(leftQuery)); 62 } 63 64 [Theory] 65 [OuterLoop] 66 [MemberData(nameof(SequenceEqualData), new int[] { /* Sources.OuterLoopCount */ })] SequenceEqual_Longrunning(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count)67 public static void SequenceEqual_Longrunning(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count) 68 { 69 SequenceEqual(left, right, count); 70 } 71 72 [Theory] 73 [MemberData(nameof(SequenceEqualData), new[] { 0, 1, 2, 16 })] SequenceEqual_CustomComparator(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count)74 public static void SequenceEqual_CustomComparator(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count) 75 { 76 ParallelQuery<int> leftQuery = left.Item; 77 ParallelQuery<int> rightQuery = right.Item; 78 Assert.True(leftQuery.SequenceEqual(rightQuery, new ModularCongruenceComparer(DuplicateFactor))); 79 Assert.True(rightQuery.SequenceEqual(leftQuery, new ModularCongruenceComparer(DuplicateFactor))); 80 Assert.True(leftQuery.SequenceEqual(leftQuery, new ModularCongruenceComparer(DuplicateFactor))); 81 82 ParallelQuery<int> repeating = Enumerable.Range(0, (count + (DuplicateFactor - 1)) / DuplicateFactor).SelectMany(x => Enumerable.Range(0, DuplicateFactor)).Take(count).AsParallel().AsOrdered(); 83 Assert.True(leftQuery.SequenceEqual(repeating, new ModularCongruenceComparer(DuplicateFactor))); 84 Assert.True(rightQuery.SequenceEqual(repeating, new ModularCongruenceComparer(DuplicateFactor))); 85 Assert.True(repeating.SequenceEqual(rightQuery, new ModularCongruenceComparer(DuplicateFactor))); 86 Assert.True(repeating.SequenceEqual(leftQuery, new ModularCongruenceComparer(DuplicateFactor))); 87 } 88 89 [Theory] 90 [OuterLoop] 91 [MemberData(nameof(SequenceEqualData), new int[] { /* Sources.OuterLoopCount */ })] SequenceEqual_CustomComparator_Longrunning(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count)92 public static void SequenceEqual_CustomComparator_Longrunning(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count) 93 { 94 SequenceEqual_CustomComparator(left, right, count); 95 } 96 97 [Theory] 98 [MemberData(nameof(SequenceEqualUnequalSizeData), new[] { 0, 4, 16 })] SequenceEqual_UnequalSize(Labeled<ParallelQuery<int>> left, int leftCount, Labeled<ParallelQuery<int>> right, int rightCount)99 public static void SequenceEqual_UnequalSize(Labeled<ParallelQuery<int>> left, int leftCount, Labeled<ParallelQuery<int>> right, int rightCount) 100 { 101 ParallelQuery<int> leftQuery = left.Item; 102 ParallelQuery<int> rightQuery = right.Item; 103 Assert.False(leftQuery.SequenceEqual(rightQuery)); 104 Assert.False(rightQuery.SequenceEqual(leftQuery)); 105 Assert.False(leftQuery.SequenceEqual(rightQuery, new ModularCongruenceComparer(2))); 106 Assert.False(rightQuery.SequenceEqual(leftQuery, new ModularCongruenceComparer(2))); 107 } 108 109 [Theory] 110 [OuterLoop] 111 [MemberData(nameof(SequenceEqualUnequalSizeData), new int[] { /* Sources.OuterLoopCount */ })] SequenceEqual_UnequalSize_Longrunning(Labeled<ParallelQuery<int>> left, int leftCount, Labeled<ParallelQuery<int>> right, int rightCount)112 public static void SequenceEqual_UnequalSize_Longrunning(Labeled<ParallelQuery<int>> left, int leftCount, Labeled<ParallelQuery<int>> right, int rightCount) 113 { 114 SequenceEqual_UnequalSize(left, leftCount, right, rightCount); 115 } 116 117 [Theory] 118 [MemberData(nameof(SequenceEqualUnequalData), new[] { 1, 2, 16 })] SequenceEqual_Unequal(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count, int item)119 public static void SequenceEqual_Unequal(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count, int item) 120 { 121 ParallelQuery<int> leftQuery = left.Item; 122 ParallelQuery<int> rightQuery = right.Item.Select(x => x == item ? -1 : x); 123 124 Assert.False(leftQuery.SequenceEqual(rightQuery)); 125 Assert.False(rightQuery.SequenceEqual(leftQuery)); 126 Assert.True(leftQuery.SequenceEqual(leftQuery)); 127 } 128 129 [Theory] 130 [OuterLoop] 131 [MemberData(nameof(SequenceEqualUnequalData), new int[] { /* Sources.OuterLoopCount */ })] SequenceEqual_Unequal_Longrunning(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count, int item)132 public static void SequenceEqual_Unequal_Longrunning(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count, int item) 133 { 134 SequenceEqual_Unequal(left, right, count, item); 135 } 136 SequenceEqual_NotSupportedException()137 public static void SequenceEqual_NotSupportedException() 138 { 139 #pragma warning disable 618 140 Assert.Throws<NotSupportedException>(() => ParallelEnumerable.Range(0, 1).SequenceEqual(Enumerable.Range(0, 1))); 141 Assert.Throws<NotSupportedException>(() => ParallelEnumerable.Range(0, 1).SequenceEqual(Enumerable.Range(0, 1), null)); 142 #pragma warning restore 618 143 } 144 145 [Fact] SequenceEqual_OperationCanceledException()146 public static void SequenceEqual_OperationCanceledException() 147 { 148 AssertThrows.EventuallyCanceled((source, canceler) => source.OrderBy(x => x).SequenceEqual(ParallelEnumerable.Range(0, 128).AsOrdered(), new CancelingEqualityComparer<int>(canceler))); 149 AssertThrows.EventuallyCanceled((source, canceler) => ParallelEnumerable.Range(0, 128).AsOrdered().SequenceEqual(source.OrderBy(x => x), new CancelingEqualityComparer<int>(canceler))); 150 } 151 152 [Fact] SequenceEqual_AggregateException_Wraps_OperationCanceledException()153 public static void SequenceEqual_AggregateException_Wraps_OperationCanceledException() 154 { 155 AssertThrows.OtherTokenCanceled((source, canceler) => source.OrderBy(x => x).SequenceEqual(ParallelEnumerable.Range(0, 128).AsOrdered(), new CancelingEqualityComparer<int>(canceler))); 156 AssertThrows.OtherTokenCanceled((source, canceler) => ParallelEnumerable.Range(0, 128).AsOrdered().SequenceEqual(source.OrderBy(x => x), new CancelingEqualityComparer<int>(canceler))); 157 AssertThrows.SameTokenNotCanceled((source, canceler) => source.OrderBy(x => x).SequenceEqual(ParallelEnumerable.Range(0, 128).AsOrdered(), new CancelingEqualityComparer<int>(canceler))); 158 AssertThrows.SameTokenNotCanceled((source, canceler) => ParallelEnumerable.Range(0, 128).AsOrdered().SequenceEqual(source.OrderBy(x => x), new CancelingEqualityComparer<int>(canceler))); 159 } 160 161 [Fact] SequenceEqual_OperationCanceledException_PreCanceled()162 public static void SequenceEqual_OperationCanceledException_PreCanceled() 163 { 164 AssertThrows.AlreadyCanceled(source => source.SequenceEqual(ParallelEnumerable.Range(0, 2))); 165 AssertThrows.AlreadyCanceled(source => source.SequenceEqual(ParallelEnumerable.Range(0, 2), new ModularCongruenceComparer(1))); 166 167 AssertThrows.AlreadyCanceled(source => ParallelEnumerable.Range(0, 2).SequenceEqual(source)); 168 AssertThrows.AlreadyCanceled(source => ParallelEnumerable.Range(0, 2).SequenceEqual(source, new ModularCongruenceComparer(1))); 169 } 170 171 [Theory] 172 [MemberData(nameof(SequenceEqualData), new[] { 4 })] SequenceEqual_AggregateException(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count)173 public static void SequenceEqual_AggregateException(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count) 174 { 175 AssertThrows.Wrapped<DeliberateTestException>(() => left.Item.SequenceEqual(right.Item, new FailingEqualityComparer<int>())); 176 } 177 178 [Fact] 179 // Should not get the same setting from both operands. SequenceEqual_NoDuplicateSettings()180 public static void SequenceEqual_NoDuplicateSettings() 181 { 182 CancellationToken t = new CancellationTokenSource().Token; 183 Assert.Throws<InvalidOperationException>(() => ParallelEnumerable.Range(0, 1).WithCancellation(t).SequenceEqual(ParallelEnumerable.Range(0, 1).WithCancellation(t))); 184 Assert.Throws<InvalidOperationException>(() => ParallelEnumerable.Range(0, 1).WithDegreeOfParallelism(1).SequenceEqual(ParallelEnumerable.Range(0, 1).WithDegreeOfParallelism(1))); 185 Assert.Throws<InvalidOperationException>(() => ParallelEnumerable.Range(0, 1).WithExecutionMode(ParallelExecutionMode.Default).SequenceEqual(ParallelEnumerable.Range(0, 1).WithExecutionMode(ParallelExecutionMode.Default))); 186 Assert.Throws<InvalidOperationException>(() => ParallelEnumerable.Range(0, 1).WithMergeOptions(ParallelMergeOptions.Default).SequenceEqual(ParallelEnumerable.Range(0, 1).WithMergeOptions(ParallelMergeOptions.Default))); 187 } 188 189 [Fact] SequenceEqual_ArgumentNullException()190 public static void SequenceEqual_ArgumentNullException() 191 { 192 AssertExtensions.Throws<ArgumentNullException>("first", () => ((ParallelQuery<int>)null).SequenceEqual(ParallelEnumerable.Range(0, 1))); 193 AssertExtensions.Throws<ArgumentNullException>("second", () => ParallelEnumerable.Range(0, 1).SequenceEqual((ParallelQuery<int>)null)); 194 AssertExtensions.Throws<ArgumentNullException>("first", () => ((ParallelQuery<int>)null).SequenceEqual(ParallelEnumerable.Range(0, 1), EqualityComparer<int>.Default)); 195 AssertExtensions.Throws<ArgumentNullException>("second", () => ParallelEnumerable.Range(0, 1).SequenceEqual((ParallelQuery<int>)null, EqualityComparer<int>.Default)); 196 } 197 198 [Theory] 199 [MemberData(nameof(SequenceEqualData), new[] { 0, 1, 2, 16 })] SequenceEqual_DisposeException(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count)200 public static void SequenceEqual_DisposeException(Labeled<ParallelQuery<int>> left, Labeled<ParallelQuery<int>> right, int count) 201 { 202 ParallelQuery<int> leftQuery = left.Item; 203 ParallelQuery<int> rightQuery = right.Item; 204 205 AssertThrows.Wrapped<TestDisposeException>(() => leftQuery.SequenceEqual(new DisposeExceptionEnumerable<int>(rightQuery).AsParallel())); 206 AssertThrows.Wrapped<TestDisposeException>(() => new DisposeExceptionEnumerable<int>(leftQuery).AsParallel().SequenceEqual(rightQuery)); 207 } 208 209 private class DisposeExceptionEnumerable<T> : IEnumerable<T> 210 { 211 private IEnumerable<T> _enumerable; 212 DisposeExceptionEnumerable(IEnumerable<T> enumerable)213 public DisposeExceptionEnumerable(IEnumerable<T> enumerable) 214 { 215 _enumerable = enumerable; 216 } 217 GetEnumerator()218 public IEnumerator<T> GetEnumerator() 219 { 220 return new DisposeExceptionEnumerator(_enumerable.GetEnumerator()); 221 } 222 IEnumerable.GetEnumerator()223 IEnumerator IEnumerable.GetEnumerator() 224 { 225 return GetEnumerator(); 226 } 227 228 private class DisposeExceptionEnumerator : IEnumerator<T> 229 { 230 private IEnumerator<T> _enumerator; 231 DisposeExceptionEnumerator(IEnumerator<T> enumerator)232 public DisposeExceptionEnumerator(IEnumerator<T> enumerator) 233 { 234 _enumerator = enumerator; 235 } 236 237 public T Current 238 { 239 get { return _enumerator.Current; } 240 } 241 Dispose()242 public void Dispose() 243 { 244 throw new TestDisposeException(); 245 } 246 247 object IEnumerator.Current 248 { 249 get { return Current; } 250 } 251 MoveNext()252 public bool MoveNext() 253 { 254 return _enumerator.MoveNext(); 255 } 256 Reset()257 public void Reset() 258 { 259 _enumerator.Reset(); 260 } 261 } 262 } 263 264 private class TestDisposeException : Exception 265 { 266 } 267 } 268 } 269