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 LastLastOrDefaultTests 11 { 12 private static Func<int, IEnumerable<int>> Positions = x => new[] { 1, x / 2 + 1, Math.Max(1, x - 1) }.Distinct(); 13 LastUnorderedData(int[] counts)14 public static IEnumerable<object[]> LastUnorderedData(int[] counts) 15 { 16 foreach (int count in counts.DefaultIfEmpty(Sources.OuterLoopCount)) 17 { 18 foreach (int position in Positions(count)) 19 { 20 yield return new object[] { Labeled.Label("UnorderedDefault", UnorderedSources.Default(count)), count, position }; 21 } 22 } 23 } 24 LastData(int[] counts)25 public static IEnumerable<object[]> LastData(int[] counts) 26 { 27 foreach (object[] results in Sources.Ranges(counts.DefaultIfEmpty(Sources.OuterLoopCount), Positions)) yield return results; 28 } 29 30 // 31 // Last and LastOrDefault 32 // 33 [Theory] 34 [MemberData(nameof(LastUnorderedData), new[] { 1, 2, 16 })] 35 [MemberData(nameof(LastData), new[] { 1, 2, 16 })] Last(Labeled<ParallelQuery<int>> labeled, int count, int position)36 public static void Last(Labeled<ParallelQuery<int>> labeled, int count, int position) 37 { 38 // For unordered collections, which element is chosen isn't actually guaranteed, but an effect of the implementation. 39 // If this test starts failing it should be split, and possibly mentioned in release notes. 40 ParallelQuery<int> query = labeled.Item; 41 Assert.Equal(count - 1, query.Last()); 42 Assert.Equal(position - 1, query.Last(x => x < position)); 43 } 44 45 [Theory] 46 [OuterLoop] 47 [MemberData(nameof(LastUnorderedData), new int[] { /* Sources.OuterLoopCount */ })] 48 [MemberData(nameof(LastData), new int[] { /* Sources.OuterLoopCount */ })] Last_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int position)49 public static void Last_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int position) 50 { 51 Last(labeled, count, position); 52 } 53 54 [Theory] 55 [MemberData(nameof(LastUnorderedData), new[] { 1, 2, 16 })] 56 [MemberData(nameof(LastData), new[] { 1, 2, 16 })] LastOrDefault(Labeled<ParallelQuery<int>> labeled, int count, int position)57 public static void LastOrDefault(Labeled<ParallelQuery<int>> labeled, int count, int position) 58 { 59 // For unordered collections, which element is chosen isn't actually guaranteed, but an effect of the implementation. 60 // If this test starts failing it should be split, and possibly mentioned in release notes. 61 ParallelQuery<int> query = labeled.Item; 62 Assert.Equal(count - 1, query.Last()); 63 Assert.Equal(position - 1, query.Last(x => x < position)); 64 } 65 66 [Theory] 67 [OuterLoop] 68 [MemberData(nameof(LastUnorderedData), new int[] { /* Sources.OuterLoopCount */ })] 69 [MemberData(nameof(LastData), new int[] { /* Sources.OuterLoopCount */ })] LastOrDefault_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int position)70 public static void LastOrDefault_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int position) 71 { 72 LastOrDefault(labeled, count, position); 73 } 74 75 [Theory] 76 [MemberData(nameof(LastUnorderedData), new[] { 0 })] 77 [MemberData(nameof(LastData), new[] { 0 })] Last_Empty(Labeled<ParallelQuery<int>> labeled, int count, int position)78 public static void Last_Empty(Labeled<ParallelQuery<int>> labeled, int count, int position) 79 { 80 ParallelQuery<int> query = labeled.Item; 81 Assert.Throws<InvalidOperationException>(() => query.Last()); 82 } 83 84 [Theory] 85 [MemberData(nameof(LastUnorderedData), new[] { 0 })] 86 [MemberData(nameof(LastData), new[] { 0 })] LastOrDefault_Empty(Labeled<ParallelQuery<int>> labeled, int count, int position)87 public static void LastOrDefault_Empty(Labeled<ParallelQuery<int>> labeled, int count, int position) 88 { 89 ParallelQuery<int> query = labeled.Item; 90 Assert.Equal(default(int), query.LastOrDefault()); 91 } 92 93 [Theory] 94 [MemberData(nameof(LastUnorderedData), new[] { 1, 2, 16 })] 95 [MemberData(nameof(LastData), new[] { 1, 2, 16 })] Last_NoMatch(Labeled<ParallelQuery<int>> labeled, int count, int position)96 public static void Last_NoMatch(Labeled<ParallelQuery<int>> labeled, int count, int position) 97 { 98 ParallelQuery<int> query = labeled.Item; 99 IntegerRangeSet seen = new IntegerRangeSet(0, count); 100 Assert.Throws<InvalidOperationException>(() => query.Last(x => !seen.Add(x))); 101 seen.AssertComplete(); 102 } 103 104 [Theory] 105 [OuterLoop] 106 [MemberData(nameof(LastUnorderedData), new int[] { /* Sources.OuterLoopCount */ })] 107 [MemberData(nameof(LastData), new int[] { /* Sources.OuterLoopCount */ })] Last_NoMatch_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int position)108 public static void Last_NoMatch_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int position) 109 { 110 Last_NoMatch(labeled, count, position); 111 } 112 113 [Theory] 114 [MemberData(nameof(LastUnorderedData), new[] { 1, 2, 16 })] 115 [MemberData(nameof(LastData), new[] { 1, 2, 16 })] LastOrDefault_NoMatch(Labeled<ParallelQuery<int>> labeled, int count, int position)116 public static void LastOrDefault_NoMatch(Labeled<ParallelQuery<int>> labeled, int count, int position) 117 { 118 ParallelQuery<int> query = labeled.Item; 119 IntegerRangeSet seen = new IntegerRangeSet(0, count); 120 Assert.Equal(default(int), query.LastOrDefault(x => !seen.Add(x))); 121 seen.AssertComplete(); 122 } 123 124 [Theory] 125 [OuterLoop] 126 [MemberData(nameof(LastUnorderedData), new int[] { /* Sources.OuterLoopCount */ })] 127 [MemberData(nameof(LastData), new int[] { /* Sources.OuterLoopCount */ })] LastOrDefault_NoMatch_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int position)128 public static void LastOrDefault_NoMatch_Longrunning(Labeled<ParallelQuery<int>> labeled, int count, int position) 129 { 130 LastOrDefault_NoMatch(labeled, count, position); 131 } 132 133 [Fact] Last_OperationCanceledException()134 public static void Last_OperationCanceledException() 135 { 136 AssertThrows.EventuallyCanceled((source, canceler) => source.Last(x => { canceler(); return true; })); 137 AssertThrows.EventuallyCanceled((source, canceler) => source.LastOrDefault(x => { canceler(); return true; })); 138 } 139 140 [Fact] Last_AggregateException_Wraps_OperationCanceledException()141 public static void Last_AggregateException_Wraps_OperationCanceledException() 142 { 143 AssertThrows.OtherTokenCanceled((source, canceler) => source.Last(x => { canceler(); return true; })); 144 AssertThrows.OtherTokenCanceled((source, canceler) => source.LastOrDefault(x => { canceler(); return false; })); 145 AssertThrows.SameTokenNotCanceled((source, canceler) => source.Last(x => { canceler(); return true; })); 146 AssertThrows.SameTokenNotCanceled((source, canceler) => source.LastOrDefault(x => { canceler(); return false; })); 147 } 148 149 [Fact] Last_OperationCanceledException_PreCanceled()150 public static void Last_OperationCanceledException_PreCanceled() 151 { 152 AssertThrows.AlreadyCanceled(source => source.Last()); 153 AssertThrows.AlreadyCanceled(source => source.Last(x => true)); 154 155 AssertThrows.AlreadyCanceled(source => source.LastOrDefault()); 156 AssertThrows.AlreadyCanceled(source => source.LastOrDefault(x => true)); 157 } 158 159 [Fact] Last_AggregateException()160 public static void Last_AggregateException() 161 { 162 AssertThrows.Wrapped<DeliberateTestException>(() => UnorderedSources.Default(1).Last(x => { throw new DeliberateTestException(); })); 163 AssertThrows.Wrapped<DeliberateTestException>(() => UnorderedSources.Default(1).LastOrDefault(x => { throw new DeliberateTestException(); })); 164 } 165 166 [Fact] Last_ArgumentNullException()167 public static void Last_ArgumentNullException() 168 { 169 AssertExtensions.Throws<ArgumentNullException>("source", () => ((ParallelQuery<bool>)null).Last()); 170 AssertExtensions.Throws<ArgumentNullException>("source", () => ((ParallelQuery<bool>)null).LastOrDefault()); 171 172 AssertExtensions.Throws<ArgumentNullException>("predicate", () => ParallelEnumerable.Empty<int>().Last(null)); 173 AssertExtensions.Throws<ArgumentNullException>("predicate", () => ParallelEnumerable.Empty<int>().LastOrDefault(null)); 174 } 175 } 176 } 177