1/*
2 * Copyright (c) 2007 Mockito contributors
3 * This program is made available under the terms of the MIT License.
4 */
5package org.mockito.internal.invocation;
6
7import org.hamcrest.Matcher;
8import org.mockito.internal.matchers.MatcherDecorator;
9import org.mockito.internal.matchers.VarargMatcher;
10import org.mockito.invocation.Invocation;
11
12import java.util.List;
13
14@SuppressWarnings("unchecked")
15public class ArgumentsComparator {
16    public boolean argumentsMatch(InvocationMatcher invocationMatcher, Invocation actual) {
17        Object[] actualArgs = actual.getArguments();
18        return argumentsMatch(invocationMatcher, actualArgs) || varArgsMatch(invocationMatcher, actual);
19    }
20
21    public boolean argumentsMatch(InvocationMatcher invocationMatcher, Object[] actualArgs) {
22        if (actualArgs.length != invocationMatcher.getMatchers().size()) {
23            return false;
24        }
25        for (int i = 0; i < actualArgs.length; i++) {
26            if (!invocationMatcher.getMatchers().get(i).matches(actualArgs[i])) {
27                return false;
28            }
29        }
30        return true;
31    }
32
33    //ok, this method is a little bit messy but the vararg business unfortunately is messy...
34    private boolean varArgsMatch(InvocationMatcher invocationMatcher, Invocation actual) {
35        if (!actual.getMethod().isVarArgs()) {
36            //if the method is not vararg forget about it
37            return false;
38        }
39
40        //we must use raw arguments, not arguments...
41        Object[] rawArgs = actual.getRawArguments();
42        List<Matcher> matchers = invocationMatcher.getMatchers();
43
44        if (rawArgs.length != matchers.size()) {
45            return false;
46        }
47
48        for (int i = 0; i < rawArgs.length; i++) {
49            Matcher m = matchers.get(i);
50            //it's a vararg because it's the last array in the arg list
51            if (rawArgs[i] != null && rawArgs[i].getClass().isArray() && i == rawArgs.length-1) {
52                Matcher actualMatcher;
53                //this is necessary as the framework often decorates matchers
54                if (m instanceof MatcherDecorator) {
55                    actualMatcher = ((MatcherDecorator)m).getActualMatcher();
56                } else {
57                    actualMatcher = m;
58                }
59                //this is very important to only allow VarargMatchers here. If you're not sure why remove it and run all tests.
60                if (!(actualMatcher instanceof VarargMatcher) || !actualMatcher.matches(rawArgs[i])) {
61                    return false;
62                }
63            //it's not a vararg (i.e. some ordinary argument before varargs), just do the ordinary check
64            } else if (!m.matches(rawArgs[i])){
65                return false;
66            }
67        }
68
69        return true;
70    }
71}