• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.hamcrest.comparator;
2 
3 import org.hamcrest.Description;
4 import org.hamcrest.Matcher;
5 import org.hamcrest.TypeSafeMatcher;
6 
7 import java.util.Comparator;
8 
9 import static java.lang.Integer.signum;
10 
11 public final class ComparatorMatcherBuilder<T> {
12 
13     private final Comparator<T> comparator;
14     private final boolean includeComparatorInDescription;
15 
16     /**
17      * Creates a matcher factory for matchers of {@code Comparable}s.
18      * For example:
19      * <pre>assertThat(1, ComparatorMatcherBuilder.&lt;Integer&gt;usingNaturalOrdering().lessThanOrEqualTo(1))</pre>
20      */
usingNaturalOrdering()21     public static <T extends Comparable<T>> ComparatorMatcherBuilder<T> usingNaturalOrdering() {
22         return new ComparatorMatcherBuilder<T>(new Comparator<T>() {
23             @Override
24             public int compare(T o1, T o2) {
25                 return o1.compareTo(o2);
26             }
27         }, false);
28     }
29 
30     /**
31      * Creates a matcher factory for matchers of {@code Comparators}s of {@code T}.
32      * For example:
33      * <pre>assertThat(5, comparedBy(new Comparator&lt;Integer&gt;() {
34      * public int compare(Integer o1, Integer o2) {
35      * return -o1.compareTo(o2);
36      * }
37      * }).lessThan(4))</pre>
38      */
39     public static <T> ComparatorMatcherBuilder<T> comparedBy(Comparator<T> comparator) {
40         return new ComparatorMatcherBuilder<T>(comparator, true);
41     }
42 
43     private ComparatorMatcherBuilder(Comparator<T> comparator, boolean includeComparatorInDescription) {
44         this.comparator = comparator;
45         this.includeComparatorInDescription = includeComparatorInDescription;
46     }
47 
48     private static final class ComparatorMatcher<T> extends TypeSafeMatcher<T> {
49         private static final int LESS_THAN = -1;
50         private static final int GREATER_THAN = 1;
51         private static final int EQUAL = 0;
52 
53         private final Comparator<T> comparator;
54         private final T expected;
55         private final int minCompare;
56         private final int maxCompare;
57         private final boolean includeComparatorInDescription;
58 
59         private static final String[] comparisonDescriptions = {
60                 "less than",
61                 "equal to",
62                 "greater than"
63         };
64 
65         private ComparatorMatcher(Comparator<T> comparator, T expected, int minCompare, int maxCompare, boolean includeComparatorInDescription) {
66             this.comparator = comparator;
67             this.expected = expected;
68             this.minCompare = minCompare;
69             this.maxCompare = maxCompare;
70             this.includeComparatorInDescription = includeComparatorInDescription;
71         }
72 
73         @Override
74         public boolean matchesSafely(T actual) {
75             try {
76                 int compare = signum(comparator.compare(actual, expected));
77                 return minCompare <= compare && compare <= maxCompare;
78             } catch (ClassCastException e) {
79                 return false; // type erasure means someone can shonk in a non-T :(
80             }
81         }
82 
83         @Override
84         public void describeMismatchSafely(T actual, Description mismatchDescription) {
85             mismatchDescription.appendValue(actual).appendText(" was ")
86                     .appendText(asText(comparator.compare(actual, expected)))
87                     .appendText(" ").appendValue(expected);
88             if (includeComparatorInDescription) {
89                 mismatchDescription.appendText(" when compared by ").appendValue(comparator);
90             }
91         }
92 
93         @Override
94         public void describeTo(Description description) {
95             description.appendText("a value ").appendText(asText(minCompare));
96             if (minCompare != maxCompare) {
97                 description.appendText(" or ").appendText(asText(maxCompare));
98             }
99             description.appendText(" ").appendValue(expected);
100             if (includeComparatorInDescription) {
101                 description.appendText(" when compared by ").appendValue(comparator);
102             }
103         }
104 
105         private static String asText(int comparison) {
106             return comparisonDescriptions[signum(comparison) + 1];
107         }
108     }
109 
110     /**
111      * Creates a matcher of {@code T} object that matches when the examined object is
112      * equal to the specified value, as reported by the {@code Comparator} used to
113      * create this builder.
114      * For example:
115      * <pre>assertThat(1, ComparatorMatcherBuilder.&lt;Integer&gt;usingNaturalOrdering().comparesEqualTo(1))</pre>
116      *
117      * @param value the value which, when passed to the Comparator supplied to this builder, should return zero
118      */
119     public Matcher<T> comparesEqualTo(T value) {
120         return new ComparatorMatcher<T>(comparator, value, ComparatorMatcher.EQUAL, ComparatorMatcher.EQUAL, includeComparatorInDescription);
121     }
122 
123     /**
124      * Creates a matcher of {@code T} object that matches when the examined object is
125      * greater than the specified value, as reported by the {@code Comparator} used to
126      * create this builder.
127      * For example:
128      * <pre>assertThat(2, ComparatorMatcherBuilder.&lt;Integer&gt;usingNaturalOrdering().greaterThan(1))</pre>
129      *
130      * @param value the value which, when passed to the Comparator supplied to this builder, should return greater
131      *              than zero
132      */
133     public Matcher<T> greaterThan(T value) {
134         return new ComparatorMatcher<T>(comparator, value, ComparatorMatcher.GREATER_THAN, ComparatorMatcher.GREATER_THAN, includeComparatorInDescription);
135     }
136 
137     /**
138      * Creates a matcher of {@code T} object that matches when the examined object is
139      * greater than or equal to the specified value, as reported by the {@code Comparator} used to
140      * create this builder.
141      * For example:
142      * <pre>assertThat(1, ComparatorMatcherBuilder.&lt;Integer&gt;usingNaturalOrdering().greaterThanOrEqualTo(1))</pre>
143      *
144      * @param value the value which, when passed to the Comparator supplied to this builder, should return greater
145      *              than or equal to zero
146      */
147     public Matcher<T> greaterThanOrEqualTo(T value) {
148         return new ComparatorMatcher<T>(comparator, value, ComparatorMatcher.EQUAL, ComparatorMatcher.GREATER_THAN, includeComparatorInDescription);
149     }
150 
151     /**
152      * Creates a matcher of {@code T} object that matches when the examined object is
153      * less than the specified value, as reported by the {@code Comparator} used to
154      * create this builder.
155      * For example:
156      * <pre>assertThat(1, ComparatorMatcherBuilder.&lt;Integer&gt;usingNaturalOrdering().lessThan(2))</pre>
157      *
158      * @param value the value which, when passed to the Comparator supplied to this builder, should return less
159      *              than zero
160      */
161     public Matcher<T> lessThan(T value) {
162         return new ComparatorMatcher<T>(comparator, value, ComparatorMatcher.LESS_THAN, ComparatorMatcher.LESS_THAN, includeComparatorInDescription);
163     }
164 
165     /**
166      * Creates a matcher of {@code T} object that matches when the examined object is
167      * less than or equal to the specified value, as reported by the {@code Comparator} used to
168      * create this builder.
169      * For example:
170      * <pre>assertThat(1, ComparatorMatcherBuilder.&lt;Integer&gt;usingNaturalOrdering().lessThanOrEqualTo(1))</pre>
171      *
172      * @param value the value which, when passed to the Comparator supplied to this builder, should return less
173      *              than or equal to zero
174      */
175     public Matcher<T> lessThanOrEqualTo(T value) {
176         return new ComparatorMatcher<T>(comparator, value, ComparatorMatcher.LESS_THAN, ComparatorMatcher.EQUAL, includeComparatorInDescription);
177     }
178 }
179