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