001package org.junit.internal;
002
003import java.lang.reflect.Method;
004import java.util.Arrays;
005import java.util.Comparator;
006
007import org.junit.FixMethodOrder;
008
009public class MethodSorter {
010    /**
011     * DEFAULT sort order
012     */
013    public static final Comparator<Method> DEFAULT = new Comparator<Method>() {
014        public int compare(Method m1, Method m2) {
015            int i1 = m1.getName().hashCode();
016            int i2 = m2.getName().hashCode();
017            if (i1 != i2) {
018                return i1 < i2 ? -1 : 1;
019            }
020            return NAME_ASCENDING.compare(m1, m2);
021        }
022    };
023
024    /**
025     * Method name ascending lexicographic sort order, with {@link Method#toString()} as a tiebreaker
026     */
027    public static final Comparator<Method> NAME_ASCENDING = new Comparator<Method>() {
028        public int compare(Method m1, Method m2) {
029            final int comparison = m1.getName().compareTo(m2.getName());
030            if (comparison != 0) {
031                return comparison;
032            }
033            return m1.toString().compareTo(m2.toString());
034        }
035    };
036
037    /**
038     * Gets declared methods of a class in a predictable order, unless @FixMethodOrder(MethodSorters.JVM) is specified.
039     *
040     * Using the JVM order is unwise since the Java platform does not
041     * specify any particular order, and in fact JDK 7 returns a more or less
042     * random order; well-written test code would not assume any order, but some
043     * does, and a predictable failure is better than a random failure on
044     * certain platforms. By default, uses an unspecified but deterministic order.
045     *
046     * @param clazz a class
047     * @return same as {@link Class#getDeclaredMethods} but sorted
048     * @see <a href="http://bugs.sun.com/view_bug.do?bug_id=7023180">JDK
049     *      (non-)bug #7023180</a>
050     */
051    public static Method[] getDeclaredMethods(Class<?> clazz) {
052        Comparator<Method> comparator = getSorter(clazz.getAnnotation(FixMethodOrder.class));
053
054        Method[] methods = clazz.getDeclaredMethods();
055        if (comparator != null) {
056            Arrays.sort(methods, comparator);
057        }
058
059        return methods;
060    }
061
062    private MethodSorter() {
063    }
064
065    private static Comparator<Method> getSorter(FixMethodOrder fixMethodOrder) {
066        if (fixMethodOrder == null) {
067            return DEFAULT;
068        }
069
070        return fixMethodOrder.value().getComparator();
071    }
072}