1package org.mockito.internal.util.reflection;
2
3import org.junit.Test;
4
5import java.lang.reflect.Field;
6import java.util.*;
7
8import static org.assertj.core.api.Assertions.assertThat;
9import static org.mockito.internal.util.reflection.SuperTypesLastSorter.sortSuperTypesLast;
10
11@SuppressWarnings("unused")
12public class SuperTypesLastSorterTest {
13    /**
14     * A Comparator that behaves like the old one, so the existing tests
15     * continue to work.
16     */
17    private static Comparator<Field> cmp = new Comparator<Field>() {
18        public int compare(Field o1, Field o2) {
19            if (o1.equals(o2)) {
20                return 0;
21            }
22
23            List<Field> l = sortSuperTypesLast(Arrays.asList(o1, o2));
24
25            if (l.get(0) == o1) {
26                return -1;
27            } else {
28                return 1;
29            }
30        }
31    };
32
33    private Object objectA;
34    private Object objectB;
35
36    private Number numberA;
37    private Number numberB;
38
39    private Integer integerA;
40    private Integer integerB;
41
42    private Iterable<?> iterableA;
43
44    private Number xNumber;
45    private Iterable<?> yIterable;
46    private Integer zInteger;
47
48
49    @Test
50    public void when_same_type_the_order_is_based_on_field_name() throws Exception {
51        assertThat(cmp.compare(field("objectA"), field("objectB"))).isEqualTo(-1);
52        assertThat(cmp.compare(field("objectB"), field("objectA"))).isEqualTo(1);
53        assertThat(cmp.compare(field("objectB"), field("objectB"))).isEqualTo(0);
54    }
55
56    @Test
57    public void when_type_is_different_the_supertype_comes_last() throws Exception {
58        assertThat(cmp.compare(field("numberA"), field("objectB"))).isEqualTo(-1);
59        assertThat(cmp.compare(field("objectB"), field("numberA"))).isEqualTo(1);
60    }
61
62    @Test
63    public void using_Collections_dot_sort() throws Exception {
64        List<Field> unsortedFields = Arrays.asList(
65                field("objectB"),
66                field("integerB"),
67                field("numberA"),
68                field("numberB"),
69                field("objectA"),
70                field("integerA")
71        );
72
73        List<Field> sortedFields =  sortSuperTypesLast(unsortedFields);
74
75        assertThat(sortedFields).containsSequence(
76                field("integerA"),
77                field("integerB"),
78                field("numberA"),
79                field("numberB"),
80                field("objectA"),
81                field("objectB")
82        );
83    }
84
85
86    @Test
87    public void issue_352_order_was_different_between_JDK6_and_JDK7() throws Exception {
88        List<Field> unsortedFields = Arrays.asList(
89                field("objectB"),
90                field("objectA")
91        );
92
93        Collections.sort(unsortedFields, cmp);
94
95        assertThat(unsortedFields).containsSequence(
96                field("objectA"),
97                field("objectB")
98        );
99    }
100
101    @Test
102    public void fields_sort_consistently_when_interfaces_are_included() throws NoSuchFieldException {
103        assertSortConsistently(field("iterableA"), field("numberA"), field("integerA"));
104    }
105
106    @Test
107    public void fields_sort_consistently_when_names_and_type_indicate_different_order() throws NoSuchFieldException {
108        assertSortConsistently(field("xNumber"), field("yIterable"), field("zInteger"));
109    }
110
111    /**
112     * Assert that these fields sort in the same order no matter which order
113     * they start in.
114     */
115    private static void assertSortConsistently(Field a, Field b, Field c) {
116        Field[][] initialOrderings = {
117                {a, b, c},
118                {a, c, b},
119                {b, a, c},
120                {b, c, a},
121                {c, a, b},
122                {c, b, a}
123        };
124
125        Set<List<Field>> results = new HashSet<List<Field>>();
126
127        for (Field[] o : initialOrderings) {
128            results.add(sortSuperTypesLast(Arrays.asList(o)));
129        }
130
131        assertThat(results).hasSize(1);
132    }
133
134    private Field field(String field) throws NoSuchFieldException {
135        return getClass().getDeclaredField(field);
136    }
137}
138