    001    /*  Copyright (c) 2000-2006 hamcrest.org
    002     */
    003    package org.hamcrest.core;
    004
    005    import org.hamcrest.BaseMatcher;
    006    import org.hamcrest.Description;
    007    import org.hamcrest.Factory;
    008    import org.hamcrest.Matcher;
    009
    010    import java.lang.reflect.Array;
    011
    012
    013    /**
    014     * Is the value equal to another value, as tested by the
    015     * {@link java.lang.Object#equals} invokedMethod?
    016     */
    017    public class IsEqual<T> extends BaseMatcher<T> {
    018        private final Object expectedValue;
    019
    020        public IsEqual(T equalArg) {
    021            expectedValue = equalArg;
    022        }
    023
    024        @Override
    025        public boolean matches(Object actualValue) {
    026            return areEqual(actualValue, expectedValue);
    027        }
    028
    029        @Override
    030        public void describeTo(Description description) {
    031            description.appendValue(expectedValue);
    032        }
    033
    034        private static boolean areEqual(Object actual, Object expected) {
    035            if (actual == null) {
    036                return expected == null;
    037            }
    038
    039            if (expected != null && isArray(actual)) {
    040                return isArray(expected) && areArraysEqual(actual, expected);
    041            }
    042
    043            return actual.equals(expected);
    044        }
    045
    046        private static boolean areArraysEqual(Object actualArray, Object expectedArray) {
    047            return areArrayLengthsEqual(actualArray, expectedArray) && areArrayElementsEqual(actualArray, expectedArray);
    048        }
    049
    050        private static boolean areArrayLengthsEqual(Object actualArray, Object expectedArray) {
    051            return Array.getLength(actualArray) == Array.getLength(expectedArray);
    052        }
    053
    054        private static boolean areArrayElementsEqual(Object actualArray, Object expectedArray) {
    055            for (int i = 0; i < Array.getLength(actualArray); i++) {
    056                if (!areEqual(Array.get(actualArray, i), Array.get(expectedArray, i))) {
    057                    return false;
    058                }
    059            }
    060            return true;
    061        }
    062
    063        private static boolean isArray(Object o) {
    064            return o.getClass().isArray();
    065        }
    066
    067        /**
    068         * Creates a matcher that matches when the examined object is logically equal to the specified
    069         * <code>operand</code>, as determined by calling the {@link java.lang.Object#equals} method on
    070         * the <b>examined</b> object.
    071         *
    072         * <p>If the specified operand is <code>null</code> then the created matcher will only match if
    073         * the examined object's <code>equals</code> method returns <code>true</code> when passed a
    074         * <code>null</code> (which would be a violation of the <code>equals</code> contract), unless the
    075         * examined object itself is <code>null</code>, in which case the matcher will return a positive
    076         * match.</p>
    077         *
    078         * <p>The created matcher provides a special behaviour when examining <code>Array</code>s, whereby
    079         * it will match if both the operand and the examined object are arrays of the same length and
    080         * contain items that are equal to each other (according to the above rules) <b>in the same
    081         * indexes</b>.</p>
    082         * <p/>
    083         * For example:
    084         * <pre>
    085         * assertThat("foo", equalTo("foo"));
    086         * assertThat(new String[] {"foo", "bar"}, equalTo(new String[] {"foo", "bar"}));
    087         * </pre>
    088         *
    089         */
    090        @Factory
    091        public static <T> Matcher<T> equalTo(T operand) {
    092            return new IsEqual<T>(operand);
    093        }
    094    }