am 83c2b5de: Merge "android.util: Add CTS tests for Rational and Range" into lmp-preview-dev

* commit '83c2b5de324e06b5206f8ebff39273ab0a20fc48':
  android.util: Add CTS tests for Rational and Range
diff --git a/tests/tests/util/src/android/util/cts/RangeTest.java b/tests/tests/util/src/android/util/cts/RangeTest.java
new file mode 100644
index 0000000..45c1fef
--- /dev/null
+++ b/tests/tests/util/src/android/util/cts/RangeTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.cts;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Range;
+import android.util.Rational;
+
+public class RangeTest extends junit.framework.TestCase {
+
+    @SmallTest
+    public void testConstructor() {
+        // Trivial, same range
+        Range<Integer> intRange = new Range<Integer>(1, 1);
+
+        assertLower(intRange, 1);
+        assertUpper(intRange, 1);
+
+        // Different values in range
+        Range<Integer> intRange2 = new Range<Integer>(100, 200);
+        assertLower(intRange2, 100);
+        assertUpper(intRange2, 200);
+
+        Range<Float> floatRange = new Range<Float>(Float.NEGATIVE_INFINITY,
+                Float.POSITIVE_INFINITY);
+        assertLower(floatRange, Float.NEGATIVE_INFINITY);
+        assertUpper(floatRange, Float.POSITIVE_INFINITY);
+    }
+
+    @SmallTest
+    public void testIllegalValues() {
+        // Test NPEs
+        try {
+            new Range<Integer>(null, null);
+            fail("Expected exception to be thrown for (null, null)");
+        } catch (NullPointerException e) {
+            // OK: both args are null
+        }
+
+        try {
+            new Range<Integer>(null, 0);
+            fail("Expected exception to be thrown for (null, 0)");
+        } catch (NullPointerException e) {
+            // OK: left arg is null
+        }
+
+        try {
+            new Range<Integer>(0, null);
+            fail("Expected exception to be thrown for (0, null)");
+        } catch (NullPointerException e) {
+            // OK: right arg is null
+        }
+
+        // Test IAEs
+
+        try {
+            new Range<Integer>(50, -50);
+            fail("Expected exception to be thrown for (50, -50)");
+        } catch (IllegalArgumentException e) {
+            // OK: 50 > -50 so it fails
+        }
+
+        try {
+            new Range<Float>(0.0f, Float.NEGATIVE_INFINITY);
+            fail("Expected exception to be thrown for (0.0f, -Infinity)");
+        } catch (IllegalArgumentException e) {
+            // OK: 0.0f is > NEGATIVE_INFINITY, so it fails
+        }
+    }
+
+    @SmallTest
+    public void testEquals() {
+        Range<Float> oneHalf = Range.create(1.0f, 2.0f);
+        Range<Float> oneHalf2 = new Range<Float>(1.0f, 2.0f);
+        assertEquals(oneHalf, oneHalf2);
+        assertHashCodeEquals(oneHalf, oneHalf2);
+
+        Range<Float> twoThirds = new Range<Float>(2.0f, 3.0f);
+        Range<Float> twoThirds2 = Range.create(2.0f, 3.0f);
+        assertEquals(twoThirds, twoThirds2);
+        assertHashCodeEquals(twoThirds, twoThirds2);
+
+        Range<Rational> negativeOneTenthPositiveOneTenth =
+                new Range<Rational>(new Rational(-1, 10), new Rational(1, 10));
+        Range<Rational> negativeOneTenthPositiveOneTenth2 =
+                Range.create(new Rational(-1, 10), new Rational(1, 10));
+        assertEquals(negativeOneTenthPositiveOneTenth, negativeOneTenthPositiveOneTenth2);
+        assertHashCodeEquals(negativeOneTenthPositiveOneTenth, negativeOneTenthPositiveOneTenth2);
+    }
+
+    @SmallTest
+    public void testInRange() {
+        Range<Integer> hundredOneTwo = Range.create(100, 200);
+
+        assertInRange(hundredOneTwo, 100);
+        assertInRange(hundredOneTwo, 200);
+        assertInRange(hundredOneTwo, 150);
+        assertOutOfRange(hundredOneTwo, 99);
+        assertOutOfRange(hundredOneTwo, 201);
+        assertOutOfRange(hundredOneTwo, 100000);
+
+        Range<Float> infinities = Range.create(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY);
+
+        assertInRange(infinities, Float.NEGATIVE_INFINITY);
+        assertInRange(infinities, Float.POSITIVE_INFINITY);
+        assertInRange(infinities, 0.0f);
+        assertOutOfRange(infinities, Float.NaN);
+
+        Range<Rational> negativeOneTenthPositiveOneTenth =
+                new Range<Rational>(new Rational(-1, 10), new Rational(1, 10));
+        assertInRange(negativeOneTenthPositiveOneTenth, new Rational(-1, 10));
+        assertInRange(negativeOneTenthPositiveOneTenth, new Rational(1, 10));
+        assertInRange(negativeOneTenthPositiveOneTenth, Rational.ZERO);
+        assertOutOfRange(negativeOneTenthPositiveOneTenth, new Rational(-100, 1));
+        assertOutOfRange(negativeOneTenthPositiveOneTenth, new Rational(100, 1));
+    }
+
+    private static <T extends Comparable<? super T>> void assertInRange(Range<T> object, T needle) {
+        assertAction("in-range", object, needle, true, object.inRange(needle));
+    }
+
+    private static <T extends Comparable<? super T>> void assertOutOfRange(Range<T> object,
+            T needle) {
+        assertAction("out-of-range", object, needle, false, object.inRange(needle));
+    }
+
+    private static <T extends Comparable<? super T>> void assertUpper(Range<T> object, T expected) {
+        assertAction("upper", object, expected, object.getUpper());
+    }
+
+    private static <T extends Comparable<? super T>> void assertLower(Range<T> object, T expected) {
+        assertAction("lower", object, expected, object.getLower());
+    }
+
+    private static <T, T2> void assertAction(String action, T object, T2 expected,
+            T2 actual) {
+        assertEquals("Expected " + object + " " + action + " to be ",
+                expected, actual);
+    }
+
+    private static <T, T2> void assertAction(String action, T object, T2 needle, boolean expected,
+            boolean actual) {
+        String expectedMessage = expected ? action : ("not " + action);
+        assertEquals("Expected " + needle + " to be " + expectedMessage + " of " + object,
+                expected, actual);
+    }
+
+    private static <T extends Comparable<? super T>> void assertHashCodeEquals(
+            Range<T> left, Range<T> right) {
+        assertEquals("Left hash code for " + left +
+                " expected to be equal to right hash code for " + right,
+                left.hashCode(), right.hashCode());
+    }
+}
diff --git a/tests/tests/util/src/android/util/cts/RationalTest.java b/tests/tests/util/src/android/util/cts/RationalTest.java
new file mode 100644
index 0000000..ab5c063
--- /dev/null
+++ b/tests/tests/util/src/android/util/cts/RationalTest.java
@@ -0,0 +1,492 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.cts;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Rational;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+
+import static android.util.Rational.*;
+
+public class RationalTest extends junit.framework.TestCase {
+
+    /** (1,1) */
+    private static final Rational UNIT = new Rational(1, 1);
+
+    @SmallTest
+    public void testConstructor() {
+
+        // Simple case
+        Rational r = new Rational(1, 2);
+        assertEquals(1, r.getNumerator());
+        assertEquals(2, r.getDenominator());
+
+        // Denominator negative
+        r = new Rational(-1, 2);
+        assertEquals(-1, r.getNumerator());
+        assertEquals(2, r.getDenominator());
+
+        // Numerator negative
+        r = new Rational(1, -2);
+        assertEquals(-1, r.getNumerator());
+        assertEquals(2, r.getDenominator());
+
+        // Both negative
+        r = new Rational(-1, -2);
+        assertEquals(1, r.getNumerator());
+        assertEquals(2, r.getDenominator());
+
+        // Infinity.
+        r = new Rational(1, 0);
+        assertEquals(1, r.getNumerator());
+        assertEquals(0, r.getDenominator());
+
+        // Negative infinity.
+        r = new Rational(-1, 0);
+        assertEquals(-1, r.getNumerator());
+        assertEquals(0, r.getDenominator());
+
+        // NaN.
+        r = new Rational(0, 0);
+        assertEquals(0, r.getNumerator());
+        assertEquals(0, r.getDenominator());
+    }
+
+    @SmallTest
+    public void testEquals() {
+        Rational r = new Rational(1, 2);
+        assertEquals(1, r.getNumerator());
+        assertEquals(2, r.getDenominator());
+
+        assertEquals(r, r);
+        assertFalse(r.equals(null));
+        assertFalse(r.equals(new Object()));
+
+        Rational twoThirds = new Rational(2, 3);
+        assertFalse(r.equals(twoThirds));
+        assertFalse(twoThirds.equals(r));
+
+        Rational fourSixths = new Rational(4, 6);
+        assertEquals(twoThirds, fourSixths);
+        assertEquals(fourSixths, twoThirds);
+
+        Rational moreComplicated = new Rational(5*6*7*8*9, 1*2*3*4*5);
+        Rational moreComplicated2 = new Rational(5*6*7*8*9*78, 1*2*3*4*5*78);
+        assertEquals(moreComplicated, moreComplicated2);
+        assertEquals(moreComplicated2, moreComplicated);
+
+        // Ensure negatives are fine
+        twoThirds = new Rational(-2, 3);
+        fourSixths = new Rational(-4, 6);
+        assertEquals(twoThirds, fourSixths);
+        assertEquals(fourSixths, twoThirds);
+
+        moreComplicated = new Rational(-5*6*7*8*9, 1*2*3*4*5);
+        moreComplicated2 = new Rational(-5*6*7*8*9*78, 1*2*3*4*5*78);
+        assertEquals(moreComplicated, moreComplicated2);
+        assertEquals(moreComplicated2, moreComplicated);
+
+        // Zero is always equal to itself
+        Rational zero2 = new Rational(0, 100);
+        assertEquals(ZERO, zero2);
+        assertEquals(zero2, ZERO);
+
+        // NaN is always equal to itself
+        Rational nan = NaN;
+        Rational nan2 = new Rational(0, 0);
+        assertTrue(nan.equals(nan));
+        assertTrue(nan.equals(nan2));
+        assertTrue(nan2.equals(nan));
+        assertFalse(nan.equals(r));
+        assertFalse(r.equals(nan));
+
+        // Infinities of the same sign are equal.
+        Rational posInf = POSITIVE_INFINITY;
+        Rational posInf2 = new Rational(2, 0);
+        Rational negInf = NEGATIVE_INFINITY;
+        Rational negInf2 = new Rational(-2, 0);
+        assertEquals(posInf, posInf);
+        assertEquals(negInf, negInf);
+        assertEquals(posInf, posInf2);
+        assertEquals(negInf, negInf2);
+
+        // Infinities aren't equal to anything else.
+        assertFalse(posInf.equals(negInf));
+        assertFalse(negInf.equals(posInf));
+        assertFalse(negInf.equals(r));
+        assertFalse(posInf.equals(r));
+        assertFalse(r.equals(negInf));
+        assertFalse(r.equals(posInf));
+        assertFalse(posInf.equals(nan));
+        assertFalse(negInf.equals(nan));
+        assertFalse(nan.equals(posInf));
+        assertFalse(nan.equals(negInf));
+    }
+
+    @SmallTest
+    public void testReduction() {
+        Rational moreComplicated = new Rational(5 * 78, 7 * 78);
+        assertEquals(new Rational(5, 7), moreComplicated);
+        assertEquals(5, moreComplicated.getNumerator());
+        assertEquals(7, moreComplicated.getDenominator());
+
+        Rational posInf = new Rational(5, 0);
+        assertEquals(1, posInf.getNumerator());
+        assertEquals(0, posInf.getDenominator());
+        assertEquals(POSITIVE_INFINITY, posInf);
+
+        Rational negInf = new Rational(-100, 0);
+        assertEquals(-1, negInf.getNumerator());
+        assertEquals(0, negInf.getDenominator());
+        assertEquals(NEGATIVE_INFINITY, negInf);
+
+        Rational zero = new Rational(0, -100);
+        assertEquals(0, zero.getNumerator());
+        assertEquals(1, zero.getDenominator());
+        assertEquals(ZERO, zero);
+
+        Rational flipSigns = new Rational(1, -1);
+        assertEquals(-1, flipSigns.getNumerator());
+        assertEquals(1, flipSigns.getDenominator());
+
+        Rational flipAndReduce = new Rational(100, -200);
+        assertEquals(-1, flipAndReduce.getNumerator());
+        assertEquals(2, flipAndReduce.getDenominator());
+    }
+
+    @SmallTest
+    public void testCompareTo() {
+        // unit is equal to itself
+        assertCompareEquals(UNIT, new Rational(1, 1));
+
+        // NaN is greater than anything but NaN
+        assertCompareEquals(NaN, new Rational(0, 0));
+        assertGreaterThan(NaN, UNIT);
+        assertGreaterThan(NaN, POSITIVE_INFINITY);
+        assertGreaterThan(NaN, NEGATIVE_INFINITY);
+        assertGreaterThan(NaN, ZERO);
+
+        // Positive infinity is greater than any other non-NaN
+        assertCompareEquals(POSITIVE_INFINITY, new Rational(1, 0));
+        assertGreaterThan(POSITIVE_INFINITY, UNIT);
+        assertGreaterThan(POSITIVE_INFINITY, NEGATIVE_INFINITY);
+        assertGreaterThan(POSITIVE_INFINITY, ZERO);
+
+        // Negative infinity is smaller than any other non-NaN
+        assertCompareEquals(NEGATIVE_INFINITY, new Rational(-1, 0));
+        assertLessThan(NEGATIVE_INFINITY, UNIT);
+        assertLessThan(NEGATIVE_INFINITY, POSITIVE_INFINITY);
+        assertLessThan(NEGATIVE_INFINITY, ZERO);
+
+        // A finite number with the same denominator is trivially comparable
+        assertGreaterThan(new Rational(3, 100), new Rational(1, 100));
+        assertGreaterThan(new Rational(3, 100), ZERO);
+
+        // Compare finite numbers with different divisors
+        assertGreaterThan(new Rational(5, 25), new Rational(1, 10));
+        assertGreaterThan(new Rational(5, 25), ZERO);
+
+        // Compare finite numbers with different signs
+        assertGreaterThan(new Rational(5, 25), new Rational(-1, 10));
+        assertLessThan(new Rational(-5, 25), ZERO);
+    }
+
+    @SmallTest
+    public void testConvenienceMethods() {
+        // isFinite
+        assertFinite(ZERO, true);
+        assertFinite(NaN, false);
+        assertFinite(NEGATIVE_INFINITY, false);
+        assertFinite(POSITIVE_INFINITY, false);
+        assertFinite(UNIT, true);
+
+        // isInfinite
+        assertInfinite(ZERO, false);
+        assertInfinite(NaN, false);
+        assertInfinite(NEGATIVE_INFINITY, true);
+        assertInfinite(POSITIVE_INFINITY, true);
+        assertInfinite(UNIT, false);
+
+        // isNaN
+        assertNaN(ZERO, false);
+        assertNaN(NaN, true);
+        assertNaN(NEGATIVE_INFINITY, false);
+        assertNaN(POSITIVE_INFINITY, false);
+        assertNaN(UNIT, false);
+
+        // isZero
+        assertZero(ZERO, true);
+        assertZero(NaN, false);
+        assertZero(NEGATIVE_INFINITY, false);
+        assertZero(POSITIVE_INFINITY, false);
+        assertZero(UNIT, false);
+    }
+
+    @SmallTest
+    public void testValueConversions() {
+        // Unit, simple case
+        assertValueEquals(UNIT, 1.0f);
+        assertValueEquals(UNIT, 1.0);
+        assertValueEquals(UNIT, 1L);
+        assertValueEquals(UNIT, 1);
+        assertValueEquals(UNIT, (short)1);
+
+        // Zero, simple case
+        assertValueEquals(ZERO, 0.0f);
+        assertValueEquals(ZERO, 0.0);
+        assertValueEquals(ZERO, 0L);
+        assertValueEquals(ZERO, 0);
+        assertValueEquals(ZERO, (short)0);
+
+        // NaN is 0 for integers, not-a-number for floating point
+        assertValueEquals(NaN, Float.NaN);
+        assertValueEquals(NaN, Double.NaN);
+        assertValueEquals(NaN, 0L);
+        assertValueEquals(NaN, 0);
+        assertValueEquals(NaN, (short)0);
+
+        // Positive infinity, saturates upwards for integers
+        assertValueEquals(POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
+        assertValueEquals(POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+        assertValueEquals(POSITIVE_INFINITY, Long.MAX_VALUE);
+        assertValueEquals(POSITIVE_INFINITY, Integer.MAX_VALUE);
+        assertValueEquals(POSITIVE_INFINITY, (short)-1);
+
+        // Negative infinity, saturates downwards for integers
+        assertValueEquals(NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
+        assertValueEquals(NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
+        assertValueEquals(NEGATIVE_INFINITY, Long.MIN_VALUE);
+        assertValueEquals(NEGATIVE_INFINITY, Integer.MIN_VALUE);
+        assertValueEquals(NEGATIVE_INFINITY, (short)0);
+
+        // Normal finite values, round down for integers
+        final Rational oneQuarter = new Rational(1, 4);
+        assertValueEquals(oneQuarter, 1.0f / 4.0f);
+        assertValueEquals(oneQuarter, 1.0 / 4.0);
+        assertValueEquals(oneQuarter, 0L);
+        assertValueEquals(oneQuarter, 0);
+        assertValueEquals(oneQuarter, (short)0);
+
+        final Rational nineFifths = new Rational(9, 5);
+        assertValueEquals(nineFifths, 9.0f / 5.0f);
+        assertValueEquals(nineFifths, 9.0 / 5.0);
+        assertValueEquals(nineFifths, 1L);
+        assertValueEquals(nineFifths, 1);
+        assertValueEquals(nineFifths, (short)1);
+
+        final Rational negativeHundred = new Rational(-1000, 10);
+        assertValueEquals(negativeHundred, -100.f / 1.f);
+        assertValueEquals(negativeHundred, -100.0 / 1.0);
+        assertValueEquals(negativeHundred, -100L);
+        assertValueEquals(negativeHundred, -100);
+        assertValueEquals(negativeHundred, (short)-100);
+
+        // Short truncates if the result is too large
+        assertValueEquals(new Rational(Integer.MAX_VALUE, 1), (short)Integer.MAX_VALUE);
+        assertValueEquals(new Rational(0x00FFFFFF, 1), (short)0x00FFFFFF);
+        assertValueEquals(new Rational(0x00FF00FF, 1), (short)0x00FF00FF);
+    }
+
+    @SmallTest
+    public void testSerialize() throws ClassNotFoundException, IOException {
+        /*
+         * Check correct [de]serialization
+         */
+        assertEqualsAfterSerializing(ZERO);
+        assertEqualsAfterSerializing(NaN);
+        assertEqualsAfterSerializing(NEGATIVE_INFINITY);
+        assertEqualsAfterSerializing(POSITIVE_INFINITY);
+        assertEqualsAfterSerializing(UNIT);
+        assertEqualsAfterSerializing(new Rational(100, 200));
+        assertEqualsAfterSerializing(new Rational(-100, 200));
+        assertEqualsAfterSerializing(new Rational(5, 1));
+        assertEqualsAfterSerializing(new Rational(Integer.MAX_VALUE, Integer.MIN_VALUE));
+
+        /*
+         * Check bad deserialization fails
+         */
+        try {
+            Rational badZero = createIllegalRational(0, 100); // [0, 100] , should be [0, 1]
+            Rational results = serializeRoundTrip(badZero);
+            fail("Deserializing " + results + " should not have succeeded");
+        } catch (InvalidObjectException e) {
+            // OK
+        }
+
+        try {
+            Rational badPosInfinity = createIllegalRational(100, 0); // [100, 0] , should be [1, 0]
+            Rational results = serializeRoundTrip(badPosInfinity);
+            fail("Deserializing " + results + " should not have succeeded");
+        } catch (InvalidObjectException e) {
+            // OK
+        }
+
+        try {
+            Rational badNegInfinity =
+                    createIllegalRational(-100, 0); // [-100, 0] , should be [-1, 0]
+            Rational results = serializeRoundTrip(badNegInfinity);
+            fail("Deserializing " + results + " should not have succeeded");
+        } catch (InvalidObjectException e) {
+            // OK
+        }
+
+        try {
+            Rational badReduced = createIllegalRational(2, 4); // [2,4] , should be [1, 2]
+            Rational results = serializeRoundTrip(badReduced);
+            fail("Deserializing " + results + " should not have succeeded");
+        } catch (InvalidObjectException e) {
+            // OK
+        }
+
+        try {
+            Rational badReducedNeg = createIllegalRational(-2, 4); // [-2, 4] should be [-1, 2]
+            Rational results = serializeRoundTrip(badReducedNeg);
+            fail("Deserializing " + results + " should not have succeeded");
+        } catch (InvalidObjectException e) {
+            // OK
+        }
+    }
+
+    private static void assertValueEquals(Rational object, float expected) {
+        assertEquals("Checking floatValue() for " + object + ";",
+                expected, object.floatValue());
+    }
+
+    private static void assertValueEquals(Rational object, double expected) {
+        assertEquals("Checking doubleValue() for " + object + ";",
+                expected, object.doubleValue());
+    }
+
+    private static void assertValueEquals(Rational object, long expected) {
+        assertEquals("Checking longValue() for " + object + ";",
+                expected, object.longValue());
+    }
+
+    private static void assertValueEquals(Rational object, int expected) {
+        assertEquals("Checking intValue() for " + object + ";",
+                expected, object.intValue());
+    }
+
+    private static void assertValueEquals(Rational object, short expected) {
+        assertEquals("Checking shortValue() for " + object + ";",
+                expected, object.shortValue());
+    }
+
+    private static void assertFinite(Rational object, boolean expected) {
+        assertAction("finite", object, expected, object.isFinite());
+    }
+
+    private static void assertInfinite(Rational object, boolean expected) {
+        assertAction("infinite", object, expected, object.isInfinite());
+    }
+
+    private static void assertNaN(Rational object, boolean expected) {
+        assertAction("NaN", object, expected, object.isNaN());
+    }
+
+    private static void assertZero(Rational object, boolean expected) {
+        assertAction("zero", object, expected, object.isZero());
+    }
+
+    private static <T> void assertAction(String action, T object, boolean expected,
+            boolean actual) {
+        String expectedMessage = expected ? action : ("not " + action);
+        assertEquals("Expected " + object + " to be " + expectedMessage,
+                expected, actual);
+    }
+
+    private static <T extends Comparable<? super T>> void assertLessThan(T left, T right) {
+        assertTrue("Expected (LR) left " + left + " to be less than right " + right,
+                left.compareTo(right) < 0);
+        assertTrue("Expected (RL) left " + left + " to be less than right " + right,
+                right.compareTo(left) > 0);
+    }
+
+    private static <T extends Comparable<? super T>> void assertGreaterThan(T left, T right) {
+        assertTrue("Expected (LR) left " + left + " to be greater than right " + right,
+                left.compareTo(right) > 0);
+        assertTrue("Expected (RL) left " + left + " to be greater than right " + right,
+                right.compareTo(left) < 0);
+    }
+
+    private static <T extends Comparable<? super T>> void assertCompareEquals(T left, T right) {
+        assertTrue("Expected (LR) left " + left + " to be compareEquals to right " + right,
+                left.compareTo(right) == 0);
+        assertTrue("Expected (RL) left " + left + " to be compareEquals to right " + right,
+                right.compareTo(left) == 0);
+    }
+
+    private static <T extends Serializable> byte[] serialize(T obj) throws IOException {
+        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+        try (ObjectOutputStream objectStream = new ObjectOutputStream(byteStream)) {
+            objectStream.writeObject(obj);
+        }
+        return byteStream.toByteArray();
+    }
+
+    private static <T extends Serializable> T deserialize(byte[] array, Class<T> klass)
+            throws IOException, ClassNotFoundException {
+        ByteArrayInputStream bais = new ByteArrayInputStream(array);
+        ObjectInputStream ois = new ObjectInputStream(bais);
+        Object obj = ois.readObject();
+        return klass.cast(obj);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T extends Serializable> T serializeRoundTrip(T obj)
+            throws IOException, ClassNotFoundException {
+        Class<T> klass = (Class<T>) obj.getClass();
+        byte[] arr = serialize(obj);
+        T serialized = deserialize(arr, klass);
+        return serialized;
+    }
+
+    private static <T extends Serializable> void assertEqualsAfterSerializing(T obj)
+            throws ClassNotFoundException, IOException {
+        T serialized = serializeRoundTrip(obj);
+        assertEquals("Expected values to be equal after serialization round-trip", obj, serialized);
+    }
+
+    private static Rational createIllegalRational(int numerator, int denominator) {
+        Rational r = new Rational(numerator, denominator);
+        mutateField(r, "mNumerator", numerator);
+        mutateField(r, "mDenominator", denominator);
+        return r;
+    }
+
+    private static <T> void mutateField(T object, String name, int value) {
+        try {
+            Field f = object.getClass().getDeclaredField(name);
+            f.setAccessible(true);
+            f.set(object, value);
+        } catch (NoSuchFieldException e) {
+            throw new AssertionError(e);
+        } catch (IllegalAccessException e) {
+            throw new AssertionError(e);
+        } catch (IllegalArgumentException e) {
+            throw new AssertionError(e);
+        }
+    }
+}