All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.organicdesign.testUtils.ComparatorContract Maven / Gradle / Ivy

package org.organicdesign.testUtils;

import java.util.Arrays;
import java.util.Comparator;
import java.util.concurrent.atomic.AtomicBoolean;

import static org.junit.Assert.*;
import static org.organicdesign.testUtils.ComparatorContract.CompToZero.*;
/**
 Created by gpeterso on 3/28/17.
 */
@SuppressWarnings("WeakerAccess")
public class ComparatorContract {
    public enum CompToZero {
        LTZ {
            @Override public String english() { return "less than"; }
            @Override public boolean vsZero(int i) { return i < 0; }
        },
        GTZ {
            @Override public String english() { return "greater than"; }
            @Override public boolean vsZero(int i) { return i > 0; }
        },
        EQZ {
            @Override public String english() { return "equal to"; }
            @Override public boolean vsZero(int i) { return i == 0; }
        };
        public abstract String english();
        public abstract boolean vsZero(int i);
    }

    private static class Named {
        final T a;
        final String name;
        Named(T theA, String nm) {a = theA;name = nm; }
    }

    private static  Named t2(T a, String c) {
        return new Named<>(a, c);
    }

    private static 
    void pairComp(Named first, CompToZero comp, Named second,
                                 Comparator comparator) {
        assertTrue("The " + first.name + " item must be " + comp.english() +
                   " the " + second.name,
                   comp.vsZero(comparator.compare(first.a, second.a)));
    }

    /**
     Tests the various properties the Comparable contract is supposed to uphold.  Also tests that
     the behavior of compareTo() is compatible with equals() and hashCode() which is strongly
     suggested, but not actually required.
     Write your own test if you don't want that.
     Expects three unique objects.
     The first must be less than the second, which in turn is less than the third.

     See note in class documentation.
     */
    // Many of the comments in this method are paraphrases or direct quotes from the Javadocs for
    // the Comparable interface.  That is where this contract is specified.
    // https://docs.oracle.com/javase/8/docs/api/
    public static 
    void testComparator(T least1, T middle1, T greatest1, Comparator comparator) {

        // TODO: Do we want to ensure that comparators are serializable?

        AtomicBoolean anySame = new AtomicBoolean();
        EqualsContract.permutations(Arrays.asList(least1, middle1, greatest1),
                                    (T a, T b) -> {
                                        if (a == b) {
                                            anySame.set(true);
                                        }
                                        return null;
                                    });
        if (anySame.get()) {
            throw new IllegalArgumentException("You must provide three pair of different objects in order");
        }

        int i = 0;
        for (T item : Arrays.asList(least1, middle1, greatest1)) {
            i++;
            // null is not an instance of any class, and e.compareTo(null) should throw a
            // NullPointerException
            try {
                //noinspection ResultOfMethodCallIgnored
                comparator.compare(item, null);
                fail("comparator.compare(item, null) should throw an exception " +
                     "even though e.equals(null) returns false, but item " + i + " did not.");
            } catch (RuntimeException ignore) {
                // Previously we had allowed NullPointerException and IllegalArgumentException.
                // Kotlin throws IllegalStateException, so we now expect any RuntimeException
                // to be thrown.
            }

            try {
                //noinspection ResultOfMethodCallIgnored
                comparator.compare(null, item);
                fail("comparator.compare(null, item) should throw an exception " +
                     "even though e.equals(null) returns false, but item " + i + " did not.");
            } catch (RuntimeException ignore) {
                // Previously we had allowed NullPointerException and IllegalArgumentException.
                // Kotlin throws IllegalStateException, so we now expect any RuntimeException
                // to be thrown.
            }
        }

        Named least = t2(least1, "Least");
        Named middle = t2(middle1, "Middle");
        Named greatest = t2(greatest1, "Greatest");

        for (Named pair : Arrays.asList(least, middle, greatest)) {
            // Consistent with equals: (e1.compareTo(e2) == 0) if and only if e1.equals(e2)
            pairComp(pair, EQZ, pair, comparator);
        }

        pairComp(least, LTZ, middle, comparator);
        pairComp(least, LTZ, greatest, comparator);
        pairComp(middle, LTZ, greatest, comparator);

        pairComp(greatest, GTZ, middle, comparator);
        pairComp(greatest, GTZ, least, comparator);
        pairComp(middle, GTZ, least, comparator);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy