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