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