1package org.hamcrest.core;
2
3import org.hamcrest.BaseMatcher;
4import org.hamcrest.Description;
5import org.hamcrest.Matcher;
6
7import java.lang.reflect.Array;
8
9
10/**
11 * Is the value equal to another value, as tested by the
12 * {@link java.lang.Object#equals} invokedMethod?
13 */
14public class IsEqual<T> extends BaseMatcher<T> {
15    private final Object expectedValue;
16
17    public IsEqual(T equalArg) {
18        expectedValue = equalArg;
19    }
20
21    @Override
22    public boolean matches(Object actualValue) {
23        return areEqual(actualValue, expectedValue);
24    }
25
26    @Override
27    public void describeTo(Description description) {
28        description.appendValue(expectedValue);
29    }
30
31    private static boolean areEqual(Object actual, Object expected) {
32        if (actual == null) {
33            return expected == null;
34        }
35
36        if (expected != null && isArray(actual)) {
37            return isArray(expected) && areArraysEqual(actual, expected);
38        }
39
40        return actual.equals(expected);
41    }
42
43    private static boolean areArraysEqual(Object actualArray, Object expectedArray) {
44        return areArrayLengthsEqual(actualArray, expectedArray) && areArrayElementsEqual(actualArray, expectedArray);
45    }
46
47    private static boolean areArrayLengthsEqual(Object actualArray, Object expectedArray) {
48        return Array.getLength(actualArray) == Array.getLength(expectedArray);
49    }
50
51    private static boolean areArrayElementsEqual(Object actualArray, Object expectedArray) {
52        for (int i = 0; i < Array.getLength(actualArray); i++) {
53            if (!areEqual(Array.get(actualArray, i), Array.get(expectedArray, i))) {
54                return false;
55            }
56        }
57        return true;
58    }
59
60    private static boolean isArray(Object o) {
61        return o.getClass().isArray();
62    }
63
64    /**
65     * Creates a matcher that matches when the examined object is logically equal to the specified
66     * <code>operand</code>, as determined by calling the {@link java.lang.Object#equals} method on
67     * the <b>examined</b> object.
68     *
69     * <p>If the specified operand is <code>null</code> then the created matcher will only match if
70     * the examined object's <code>equals</code> method returns <code>true</code> when passed a
71     * <code>null</code> (which would be a violation of the <code>equals</code> contract), unless the
72     * examined object itself is <code>null</code>, in which case the matcher will return a positive
73     * match.</p>
74     *
75     * <p>The created matcher provides a special behaviour when examining <code>Array</code>s, whereby
76     * it will match if both the operand and the examined object are arrays of the same length and
77     * contain items that are equal to each other (according to the above rules) <b>in the same
78     * indexes</b>.</p>
79     * For example:
80     * <pre>
81     * assertThat("foo", equalTo("foo"));
82     * assertThat(new String[] {"foo", "bar"}, equalTo(new String[] {"foo", "bar"}));
83     * </pre>
84     *
85     */
86    public static <T> Matcher<T> equalTo(T operand) {
87        return new IsEqual<T>(operand);
88    }
89
90    /**
91     * Creates an {@link org.hamcrest.core.IsEqual} matcher that does not enforce the values being
92     * compared to be of the same static type.
93     */
94    public static Matcher<Object> equalToObject(Object operand) {
95        return new IsEqual<Object>(operand);
96    }
97}
98