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