1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.tv.testing;
18
19import junit.framework.Assert;
20
21import java.util.ArrayList;
22import java.util.Arrays;
23import java.util.Collection;
24import java.util.List;
25
26/**
27 * Tester for {@link java.lang.Comparable}s.
28 *
29 * <p>
30 * To use, create a new {@link ComparableTester} and add comparable groups
31 * where each group contains objects that are
32 * {@link java.util.Comparator#compare(Object, Object)} == 0 to each other.
33 * Groups are added in order asserting that all earlier groups have compare < 0
34 * for all later groups.
35 *
36 * <pre>{@code
37 * new ComparableTester<String>()
38 *     .addEquivalentGroup("Hello", "HELLO")
39 *     .addEquivalentGroup("World", "wORLD")
40 *     .addEquivalentGroup("ZEBRA")
41 *     .test();
42 * }
43 * </pre>
44 *
45 * @param <T> the type of objects to compare.
46 */
47public class ComparableTester<T extends Comparable<T>> {
48
49    private final List<List<T>> listOfGroups = new ArrayList<>();
50
51    @SafeVarargs
52    public final ComparableTester<T> addEquivalentGroup(T... items) {
53        listOfGroups.add(Arrays.asList(items));
54        return this;
55    }
56
57    public void test() {
58        for (int i = 0; i < listOfGroups.size(); i++) {
59            List<T> currentGroup = listOfGroups.get(i);
60            for (int j = 0; j < i; j++) {
61                List<T> lhs = listOfGroups.get(j);
62                assertOrder(i, j, lhs, currentGroup);
63            }
64            assertZero(currentGroup);
65            for (int j = i + 1; j < listOfGroups.size(); j++) {
66                List<T> rhs = listOfGroups.get(j);
67                assertOrder(i, j, currentGroup, rhs);
68            }
69        }
70    }
71
72    private void assertOrder(int less, int more, List<T> lessGroup, List<T> moreGroup) {
73        assertLess(less, more, lessGroup, moreGroup);
74        assertMore(more, less, moreGroup, lessGroup);
75    }
76
77    private void assertLess(int left, int right, Collection<T> leftGroup,
78            Collection<T> rightGroup) {
79        int leftSub = 0;
80        for (T leftItem : leftGroup) {
81            int rightSub = 0;
82            String leftName = "Item[" + left + "," + (leftSub++) + "]";
83            for (T rightItem : rightGroup) {
84                String rightName = "Item[" + right + "," + (rightSub++) + "]";
85                Assert.assertEquals(
86                        leftName + " " + leftItem + " compareTo  " + rightName + " " + rightItem
87                                + " is <0", true, leftItem.compareTo(rightItem) < 0);
88            }
89        }
90    }
91
92    private void assertMore(int left, int right, Collection<T> leftGroup,
93            Collection<T> rightGroup) {
94        int leftSub = 0;
95        for (T leftItem : leftGroup) {
96            int rightSub = 0;
97            String leftName = "Item[" + left + "," + (leftSub++) + "]";
98            for (T rightItem : rightGroup) {
99                String rightName = "Item[" + right + "," + (rightSub++) + "]";
100                Assert.assertEquals(
101                        leftName + " " + leftItem + " compareTo  " + rightName + " " + rightItem
102                                + " is >0", true, leftItem.compareTo(rightItem) > 0);
103            }
104        }
105    }
106
107    private void assertZero(Collection<T> group) {
108        // Test everything against everything in both directions, including against itself.
109        for (T lhs : group) {
110            for (T rhs : group) {
111                Assert.assertEquals(lhs + " compareTo " + rhs, 0, lhs.compareTo(rhs));
112            }
113        }
114    }
115}
116