1b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotpackage org.junit.runners.model; 2b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 3b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport static java.lang.reflect.Modifier.isStatic; 4b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 5b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.lang.annotation.Annotation; 6b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.lang.reflect.Constructor; 7b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.lang.reflect.Field; 8b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.lang.reflect.Method; 9b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.util.ArrayList; 10b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.util.HashMap; 11b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.util.List; 12b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.util.Map; 13b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 14b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.Assert; 15b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.Before; 16b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.BeforeClass; 17b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 18b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot/** 19b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Wraps a class to be run, providing method validation and annotation searching 20b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 21b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotpublic class TestClass { 22b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private final Class<?> fClass; 23b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 24b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private Map<Class<?>, List<FrameworkMethod>> fMethodsForAnnotations= new HashMap<Class<?>, List<FrameworkMethod>>(); 25b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 26b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private Map<Class<?>, List<FrameworkField>> fFieldsForAnnotations= new HashMap<Class<?>, List<FrameworkField>>(); 27b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 28b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot /** 29b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Creates a {@code TestClass} wrapping {@code klass}. Each time this 30b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * constructor executes, the class is scanned for annotations, which can be 31b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * an expensive process (we hope in future JDK's it will not be.) Therefore, 32b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * try to share instances of {@code TestClass} where possible. 33b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 34b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public TestClass(Class<?> klass) { 35b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot fClass= klass; 36b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot if (klass != null && klass.getConstructors().length > 1) 37b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot throw new IllegalArgumentException( 38b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot "Test class can only have one constructor"); 39b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 40b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot for (Class<?> eachClass : getSuperClasses(fClass)) { 41b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot for (Method eachMethod : eachClass.getDeclaredMethods()) 42b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot addToAnnotationLists(new FrameworkMethod(eachMethod), 43b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot fMethodsForAnnotations); 44b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot for (Field eachField : eachClass.getDeclaredFields()) 45b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot addToAnnotationLists(new FrameworkField(eachField), 46b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot fFieldsForAnnotations); 47b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 48b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 49b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 50b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private <T extends FrameworkMember<T>> void addToAnnotationLists(T member, 51b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot Map<Class<?>, List<T>> map) { 52b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot for (Annotation each : member.getAnnotations()) { 53b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot Class<? extends Annotation> type= each.annotationType(); 54b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot List<T> members= getAnnotatedMembers(map, type); 55b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot if (member.isShadowedBy(members)) 56b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return; 57b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot if (runsTopToBottom(type)) 58b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot members.add(0, member); 59b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot else 60b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot members.add(member); 61b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 62b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 63b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 64b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot /** 65b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Returns, efficiently, all the non-overridden methods in this class and 66b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * its superclasses that are annotated with {@code annotationClass}. 67b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 68b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public List<FrameworkMethod> getAnnotatedMethods( 69b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot Class<? extends Annotation> annotationClass) { 70b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return getAnnotatedMembers(fMethodsForAnnotations, annotationClass); 71b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 72b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 73b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot /** 74b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Returns, efficiently, all the non-overridden fields in this class and its 75b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * superclasses that are annotated with {@code annotationClass}. 76b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 77b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public List<FrameworkField> getAnnotatedFields( 78b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot Class<? extends Annotation> annotationClass) { 79b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return getAnnotatedMembers(fFieldsForAnnotations, annotationClass); 80b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 81b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 82b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private <T> List<T> getAnnotatedMembers(Map<Class<?>, List<T>> map, 83b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot Class<? extends Annotation> type) { 84b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot if (!map.containsKey(type)) 85b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot map.put(type, new ArrayList<T>()); 86b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return map.get(type); 87b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 88b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 89b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private boolean runsTopToBottom(Class<? extends Annotation> annotation) { 90b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return annotation.equals(Before.class) 91b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot || annotation.equals(BeforeClass.class); 92b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 93b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 94b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private List<Class<?>> getSuperClasses(Class<?> testClass) { 95b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot ArrayList<Class<?>> results= new ArrayList<Class<?>>(); 96b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot Class<?> current= testClass; 97b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot while (current != null) { 98b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot results.add(current); 99b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot current= current.getSuperclass(); 100b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 101b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return results; 102b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 103b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 104b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot /** 105b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Returns the underlying Java class. 106b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 107b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public Class<?> getJavaClass() { 108b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return fClass; 109b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 110b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 111b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot /** 112b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Returns the class's name. 113b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 114b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public String getName() { 115b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot if (fClass == null) 116b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return "null"; 117b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return fClass.getName(); 118b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 119b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 120b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot /** 121b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Returns the only public constructor in the class, or throws an {@code 122b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * AssertionError} if there are more or less than one. 123b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 124b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 125b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public Constructor<?> getOnlyConstructor() { 126b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot Constructor<?>[] constructors= fClass.getConstructors(); 127b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot Assert.assertEquals(1, constructors.length); 128b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return constructors[0]; 129b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 130b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 131b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot /** 132b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Returns the annotations on this class 133b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 134b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public Annotation[] getAnnotations() { 135b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot if (fClass == null) 136b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return new Annotation[0]; 137b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return fClass.getAnnotations(); 138b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 139b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 140b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public <T> List<T> getAnnotatedFieldValues(Object test, 141b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot Class<? extends Annotation> annotationClass, Class<T> valueClass) { 142b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot List<T> results= new ArrayList<T>(); 143b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot for (FrameworkField each : getAnnotatedFields(annotationClass)) { 144b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot try { 145b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot Object fieldValue= each.get(test); 146b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot if (valueClass.isInstance(fieldValue)) 147b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot results.add(valueClass.cast(fieldValue)); 148b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } catch (IllegalAccessException e) { 149b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot throw new RuntimeException( 150b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot "How did getFields return a field we couldn't access?", e); 151b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 152b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 153b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return results; 154b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 155b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 156b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public boolean isANonStaticInnerClass() { 157b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return fClass.isMemberClass() && !isStatic(fClass.getModifiers()); 158b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 159b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot} 160