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 DistinctTests
11     {
12         private const int DuplicateFactor = 4;
13 
DistinctUnorderedData(int[] counts)14         public static IEnumerable<object[]> DistinctUnorderedData(int[] counts)
15         {
16             foreach (int count in counts)
17             {
18                 yield return new object[] { count * DuplicateFactor, count };
19             }
20         }
21 
DistinctData(int[] counts)22         public static IEnumerable<object[]> DistinctData(int[] counts)
23         {
24             foreach (object[] results in Sources.Ranges(counts.Select(x => x * DuplicateFactor).DefaultIfEmpty(Sources.OuterLoopCount)))
25             {
26                 yield return new object[] { results[0], ((int)results[1]) / DuplicateFactor };
27             }
28         }
29 
DistinctSourceMultipleData(int[] counts)30         public static IEnumerable<object[]> DistinctSourceMultipleData(int[] counts)
31         {
32             foreach (int count in counts.DefaultIfEmpty(Sources.OuterLoopCount))
33             {
34                 int[] source = Enumerable.Range(0, count * DuplicateFactor).Select(x => x % count).ToArray();
35 
36                 yield return new object[] { Labeled.Label("Array", source.AsParallel().AsOrdered()), count };
37                 yield return new object[] { Labeled.Label("List", source.ToList().AsParallel().AsOrdered()), count };
38                 yield return new object[] { Labeled.Label("Enumerable", source.AsEnumerable().AsParallel().AsOrdered()), count };
39             }
40         }
41 
42         //
43         // Distinct
44         //
45         [Theory]
46         [MemberData(nameof(DistinctUnorderedData), new[] { 0, 1, 2, 16 })]
Distinct_Unordered(int count, int uniqueCount)47         public static void Distinct_Unordered(int count, int uniqueCount)
48         {
49             IntegerRangeSet seen = new IntegerRangeSet(0, uniqueCount);
50             foreach (int i in UnorderedSources.Default(count).Distinct(new ModularCongruenceComparer(uniqueCount)))
51             {
52                 seen.Add(i % uniqueCount);
53             }
54             seen.AssertComplete();
55         }
56 
57         [Fact]
58         [OuterLoop]
Distinct_Unordered_Longrunning()59         public static void Distinct_Unordered_Longrunning()
60         {
61             Distinct_Unordered(Sources.OuterLoopCount, Sources.OuterLoopCount / DuplicateFactor);
62         }
63 
64         [Theory]
65         [MemberData(nameof(DistinctData), new[] { 0, 1, 2, 16 })]
Distinct(Labeled<ParallelQuery<int>> labeled, int count)66         public static void Distinct(Labeled<ParallelQuery<int>> labeled, int count)
67         {
68             ParallelQuery<int> query = labeled.Item;
69             int seen = 0;
70             foreach (int i in query.Distinct(new ModularCongruenceComparer(count)))
71             {
72                 Assert.Equal(seen++, i % count);
73             }
74             Assert.Equal(count, seen);
75         }
76 
77         [Theory]
78         [OuterLoop]
79         [MemberData(nameof(DistinctData), new int[] { /* Sources.OuterLoopCount */ })]
Distinct_Longrunning(Labeled<ParallelQuery<int>> labeled, int count)80         public static void Distinct_Longrunning(Labeled<ParallelQuery<int>> labeled, int count)
81         {
82             Distinct(labeled, count);
83         }
84 
85         [Theory]
86         [MemberData(nameof(DistinctUnorderedData), new[] { 0, 1, 2, 16 })]
Distinct_Unordered_NotPipelined(int count, int uniqueCount)87         public static void Distinct_Unordered_NotPipelined(int count, int uniqueCount)
88         {
89             IntegerRangeSet seen = new IntegerRangeSet(0, uniqueCount);
90             Assert.All(UnorderedSources.Default(count).Distinct(new ModularCongruenceComparer(uniqueCount)).ToList(), x => seen.Add(x % uniqueCount));
91             seen.AssertComplete();
92         }
93 
94         [Fact]
95         [OuterLoop]
Distinct_Unordered_NotPipelined_Longrunning()96         public static void Distinct_Unordered_NotPipelined_Longrunning()
97         {
98             Distinct_Unordered_NotPipelined(Sources.OuterLoopCount, Sources.OuterLoopCount / DuplicateFactor);
99         }
100 
101         [Theory]
102         [MemberData(nameof(DistinctData), new[] { 0, 1, 2, 16 })]
Distinct_NotPipelined(Labeled<ParallelQuery<int>> labeled, int count)103         public static void Distinct_NotPipelined(Labeled<ParallelQuery<int>> labeled, int count)
104         {
105             ParallelQuery<int> query = labeled.Item;
106             int seen = 0;
107             Assert.All(query.Distinct(new ModularCongruenceComparer(count)).ToList(), x => Assert.Equal(seen++, x % count));
108             Assert.Equal(count, seen);
109         }
110 
111         [Theory]
112         [OuterLoop]
113         [MemberData(nameof(DistinctData), new int[] { /* Sources.OuterLoopCount */ })]
Distinct_NotPiplined_Longrunning(Labeled<ParallelQuery<int>> labeled, int count)114         public static void Distinct_NotPiplined_Longrunning(Labeled<ParallelQuery<int>> labeled, int count)
115         {
116             Distinct_NotPipelined(labeled, count);
117         }
118 
119         [Theory]
120         [MemberData(nameof(DistinctSourceMultipleData), new[] { 0, 1, 2, 16 })]
Distinct_Unordered_SourceMultiple(Labeled<ParallelQuery<int>> labeled, int count)121         public static void Distinct_Unordered_SourceMultiple(Labeled<ParallelQuery<int>> labeled, int count)
122         {
123             // The difference between this test and the previous, is that it's not possible to
124             // get non-unique results from ParallelEnumerable.Range()...
125             // Those tests either need modification of source (via .Select(x => x / DuplicateFactor) or similar,
126             // or via a comparator that considers some elements equal.
127             IntegerRangeSet seen = new IntegerRangeSet(0, count);
128             Assert.All(labeled.Item.AsUnordered().Distinct(), x => seen.Add(x));
129             seen.AssertComplete();
130         }
131 
132         [Theory]
133         [OuterLoop]
134         [MemberData(nameof(DistinctSourceMultipleData), new int[] { /* Sources.OuterLoopCount */ })]
Distinct_Unordered_SourceMultiple_Longrunning(Labeled<ParallelQuery<int>> labeled, int count)135         public static void Distinct_Unordered_SourceMultiple_Longrunning(Labeled<ParallelQuery<int>> labeled, int count)
136         {
137             Distinct_Unordered_SourceMultiple(labeled, count);
138         }
139 
140         [Theory]
141         [MemberData(nameof(DistinctSourceMultipleData), new[] { 0, 1, 2, 16 })]
Distinct_SourceMultiple(Labeled<ParallelQuery<int>> labeled, int count)142         public static void Distinct_SourceMultiple(Labeled<ParallelQuery<int>> labeled, int count)
143         {
144             int seen = 0;
145             Assert.All(labeled.Item.Distinct(), x => Assert.Equal(seen++, x));
146             Assert.Equal(count, seen);
147         }
148 
149         [Theory]
150         [OuterLoop]
151         [MemberData(nameof(DistinctSourceMultipleData), new int[] { /* Sources.OuterLoopCount */ })]
Distinct_SourceMultiple_Longrunning(Labeled<ParallelQuery<int>> labeled, int count)152         public static void Distinct_SourceMultiple_Longrunning(Labeled<ParallelQuery<int>> labeled, int count)
153         {
154             Distinct_SourceMultiple(labeled, count);
155         }
156 
157         [Fact]
Distinct_ArgumentNullException()158         public static void Distinct_ArgumentNullException()
159         {
160             AssertExtensions.Throws<ArgumentNullException>("source", () => ((ParallelQuery<int>)null).Distinct());
161         }
162     }
163 }
164