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 static java.util.Arrays.asList;
8import static org.junit.Assert.assertFalse;
9import static org.junit.Assert.assertTrue;
10import static org.assertj.core.api.Assertions.assertThat;
11import static org.mockito.internal.invocation.MatcherApplicationStrategy.getMatcherApplicationStrategyFor;
12import static org.mockito.internal.matchers.Any.ANY;
13
14import java.util.ArrayList;
15import java.util.List;
16
17import org.junit.Before;
18import org.junit.Test;
19import org.mockito.ArgumentMatcher;
20import org.mockito.Mock;
21import org.mockito.internal.matchers.Any;
22import org.mockito.internal.matchers.Equals;
23import org.mockito.internal.matchers.InstanceOf;
24import org.mockito.invocation.Invocation;
25import org.mockitousage.IMethods;
26import org.mockitoutil.TestBase;
27
28@SuppressWarnings("unchecked")
29public class MatcherApplicationStrategyTest extends TestBase {
30
31    @Mock
32    IMethods mock;
33    private Invocation invocation;
34    private List matchers;
35
36    private RecordingAction recordAction;
37
38    @Before
39    public void before() {
40        recordAction = new RecordingAction();
41    }
42
43    @Test
44    public void shouldKnowWhenActualArgsSizeIsDifferent1() {
45        // given
46        invocation = varargs("1");
47        matchers = asList(new Equals("1"));
48
49        // when
50        boolean match = getMatcherApplicationStrategyFor(invocation, matchers).forEachMatcherAndArgument(RETURN_ALWAYS_FALSE);
51
52        // then
53        assertFalse(match);
54    }
55
56    @Test
57    public void shouldKnowWhenActualArgsSizeIsDifferent2() {
58        // given
59        invocation = varargs("1");
60        matchers = asList(new Equals("1"));
61
62        // when
63        boolean match = getMatcherApplicationStrategyFor(invocation, matchers).forEachMatcherAndArgument(RETURN_ALWAYS_TRUE);
64
65        // then
66        assertTrue(match);
67    }
68
69    @Test
70    public void shouldKnowWhenActualArgsSizeIsDifferent() {
71        // given
72        invocation = varargs("1", "2");
73        matchers = asList(new Equals("1"));
74
75        // when
76        boolean match = getMatcherApplicationStrategyFor(invocation, matchers).forEachMatcherAndArgument(RETURN_ALWAYS_TRUE);
77
78        // then
79        assertFalse(match);
80    }
81
82    @Test
83    public void shouldKnowWhenMatchersSizeIsDifferent() {
84        // given
85        invocation = varargs("1");
86        matchers = asList(new Equals("1"), new Equals("2"));
87
88        // when
89        boolean match = getMatcherApplicationStrategyFor(invocation, matchers).forEachMatcherAndArgument(RETURN_ALWAYS_TRUE);
90
91        // then
92        assertFalse(match);
93    }
94
95    @Test
96    public void shouldKnowWhenVarargsMatch() {
97        // given
98        invocation = varargs("1", "2", "3");
99        matchers = asList(new Equals("1"), Any.ANY, new InstanceOf(String.class));
100
101        // when
102        boolean match = getMatcherApplicationStrategyFor(invocation, matchers).forEachMatcherAndArgument(recordAction);
103
104        // then
105        assertTrue(match);
106    }
107
108    @Test
109    public void shouldAllowAnyVarargMatchEntireVararg() {
110        // given
111        invocation = varargs("1", "2");
112        matchers = asList(ANY);
113
114        // when
115        boolean match = getMatcherApplicationStrategyFor(invocation, matchers).forEachMatcherAndArgument(recordAction);
116
117        // then
118        assertTrue(match);
119    }
120
121    @Test
122    public void shouldNotAllowAnyObjectWithMixedVarargs() {
123        // given
124        invocation = mixedVarargs(1, "1", "2");
125        matchers = asList(new Equals(1));
126
127        // when
128        boolean match = getMatcherApplicationStrategyFor(invocation, matchers).forEachMatcherAndArgument(recordAction);
129
130        // then
131        assertFalse(match);
132    }
133
134    @Test
135    public void shouldAllowAnyObjectWithMixedVarargs() {
136        // given
137        invocation = mixedVarargs(1, "1", "2");
138        matchers = asList(new Equals(1), ANY);
139
140        // when
141        boolean match = getMatcherApplicationStrategyFor(invocation, matchers).forEachMatcherAndArgument(recordAction);
142
143        // then
144        assertTrue(match);
145    }
146
147    @Test
148    public void shouldAnyObjectVarargDealWithDifferentSizeOfArgs() {
149        // given
150        invocation = mixedVarargs(1, "1", "2");
151        matchers = asList(new Equals(1));
152
153        // when
154        boolean match = getMatcherApplicationStrategyFor(invocation, matchers).forEachMatcherAndArgument(recordAction);
155
156        // then
157        assertFalse(match);
158
159        recordAction.assertIsEmpty();
160    }
161
162    @Test
163    public void shouldMatchAnyVarargEvenIfOneOfTheArgsIsNull() {
164        // given
165        invocation = mixedVarargs(null, null, "2");
166        matchers = asList(new Equals(null), ANY);
167
168        // when
169        getMatcherApplicationStrategyFor(invocation, matchers).forEachMatcherAndArgument(recordAction);
170
171        // then
172        recordAction.assertContainsExactly(new Equals(null), ANY, ANY);
173
174    }
175
176    @Test
177    public void shouldMatchAnyVarargEvenIfMatcherIsDecorated() {
178        // given
179        invocation = varargs("1", "2");
180        matchers = asList(ANY);
181
182        // when
183        getMatcherApplicationStrategyFor(invocation, matchers).forEachMatcherAndArgument(recordAction);
184
185        // then
186        recordAction.assertContainsExactly(ANY, ANY);
187    }
188
189    private Invocation mixedVarargs(Object a, String... s) {
190        mock.mixedVarargs(a, s);
191        return getLastInvocation();
192    }
193
194    private Invocation varargs(String... s) {
195        mock.varargs(s);
196        return getLastInvocation();
197    }
198
199    private class RecordingAction implements ArgumentMatcherAction {
200        private List<ArgumentMatcher<?>> matchers = new ArrayList<ArgumentMatcher<?>>();
201
202        @Override
203        public boolean apply(ArgumentMatcher<?> matcher, Object argument) {
204            matchers.add(matcher);
205            return true;
206        }
207
208        public void assertIsEmpty() {
209            assertThat(matchers).isEmpty();
210        }
211
212        public void assertContainsExactly(ArgumentMatcher<?>... matchers) {
213            assertThat(this.matchers).containsExactly(matchers);
214        }
215    }
216
217    private static final ArgumentMatcherAction RETURN_ALWAYS_TRUE = new ArgumentMatcherAction() {
218        @Override
219        public boolean apply(ArgumentMatcher<?> matcher, Object argument) {
220            return true;
221        }
222    };
223
224    private static final ArgumentMatcherAction RETURN_ALWAYS_FALSE = new ArgumentMatcherAction() {
225        @Override
226        public boolean apply(ArgumentMatcher<?> matcher, Object argument) {
227            return false;
228        }
229    };
230
231}
232