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.assertNotNull;
12  import static org.junit.jupiter.api.Assertions.assertNull;
13  import static org.junit.jupiter.api.Assertions.assertTrue;
14  import static org.junit.jupiter.api.Assertions.fail;
15  
16  import java.io.IOException;
17  import java.util.ArrayList;
18  import java.util.List;
19  import java.util.concurrent.AbstractExecutorService;
20  
21  import mockit.integration.junit5.JMockitExtension;
22  
23  import org.junit.jupiter.api.Test;
24  import org.junit.jupiter.api.extension.ExtendWith;
25  
26  /**
27   * The Class DelegateInvocationProceedTest.
28   */
29  @ExtendWith(JMockitExtension.class)
30  class DelegateInvocationProceedTest {
31  
32      /**
33       * The Class BaseClassToBeMocked.
34       */
35      public static class BaseClassToBeMocked {
36  
37          /** The name. */
38          protected String name;
39  
40          /**
41           * Gets the name.
42           *
43           * @return the name
44           */
45          public final String getName() {
46              return name;
47          }
48  
49          /**
50           * Base method.
51           *
52           * @param i
53           *            the i
54           *
55           * @return the int
56           */
57          public final int baseMethod(int i) {
58              return i + 1;
59          }
60  
61          /**
62           * Method to be mocked.
63           *
64           * @param i
65           *            the i
66           *
67           * @return the int
68           *
69           * @throws IOException
70           *             Signals that an I/O exception has occurred.
71           */
72          protected int methodToBeMocked(int i) throws IOException {
73              return i;
74          }
75      }
76  
77      /**
78       * The Class ClassToBeMocked.
79       */
80      public static class ClassToBeMocked extends BaseClassToBeMocked {
81  
82          /**
83           * Instantiates a new class to be mocked.
84           */
85          public ClassToBeMocked() {
86              name = "";
87          }
88  
89          /**
90           * Instantiates a new class to be mocked.
91           *
92           * @param name
93           *            the name
94           */
95          public ClassToBeMocked(String name) {
96              this.name = name;
97          }
98  
99          /**
100          * Method to be mocked.
101          *
102          * @return true, if successful
103          */
104         public boolean methodToBeMocked() {
105             return true;
106         }
107 
108         @Override
109         protected int methodToBeMocked(int i) throws IOException {
110             return super.methodToBeMocked(i);
111         }
112 
113         /**
114          * Method to be mocked.
115          *
116          * @param i
117          *            the i
118          * @param args
119          *            the args
120          *
121          * @return the int
122          */
123         int methodToBeMocked(int i, Object... args) {
124             int result = i;
125 
126             for (Object arg : args) {
127                 if (arg != null) {
128                     result++;
129                 }
130             }
131 
132             return result;
133         }
134 
135         /**
136          * Another method to be mocked.
137          *
138          * @param s
139          *            the s
140          * @param b
141          *            the b
142          * @param ints
143          *            the ints
144          *
145          * @return the string
146          */
147         String anotherMethodToBeMocked(String s, boolean b, List<Integer> ints) {
148             return (b ? s.toUpperCase() : s.toLowerCase()) + ints;
149         }
150     }
151 
152     /**
153      * Proceed from delegate method on regular mocked class.
154      *
155      * @param mocked
156      *            the mocked
157      */
158     @Test
159     void proceedFromDelegateMethodOnRegularMockedClass(@Mocked final ClassToBeMocked mocked) {
160         new Expectations() {
161             {
162                 mocked.methodToBeMocked();
163                 result = new Delegate<Object>() {
164                     @Mock
165                     boolean delegate(Invocation inv) {
166                         return inv.proceed();
167                     }
168                 };
169             }
170         };
171 
172         assertTrue(mocked.methodToBeMocked());
173     }
174 
175     /**
176      * Proceed from delegate method on injectable mocked class.
177      *
178      * @param mocked
179      *            the mocked
180      */
181     @Test
182     void proceedFromDelegateMethodOnInjectableMockedClass(@Injectable final ClassToBeMocked mocked) {
183         new Expectations() {
184             {
185                 mocked.methodToBeMocked();
186                 result = new Delegate<Object>() {
187                     @Mock
188                     boolean delegate(Invocation inv) {
189                         return inv.proceed();
190                     }
191                 };
192             }
193         };
194 
195         assertTrue(mocked.methodToBeMocked());
196     }
197 
198     /**
199      * Proceed from delegate method with parameters.
200      *
201      * @throws Exception
202      *             the exception
203      */
204     @Test
205     void proceedFromDelegateMethodWithParameters() throws Exception {
206         final ClassToBeMocked mocked = new ClassToBeMocked();
207 
208         new Expectations(mocked) {
209             {
210                 mocked.methodToBeMocked(anyInt);
211                 result = new Delegate<Object>() {
212                     @Mock
213                     int delegate(Invocation inv, int i) {
214                         Integer j = inv.proceed();
215                         return j + 1;
216                     }
217                 };
218 
219                 mocked.methodToBeMocked(anyInt, (Object[]) any);
220                 maxTimes = 1;
221                 result = new Delegate<Object>() {
222                     @Mock
223                     Integer delegate(Invocation inv, int i, Object... args) {
224                         args[2] = "mock";
225                         return inv.proceed();
226                     }
227                 };
228             }
229         };
230 
231         assertEquals(124, mocked.methodToBeMocked(123));
232         assertEquals(-8, mocked.methodToBeMocked(-9));
233         assertEquals(7, mocked.methodToBeMocked(3, "Test", new Object(), null, 45));
234     }
235 
236     /**
237      * Proceed conditionally from delegate method.
238      */
239     @Test
240     void proceedConditionallyFromDelegateMethod() {
241         final ClassToBeMocked mocked = new ClassToBeMocked();
242 
243         new Expectations(mocked) {
244             {
245                 mocked.anotherMethodToBeMocked(anyString, anyBoolean, null);
246                 result = new Delegate<Object>() {
247                     @Mock
248                     String delegate(Invocation inv, String s, boolean b, List<Number> ints) {
249                         if (!b) {
250                             return s;
251                         }
252 
253                         ints.add(45);
254                         return inv.proceed();
255                     }
256                 };
257             }
258         };
259 
260         // Do not proceed:
261         assertNull(mocked.anotherMethodToBeMocked(null, false, null));
262 
263         // Do proceed:
264         List<Integer> values = new ArrayList<>();
265         assertEquals("TEST[45]", mocked.anotherMethodToBeMocked("test", true, values));
266 
267         // Do not proceed again:
268         assertEquals("No proceed", mocked.anotherMethodToBeMocked("No proceed", false, null));
269     }
270 
271     /**
272      * Proceed from delegate method into real method with modified arguments.
273      *
274      * @throws Exception
275      *             the exception
276      */
277     @Test
278     void proceedFromDelegateMethodIntoRealMethodWithModifiedArguments() throws Exception {
279         final ClassToBeMocked mocked = new ClassToBeMocked();
280 
281         new Expectations(mocked) {
282             {
283                 mocked.methodToBeMocked(anyInt);
284                 result = new Delegate<Object>() {
285                     @Mock
286                     Integer delegate1(Invocation invocation, int i) {
287                         return invocation.proceed(i + 2);
288                     }
289                 };
290 
291                 mocked.methodToBeMocked(anyInt, (Object[]) any);
292                 result = new Delegate<Object>() {
293                     @Mock
294                     Integer delegate2(Invocation inv, int i, Object... args) {
295                         Object[] newArgs = { 2, "3" };
296                         return inv.proceed(1, newArgs);
297                     }
298                 };
299             }
300         };
301 
302         assertEquals(3, mocked.methodToBeMocked(1));
303         assertEquals(3, mocked.methodToBeMocked(-2, null, "Abc", true, 'a'));
304     }
305 
306     /**
307      * Proceed from delegate method into constructor.
308      *
309      * @param mock
310      *            the mock
311      */
312     @Test
313     void proceedFromDelegateMethodIntoConstructor(@Mocked ClassToBeMocked mock) {
314         new Expectations() {
315             {
316                 new ClassToBeMocked();
317                 result = new Delegate<Object>() {
318                     @Mock
319                     void init(Invocation inv) {
320                         assertNotNull(inv.getInvokedInstance());
321                         inv.proceed();
322                     }
323                 };
324             }
325         };
326 
327         ClassToBeMocked obj = new ClassToBeMocked();
328         assertEquals("", obj.name);
329     }
330 
331     /**
332      * Proceed conditionally from delegate method into constructor.
333      *
334      * @param mock
335      *            the mock
336      */
337     @Test
338     void proceedConditionallyFromDelegateMethodIntoConstructor(@Mocked ClassToBeMocked mock) {
339         new Expectations() {
340             {
341                 new ClassToBeMocked(anyString);
342                 result = new Delegate<Object>() {
343                     @Mock
344                     void init(Invocation inv, String name) {
345                         assertNotNull(inv.getInvokedInstance());
346 
347                         if ("proceed".equals(name)) {
348                             inv.proceed();
349                         }
350                     }
351                 };
352             }
353         };
354 
355         assertEquals("proceed", new ClassToBeMocked("proceed").name);
356         assertNull(new ClassToBeMocked("do not proceed").name);
357     }
358 
359     /**
360      * Proceed from delegate method into JRE constructor.
361      *
362      * @param mock
363      *            the mock
364      */
365     @Test
366     void proceedFromDelegateMethodIntoJREConstructor(@Mocked ProcessBuilder mock) {
367         new Expectations() {
368             {
369                 ProcessBuilder pb = new ProcessBuilder((String[]) any);
370                 result = new Delegate<Object>() {
371                     @Mock
372                     void init(Invocation inv) {
373                         inv.proceed();
374                     }
375                 };
376 
377                 pb.command();
378                 result = new Delegate<Object>() {
379                     @Mock
380                     List<String> delegate(Invocation inv) {
381                         return inv.proceed();
382                     }
383                 };
384             }
385         };
386 
387         ProcessBuilder pb1 = new ProcessBuilder("proceed");
388         assertEquals("proceed", pb1.command().get(0));
389 
390         ProcessBuilder pb2 = new ProcessBuilder("proceed", "again");
391         assertEquals(asList("proceed", "again"), pb2.command());
392     }
393 
394     /**
395      * Proceed from delegate method into method inherited from base class.
396      */
397     @Test
398     void proceedFromDelegateMethodIntoMethodInheritedFromBaseClass() {
399         final ClassToBeMocked obj = new ClassToBeMocked();
400 
401         new Expectations(obj) {
402             {
403                 obj.baseMethod(anyInt);
404                 result = new Delegate<Object>() {
405                     @Mock
406                     int baseMethod(Invocation inv, int i) {
407                         return inv.proceed(i + 1);
408                     }
409                 };
410             }
411         };
412 
413         assertEquals(3, obj.baseMethod(1));
414     }
415 
416     /**
417      * Proceed from delegate method into overriding method which calls super.
418      *
419      * @param mocked
420      *            the mocked
421      *
422      * @throws Exception
423      *             the exception
424      */
425     @Test
426     void proceedFromDelegateMethodIntoOverridingMethodWhichCallsSuper(@Mocked final ClassToBeMocked mocked)
427             throws Exception {
428         new Expectations() {
429             {
430                 mocked.methodToBeMocked(1);
431                 result = new Delegate<Object>() {
432                     @Mock
433                     int delegate(Invocation inv) {
434                         return inv.proceed();
435                     }
436                 };
437             }
438         };
439 
440         assertEquals(1, mocked.methodToBeMocked(1));
441     }
442 
443     /**
444      * Proceed from delegate method into overriding method that calls super which also has A proceeding delegate.
445      *
446      * @param mockedBase
447      *            the mocked base
448      * @param mocked
449      *            the mocked
450      *
451      * @throws Exception
452      *             the exception
453      */
454     @Test
455     void proceedFromDelegateMethodIntoOverridingMethodThatCallsSuperWhichAlsoHasAProceedingDelegate(
456             @Mocked final BaseClassToBeMocked mockedBase, @Mocked final ClassToBeMocked mocked) throws Exception {
457         new Expectations() {
458             {
459                 mockedBase.methodToBeMocked(1);
460                 result = new Delegate<Object>() {
461                     // Will not execute when calling on subclass instance.
462                     @Mock
463                     int delegate(Invocation inv) {
464                         int i = inv.proceed();
465                         return i + 1;
466                     }
467                 };
468 
469                 mocked.methodToBeMocked(1);
470                 result = new Delegate<Object>() {
471                     @Mock
472                     int delegate(Invocation inv) {
473                         return inv.proceed();
474                     }
475                 };
476             }
477         };
478 
479         assertEquals(2, mockedBase.methodToBeMocked(1));
480         assertEquals(1, mocked.methodToBeMocked(1));
481     }
482 
483     /**
484      * Throw exception from proceed into JRE method.
485      *
486      * @param c1
487      *            the c 1
488      * @param c2
489      *            the c 2
490      *
491      * @throws Exception
492      *             the exception
493      */
494     @Test
495     void throwExceptionFromProceedIntoJREMethod(@Injectable final AbstractExecutorService c1,
496             @Mocked final ClassToBeMocked c2) throws Exception {
497         new Expectations() {
498             {
499                 c1.submit((Runnable) any);
500                 result = new Delegate<Object>() {
501                     @Mock
502                     void delegate(Invocation inv) {
503                         inv.proceed();
504                     }
505                 };
506             }
507         };
508 
509         try {
510             c1.submit((Runnable) null);
511             fail();
512         } catch (NullPointerException ignored) {
513             new Expectations() {
514                 {
515                     c2.methodToBeMocked(anyInt);
516                     result = 123;
517                 }
518             };
519 
520             assertEquals(123, c2.methodToBeMocked(1));
521         }
522     }
523 }