View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit;
7   
8   import static java.util.Arrays.asList;
9   
10  import static org.junit.jupiter.api.Assertions.assertEquals;
11  import static org.junit.jupiter.api.Assertions.assertFalse;
12  import static org.junit.jupiter.api.Assertions.assertSame;
13  import static org.junit.jupiter.api.Assertions.assertTrue;
14  
15  import java.util.Collections;
16  import java.util.List;
17  
18  import mockit.integration.junit5.ExpectedException;
19  import mockit.integration.junit5.JMockitExtension;
20  import mockit.internal.expectations.invocation.MissingInvocation;
21  
22  import org.junit.jupiter.api.Disabled;
23  import org.junit.jupiter.api.Test;
24  import org.junit.jupiter.api.extension.ExtendWith;
25  
26  /**
27   * The Class ExpectationsWithVarArgsMatchersTest.
28   */
29  @ExtendWith(JMockitExtension.class)
30  class ExpectationsWithVarArgsMatchersTest {
31  
32      /**
33       * The Class Collaborator.
34       */
35      static class Collaborator {
36  
37          /**
38           * Complex operation.
39           *
40           * @param input1
41           *            the input 1
42           * @param otherInputs
43           *            the other inputs
44           *
45           * @return the list
46           */
47          List<?> complexOperation(Object input1, Object... otherInputs) {
48              return input1 == null ? Collections.emptyList() : asList(otherInputs);
49          }
50  
51          /**
52           * Another operation.
53           *
54           * @param i
55           *            the i
56           * @param b
57           *            the b
58           * @param s
59           *            the s
60           * @param otherStrings
61           *            the other strings
62           *
63           * @return the int
64           */
65          @SuppressWarnings("unused")
66          int anotherOperation(int i, boolean b, String s, String... otherStrings) {
67              return -1;
68          }
69  
70          /**
71           * Do something.
72           *
73           * @param i
74           *            the i
75           * @param values
76           *            the values
77           *
78           * @return true, if successful
79           */
80          static boolean doSomething(int i, Object... values) {
81              return i + values.length > 0;
82          }
83      }
84  
85      /**
86       * The Interface Dependency.
87       */
88      public interface Dependency {
89          /**
90           * Do something.
91           *
92           * @param args
93           *            the args
94           */
95          void doSomething(String... args);
96      }
97  
98      /** The mock. */
99      @Mocked
100     Collaborator mock;
101 
102     /** The mock 2. */
103     @Mocked
104     Dependency mock2;
105 
106     /**
107      * Replay varargs method with different than expected non varargs argument.
108      */
109     @Test
110     @ExpectedException(MissingInvocation.class)
111     void replayVarargsMethodWithDifferentThanExpectedNonVarargsArgument() {
112         mock.complexOperation(2, 2, 3);
113 
114         new Verifications() {
115             {
116                 mock.complexOperation(1, 2, 3);
117             }
118         };
119     }
120 
121     /**
122      * Replay varargs method with different than expected number of varargs arguments.
123      */
124     @Test
125     @ExpectedException(MissingInvocation.class)
126     void replayVarargsMethodWithDifferentThanExpectedNumberOfVarargsArguments() {
127         new Expectations() {
128             {
129                 mock2.doSomething("1", "2", "3");
130                 times = 1;
131             }
132         };
133 
134         mock2.doSomething("1", "2");
135     }
136 
137     /**
138      * Replay varargs method with different than expected varargs argument.
139      */
140     @Test
141     @ExpectedException(MissingInvocation.class)
142     void replayVarargsMethodWithDifferentThanExpectedVarargsArgument() {
143         new Expectations() {
144             {
145                 mock2.doSomething("1", "2", "3");
146             }
147         };
148 
149         mock2.doSomething("1", "2", "4");
150     }
151 
152     /**
153      * Expect invocation on method with varargs argument using argument matchers.
154      */
155     @Test
156     void expectInvocationOnMethodWithVarargsArgumentUsingArgumentMatchers() {
157         new Expectations() {
158             {
159                 mock.complexOperation(withEqual(1), withNotEqual(2), withNull());
160                 mock2.doSomething(withPrefix("C"), withSuffix("."));
161             }
162         };
163 
164         mock.complexOperation(1, 3, null);
165         mock2.doSomething("Cab", "123.");
166     }
167 
168     /**
169      * Expect invocation with any number of variable arguments.
170      */
171     @Test
172     void expectInvocationWithAnyNumberOfVariableArguments() {
173         new Expectations() {
174             {
175                 mock.complexOperation(any, (Object[]) null);
176                 times = 3;
177                 mock2.doSomething((String[]) any);
178                 minTimes = 2;
179             }
180         };
181 
182         mock.complexOperation("test");
183         mock.complexOperation(null, 'X');
184         mock2.doSomething();
185         mock2.doSomething("test", "abc");
186         mock.complexOperation(123, true, "test", 3);
187     }
188 
189     /**
190      * Expect invocations with matcher for varargs parameter only.
191      */
192     @Test
193     void expectInvocationsWithMatcherForVarargsParameterOnly() {
194         final List<Integer> values = asList(1, 2, 3);
195 
196         new Expectations() {
197             {
198                 mock.complexOperation("test", (Object[]) any);
199                 result = values;
200                 mock.anotherOperation(1, true, null, (String[]) any);
201                 result = 123;
202                 Collaborator.doSomething(anyInt, (Object[]) any);
203                 result = true;
204             }
205         };
206 
207         assertSame(values, mock.complexOperation("test", true, 'a', 2.5));
208         assertSame(values, mock.complexOperation("test", 123));
209         assertSame(values, mock.complexOperation("test"));
210 
211         assertEquals(123, mock.anotherOperation(1, true, null));
212         assertEquals(123, mock.anotherOperation(1, true, null, "A", null, "b"));
213         assertEquals(123, mock.anotherOperation(1, true, "test", "a", "b"));
214 
215         assertTrue(Collaborator.doSomething(-1));
216         assertTrue(Collaborator.doSomething(-2, "test"));
217     }
218 
219     /**
220      * Expect invocation on varargs method with matcher only for regular first parameter.
221      */
222     @Test
223     void expectInvocationOnVarargsMethodWithMatcherOnlyForRegularFirstParameter() {
224         new Expectations() {
225             {
226                 mock.complexOperation(any, 1, 2);
227             }
228         };
229 
230         mock.complexOperation("test", 1, 2);
231     }
232 
233     /**
234      * Expect invocation with matchers for regular parameters and all varargs values.
235      */
236     @Test
237     void expectInvocationWithMatchersForRegularParametersAndAllVarargsValues() {
238         new Expectations() {
239             {
240                 mock.complexOperation(anyBoolean, anyInt, withEqual(2));
241                 mock.complexOperation(anyString, withEqual(1), any, withEqual(3), anyBoolean);
242             }
243         };
244 
245         mock.complexOperation(true, 1, 2);
246         mock.complexOperation("abc", 1, 2, 3, true);
247     }
248 
249     /**
250      * Record expectations with matchers for some regular parameters and none for varargs.
251      */
252     @Test
253     void recordExpectationsWithMatchersForSomeRegularParametersAndNoneForVarargs() {
254         new Expectations() {
255             {
256                 mock.anotherOperation(1, anyBoolean, "test", "a");
257                 result = 1;
258                 mock.anotherOperation(anyInt, true, withSubstring("X"), "a", "b");
259                 result = 2;
260             }
261         };
262 
263         // Invocations that match a recorded expectation:
264         assertEquals(1, mock.anotherOperation(1, true, "test", "a"));
265         assertEquals(1, mock.anotherOperation(1, true, "test", "a"));
266         assertEquals(1, mock.anotherOperation(1, false, "test", "a"));
267 
268         assertEquals(2, mock.anotherOperation(2, true, "aXb", "a", "b"));
269         assertEquals(2, mock.anotherOperation(-1, true, "  X", "a", "b"));
270         assertEquals(2, mock.anotherOperation(0, true, "XXX", "a", "b"));
271         assertEquals(2, mock.anotherOperation(1, true, "X", "a", "b"));
272 
273         // Invocations that don't match any expectation:
274         assertEquals(0, mock.anotherOperation(1, false, "test", null, "a"));
275         assertEquals(0, mock.anotherOperation(1, false, "tst", "a"));
276         assertEquals(0, mock.anotherOperation(0, false, "test", "a"));
277         assertEquals(0, mock.anotherOperation(1, true, "test", "b"));
278         assertEquals(0, mock.anotherOperation(1, true, "test"));
279 
280         assertEquals(0, mock.anotherOperation(2, false, "aXb", "a", "b"));
281         assertEquals(0, mock.anotherOperation(1, true, "  X", "A", "b"));
282         assertEquals(0, mock.anotherOperation(0, true, "XXX", "a"));
283         assertEquals(0, mock.anotherOperation(0, true, "XXX", "b"));
284         assertEquals(0, mock.anotherOperation(32, true, "-Xx", "a", null));
285     }
286 
287     /**
288      * Expect invocations with non null regular argument and any varargs.
289      */
290     @Test
291     void expectInvocationsWithNonNullRegularArgumentAndAnyVarargs() {
292         new Expectations() {
293             {
294                 mock.complexOperation(withNotNull(), (Object[]) any);
295                 times = 3;
296             }
297         };
298 
299         mock.complexOperation(new Object(), 1, "2");
300         mock.complexOperation("", true, 'a', 2.5);
301         mock.complexOperation(123);
302     }
303 
304     /**
305      * Expect invocation with non null regular argument and any varargs but replay with null.
306      */
307     @Test
308     @ExpectedException(MissingInvocation.class)
309     void expectInvocationWithNonNullRegularArgumentAndAnyVarargsButReplayWithNull() {
310         mock.complexOperation(null, 1, "2");
311 
312         new Verifications() {
313             {
314                 mock.complexOperation(withNotNull(), (Object[]) any);
315             }
316         };
317     }
318 
319     /**
320      * Expect invocation with matchers for some regular parameters and all for varargs.
321      */
322     @Test
323     void expectInvocationWithMatchersForSomeRegularParametersAndAllForVarargs() {
324         new Expectations() {
325             {
326                 mock.anotherOperation(anyInt, true, withEqual("abc"), anyString, withEqual("test"));
327                 result = 1;
328                 mock.anotherOperation(0, anyBoolean, withEqual("Abc"), anyString, anyString, anyString);
329                 result = 2;
330             }
331         };
332 
333         assertEquals(0, mock.anotherOperation(1, false, "test", null, "a"));
334 
335         assertEquals(1, mock.anotherOperation(2, true, "abc", "xyz", "test"));
336         assertEquals(1, mock.anotherOperation(-1, true, "abc", null, "test"));
337         assertEquals(0, mock.anotherOperation(-1, true, "abc", null, "test", null));
338 
339         assertEquals(2, mock.anotherOperation(0, false, "Abc", "", "Abc", "test"));
340         assertEquals(0, mock.anotherOperation(0, false, "Abc", "", "Abc", "test", ""));
341     }
342 
343     /**
344      * The Class VarArgs.
345      */
346     @SuppressWarnings("unused")
347     static class VarArgs {
348 
349         /**
350          * Vars only.
351          *
352          * @param ints
353          *            the ints
354          */
355         public void varsOnly(int... ints) {
356         }
357 
358         /**
359          * Mixed.
360          *
361          * @param arg0
362          *            the arg 0
363          * @param ints
364          *            the ints
365          */
366         public void mixed(String arg0, int... ints) {
367         }
368     }
369 
370     /**
371      * Expect invocation with no var args.
372      *
373      * @param varargs
374      *            the varargs
375      */
376     @SuppressWarnings("NullArgumentToVariableArgMethod")
377     @Test
378     void expectInvocationWithNoVarArgs(@Mocked final VarArgs varargs) {
379         new Expectations() {
380             {
381                 varargs.varsOnly();
382                 times = 2;
383                 varargs.mixed("arg");
384                 times = 2;
385             }
386         };
387 
388         varargs.varsOnly();
389         varargs.varsOnly(null);
390         varargs.mixed("arg");
391         varargs.mixed("arg", null);
392     }
393 
394     /**
395      * The Class ReferenceVarArgs.
396      */
397     static class ReferenceVarArgs {
398 
399         /**
400          * Mixed.
401          *
402          * @param strings
403          *            the strings
404          * @param ints
405          *            the ints
406          */
407         @SuppressWarnings("unused")
408         public void mixed(String[] strings, Integer... ints) {
409         }
410     }
411 
412     /**
413      * Expect invocation with non primitive var args.
414      *
415      * @param varargs
416      *            the varargs
417      */
418     @Test
419     void expectInvocationWithNonPrimitiveVarArgs(@Mocked final ReferenceVarArgs varargs) {
420         final String[] strings1 = {};
421         final String[] strings2 = { "first", "second" };
422 
423         new Expectations() {
424             {
425                 varargs.mixed(null, 4, 5, 6);
426                 varargs.mixed(strings1, 4, 5, 6);
427                 varargs.mixed(strings2, 4, 5, 6);
428                 varargs.mixed(null);
429                 varargs.mixed(strings1);
430                 varargs.mixed(strings2);
431             }
432         };
433 
434         varargs.mixed(null, 4, 5, 6);
435         varargs.mixed(strings1, 4, 5, 6);
436         varargs.mixed(strings2, 4, 5, 6);
437         varargs.mixed(null);
438         varargs.mixed(strings1);
439         varargs.mixed(strings2);
440     }
441 
442     /**
443      * The Class PrimitiveVarArgs.
444      */
445     @SuppressWarnings("unused")
446     static class PrimitiveVarArgs {
447 
448         /**
449          * Vars only.
450          *
451          * @param ints
452          *            the ints
453          */
454         public void varsOnly(int... ints) {
455         }
456 
457         /**
458          * Mixed.
459          *
460          * @param arg0
461          *            the arg 0
462          * @param strings
463          *            the strings
464          * @param ints
465          *            the ints
466          */
467         public void mixed(String arg0, String[] strings, int... ints) {
468         }
469     }
470 
471     /**
472      * Expect invocation with primitive var args.
473      *
474      * @param varargs
475      *            the varargs
476      */
477     @SuppressWarnings("NullArgumentToVariableArgMethod")
478     @Test
479     void expectInvocationWithPrimitiveVarArgs(@Mocked final PrimitiveVarArgs varargs) {
480         final String[] strings1 = {};
481         final String[] strings2 = { "first", "second" };
482 
483         new Expectations() {
484             {
485                 varargs.varsOnly(1, 2, 3);
486                 varargs.varsOnly(null);
487                 varargs.mixed("arg", null, 4, 5, 6);
488                 varargs.mixed("arg", strings1, 4, 5, 6);
489                 varargs.mixed("arg", strings2, 4, 5, 6);
490                 varargs.mixed("arg", null);
491                 varargs.mixed("arg", strings1);
492                 varargs.mixed("arg", strings2);
493                 varargs.mixed("arg", null, null);
494                 varargs.mixed(null, null, null);
495             }
496         };
497 
498         varargs.varsOnly(1, 2, 3);
499         varargs.varsOnly(null);
500         varargs.mixed("arg", null, 4, 5, 6);
501         varargs.mixed("arg", strings1, 4, 5, 6);
502         varargs.mixed("arg", strings2, 4, 5, 6);
503         varargs.mixed("arg", null);
504         varargs.mixed("arg", strings1);
505         varargs.mixed("arg", strings2);
506         varargs.mixed("arg", null, null);
507         varargs.mixed(null, null, null);
508     }
509 
510     /**
511      * The Class MixedVarArgs.
512      */
513     static class MixedVarArgs {
514         /**
515          * Mixed.
516          *
517          * @param strings
518          *            the strings
519          * @param ints
520          *            the ints
521          */
522         @SuppressWarnings("unused")
523         public void mixed(String[] strings, int... ints) {
524         }
525     }
526 
527     /**
528      * Expect invocation with primitive var args using matchers.
529      *
530      * @param varargs
531      *            the varargs
532      */
533     @Test
534     void expectInvocationWithPrimitiveVarArgsUsingMatchers(@Mocked final MixedVarArgs varargs) {
535         final String[] strings1 = {};
536         final String[] strings2 = { "first", "second" };
537 
538         new Expectations() {
539             {
540                 varargs.mixed((String[]) withNull(), withEqual(4), withEqual(5), withEqual(6));
541                 varargs.mixed(withEqual(strings1), withEqual(4), withEqual(5), withEqual(6));
542                 varargs.mixed(withEqual(strings2), withEqual(4), withEqual(5), withEqual(6));
543                 varargs.mixed((String[]) withNull());
544                 varargs.mixed(withEqual(strings1));
545                 varargs.mixed(withEqual(strings2));
546             }
547         };
548 
549         varargs.mixed(null, 4, 5, 6);
550         varargs.mixed(strings1, 4, 5, 6);
551         varargs.mixed(strings2, 4, 5, 6);
552         varargs.mixed(null);
553         varargs.mixed(strings1);
554         varargs.mixed(strings2);
555     }
556 
557     /**
558      * Expect invocation with matchers for all parameters and varargs values but replay with different vararg value.
559      */
560     @Test
561     @ExpectedException(MissingInvocation.class)
562     void expectInvocationWithMatchersForAllParametersAndVarargsValuesButReplayWithDifferentVarargValue() {
563         mock.complexOperation("abc", true, 1L);
564 
565         new Verifications() {
566             {
567                 mock.complexOperation(anyString, anyBoolean, withEqual(123L));
568             }
569         };
570     }
571 
572     /**
573      * Expectation recorded with not null matcher for varargs parameter.
574      */
575     @Test
576     void expectationRecordedWithNotNullMatcherForVarargsParameter() {
577         new Expectations() {
578             {
579                 Collaborator.doSomething(0, (Object[]) withNotNull());
580                 result = true;
581             }
582         };
583 
584         assertTrue(Collaborator.doSomething(0, "test"));
585         // noinspection NullArgumentToVariableArgMethod
586         assertFalse(Collaborator.doSomething(0, (Object[]) null));
587     }
588 
589     /**
590      * Record varargs method with regular parameter using matcher for varargs only.
591      */
592     @Test
593     @Disabled("issue #292")
594     void recordVarargsMethodWithRegularParameterUsingMatcherForVarargsOnly() {
595         new Expectations() {
596             {
597                 Collaborator.doSomething(123, anyString);
598             }
599         };
600 
601         Collaborator.doSomething(123, "test");
602     }
603 }