1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.test;
18
19import com.google.android.collect.Lists;
20import junit.framework.Assert;
21
22import java.util.Arrays;
23import java.util.HashMap;
24import java.util.HashSet;
25import java.util.Map;
26import java.util.Set;
27import java.util.ArrayList;
28import java.util.regex.MatchResult;
29import java.util.regex.Matcher;
30import java.util.regex.Pattern;
31
32/**
33 * Contains additional assertion methods not found in JUnit.
34 */
35public final class MoreAsserts {
36
37    private MoreAsserts() { }
38
39    /**
40     * Asserts that the class  {@code expected} is assignable from the object
41     * {@code actual}. This verifies {@code expected} is a parent class or a
42     * interface that {@code actual} implements.
43     */
44    public static void assertAssignableFrom(Class<?> expected, Object actual) {
45        assertAssignableFrom(expected, actual.getClass());
46    }
47
48    /**
49     * Asserts that class {@code expected} is assignable from the class
50     * {@code actual}. This verifies {@code expected} is a parent class or a
51     * interface that {@code actual} implements.
52     */
53    public static void assertAssignableFrom(Class<?> expected, Class<?> actual) {
54        Assert.assertTrue(
55                "Expected " + expected.getCanonicalName() +
56                        " to be assignable from actual class " + actual.getCanonicalName(),
57                expected.isAssignableFrom(actual));
58    }
59
60    /**
61     * Asserts that {@code actual} is not equal {@code unexpected}, according
62     * to both {@code ==} and {@link Object#equals}.
63     */
64    public static void assertNotEqual(
65            String message, Object unexpected, Object actual) {
66        if (equal(unexpected, actual)) {
67            failEqual(message, unexpected);
68        }
69    }
70
71    /**
72     * Variant of {@link #assertNotEqual(String,Object,Object)} using a
73     * generic message.
74     */
75    public static void assertNotEqual(Object unexpected, Object actual) {
76        assertNotEqual(null, unexpected, actual);
77    }
78
79    /**
80     * Asserts that array {@code actual} is the same size and every element equals
81     * those in array {@code expected}. On failure, message indicates specific
82     * element mismatch.
83     */
84    public static void assertEquals(
85            String message, byte[] expected, byte[] actual) {
86        if (expected.length != actual.length) {
87            failWrongLength(message, expected.length, actual.length);
88        }
89        for (int i = 0; i < expected.length; i++) {
90            if (expected[i] != actual[i]) {
91                failWrongElement(message, i, expected[i], actual[i]);
92            }
93        }
94    }
95
96    /**
97     * Asserts that array {@code actual} is the same size and every element equals
98     * those in array {@code expected}. On failure, message indicates specific
99     * element mismatch.
100     */
101    public static void assertEquals(byte[] expected, byte[] actual) {
102        assertEquals(null, expected, actual);
103    }
104
105    /**
106     * Asserts that array {@code actual} is the same size and every element equals
107     * those in array {@code expected}. On failure, message indicates first
108     * specific element mismatch.
109     */
110    public static void assertEquals(
111            String message, int[] expected, int[] actual) {
112        if (expected.length != actual.length) {
113            failWrongLength(message, expected.length, actual.length);
114        }
115        for (int i = 0; i < expected.length; i++) {
116            if (expected[i] != actual[i]) {
117                failWrongElement(message, i, expected[i], actual[i]);
118            }
119        }
120    }
121
122    /**
123     * Asserts that array {@code actual} is the same size and every element equals
124     * those in array {@code expected}. On failure, message indicates first
125     * specific element mismatch.
126     */
127    public static void assertEquals(int[] expected, int[] actual) {
128        assertEquals(null, expected, actual);
129    }
130
131    /**
132     * Asserts that array {@code actual} is the same size and every element equals
133     * those in array {@code expected}. On failure, message indicates first
134     * specific element mismatch.
135     */
136    public static void assertEquals(
137            String message, double[] expected, double[] actual) {
138        if (expected.length != actual.length) {
139            failWrongLength(message, expected.length, actual.length);
140        }
141        for (int i = 0; i < expected.length; i++) {
142            if (expected[i] != actual[i]) {
143                failWrongElement(message, i, expected[i], actual[i]);
144            }
145        }
146    }
147
148    /**
149     * Asserts that array {@code actual} is the same size and every element equals
150     * those in array {@code expected}. On failure, message indicates first
151     * specific element mismatch.
152     */
153    public static void assertEquals(double[] expected, double[] actual) {
154        assertEquals(null, expected, actual);
155    }
156
157    /**
158     * Asserts that array {@code actual} is the same size and every element
159     * is the same as those in array {@code expected}. Note that this uses
160     * {@code equals()} instead of {@code ==} to compare the objects.
161     * {@code null} will be considered equal to {@code null} (unlike SQL).
162     * On failure, message indicates first specific element mismatch.
163     */
164    public static void assertEquals(
165            String message, Object[] expected, Object[] actual) {
166        if (expected.length != actual.length) {
167            failWrongLength(message, expected.length, actual.length);
168        }
169        for (int i = 0; i < expected.length; i++) {
170            Object exp = expected[i];
171            Object act = actual[i];
172            // The following borrowed from java.util.equals(Object[], Object[]).
173            if (!((exp==null) ? act==null : exp.equals(act))) {
174                failWrongElement(message, i, exp, act);
175            }
176        }
177    }
178
179    /**
180     * Asserts that array {@code actual} is the same size and every element
181     * is the same as those in array {@code expected}. Note that this uses
182     * {@code ==} instead of {@code equals()} to compare the objects.
183     * On failure, message indicates first specific element mismatch.
184     */
185    public static void assertEquals(Object[] expected, Object[] actual) {
186        assertEquals(null, expected, actual);
187    }
188
189    /** Asserts that two sets contain the same elements. */
190    public static void assertEquals(
191            String message, Set<? extends Object> expected, Set<? extends Object> actual) {
192        Set<Object> onlyInExpected = new HashSet<Object>(expected);
193        onlyInExpected.removeAll(actual);
194        Set<Object> onlyInActual = new HashSet<Object>(actual);
195        onlyInActual.removeAll(expected);
196        if (onlyInExpected.size() != 0 || onlyInActual.size() != 0) {
197            Set<Object> intersection = new HashSet<Object>(expected);
198            intersection.retainAll(actual);
199            failWithMessage(
200                    message,
201                    "Sets do not match.\nOnly in expected: " + onlyInExpected
202                    + "\nOnly in actual: " + onlyInActual
203                    + "\nIntersection: " + intersection);
204        }
205    }
206
207    /** Asserts that two sets contain the same elements. */
208    public static void assertEquals(Set<? extends Object> expected, Set<? extends Object> actual) {
209        assertEquals(null, expected, actual);
210    }
211
212    /**
213     * Asserts that {@code expectedRegex} exactly matches {@code actual} and
214     * fails with {@code message} if it does not.  The MatchResult is returned
215     * in case the test needs access to any captured groups.  Note that you can
216     * also use this for a literal string, by wrapping your expected string in
217     * {@link Pattern#quote}.
218     */
219    public static MatchResult assertMatchesRegex(
220            String message, String expectedRegex, String actual) {
221        if (actual == null) {
222            failNotMatches(message, expectedRegex, actual);
223        }
224        Matcher matcher = getMatcher(expectedRegex, actual);
225        if (!matcher.matches()) {
226            failNotMatches(message, expectedRegex, actual);
227        }
228        return matcher;
229    }
230
231    /**
232     * Variant of {@link #assertMatchesRegex(String,String,String)} using a
233     * generic message.
234     */
235    public static MatchResult assertMatchesRegex(
236            String expectedRegex, String actual) {
237        return assertMatchesRegex(null, expectedRegex, actual);
238    }
239
240    /**
241     * Asserts that {@code expectedRegex} matches any substring of {@code actual}
242     * and fails with {@code message} if it does not.  The Matcher is returned in
243     * case the test needs access to any captured groups.  Note that you can also
244     * use this for a literal string, by wrapping your expected string in
245     * {@link Pattern#quote}.
246     */
247    public static MatchResult assertContainsRegex(
248            String message, String expectedRegex, String actual) {
249        if (actual == null) {
250            failNotContains(message, expectedRegex, actual);
251        }
252        Matcher matcher = getMatcher(expectedRegex, actual);
253        if (!matcher.find()) {
254            failNotContains(message, expectedRegex, actual);
255        }
256        return matcher;
257    }
258
259    /**
260     * Variant of {@link #assertContainsRegex(String,String,String)} using a
261     * generic message.
262     */
263    public static MatchResult assertContainsRegex(
264            String expectedRegex, String actual) {
265        return assertContainsRegex(null, expectedRegex, actual);
266    }
267
268    /**
269     * Asserts that {@code expectedRegex} does not exactly match {@code actual},
270     * and fails with {@code message} if it does. Note that you can also use
271     * this for a literal string, by wrapping your expected string in
272     * {@link Pattern#quote}.
273     */
274    public static void assertNotMatchesRegex(
275            String message, String expectedRegex, String actual) {
276        Matcher matcher = getMatcher(expectedRegex, actual);
277        if (matcher.matches()) {
278            failMatch(message, expectedRegex, actual);
279        }
280    }
281
282    /**
283     * Variant of {@link #assertNotMatchesRegex(String,String,String)} using a
284     * generic message.
285     */
286    public static void assertNotMatchesRegex(
287            String expectedRegex, String actual) {
288        assertNotMatchesRegex(null, expectedRegex, actual);
289    }
290
291    /**
292     * Asserts that {@code expectedRegex} does not match any substring of
293     * {@code actual}, and fails with {@code message} if it does.  Note that you
294     * can also use this for a literal string, by wrapping your expected string
295     * in {@link Pattern#quote}.
296     */
297    public static void assertNotContainsRegex(
298            String message, String expectedRegex, String actual) {
299        Matcher matcher = getMatcher(expectedRegex, actual);
300        if (matcher.find()) {
301            failContains(message, expectedRegex, actual);
302        }
303    }
304
305    /**
306     * Variant of {@link #assertNotContainsRegex(String,String,String)} using a
307     * generic message.
308     */
309    public static void assertNotContainsRegex(
310            String expectedRegex, String actual) {
311        assertNotContainsRegex(null, expectedRegex, actual);
312    }
313
314    /**
315     * Asserts that {@code actual} contains precisely the elements
316     * {@code expected}, and in the same order.
317     */
318    public static void assertContentsInOrder(
319            String message, Iterable<?> actual, Object... expected) {
320        ArrayList actualList = new ArrayList();
321        for (Object o : actual) {
322            actualList.add(o);
323        }
324        Assert.assertEquals(message, Arrays.asList(expected), actualList);
325    }
326
327    /**
328     * Variant of assertContentsInOrder(String, Iterable<?>, Object...)
329     * using a generic message.
330     */
331    public static void assertContentsInOrder(
332            Iterable<?> actual, Object... expected) {
333        assertContentsInOrder((String) null, actual, expected);
334    }
335
336    /**
337     * Asserts that {@code actual} contains precisely the elements
338     * {@code expected}, but in any order.
339     */
340    public static void assertContentsInAnyOrder(String message, Iterable<?> actual,
341            Object... expected) {
342        HashMap<Object, Object> expectedMap = new HashMap<Object, Object>(expected.length);
343        for (Object expectedObj : expected) {
344            expectedMap.put(expectedObj, expectedObj);
345        }
346
347        for (Object actualObj : actual) {
348            if (expectedMap.remove(actualObj) == null) {
349                failWithMessage(message, "Extra object in actual: (" + actualObj.toString() + ")");
350            }
351        }
352
353        if (expectedMap.size() > 0) {
354            failWithMessage(message, "Extra objects in expected.");
355        }
356    }
357
358    /**
359     * Variant of assertContentsInAnyOrder(String, Iterable<?>, Object...)
360     * using a generic message.
361     */
362    public static void assertContentsInAnyOrder(Iterable<?> actual, Object... expected) {
363        assertContentsInAnyOrder((String)null, actual, expected);
364    }
365
366    /**
367     * Asserts that {@code iterable} is empty.
368     */
369    public static void assertEmpty(String message, Iterable<?> iterable) {
370        if (iterable.iterator().hasNext()) {
371            failNotEmpty(message, iterable.toString());
372        }
373    }
374
375    /**
376     * Variant of {@link #assertEmpty(String, Iterable)} using a
377     * generic message.
378     */
379    public static void assertEmpty(Iterable<?> iterable) {
380        assertEmpty(null, iterable);
381    }
382
383    /**
384     * Asserts that {@code map} is empty.
385     */
386    public static void assertEmpty(String message, Map<?,?> map) {
387        if (!map.isEmpty()) {
388            failNotEmpty(message, map.toString());
389        }
390    }
391
392    /**
393     * Variant of {@link #assertEmpty(String, Map)} using a generic
394     * message.
395     */
396    public  static void assertEmpty(Map<?,?> map) {
397        assertEmpty(null, map);
398    }
399
400    /**
401     * Asserts that {@code iterable} is not empty.
402     */
403    public static void assertNotEmpty(String message, Iterable<?> iterable) {
404        if (!iterable.iterator().hasNext()) {
405            failEmpty(message);
406        }
407    }
408
409    /**
410     * Variant of assertNotEmpty(String, Iterable<?>)
411     * using a generic message.
412     */
413    public static void assertNotEmpty(Iterable<?> iterable) {
414        assertNotEmpty(null, iterable);
415    }
416
417    /**
418     * Asserts that {@code map} is not empty.
419     */
420    public static void assertNotEmpty(String message, Map<?,?> map) {
421        if (map.isEmpty()) {
422            failEmpty(message);
423        }
424    }
425
426    /**
427     * Variant of {@link #assertNotEmpty(String, Map)} using a generic
428     * message.
429     */
430    public static void assertNotEmpty(Map<?,?> map) {
431        assertNotEmpty(null, map);
432    }
433
434    /**
435     * Utility for testing equals() and hashCode() results at once.
436     * Tests that lhs.equals(rhs) matches expectedResult, as well as
437     * rhs.equals(lhs).  Also tests that hashCode() return values are
438     * equal if expectedResult is true.  (hashCode() is not tested if
439     * expectedResult is false, as unequal objects can have equal hashCodes.)
440     *
441     * @param lhs An Object for which equals() and hashCode() are to be tested.
442     * @param rhs As lhs.
443     * @param expectedResult True if the objects should compare equal,
444     *   false if not.
445     */
446    public static void checkEqualsAndHashCodeMethods(
447            String message, Object lhs, Object rhs, boolean expectedResult) {
448
449        if ((lhs == null) && (rhs == null)) {
450            Assert.assertTrue(
451                    "Your check is dubious...why would you expect null != null?",
452                    expectedResult);
453            return;
454        }
455
456        if ((lhs == null) || (rhs == null)) {
457            Assert.assertFalse(
458                    "Your check is dubious...why would you expect an object "
459                            + "to be equal to null?", expectedResult);
460        }
461
462        if (lhs != null) {
463            Assert.assertEquals(message, expectedResult, lhs.equals(rhs));
464        }
465        if (rhs != null) {
466            Assert.assertEquals(message, expectedResult, rhs.equals(lhs));
467        }
468
469        if (expectedResult) {
470            String hashMessage =
471                    "hashCode() values for equal objects should be the same";
472            if (message != null) {
473                hashMessage += ": " + message;
474            }
475            Assert.assertTrue(hashMessage, lhs.hashCode() == rhs.hashCode());
476        }
477    }
478
479    /**
480     * Variant of
481     * checkEqualsAndHashCodeMethods(String,Object,Object,boolean...)}
482     * using a generic message.
483     */
484    public static void checkEqualsAndHashCodeMethods(Object lhs, Object rhs,
485            boolean expectedResult) {
486        checkEqualsAndHashCodeMethods((String) null, lhs, rhs, expectedResult);
487    }
488
489    private static Matcher getMatcher(String expectedRegex, String actual) {
490        Pattern pattern = Pattern.compile(expectedRegex);
491        return pattern.matcher(actual);
492    }
493
494    private static void failEqual(String message, Object unexpected) {
495        failWithMessage(message, "expected not to be:<" + unexpected + ">");
496    }
497
498    private static void failWrongLength(
499            String message, int expected, int actual) {
500        failWithMessage(message, "expected array length:<" + expected
501                + "> but was:<" + actual + '>');
502    }
503
504    private static void failWrongElement(
505            String message, int index, Object expected, Object actual) {
506        failWithMessage(message, "expected array element[" + index + "]:<"
507                + expected + "> but was:<" + actual + '>');
508    }
509
510    private static void failNotMatches(
511            String message, String expectedRegex, String actual) {
512        String actualDesc = (actual == null) ? "null" : ('<' + actual + '>');
513        failWithMessage(message, "expected to match regex:<" + expectedRegex
514                + "> but was:" + actualDesc);
515    }
516
517    private static void failNotContains(
518            String message, String expectedRegex, String actual) {
519        String actualDesc = (actual == null) ? "null" : ('<' + actual + '>');
520        failWithMessage(message, "expected to contain regex:<" + expectedRegex
521                + "> but was:" + actualDesc);
522    }
523
524    private static void failMatch(
525            String message, String expectedRegex, String actual) {
526        failWithMessage(message, "expected not to match regex:<" + expectedRegex
527                + "> but was:<" + actual + '>');
528    }
529
530    private static void failContains(
531            String message, String expectedRegex, String actual) {
532        failWithMessage(message, "expected not to contain regex:<" + expectedRegex
533                + "> but was:<" + actual + '>');
534    }
535
536    private static void failNotEmpty(
537            String message, String actual) {
538        failWithMessage(message, "expected to be empty, but contained: <"
539                + actual + ">");
540    }
541
542    private static void failEmpty(String message) {
543        failWithMessage(message, "expected not to be empty, but was");
544    }
545
546    private static void failWithMessage(String userMessage, String ourMessage) {
547        Assert.fail((userMessage == null)
548                ? ourMessage
549                : userMessage + ' ' + ourMessage);
550    }
551
552    private static boolean equal(Object a, Object b) {
553        return a == b || (a != null && a.equals(b));
554    }
555
556}
557