1 /* 2 * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 import java.util.Arrays; 27 import java.util.LinkedList; 28 import java.util.List; 29 import java.util.Random; 30 import java.util.Set; 31 32 import org.testng.TestException; 33 34 import static org.testng.Assert.assertTrue; 35 36 import java.lang.reflect.Constructor; 37 import java.util.Collection; 38 import java.util.Collections; 39 import java.util.function.Supplier; 40 41 /** 42 * @library 43 * @summary A Supplier of test cases for Collection tests 44 */ 45 public final class CollectionSupplier implements Supplier<Iterable<CollectionSupplier.TestCase>> { 46 47 private final String[] classNames; 48 private final int size; 49 50 /** 51 * A Collection test case. 52 */ 53 public static final class TestCase { 54 55 /** 56 * The name of the test case. 57 */ 58 public final String name; 59 60 /** 61 * Class name of the instantiated Collection. 62 */ 63 public final String className; 64 65 /** 66 * Unmodifiable reference collection, useful for comparisons. 67 */ 68 public final Collection<Integer> original; 69 70 /** 71 * A modifiable test collection. 72 */ 73 public final Collection<Integer> collection; 74 75 /** 76 * Create a Collection test case. 77 * @param name name of the test case 78 * @param className class name of the instantiated collection 79 * @param original reference collection 80 * @param collection the modifiable test collection 81 */ 82 public TestCase(final String name, final String className, 83 final Collection<Integer> original, final Collection<Integer> collection) { 84 this.name = name; 85 this.className = className; 86 this.original = List.class.isAssignableFrom(original.getClass()) ? 87 Collections.unmodifiableList((List<Integer>) original) : 88 Set.class.isAssignableFrom(original.getClass()) ? 89 Collections.unmodifiableSet((Set<Integer>) original) : 90 Collections.unmodifiableCollection(original); 91 this.collection = collection; 92 } 93 94 @Override 95 public String toString() { 96 return name + " " + className + 97 "\n original: " + original + 98 "\n target: " + collection; 99 } 100 } 101 102 /** 103 * Shuffle a list using a PRNG with known seed for repeatability 104 * @param list the list to be shuffled 105 */ 106 public static <E> void shuffle(final List<E> list) { 107 // PRNG with known seed for repeatable tests 108 final Random prng = new Random(13); 109 final int size = list.size(); 110 for (int i=0; i < size; i++) { 111 // random index in interval [i, size) 112 final int j = i + prng.nextInt(size - i); 113 // swap elements at indices i & j 114 final E e = list.get(i); 115 list.set(i, list.get(j)); 116 list.set(j, e); 117 } 118 } 119 120 /** 121 * Create a {@code Supplier} that creates instances of specified collection 122 * classes of specified length. 123 * 124 * @param classNames class names that implement {@code Collection} 125 * @param size the desired size of each collection 126 */ 127 public CollectionSupplier(final String[] classNames, final int size) { 128 this.classNames = Arrays.copyOf(classNames, classNames.length); 129 this.size = size; 130 } 131 132 @Override 133 public Iterable<TestCase> get() { 134 try { 135 return getThrows(); 136 } catch (Exception e) { 137 throw new TestException(e); 138 } 139 } 140 141 private Iterable<TestCase> getThrows() throws Exception { 142 final Collection<TestCase> collections = new LinkedList<>(); 143 for (final String className : classNames) { 144 @SuppressWarnings("unchecked") 145 final Class<? extends Collection<Integer>> type = 146 (Class<? extends Collection<Integer>>) Class.forName(className); 147 final Constructor<? extends Collection<Integer>> 148 defaultConstructor = type.getConstructor(); 149 final Constructor<? extends Collection<Integer>> 150 copyConstructor = type.getConstructor(Collection.class); 151 152 final Collection<Integer> empty = defaultConstructor.newInstance(); 153 collections.add(new TestCase("empty", 154 className, 155 copyConstructor.newInstance(empty), 156 empty)); 157 158 final Collection<Integer> single = defaultConstructor.newInstance(); 159 single.add(42); 160 collections.add(new TestCase("single", 161 className, 162 copyConstructor.newInstance(single), 163 single)); 164 165 final Collection<Integer> regular = defaultConstructor.newInstance(); 166 for (int i=0; i < size; i++) { 167 regular.add(i); 168 } 169 collections.add(new TestCase("regular", 170 className, 171 copyConstructor.newInstance(regular), 172 regular)); 173 174 final Collection<Integer> reverse = defaultConstructor.newInstance(); 175 for (int i=size; i >= 0; i--) { 176 reverse.add(i); 177 } 178 collections.add(new TestCase("reverse", 179 className, 180 copyConstructor.newInstance(reverse), 181 reverse)); 182 183 final Collection<Integer> odds = defaultConstructor.newInstance(); 184 for (int i=0; i < size; i++) { 185 odds.add((i * 2) + 1); 186 } 187 collections.add(new TestCase("odds", 188 className, 189 copyConstructor.newInstance(odds), 190 odds)); 191 192 final Collection<Integer> evens = defaultConstructor.newInstance(); 193 for (int i=0; i < size; i++) { 194 evens.add(i * 2); 195 } 196 collections.add(new TestCase("evens", 197 className, 198 copyConstructor.newInstance(evens), 199 evens)); 200 201 final Collection<Integer> fibonacci = defaultConstructor.newInstance(); 202 int prev2 = 0; 203 int prev1 = 1; 204 for (int i=0; i < size; i++) { 205 final int n = prev1 + prev2; 206 if (n < 0) { // stop on overflow 207 break; 208 } 209 fibonacci.add(n); 210 prev2 = prev1; 211 prev1 = n; 212 } 213 collections.add(new TestCase("fibonacci", 214 className, 215 copyConstructor.newInstance(fibonacci), 216 fibonacci)); 217 218 // variants where the size of the backing storage != reported size 219 // created by removing half of the elements 220 221 final Collection<Integer> emptyWithSlack = defaultConstructor.newInstance(); 222 emptyWithSlack.add(42); 223 assertTrue(emptyWithSlack.remove(42)); 224 collections.add(new TestCase("emptyWithSlack", 225 className, 226 copyConstructor.newInstance(emptyWithSlack), 227 emptyWithSlack)); 228 229 final Collection<Integer> singleWithSlack = defaultConstructor.newInstance(); 230 singleWithSlack.add(42); 231 singleWithSlack.add(43); 232 assertTrue(singleWithSlack.remove(43)); 233 collections.add(new TestCase("singleWithSlack", 234 className, 235 copyConstructor.newInstance(singleWithSlack), 236 singleWithSlack)); 237 238 final Collection<Integer> regularWithSlack = defaultConstructor.newInstance(); 239 for (int i=0; i < 2 * size; i++) { 240 regularWithSlack.add(i); 241 } 242 assertTrue(regularWithSlack.removeAll((x) -> x >= size)); 243 collections.add(new TestCase("regularWithSlack", 244 className, 245 copyConstructor.newInstance(regularWithSlack), 246 regularWithSlack)); 247 248 final Collection<Integer> reverseWithSlack = defaultConstructor.newInstance(); 249 for (int i=2 * size; i >= 0; i--) { 250 reverseWithSlack.add(i); 251 } 252 assertTrue(reverseWithSlack.removeAll((x) -> x < size)); 253 collections.add(new TestCase("reverseWithSlack", 254 className, 255 copyConstructor.newInstance(reverseWithSlack), 256 reverseWithSlack)); 257 258 final Collection<Integer> oddsWithSlack = defaultConstructor.newInstance(); 259 for (int i = 0; i < 2 * size; i++) { 260 oddsWithSlack.add((i * 2) + 1); 261 } 262 assertTrue(oddsWithSlack.removeAll((x) -> x >= size)); 263 collections.add(new TestCase("oddsWithSlack", 264 className, 265 copyConstructor.newInstance(oddsWithSlack), 266 oddsWithSlack)); 267 268 final Collection<Integer> evensWithSlack = defaultConstructor.newInstance(); 269 for (int i = 0; i < 2 * size; i++) { 270 evensWithSlack.add(i * 2); 271 } 272 assertTrue(evensWithSlack.removeAll((x) -> x >= size)); 273 collections.add(new TestCase("evensWithSlack", 274 className, 275 copyConstructor.newInstance(evensWithSlack), 276 evensWithSlack)); 277 278 final Collection<Integer> fibonacciWithSlack = defaultConstructor.newInstance(); 279 prev2 = 0; 280 prev1 = 1; 281 for (int i=0; i < size; i++) { 282 final int n = prev1 + prev2; 283 if (n < 0) { // stop on overflow 284 break; 285 } 286 fibonacciWithSlack.add(n); 287 prev2 = prev1; 288 prev1 = n; 289 } 290 assertTrue(fibonacciWithSlack.removeAll((x) -> x < 20)); 291 collections.add(new TestCase("fibonacciWithSlack", 292 className, 293 copyConstructor.newInstance(fibonacciWithSlack), 294 fibonacciWithSlack)); 295 296 } 297 298 return collections; 299 } 300 301 }