/* * Copyright (C) 2007 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.test; import junit.framework.Assert; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.ArrayList; import java.util.regex.MatchResult; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Contains additional assertion methods not found in JUnit. */ public final class MoreAsserts { private MoreAsserts() { } /** * Asserts that the class {@code expected} is assignable from the object * {@code actual}. This verifies {@code expected} is a parent class or a * interface that {@code actual} implements. */ public static void assertAssignableFrom(Class expected, Object actual) { assertAssignableFrom(expected, actual.getClass()); } /** * Asserts that class {@code expected} is assignable from the class * {@code actual}. This verifies {@code expected} is a parent class or a * interface that {@code actual} implements. */ public static void assertAssignableFrom(Class expected, Class actual) { Assert.assertTrue( "Expected " + expected.getCanonicalName() + " to be assignable from actual class " + actual.getCanonicalName(), expected.isAssignableFrom(actual)); } /** * Asserts that {@code actual} is not equal {@code unexpected}, according * to both {@code ==} and {@link Object#equals}. */ public static void assertNotEqual( String message, Object unexpected, Object actual) { if (equal(unexpected, actual)) { failEqual(message, unexpected); } } /** * Variant of {@link #assertNotEqual(String,Object,Object)} using a * generic message. */ public static void assertNotEqual(Object unexpected, Object actual) { assertNotEqual(null, unexpected, actual); } /** * Asserts that array {@code actual} is the same size and every element equals * those in array {@code expected}. On failure, message indicates specific * element mismatch. */ public static void assertEquals( String message, byte[] expected, byte[] actual) { if (expected.length != actual.length) { failWrongLength(message, expected.length, actual.length); } for (int i = 0; i < expected.length; i++) { if (expected[i] != actual[i]) { failWrongElement(message, i, expected[i], actual[i]); } } } /** * Asserts that array {@code actual} is the same size and every element equals * those in array {@code expected}. On failure, message indicates specific * element mismatch. */ public static void assertEquals(byte[] expected, byte[] actual) { assertEquals(null, expected, actual); } /** * Asserts that array {@code actual} is the same size and every element equals * those in array {@code expected}. On failure, message indicates first * specific element mismatch. */ public static void assertEquals( String message, int[] expected, int[] actual) { if (expected.length != actual.length) { failWrongLength(message, expected.length, actual.length); } for (int i = 0; i < expected.length; i++) { if (expected[i] != actual[i]) { failWrongElement(message, i, expected[i], actual[i]); } } } /** * Asserts that array {@code actual} is the same size and every element equals * those in array {@code expected}. On failure, message indicates first * specific element mismatch. */ public static void assertEquals(int[] expected, int[] actual) { assertEquals(null, expected, actual); } /** * @hide Asserts that array {@code actual} is the same size and every element equals * those in array {@code expected}. On failure, message indicates first * specific element mismatch. */ public static void assertEquals( String message, long[] expected, long[] actual) { if (expected.length != actual.length) { failWrongLength(message, expected.length, actual.length); } for (int i = 0; i < expected.length; i++) { if (expected[i] != actual[i]) { failWrongElement(message, i, expected[i], actual[i]); } } } /** * @hide Asserts that array {@code actual} is the same size and every element equals * those in array {@code expected}. On failure, message indicates first * specific element mismatch. */ public static void assertEquals(long[] expected, long[] actual) { assertEquals(null, expected, actual); } /** * Asserts that array {@code actual} is the same size and every element equals * those in array {@code expected}. On failure, message indicates first * specific element mismatch. */ public static void assertEquals( String message, double[] expected, double[] actual) { if (expected.length != actual.length) { failWrongLength(message, expected.length, actual.length); } for (int i = 0; i < expected.length; i++) { if (expected[i] != actual[i]) { failWrongElement(message, i, expected[i], actual[i]); } } } /** * Asserts that array {@code actual} is the same size and every element equals * those in array {@code expected}. On failure, message indicates first * specific element mismatch. */ public static void assertEquals(double[] expected, double[] actual) { assertEquals(null, expected, actual); } /** * Asserts that array {@code actual} is the same size and every element * is the same as those in array {@code expected}. Note that this uses * {@code equals()} instead of {@code ==} to compare the objects. * {@code null} will be considered equal to {@code null} (unlike SQL). * On failure, message indicates first specific element mismatch. */ public static void assertEquals( String message, Object[] expected, Object[] actual) { if (expected.length != actual.length) { failWrongLength(message, expected.length, actual.length); } for (int i = 0; i < expected.length; i++) { Object exp = expected[i]; Object act = actual[i]; // The following borrowed from java.util.equals(Object[], Object[]). if (!((exp==null) ? act==null : exp.equals(act))) { failWrongElement(message, i, exp, act); } } } /** * Asserts that array {@code actual} is the same size and every element * is the same as those in array {@code expected}. Note that this uses * {@code ==} instead of {@code equals()} to compare the objects. * On failure, message indicates first specific element mismatch. */ public static void assertEquals(Object[] expected, Object[] actual) { assertEquals(null, expected, actual); } /** Asserts that two sets contain the same elements. */ public static void assertEquals( String message, Set expected, Set actual) { Set onlyInExpected = new HashSet(expected); onlyInExpected.removeAll(actual); Set onlyInActual = new HashSet(actual); onlyInActual.removeAll(expected); if (onlyInExpected.size() != 0 || onlyInActual.size() != 0) { Set intersection = new HashSet(expected); intersection.retainAll(actual); failWithMessage( message, "Sets do not match.\nOnly in expected: " + onlyInExpected + "\nOnly in actual: " + onlyInActual + "\nIntersection: " + intersection); } } /** Asserts that two sets contain the same elements. */ public static void assertEquals(Set expected, Set actual) { assertEquals(null, expected, actual); } /** * Asserts that {@code expectedRegex} exactly matches {@code actual} and * fails with {@code message} if it does not. The MatchResult is returned * in case the test needs access to any captured groups. Note that you can * also use this for a literal string, by wrapping your expected string in * {@link Pattern#quote}. */ public static MatchResult assertMatchesRegex( String message, String expectedRegex, String actual) { if (actual == null) { failNotMatches(message, expectedRegex, actual); } Matcher matcher = getMatcher(expectedRegex, actual); if (!matcher.matches()) { failNotMatches(message, expectedRegex, actual); } return matcher; } /** * Variant of {@link #assertMatchesRegex(String,String,String)} using a * generic message. */ public static MatchResult assertMatchesRegex( String expectedRegex, String actual) { return assertMatchesRegex(null, expectedRegex, actual); } /** * Asserts that {@code expectedRegex} matches any substring of {@code actual} * and fails with {@code message} if it does not. The Matcher is returned in * case the test needs access to any captured groups. Note that you can also * use this for a literal string, by wrapping your expected string in * {@link Pattern#quote}. */ public static MatchResult assertContainsRegex( String message, String expectedRegex, String actual) { if (actual == null) { failNotContains(message, expectedRegex, actual); } Matcher matcher = getMatcher(expectedRegex, actual); if (!matcher.find()) { failNotContains(message, expectedRegex, actual); } return matcher; } /** * Variant of {@link #assertContainsRegex(String,String,String)} using a * generic message. */ public static MatchResult assertContainsRegex( String expectedRegex, String actual) { return assertContainsRegex(null, expectedRegex, actual); } /** * Asserts that {@code expectedRegex} does not exactly match {@code actual}, * and fails with {@code message} if it does. Note that you can also use * this for a literal string, by wrapping your expected string in * {@link Pattern#quote}. */ public static void assertNotMatchesRegex( String message, String expectedRegex, String actual) { Matcher matcher = getMatcher(expectedRegex, actual); if (matcher.matches()) { failMatch(message, expectedRegex, actual); } } /** * Variant of {@link #assertNotMatchesRegex(String,String,String)} using a * generic message. */ public static void assertNotMatchesRegex( String expectedRegex, String actual) { assertNotMatchesRegex(null, expectedRegex, actual); } /** * Asserts that {@code expectedRegex} does not match any substring of * {@code actual}, and fails with {@code message} if it does. Note that you * can also use this for a literal string, by wrapping your expected string * in {@link Pattern#quote}. */ public static void assertNotContainsRegex( String message, String expectedRegex, String actual) { Matcher matcher = getMatcher(expectedRegex, actual); if (matcher.find()) { failContains(message, expectedRegex, actual); } } /** * Variant of {@link #assertNotContainsRegex(String,String,String)} using a * generic message. */ public static void assertNotContainsRegex( String expectedRegex, String actual) { assertNotContainsRegex(null, expectedRegex, actual); } /** * Asserts that {@code actual} contains precisely the elements * {@code expected}, and in the same order. */ public static void assertContentsInOrder( String message, Iterable actual, Object... expected) { ArrayList actualList = new ArrayList(); for (Object o : actual) { actualList.add(o); } Assert.assertEquals(message, Arrays.asList(expected), actualList); } /** * Variant of assertContentsInOrder(String, Iterable, Object...) * using a generic message. */ public static void assertContentsInOrder( Iterable actual, Object... expected) { assertContentsInOrder((String) null, actual, expected); } /** * Asserts that {@code actual} contains precisely the elements * {@code expected}, but in any order. */ public static void assertContentsInAnyOrder(String message, Iterable actual, Object... expected) { HashMap expectedMap = new HashMap(expected.length); for (Object expectedObj : expected) { expectedMap.put(expectedObj, expectedObj); } for (Object actualObj : actual) { if (expectedMap.remove(actualObj) == null) { failWithMessage(message, "Extra object in actual: (" + actualObj.toString() + ")"); } } if (expectedMap.size() > 0) { failWithMessage(message, "Extra objects in expected."); } } /** * Variant of assertContentsInAnyOrder(String, Iterable, Object...) * using a generic message. */ public static void assertContentsInAnyOrder(Iterable actual, Object... expected) { assertContentsInAnyOrder((String)null, actual, expected); } /** * Asserts that {@code iterable} is empty. */ public static void assertEmpty(String message, Iterable iterable) { if (iterable.iterator().hasNext()) { failNotEmpty(message, iterable.toString()); } } /** * Variant of {@link #assertEmpty(String, Iterable)} using a * generic message. */ public static void assertEmpty(Iterable iterable) { assertEmpty(null, iterable); } /** * Asserts that {@code map} is empty. */ public static void assertEmpty(String message, Map map) { if (!map.isEmpty()) { failNotEmpty(message, map.toString()); } } /** * Variant of {@link #assertEmpty(String, Map)} using a generic * message. */ public static void assertEmpty(Map map) { assertEmpty(null, map); } /** * Asserts that {@code iterable} is not empty. */ public static void assertNotEmpty(String message, Iterable iterable) { if (!iterable.iterator().hasNext()) { failEmpty(message); } } /** * Variant of assertNotEmpty(String, Iterable) * using a generic message. */ public static void assertNotEmpty(Iterable iterable) { assertNotEmpty(null, iterable); } /** * Asserts that {@code map} is not empty. */ public static void assertNotEmpty(String message, Map map) { if (map.isEmpty()) { failEmpty(message); } } /** * Variant of {@link #assertNotEmpty(String, Map)} using a generic * message. */ public static void assertNotEmpty(Map map) { assertNotEmpty(null, map); } /** * Utility for testing equals() and hashCode() results at once. * Tests that lhs.equals(rhs) matches expectedResult, as well as * rhs.equals(lhs). Also tests that hashCode() return values are * equal if expectedResult is true. (hashCode() is not tested if * expectedResult is false, as unequal objects can have equal hashCodes.) * * @param lhs An Object for which equals() and hashCode() are to be tested. * @param rhs As lhs. * @param expectedResult True if the objects should compare equal, * false if not. */ public static void checkEqualsAndHashCodeMethods( String message, Object lhs, Object rhs, boolean expectedResult) { if ((lhs == null) && (rhs == null)) { Assert.assertTrue( "Your check is dubious...why would you expect null != null?", expectedResult); return; } if ((lhs == null) || (rhs == null)) { Assert.assertFalse( "Your check is dubious...why would you expect an object " + "to be equal to null?", expectedResult); } if (lhs != null) { Assert.assertEquals(message, expectedResult, lhs.equals(rhs)); } if (rhs != null) { Assert.assertEquals(message, expectedResult, rhs.equals(lhs)); } if (expectedResult) { String hashMessage = "hashCode() values for equal objects should be the same"; if (message != null) { hashMessage += ": " + message; } Assert.assertTrue(hashMessage, lhs.hashCode() == rhs.hashCode()); } } /** * Variant of * checkEqualsAndHashCodeMethods(String,Object,Object,boolean...)} * using a generic message. */ public static void checkEqualsAndHashCodeMethods(Object lhs, Object rhs, boolean expectedResult) { checkEqualsAndHashCodeMethods((String) null, lhs, rhs, expectedResult); } private static Matcher getMatcher(String expectedRegex, String actual) { Pattern pattern = Pattern.compile(expectedRegex); return pattern.matcher(actual); } private static void failEqual(String message, Object unexpected) { failWithMessage(message, "expected not to be:<" + unexpected + ">"); } private static void failWrongLength( String message, int expected, int actual) { failWithMessage(message, "expected array length:<" + expected + "> but was:<" + actual + '>'); } private static void failWrongElement( String message, int index, Object expected, Object actual) { failWithMessage(message, "expected array element[" + index + "]:<" + expected + "> but was:<" + actual + '>'); } private static void failNotMatches( String message, String expectedRegex, String actual) { String actualDesc = (actual == null) ? "null" : ('<' + actual + '>'); failWithMessage(message, "expected to match regex:<" + expectedRegex + "> but was:" + actualDesc); } private static void failNotContains( String message, String expectedRegex, String actual) { String actualDesc = (actual == null) ? "null" : ('<' + actual + '>'); failWithMessage(message, "expected to contain regex:<" + expectedRegex + "> but was:" + actualDesc); } private static void failMatch( String message, String expectedRegex, String actual) { failWithMessage(message, "expected not to match regex:<" + expectedRegex + "> but was:<" + actual + '>'); } private static void failContains( String message, String expectedRegex, String actual) { failWithMessage(message, "expected not to contain regex:<" + expectedRegex + "> but was:<" + actual + '>'); } private static void failNotEmpty( String message, String actual) { failWithMessage(message, "expected to be empty, but contained: <" + actual + ">"); } private static void failEmpty(String message) { failWithMessage(message, "expected not to be empty, but was"); } private static void failWithMessage(String userMessage, String ourMessage) { Assert.fail((userMessage == null) ? ourMessage : userMessage + ' ' + ourMessage); } private static boolean equal(Object a, Object b) { return a == b || (a != null && a.equals(b)); } }