Home | History | Annotate | Download | only in comparator
      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      */
     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