1 /* 2 * Copyright (c) 2016, 2017, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.util.AbstractMap; 25 import java.util.Collection; 26 import java.util.Comparator; 27 import java.util.HashMap; 28 import java.util.Iterator; 29 import java.util.List; 30 import java.util.ListIterator; 31 import java.util.Map; 32 import java.util.Objects; 33 import java.util.Set; 34 import java.util.function.Supplier; 35 import java.util.regex.Pattern; 36 37 import static java.util.Collections.emptyList; 38 import static java.util.Collections.singleton; 39 import static java.util.Objects.requireNonNull; 40 41 // 42 // A set of testing utility functions 43 // 44 public final class TestKit { 45 46 private TestKit() { } 47 48 public static void assertNotThrows(ThrowingProcedure code) { 49 requireNonNull(code, "code"); 50 assertNotThrows(() -> { 51 code.run(); 52 return null; 53 }); 54 } 55 56 public static <V> V assertNotThrows(ThrowingFunction<V> code) { 57 requireNonNull(code, "code"); 58 try { 59 return code.run(); 60 } catch (Throwable t) { 61 throw new RuntimeException("Expected to run normally, but threw " 62 + t.getClass().getCanonicalName(), t); 63 } 64 } 65 66 public static <T extends Throwable> T assertThrows(Class<T> clazz, 67 ThrowingProcedure code) { 68 requireNonNull(clazz, "clazz"); 69 requireNonNull(code, "code"); 70 try { 71 code.run(); 72 } catch (Throwable t) { 73 if (clazz.isInstance(t)) { 74 return clazz.cast(t); 75 } 76 throw new RuntimeException("Expected to catch an exception of type " 77 + clazz.getCanonicalName() + ", but caught " 78 + t.getClass().getCanonicalName(), t); 79 80 } 81 throw new RuntimeException("Expected to catch an exception of type " 82 + clazz.getCanonicalName() + ", but caught nothing"); 83 } 84 85 public interface ThrowingProcedure { 86 void run() throws Throwable; 87 } 88 89 public interface ThrowingFunction<V> { 90 V run() throws Throwable; 91 } 92 93 // The rationale behind asking for a regex is to not pollute variable names 94 // space in the scope of assertion: if it's something as simple as checking 95 // a message, we can do it inside 96 public static <T extends Throwable> T assertThrows(Class<T> clazz, 97 String messageRegex, 98 ThrowingProcedure code) { 99 requireNonNull(messageRegex, "messagePattern"); 100 T t = assertThrows(clazz, code); 101 String m = t.getMessage(); 102 if (m == null) { 103 throw new RuntimeException(String.format( 104 "Expected exception message to match the regex '%s', " + 105 "but the message was null", messageRegex), t); 106 } 107 if (!Pattern.matches(messageRegex, m)) { 108 throw new RuntimeException(String.format( 109 "Expected exception message to match the regex '%s', " + 110 "actual message: %s", messageRegex, m), t); 111 } 112 return t; 113 } 114 115 /* 116 * Asserts that the given Collection is unmodifiable: any mutator method 117 * throw an UnsupportedOperationException unconditionally. 118 */ 119 public static void assertUnmodifiableCollection(Collection<?> collection) { 120 assertUnmodifiableCollection(collection, () -> null); 121 } 122 123 public static <E> void assertUnmodifiableCollection(Collection<E> collection, 124 Supplier<? extends E> elementsFactory) { 125 requireNonNull(collection, "collection"); 126 requireNonNull(elementsFactory, "elementsFactory"); 127 128 E e = elementsFactory.get(); 129 130 assertUOE(() -> collection.add(e)); 131 assertUOE(() -> collection.addAll(singleton(e))); 132 Iterator<?> i = collection.iterator(); 133 if (i.hasNext()) { 134 i.next(); 135 assertUOE(i::remove); 136 } 137 assertUOE(collection::clear); 138 assertUOE(() -> collection.remove(e)); 139 assertUOE(() -> collection.removeAll(singleton(e))); 140 assertUOE(() -> collection.removeIf(x -> true)); 141 assertUOE(() -> collection.retainAll(emptyList())); 142 // No need to check toArray methods, since API guarantees arrays 143 // returned by them are "safe" 144 } 145 146 public static void assertUnmodifiableSet(Set<?> set) { 147 assertUnmodifiableCollection(set, () -> null); 148 } 149 150 public static <E> void assertUnmodifiableSet(Set<E> set, 151 Supplier<? extends E> elementsFactory) { 152 assertUnmodifiableCollection(set, elementsFactory); 153 } 154 155 public static void assertUnmodifiableList(List<?> list) { 156 assertUnmodifiableList(list, () -> null); 157 } 158 159 public static <E> void assertUnmodifiableList(List<E> list, 160 Supplier<? extends E> elementsFactory) { 161 assertUnmodifiableList(list, elementsFactory, 3); // This list, its sublist and its sublist's sublist 162 } 163 164 private static <E> void assertUnmodifiableList(List<E> list, 165 Supplier<? extends E> elementsFactory, 166 int depth) { 167 requireNonNull(list, "list"); 168 requireNonNull(elementsFactory, "elementsFactory"); 169 if (depth < 0) { 170 throw new IllegalArgumentException("depth: " + depth); 171 } 172 if (depth == 0) { 173 return; 174 } 175 176 E e = elementsFactory.get(); 177 178 assertUnmodifiableCollection(list, elementsFactory); 179 assertUOE(() -> list.add(0, e)); 180 assertUOE(() -> list.addAll(0, singleton(e))); 181 182 ListIterator<E> i = list.listIterator(); 183 if (i.hasNext()) { 184 i.next(); 185 assertUOE(i::remove); 186 assertUOE(() -> i.set(e)); 187 assertUOE(() -> i.add(e)); 188 } 189 assertUOE(() -> list.remove((int) 0)); 190 assertUOE(() -> list.replaceAll(x -> e)); 191 assertUOE(() -> list.set(0, e)); 192 193 // Any non-null general-purpose Comparator would do 194 Comparator<Object> comparator = (a, b) -> Objects.hash(a, b); 195 assertUOE(() -> list.sort(comparator)); 196 197 assertUnmodifiableList(list.subList(0, list.size()), elementsFactory, depth - 1); 198 } 199 200 public static void assertUnmodifiableMap(Map<?, ?> map) { 201 assertUnmodifiableMap(map, () -> new AbstractMap.SimpleImmutableEntry<>(null, null)); 202 } 203 204 public static <K, V> void assertUnmodifiableMap(Map<K, V> map, 205 Supplier<? extends Map.Entry<? extends K, ? extends V>> entriesFactory) { 206 requireNonNull(map, "map"); 207 requireNonNull(entriesFactory, "entriesFactory"); 208 assertUOE(map::clear); 209 210 Map.Entry<? extends K, ? extends V> e1 = entriesFactory.get(); 211 K k = e1.getKey(); 212 V v = e1.getValue(); 213 214 assertUOE(() -> map.compute(k, (k1, v1) -> v)); 215 assertUOE(() -> map.computeIfAbsent(k, (k1) -> v)); 216 assertUOE(() -> map.computeIfPresent(k, (k1, v1) -> v)); 217 218 Set<Map.Entry<K, V>> entrySet = map.entrySet(); 219 assertUnmodifiableSet(entrySet); 220 for (Map.Entry<K, V> e : entrySet) { 221 assertUOE(() -> e.setValue(null)); 222 } 223 224 assertUnmodifiableSet(map.keySet()); 225 assertUOE(() -> map.merge(k, v, (k1, v1) -> v)); 226 assertUOE(() -> map.put(k, v)); 227 // Map.of(k, v) wouldn't do, as it doesn't permit nulls 228 Map<K, V> m = new HashMap<>(); 229 m.put(k, v); 230 assertUOE(() -> map.putAll(m)); 231 assertUOE(() -> map.putIfAbsent(k, v)); 232 assertUOE(() -> map.remove(k)); 233 assertUOE(() -> map.remove(k, v)); 234 assertUOE(() -> map.replace(k, v)); 235 assertUOE(() -> map.replace(k, v, v)); 236 assertUOE(() -> map.replaceAll((k1, v1) -> v)); 237 assertUnmodifiableCollection(map.values()); 238 } 239 240 public static void assertUOE(ThrowingProcedure code) { 241 assertThrows(UnsupportedOperationException.class, code); 242 } 243 }