1b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotpackage org.junit.runners.model; 2b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 3b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport static java.lang.reflect.Modifier.isStatic; 4aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffinimport static org.junit.internal.MethodSorter.NAME_ASCENDING; 5b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 6b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.lang.annotation.Annotation; 7b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.lang.reflect.Constructor; 8b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.lang.reflect.Field; 9b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.lang.reflect.Method; 10aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffinimport java.lang.reflect.Modifier; 11b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.util.ArrayList; 12aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffinimport java.util.Arrays; 13aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffinimport java.util.Collections; 14aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffinimport java.util.Comparator; 15aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffinimport java.util.LinkedHashMap; 16aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffinimport java.util.LinkedHashSet; 17b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.util.List; 18b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.util.Map; 19aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffinimport java.util.Set; 20b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 21b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.Assert; 22b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.Before; 23b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.BeforeClass; 24aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffinimport org.junit.internal.MethodSorter; 25b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 26b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot/** 27b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Wraps a class to be run, providing method validation and annotation searching 28aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * 29aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * @since 4.5 30b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 31aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffinpublic class TestClass implements Annotatable { 32aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin private static final FieldComparator FIELD_COMPARATOR = new FieldComparator(); 33aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin private static final MethodComparator METHOD_COMPARATOR = new MethodComparator(); 34aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 35aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin private final Class<?> clazz; 36aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin private final Map<Class<? extends Annotation>, List<FrameworkMethod>> methodsForAnnotations; 37aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin private final Map<Class<? extends Annotation>, List<FrameworkField>> fieldsForAnnotations; 38aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 39aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin /** 40aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * Creates a {@code TestClass} wrapping {@code clazz}. Each time this 41aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * constructor executes, the class is scanned for annotations, which can be 42aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * an expensive process (we hope in future JDK's it will not be.) Therefore, 43aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * try to share instances of {@code TestClass} where possible. 44aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin */ 45aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public TestClass(Class<?> clazz) { 46aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin this.clazz = clazz; 47aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin if (clazz != null && clazz.getConstructors().length > 1) { 48aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin throw new IllegalArgumentException( 49aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin "Test class can only have one constructor"); 50aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 51aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 52aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Map<Class<? extends Annotation>, List<FrameworkMethod>> methodsForAnnotations = 53aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin new LinkedHashMap<Class<? extends Annotation>, List<FrameworkMethod>>(); 54aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Map<Class<? extends Annotation>, List<FrameworkField>> fieldsForAnnotations = 55aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin new LinkedHashMap<Class<? extends Annotation>, List<FrameworkField>>(); 56aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 57aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin scanAnnotatedMembers(methodsForAnnotations, fieldsForAnnotations); 58aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 59aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin this.methodsForAnnotations = makeDeeplyUnmodifiable(methodsForAnnotations); 60aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin this.fieldsForAnnotations = makeDeeplyUnmodifiable(fieldsForAnnotations); 61aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 62aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 63aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin protected void scanAnnotatedMembers(Map<Class<? extends Annotation>, List<FrameworkMethod>> methodsForAnnotations, Map<Class<? extends Annotation>, List<FrameworkField>> fieldsForAnnotations) { 64aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin for (Class<?> eachClass : getSuperClasses(clazz)) { 65aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin for (Method eachMethod : MethodSorter.getDeclaredMethods(eachClass)) { 66aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin addToAnnotationLists(new FrameworkMethod(eachMethod), methodsForAnnotations); 67aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 68aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin // ensuring fields are sorted to make sure that entries are inserted 69aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin // and read from fieldForAnnotations in a deterministic order 70aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin for (Field eachField : getSortedDeclaredFields(eachClass)) { 71aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin addToAnnotationLists(new FrameworkField(eachField), fieldsForAnnotations); 72aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 73aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 74aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 75aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 76aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin private static Field[] getSortedDeclaredFields(Class<?> clazz) { 77aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Field[] declaredFields = clazz.getDeclaredFields(); 78aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Arrays.sort(declaredFields, FIELD_COMPARATOR); 79aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return declaredFields; 80aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 81aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 82aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin protected static <T extends FrameworkMember<T>> void addToAnnotationLists(T member, 83aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Map<Class<? extends Annotation>, List<T>> map) { 84aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin for (Annotation each : member.getAnnotations()) { 85aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Class<? extends Annotation> type = each.annotationType(); 86aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin List<T> members = getAnnotatedMembers(map, type, true); 87aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin if (member.isShadowedBy(members)) { 88aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return; 89aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 90aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin if (runsTopToBottom(type)) { 91aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin members.add(0, member); 92aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } else { 93aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin members.add(member); 94aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 95aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 96aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 97aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 98aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin private static <T extends FrameworkMember<T>> Map<Class<? extends Annotation>, List<T>> 99aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin makeDeeplyUnmodifiable(Map<Class<? extends Annotation>, List<T>> source) { 100aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin LinkedHashMap<Class<? extends Annotation>, List<T>> copy = 101aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin new LinkedHashMap<Class<? extends Annotation>, List<T>>(); 102aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin for (Map.Entry<Class<? extends Annotation>, List<T>> entry : source.entrySet()) { 103aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin copy.put(entry.getKey(), Collections.unmodifiableList(entry.getValue())); 104aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 105aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return Collections.unmodifiableMap(copy); 106aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 107aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 108aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin /** 109aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * Returns, efficiently, all the non-overridden methods in this class and 110aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * its superclasses that are annotated}. 111aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * 112aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * @since 4.12 113aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin */ 114aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public List<FrameworkMethod> getAnnotatedMethods() { 115aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin List<FrameworkMethod> methods = collectValues(methodsForAnnotations); 116aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Collections.sort(methods, METHOD_COMPARATOR); 117aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return methods; 118aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 119aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 120aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin /** 121aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * Returns, efficiently, all the non-overridden methods in this class and 122aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * its superclasses that are annotated with {@code annotationClass}. 123aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin */ 124aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public List<FrameworkMethod> getAnnotatedMethods( 125aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Class<? extends Annotation> annotationClass) { 126aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return Collections.unmodifiableList(getAnnotatedMembers(methodsForAnnotations, annotationClass, false)); 127aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 128aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 129aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin /** 130aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * Returns, efficiently, all the non-overridden fields in this class and its 131aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * superclasses that are annotated. 132aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * 133aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * @since 4.12 134aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin */ 135aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public List<FrameworkField> getAnnotatedFields() { 136aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return collectValues(fieldsForAnnotations); 137aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 138aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 139aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin /** 140aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * Returns, efficiently, all the non-overridden fields in this class and its 141aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * superclasses that are annotated with {@code annotationClass}. 142aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin */ 143aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public List<FrameworkField> getAnnotatedFields( 144aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Class<? extends Annotation> annotationClass) { 145aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return Collections.unmodifiableList(getAnnotatedMembers(fieldsForAnnotations, annotationClass, false)); 146aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 147aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 148aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin private <T> List<T> collectValues(Map<?, List<T>> map) { 149aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Set<T> values = new LinkedHashSet<T>(); 150aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin for (List<T> additionalValues : map.values()) { 151aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin values.addAll(additionalValues); 152aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 153aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return new ArrayList<T>(values); 154aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 155aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 156aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin private static <T> List<T> getAnnotatedMembers(Map<Class<? extends Annotation>, List<T>> map, 157aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Class<? extends Annotation> type, boolean fillIfAbsent) { 158aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin if (!map.containsKey(type) && fillIfAbsent) { 159aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin map.put(type, new ArrayList<T>()); 160aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 161aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin List<T> members = map.get(type); 162aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return members == null ? Collections.<T>emptyList() : members; 163aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 164aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 165aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin private static boolean runsTopToBottom(Class<? extends Annotation> annotation) { 166aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return annotation.equals(Before.class) 167aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin || annotation.equals(BeforeClass.class); 168aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 169aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 170aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin private static List<Class<?>> getSuperClasses(Class<?> testClass) { 171aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin ArrayList<Class<?>> results = new ArrayList<Class<?>>(); 172aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Class<?> current = testClass; 173aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin while (current != null) { 174aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin results.add(current); 175aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin current = current.getSuperclass(); 176aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 177aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return results; 178aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 179aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 180aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin /** 181aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * Returns the underlying Java class. 182aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin */ 183aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public Class<?> getJavaClass() { 184aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return clazz; 185aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 186aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 187aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin /** 188aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * Returns the class's name. 189aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin */ 190aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public String getName() { 191aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin if (clazz == null) { 192aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return "null"; 193aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 194aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return clazz.getName(); 195aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 196aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 197aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin /** 198aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * Returns the only public constructor in the class, or throws an {@code 199aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * AssertionError} if there are more or less than one. 200aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin */ 201aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 202aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public Constructor<?> getOnlyConstructor() { 203aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Constructor<?>[] constructors = clazz.getConstructors(); 204aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Assert.assertEquals(1, constructors.length); 205aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return constructors[0]; 206aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 207aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 208aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin /** 209aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * Returns the annotations on this class 210aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin */ 211aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public Annotation[] getAnnotations() { 212aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin if (clazz == null) { 213aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return new Annotation[0]; 214aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 215aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return clazz.getAnnotations(); 216aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 217aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 218aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public <T extends Annotation> T getAnnotation(Class<T> annotationType) { 219aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin if (clazz == null) { 220aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return null; 221aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 222aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return clazz.getAnnotation(annotationType); 223aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 224aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 225aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public <T> List<T> getAnnotatedFieldValues(Object test, 226aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Class<? extends Annotation> annotationClass, Class<T> valueClass) { 227aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin List<T> results = new ArrayList<T>(); 228aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin for (FrameworkField each : getAnnotatedFields(annotationClass)) { 229aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin try { 230aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Object fieldValue = each.get(test); 231aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin if (valueClass.isInstance(fieldValue)) { 232aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin results.add(valueClass.cast(fieldValue)); 233aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 234aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } catch (IllegalAccessException e) { 235aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin throw new RuntimeException( 236aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin "How did getFields return a field we couldn't access?", e); 237aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 238aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 239aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return results; 240aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 241aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 242aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public <T> List<T> getAnnotatedMethodValues(Object test, 243aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Class<? extends Annotation> annotationClass, Class<T> valueClass) { 244aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin List<T> results = new ArrayList<T>(); 245aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin for (FrameworkMethod each : getAnnotatedMethods(annotationClass)) { 246aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin try { 247aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin /* 248aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * A method annotated with @Rule may return a @TestRule or a @MethodRule, 249aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * we cannot call the method to check whether the return type matches our 250aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * expectation i.e. subclass of valueClass. If we do that then the method 251aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * will be invoked twice and we do not want to do that. So we first check 252aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * whether return type matches our expectation and only then call the method 253aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * to fetch the MethodRule 254aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin */ 255aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin if (valueClass.isAssignableFrom(each.getReturnType())) { 256aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Object fieldValue = each.invokeExplosively(test); 257aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin results.add(valueClass.cast(fieldValue)); 258aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 259aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } catch (Throwable e) { 260aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin throw new RuntimeException( 261aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin "Exception in " + each.getName(), e); 262aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 263aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 264aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return results; 265aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 266aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 267aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public boolean isPublic() { 268aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return Modifier.isPublic(clazz.getModifiers()); 269aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 270aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 271aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public boolean isANonStaticInnerClass() { 272aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return clazz.isMemberClass() && !isStatic(clazz.getModifiers()); 273aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 274aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 275aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin @Override 276aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public int hashCode() { 277aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return (clazz == null) ? 0 : clazz.hashCode(); 278aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 279aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 280aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin @Override 281aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public boolean equals(Object obj) { 282aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin if (this == obj) { 283aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return true; 284aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 285aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin if (obj == null) { 286aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return false; 287aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 288aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin if (getClass() != obj.getClass()) { 289aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return false; 290aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 291aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin TestClass other = (TestClass) obj; 292aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return clazz == other.clazz; 293aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 294aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 295aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin /** 296aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * Compares two fields by its name. 297aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin */ 298aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin private static class FieldComparator implements Comparator<Field> { 299aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public int compare(Field left, Field right) { 300aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return left.getName().compareTo(right.getName()); 301aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 302aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 303aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin 304aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin /** 305aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin * Compares two methods by its name. 306aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin */ 307aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin private static class MethodComparator implements 308aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin Comparator<FrameworkMethod> { 309aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin public int compare(FrameworkMethod left, FrameworkMethod right) { 310aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin return NAME_ASCENDING.compare(left.getMethod(), right.getMethod()); 311aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 312aeb93fc33cae3aadbb9b46083350ad2dc9aea645Paul Duffin } 313b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot} 314