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    }