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 System.Linq; 7 using Xunit; 8 9 namespace System.Collections.Tests 10 { 11 /// <summary> 12 /// Contains tests that ensure the correctness of the List class. 13 /// </summary> 14 public abstract partial class List_Generic_Tests<T> : IList_Generic_Tests<T> 15 { 16 #region Helpers 17 IndexOfDelegate(List<T> list, T value)18 public delegate int IndexOfDelegate(List<T> list, T value); 19 public enum IndexOfMethod 20 { 21 IndexOf_T, 22 IndexOf_T_int, 23 IndexOf_T_int_int, 24 LastIndexOf_T, 25 LastIndexOf_T_int, 26 LastIndexOf_T_int_int, 27 }; 28 IndexOfDelegateFromType(IndexOfMethod methodType)29 private IndexOfDelegate IndexOfDelegateFromType(IndexOfMethod methodType) 30 { 31 switch (methodType) 32 { 33 case (IndexOfMethod.IndexOf_T): 34 return ((List<T> list, T value) => { return list.IndexOf(value); }); 35 case (IndexOfMethod.IndexOf_T_int): 36 return ((List<T> list, T value) => { return list.IndexOf(value, 0); }); 37 case (IndexOfMethod.IndexOf_T_int_int): 38 return ((List<T> list, T value) => { return list.IndexOf(value, 0, list.Count); }); 39 case (IndexOfMethod.LastIndexOf_T): 40 return ((List<T> list, T value) => { return list.LastIndexOf(value); }); 41 case (IndexOfMethod.LastIndexOf_T_int): 42 return ((List<T> list, T value) => { return list.LastIndexOf(value, list.Count - 1); }); 43 case (IndexOfMethod.LastIndexOf_T_int_int): 44 return ((List<T> list, T value) => { return list.LastIndexOf(value, list.Count - 1, list.Count); }); 45 default: 46 throw new Exception("Invalid IndexOfMethod"); 47 } 48 } 49 50 /// <summary> 51 /// MemberData for a Theory to test the IndexOf methods for List. To avoid high code reuse of tests for the 6 IndexOf 52 /// methods in List, delegates are used to cover the basic behavioral cases shared by all IndexOf methods. A bool 53 /// is used to specify the ordering (front-to-back or back-to-front (e.g. LastIndexOf)) that the IndexOf method 54 /// searches in. 55 /// </summary> IndexOfTestData()56 public static IEnumerable<object[]> IndexOfTestData() 57 { 58 foreach (object[] sizes in ValidCollectionSizes()) 59 { 60 int count = (int)sizes[0]; 61 yield return new object[] { IndexOfMethod.IndexOf_T, count, true }; 62 yield return new object[] { IndexOfMethod.LastIndexOf_T, count, false }; 63 64 if (count > 0) // 0 is an invalid index for IndexOf when the count is 0. 65 { 66 yield return new object[] { IndexOfMethod.IndexOf_T_int, count, true }; 67 yield return new object[] { IndexOfMethod.LastIndexOf_T_int, count, false }; 68 yield return new object[] { IndexOfMethod.IndexOf_T_int_int, count, true }; 69 yield return new object[] { IndexOfMethod.LastIndexOf_T_int_int, count, false }; 70 } 71 } 72 } 73 74 #endregion 75 76 #region IndexOf 77 78 [Theory] 79 [MemberData(nameof(IndexOfTestData))] IndexOf_NoDuplicates(IndexOfMethod indexOfMethod, int count, bool frontToBackOrder)80 public void IndexOf_NoDuplicates(IndexOfMethod indexOfMethod, int count, bool frontToBackOrder) 81 { 82 List<T> list = GenericListFactory(count); 83 List<T> expectedList = list.ToList(); 84 IndexOfDelegate IndexOf = IndexOfDelegateFromType(indexOfMethod); 85 86 Assert.All(Enumerable.Range(0, count), i => 87 { 88 Assert.Equal(i, IndexOf(list, expectedList[i])); 89 }); 90 } 91 92 [Theory] 93 [MemberData(nameof(IndexOfTestData))] IndexOf_NonExistingValues(IndexOfMethod indexOfMethod, int count, bool frontToBackOrder)94 public void IndexOf_NonExistingValues(IndexOfMethod indexOfMethod, int count, bool frontToBackOrder) 95 { 96 List<T> list = GenericListFactory(count); 97 IEnumerable<T> nonexistentValues = CreateEnumerable(EnumerableType.List, list, count: count, numberOfMatchingElements: 0, numberOfDuplicateElements: 0); 98 IndexOfDelegate IndexOf = IndexOfDelegateFromType(indexOfMethod); 99 100 Assert.All(nonexistentValues, nonexistentValue => 101 { 102 Assert.Equal(-1, IndexOf(list, nonexistentValue)); 103 }); 104 } 105 106 [Theory] 107 [MemberData(nameof(IndexOfTestData))] IndexOf_DefaultValue(IndexOfMethod indexOfMethod, int count, bool frontToBackOrder)108 public void IndexOf_DefaultValue(IndexOfMethod indexOfMethod, int count, bool frontToBackOrder) 109 { 110 T defaultValue = default(T); 111 List<T> list = GenericListFactory(count); 112 IndexOfDelegate IndexOf = IndexOfDelegateFromType(indexOfMethod); 113 while (list.Remove(defaultValue)) 114 count--; 115 list.Add(defaultValue); 116 Assert.Equal(count, IndexOf(list, defaultValue)); 117 } 118 119 [Theory] 120 [MemberData(nameof(IndexOfTestData))] IndexOf_OrderIsCorrect(IndexOfMethod indexOfMethod, int count, bool frontToBackOrder)121 public void IndexOf_OrderIsCorrect(IndexOfMethod indexOfMethod, int count, bool frontToBackOrder) 122 { 123 List<T> list = GenericListFactory(count); 124 List<T> withoutDuplicates = list.ToList(); 125 list.AddRange(list); 126 IndexOfDelegate IndexOf = IndexOfDelegateFromType(indexOfMethod); 127 128 Assert.All(Enumerable.Range(0, count), i => 129 { 130 if (frontToBackOrder) 131 Assert.Equal(i, IndexOf(list, withoutDuplicates[i])); 132 else 133 Assert.Equal(count + i, IndexOf(list, withoutDuplicates[i])); 134 }); 135 } 136 137 [Theory] 138 [MemberData(nameof(ValidCollectionSizes))] IndexOf_int_OrderIsCorrectWithManyDuplicates(int count)139 public void IndexOf_int_OrderIsCorrectWithManyDuplicates(int count) 140 { 141 List<T> list = GenericListFactory(count); 142 List<T> withoutDuplicates = list.ToList(); 143 list.AddRange(list); 144 list.AddRange(list); 145 list.AddRange(list); 146 147 Assert.All(Enumerable.Range(0, count), i => 148 { 149 Assert.All(Enumerable.Range(0, 4), j => 150 { 151 int expectedIndex = (j * count) + i; 152 Assert.Equal(expectedIndex, list.IndexOf(withoutDuplicates[i], (count * j))); 153 Assert.Equal(expectedIndex, list.IndexOf(withoutDuplicates[i], (count * j), count)); 154 }); 155 }); 156 } 157 158 [Theory] 159 [MemberData(nameof(ValidCollectionSizes))] LastIndexOf_int_OrderIsCorrectWithManyDuplicates(int count)160 public void LastIndexOf_int_OrderIsCorrectWithManyDuplicates(int count) 161 { 162 List<T> list = GenericListFactory(count); 163 List<T> withoutDuplicates = list.ToList(); 164 list.AddRange(list); 165 list.AddRange(list); 166 list.AddRange(list); 167 168 Assert.All(Enumerable.Range(0, count), i => 169 { 170 Assert.All(Enumerable.Range(0, 4), j => 171 { 172 int expectedIndex = (j * count) + i; 173 Assert.Equal(expectedIndex, list.LastIndexOf(withoutDuplicates[i], (count * (j + 1)) - 1)); 174 Assert.Equal(expectedIndex, list.LastIndexOf(withoutDuplicates[i], (count * (j + 1)) - 1, count)); 175 }); 176 }); 177 } 178 179 [Theory] 180 [MemberData(nameof(ValidCollectionSizes))] IndexOf_int_OutOfRangeExceptions(int count)181 public void IndexOf_int_OutOfRangeExceptions(int count) 182 { 183 List<T> list = GenericListFactory(count); 184 T element = CreateT(234); 185 Assert.Throws<ArgumentOutOfRangeException>(() => list.IndexOf(element, count + 1)); //"Expect ArgumentOutOfRangeException for index greater than length of list.." 186 Assert.Throws<ArgumentOutOfRangeException>(() => list.IndexOf(element, count + 10)); //"Expect ArgumentOutOfRangeException for index greater than length of list.." 187 Assert.Throws<ArgumentOutOfRangeException>(() => list.IndexOf(element, -1)); //"Expect ArgumentOutOfRangeException for negative index." 188 Assert.Throws<ArgumentOutOfRangeException>(() => list.IndexOf(element, int.MinValue)); //"Expect ArgumentOutOfRangeException for negative index." 189 } 190 191 [Theory] 192 [MemberData(nameof(ValidCollectionSizes))] IndexOf_int_int_OutOfRangeExceptions(int count)193 public void IndexOf_int_int_OutOfRangeExceptions(int count) 194 { 195 List<T> list = GenericListFactory(count); 196 T element = CreateT(234); 197 Assert.Throws<ArgumentOutOfRangeException>(() => list.IndexOf(element, count, 1)); //"ArgumentOutOfRangeException expected on index larger than array." 198 Assert.Throws<ArgumentOutOfRangeException>(() => list.IndexOf(element, count + 1, 1)); //"ArgumentOutOfRangeException expected on index larger than array." 199 Assert.Throws<ArgumentOutOfRangeException>(() => list.IndexOf(element, 0, count + 1)); //"ArgumentOutOfRangeException expected on count larger than array." 200 Assert.Throws<ArgumentOutOfRangeException>(() => list.IndexOf(element, count / 2, count / 2 + 2)); //"ArgumentOutOfRangeException expected.." 201 Assert.Throws<ArgumentOutOfRangeException>(() => list.IndexOf(element, 0, count + 1)); //"ArgumentOutOfRangeException expected on count larger than array." 202 Assert.Throws<ArgumentOutOfRangeException>(() => list.IndexOf(element, 0, -1)); //"ArgumentOutOfRangeException expected on negative count." 203 Assert.Throws<ArgumentOutOfRangeException>(() => list.IndexOf(element, -1, 1)); //"ArgumentOutOfRangeException expected on negative index." 204 } 205 206 [Theory] 207 [MemberData(nameof(ValidCollectionSizes))] LastIndexOf_int_OutOfRangeExceptions(int count)208 public void LastIndexOf_int_OutOfRangeExceptions(int count) 209 { 210 List<T> list = GenericListFactory(count); 211 T element = CreateT(234); 212 Assert.Throws<ArgumentOutOfRangeException>(() => list.LastIndexOf(element, count)); //"ArgumentOutOfRangeException expected." 213 if (count == 0) // IndexOf with a 0 count List is special cased to return -1. 214 Assert.Equal(-1, list.LastIndexOf(element, -1)); 215 else 216 Assert.Throws<ArgumentOutOfRangeException>(() => list.LastIndexOf(element, -1)); 217 } 218 219 [Theory] 220 [MemberData(nameof(ValidCollectionSizes))] LastIndexOf_int_int_OutOfRangeExceptions(int count)221 public void LastIndexOf_int_int_OutOfRangeExceptions(int count) 222 { 223 List<T> list = GenericListFactory(count); 224 T element = CreateT(234); 225 226 if (count > 0) 227 { 228 Assert.Throws<ArgumentOutOfRangeException>(() => list.LastIndexOf(element, 0, count + 1)); //"Expected ArgumentOutOfRangeException." 229 Assert.Throws<ArgumentOutOfRangeException>(() => list.LastIndexOf(element, count / 2, count / 2 + 2)); //"Expected ArgumentOutOfRangeException." 230 Assert.Throws<ArgumentOutOfRangeException>(() => list.LastIndexOf(element, 0, count + 1)); //"Expected ArgumentOutOfRangeException." 231 Assert.Throws<ArgumentOutOfRangeException>(() => list.LastIndexOf(element, 0, -1)); //"Expected ArgumentOutOfRangeException." 232 Assert.Throws<ArgumentOutOfRangeException>(() => list.LastIndexOf(element, -1, count)); //"Expected ArgumentOutOfRangeException." 233 Assert.Throws<ArgumentOutOfRangeException>(() => list.LastIndexOf(element, -1, 1)); //"Expected ArgumentOutOfRangeException." Assert.Throws<ArgumentOutOfRangeException>(() => list.LastIndexOf(element, count, 0)); //"Expected ArgumentOutOfRangeException." 234 Assert.Throws<ArgumentOutOfRangeException>(() => list.LastIndexOf(element, count, 1)); //"Expected ArgumentOutOfRangeException." 235 } 236 else // IndexOf with a 0 count List is special cased to return -1. 237 { 238 Assert.Equal(-1, list.LastIndexOf(element, 0, count + 1)); 239 Assert.Equal(-1, list.LastIndexOf(element, count / 2, count / 2 + 2)); 240 Assert.Equal(-1, list.LastIndexOf(element, 0, count + 1)); 241 Assert.Equal(-1, list.LastIndexOf(element, 0, -1)); 242 Assert.Equal(-1, list.LastIndexOf(element, -1, count)); 243 Assert.Equal(-1, list.LastIndexOf(element, -1, 1)); 244 Assert.Equal(-1, list.LastIndexOf(element, count, 0)); 245 Assert.Equal(-1, list.LastIndexOf(element, count, 1)); 246 } 247 } 248 249 #endregion 250 } 251 } 252