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 org.junit.jupiter.api.Assertions.assertEquals;
9   import static org.junit.jupiter.api.Assertions.assertFalse;
10  import static org.junit.jupiter.api.Assertions.assertNotNull;
11  import static org.junit.jupiter.api.Assertions.assertNotSame;
12  import static org.junit.jupiter.api.Assertions.assertNull;
13  import static org.junit.jupiter.api.Assertions.assertSame;
14  import static org.junit.jupiter.api.Assertions.assertThrows;
15  import static org.junit.jupiter.api.Assertions.assertTrue;
16  import static org.junit.jupiter.api.Assertions.fail;
17  
18  import java.io.ByteArrayOutputStream;
19  import java.io.File;
20  import java.io.IOException;
21  import java.io.OutputStream;
22  import java.lang.management.CompilationMXBean;
23  import java.lang.management.ManagementFactory;
24  import java.net.InetAddress;
25  import java.net.InetSocketAddress;
26  import java.net.Socket;
27  import java.net.SocketAddress;
28  import java.nio.channels.SocketChannel;
29  import java.nio.file.Path;
30  import java.util.Arrays;
31  import java.util.Date;
32  import java.util.HashMap;
33  import java.util.List;
34  import java.util.Map;
35  import java.util.concurrent.Future;
36  
37  import mockit.integration.junit5.JMockitExtension;
38  import mockit.internal.expectations.invocation.MissingInvocation;
39  
40  import org.junit.jupiter.api.Disabled;
41  import org.junit.jupiter.api.MethodOrderer.MethodName;
42  import org.junit.jupiter.api.Test;
43  import org.junit.jupiter.api.TestMethodOrder;
44  import org.junit.jupiter.api.extension.ExtendWith;
45  
46  /**
47   * The Class CascadingParametersTest.
48   */
49  @ExtendWith(JMockitExtension.class)
50  @SuppressWarnings("ConstantConditions")
51  @TestMethodOrder(MethodName.class)
52  class CascadingParametersTest {
53  
54      /**
55       * The Class Foo.
56       */
57      static class Foo {
58  
59          /**
60           * Gets the bar.
61           *
62           * @return the bar
63           */
64          Bar getBar() {
65              return null;
66          }
67  
68          /**
69           * Global bar.
70           *
71           * @return the bar
72           */
73          static Bar globalBar() {
74              return null;
75          }
76  
77          /**
78           * Do something.
79           *
80           * @param s
81           *            the s
82           */
83          void doSomething(String s) {
84              throw new RuntimeException(s);
85          }
86  
87          /**
88           * Gets the int value.
89           *
90           * @return the int value
91           */
92          int getIntValue() {
93              return 1;
94          }
95  
96          /**
97           * Gets the boolean value.
98           *
99           * @return the boolean value
100          */
101         Boolean getBooleanValue() {
102             return true;
103         }
104 
105         /**
106          * Gets the list.
107          *
108          * @return the list
109          */
110         final List<Integer> getList() {
111             return null;
112         }
113 
114         /**
115          * Gets the map.
116          *
117          * @return the map
118          */
119         HashMap<?, ?> getMap() {
120             return null;
121         }
122     }
123 
124     /**
125      * The Class Bar.
126      */
127     static class Bar {
128 
129         /**
130          * Instantiates a new bar.
131          */
132         Bar() {
133             throw new RuntimeException();
134         }
135 
136         /**
137          * Do something.
138          *
139          * @return the int
140          */
141         int doSomething() {
142             return 1;
143         }
144 
145         /**
146          * Gets the baz.
147          *
148          * @return the baz
149          */
150         Baz getBaz() {
151             return null;
152         }
153 
154         /**
155          * Gets the baz.
156          *
157          * @param i
158          *            the i
159          *
160          * @return the baz
161          */
162         Baz getBaz(@SuppressWarnings("unused") int i) {
163             return null;
164         }
165 
166         /**
167          * Gets the enum.
168          *
169          * @return the enum
170          */
171         AnEnum getEnum() {
172             return null;
173         }
174 
175         /**
176          * Static method.
177          *
178          * @return the string
179          */
180         static String staticMethod() {
181             return "notMocked";
182         }
183     }
184 
185     /**
186      * The Class SubBar.
187      */
188     static final class SubBar extends Bar {
189     }
190 
191     /**
192      * The Interface Baz.
193      */
194     public interface Baz {
195 
196         /**
197          * Run it.
198          */
199         void runIt();
200 
201         /**
202          * Gets the date.
203          *
204          * @return the date
205          */
206         Date getDate();
207     }
208 
209     /**
210      * The Enum AnEnum.
211      */
212     enum AnEnum {
213         /** The First. */
214         First,
215         /** The Second. */
216         Second,
217         /** The Third. */
218         Third
219     }
220 
221     /** The cascaded bar 1. */
222     static Bar cascadedBar1;
223 
224     /** The cascaded bar 2. */
225     static Bar cascadedBar2;
226 
227     /**
228      * Cascade one level during replay.
229      *
230      * @param foo
231      *            the foo
232      */
233     @Test
234     void cascadeOneLevelDuringReplay(@Mocked Foo foo) {
235         cascadedBar1 = foo.getBar();
236         assertEquals(0, cascadedBar1.doSomething());
237 
238         cascadedBar2 = Foo.globalBar();
239         assertEquals(0, cascadedBar2.doSomething());
240 
241         Bar bar = foo.getBar();
242         assertSame(cascadedBar1, bar);
243 
244         Bar globalBar = Foo.globalBar();
245         assertSame(cascadedBar2, globalBar);
246         assertNotSame(bar, globalBar);
247 
248         foo.doSomething("test");
249         assertEquals(0, foo.getIntValue());
250         assertFalse(foo.getBooleanValue());
251         assertTrue(foo.getList().isEmpty());
252 
253         Map<?, ?> map = foo.getMap();
254         assertNull(map);
255     }
256 
257     /**
258      * Verify that previous cascaded instances have been discarded.
259      *
260      * @param foo
261      *            the foo
262      */
263     @Test
264     void verifyThatPreviousCascadedInstancesHaveBeenDiscarded(@Mocked Foo foo) {
265         Bar bar = foo.getBar();
266         assertNotSame(cascadedBar1, bar);
267 
268         Bar globalBar = Foo.globalBar();
269         assertNotSame(cascadedBar2, globalBar);
270     }
271 
272     /**
273      * Verify that static methods and constructors are not mocked when cascading.
274      *
275      * @param foo
276      *            the foo
277      */
278     @Test
279     void verifyThatStaticMethodsAndConstructorsAreNotMockedWhenCascading(@Mocked Foo foo) {
280         foo.getBar();
281 
282         assertEquals("notMocked", Bar.staticMethod());
283 
284         try {
285             new Bar();
286             fail();
287         } catch (RuntimeException ignored) {
288         }
289     }
290 
291     /**
292      * Verify that static methods and constructors are mocked when cascaded mock is mocked normally.
293      *
294      * @param mockFoo
295      *            the mock foo
296      * @param mockBar
297      *            the mock bar
298      */
299     @Test
300     void verifyThatStaticMethodsAndConstructorsAreMockedWhenCascadedMockIsMockedNormally(@Mocked Foo mockFoo,
301             @Mocked Bar mockBar) {
302         assertSame(mockBar, mockFoo.getBar());
303         assertEquals(0, mockBar.doSomething());
304         assertNull(Bar.staticMethod());
305         new Bar();
306     }
307 
308     /**
309      * Use available mocked instance of subclass as cascaded instance.
310      *
311      * @param foo
312      *            the foo
313      * @param bar
314      *            the bar
315      */
316     @Test
317     void useAvailableMockedInstanceOfSubclassAsCascadedInstance(@Mocked Foo foo, @Mocked SubBar bar) {
318         Bar cascadedBar = foo.getBar();
319 
320         assertSame(bar, cascadedBar);
321     }
322 
323     /**
324      * Replace cascaded instance with first one of two injectable instances.
325      *
326      * @param foo
327      *            the foo
328      * @param bar1
329      *            the bar 1
330      * @param bar2
331      *            the bar 2
332      */
333     @Test
334     void replaceCascadedInstanceWithFirstOneOfTwoInjectableInstances(@Mocked final Foo foo, @Injectable final Bar bar1,
335             @Injectable Bar bar2) {
336         new Expectations() {
337             {
338                 foo.getBar();
339                 result = bar1;
340             }
341         };
342 
343         Bar cascadedBar = foo.getBar();
344 
345         assertSame(bar1, cascadedBar);
346         assertEquals(0, bar1.doSomething());
347         assertEquals(0, bar2.doSomething());
348     }
349 
350     /**
351      * Cascade one level during record.
352      *
353      * @param mockFoo
354      *            the mock foo
355      */
356     @Test
357     void cascadeOneLevelDuringRecord(@Mocked final Foo mockFoo) {
358         final List<Integer> list = Arrays.asList(1, 2, 3);
359 
360         new Expectations() {
361             {
362                 mockFoo.doSomething(anyString);
363                 minTimes = 2;
364                 mockFoo.getBar().doSomething();
365                 result = 2;
366                 Foo.globalBar().doSomething();
367                 result = 3;
368                 mockFoo.getBooleanValue();
369                 result = true;
370                 mockFoo.getIntValue();
371                 result = -1;
372                 mockFoo.getList();
373                 result = list;
374             }
375         };
376 
377         Foo foo = new Foo();
378         foo.doSomething("1");
379         assertEquals(2, foo.getBar().doSomething());
380         foo.doSomething("2");
381         assertEquals(3, Foo.globalBar().doSomething());
382         assertTrue(foo.getBooleanValue());
383         assertEquals(-1, foo.getIntValue());
384         assertSame(list, foo.getList());
385     }
386 
387     /**
388      * Cascade one level during verify.
389      *
390      * @param foo
391      *            the foo
392      */
393     @Test
394     void cascadeOneLevelDuringVerify(@Mocked final Foo foo) {
395         Bar bar = foo.getBar();
396         bar.doSomething();
397         bar.doSomething();
398 
399         Foo.globalBar().doSomething();
400 
401         assertEquals(0, foo.getIntValue());
402         assertFalse(foo.getBooleanValue());
403 
404         assertTrue(foo.getList().isEmpty());
405 
406         new Verifications() {
407             {
408                 foo.getBar().doSomething();
409                 minTimes = 2;
410                 Foo.globalBar().doSomething();
411                 times = 1;
412             }
413         };
414 
415         new VerificationsInOrder() {
416             {
417                 foo.getIntValue();
418                 foo.getBooleanValue();
419             }
420         };
421     }
422 
423     /**
424      * Cascade two levels during replay.
425      *
426      * @param foo
427      *            the foo
428      */
429     @Test
430     void cascadeTwoLevelsDuringReplay(@Mocked Foo foo) {
431         foo.getBar().getBaz().runIt();
432     }
433 
434     /**
435      * Cascade two levels during record.
436      *
437      * @param mockFoo
438      *            the mock foo
439      */
440     @Test
441     void cascadeTwoLevelsDuringRecord(@Mocked final Foo mockFoo) {
442         new Expectations() {
443             {
444                 mockFoo.getBar().doSomething();
445                 result = 1;
446                 Foo.globalBar().doSomething();
447                 result = 2;
448 
449                 mockFoo.getBar().getBaz().runIt();
450                 times = 2;
451             }
452         };
453 
454         Foo foo = new Foo();
455         assertEquals(1, foo.getBar().doSomething());
456         assertEquals(2, Foo.globalBar().doSomething());
457 
458         Baz baz = foo.getBar().getBaz();
459         baz.runIt();
460         baz.runIt();
461     }
462 
463     /**
464      * Cascade one level and verify invocation on last mock only.
465      *
466      * @param foo
467      *            the foo
468      * @param bar
469      *            the bar
470      */
471     @Test
472     void cascadeOneLevelAndVerifyInvocationOnLastMockOnly(@Mocked Foo foo, @Injectable final Bar bar) {
473         Bar fooBar = foo.getBar();
474         assertSame(bar, fooBar);
475         fooBar.doSomething();
476 
477         new Verifications() {
478             {
479                 bar.doSomething();
480             }
481         };
482     }
483 
484     /**
485      * Cascade two levels with invocation recorded on last mock only.
486      *
487      * @param foo
488      *            the foo
489      * @param baz
490      *            the baz
491      */
492     @Test
493     void cascadeTwoLevelsWithInvocationRecordedOnLastMockOnly(@Mocked Foo foo, @Mocked final Baz baz) {
494         new Expectations() {
495             {
496                 baz.runIt();
497                 times = 1;
498             }
499         };
500 
501         Baz cascadedBaz = foo.getBar().getBaz();
502         cascadedBaz.runIt();
503     }
504 
505     /**
506      * Cascade two levels and verify invocation on last mock only.
507      *
508      * @param foo
509      *            the foo
510      * @param baz
511      *            the baz
512      */
513     @Test
514     void cascadeTwoLevelsAndVerifyInvocationOnLastMockOnly(@Mocked Foo foo, @Mocked final Baz baz) {
515         Baz cascadedBaz = foo.getBar().getBaz();
516         assertSame(baz, cascadedBaz);
517         cascadedBaz.runIt();
518 
519         new Verifications() {
520             {
521                 baz.runIt();
522             }
523         };
524     }
525 
526     // Tests using the java.lang.Process and java.lang.ProcessBuilder classes //////////////////////////////////////////
527 
528     /**
529      * Cascade on JRE classes.
530      *
531      * @param pb
532      *            the pb
533      *
534      * @throws Exception
535      *             the exception
536      */
537     @Test
538     void cascadeOnJREClasses(@Mocked final ProcessBuilder pb) throws Exception {
539         new Expectations() {
540             {
541                 ProcessBuilder sameBuilder = pb.directory((File) any);
542                 assertSame(sameBuilder, pb);
543 
544                 Process process = sameBuilder.start();
545                 process.getOutputStream().write(5);
546                 process.exitValue();
547                 result = 1;
548             }
549         };
550 
551         Process process = new ProcessBuilder("test").directory(Path.of("myDir").toFile()).start();
552         process.getOutputStream().write(5);
553         process.getOutputStream().flush();
554         assertEquals(1, process.exitValue());
555     }
556 
557     /**
558      * Return same mocked instance through cascading even with multiple candidates available.
559      *
560      * @param pb1
561      *            the pb 1
562      * @param pb2
563      *            the pb 2
564      */
565     @Test
566     void returnSameMockedInstanceThroughCascadingEvenWithMultipleCandidatesAvailable(@Injectable ProcessBuilder pb1,
567             @Injectable ProcessBuilder pb2) {
568         assertSame(pb1, pb1.command("a"));
569         assertSame(pb2, pb2.command("b"));
570     }
571 
572     /**
573      * Creates the OS process to copy temp files.
574      *
575      * @param pb
576      *            the pb
577      *
578      * @throws Exception
579      *             the exception
580      */
581     @Test
582     void createOSProcessToCopyTempFiles(@Mocked final ProcessBuilder pb) throws Exception {
583         // Code under test creates a new process to execute an OS-specific command.
584         String cmdLine = "copy /Y *.txt D:\\TEMP";
585         File wrkDir = Path.of("C:\\TEMP").toFile();
586         Process copy = new ProcessBuilder().command(cmdLine).directory(wrkDir).start();
587         int exit = copy.waitFor();
588 
589         if (exit != 0) {
590             throw new RuntimeException("Process execution failed");
591         }
592 
593         // Verify the desired process was created with the correct command.
594         new Verifications() {
595             {
596                 pb.command(withSubstring("copy")).start();
597             }
598         };
599     }
600 
601     // Tests using java.net classes ////////////////////////////////////////////////////////////////////////////////////
602 
603     /**
604      * Record and verify expectations on cascaded mocks.
605      *
606      * @param anySocket
607      *            the any socket
608      * @param cascadedChannel
609      *            the cascaded channel
610      * @param inetAddr
611      *            the inet addr
612      *
613      * @throws Exception
614      *             the exception
615      */
616     // TODO JWL 2/18/2024 Mocking Socket/InetAddress is not allowed on JDK9+ because java.net classes reside in a
617     // restricted JDK module that the JVM does not allow to be modified. To test code that depends on these classes,
618     // consider wrapping network operations behind a testable interface or abstraction that can be mocked instead.
619     @Disabled
620     @Test
621     void recordAndVerifyExpectationsOnCascadedMocks(@Mocked Socket anySocket,
622             @Mocked final SocketChannel cascadedChannel, @Mocked InetSocketAddress inetAddr) throws Exception {
623         Socket sk = new Socket();
624         SocketChannel ch = sk.getChannel();
625 
626         if (!ch.isConnected()) {
627             SocketAddress sa = new InetSocketAddress("remoteHost", 123);
628             ch.connect(sa);
629         }
630 
631         InetAddress adr1 = sk.getInetAddress();
632         InetAddress adr2 = sk.getLocalAddress();
633         assertNotSame(adr1, adr2);
634         sk.close();
635 
636         new Verifications() {
637             {
638                 cascadedChannel.connect((SocketAddress) withNotNull());
639             }
640         };
641     }
642 
643     /**
644      * A factory for creating Socket objects.
645      */
646     static final class SocketFactory {
647 
648         /**
649          * Creates a new Socket object.
650          *
651          * @return the socket
652          */
653         public Socket createSocket() {
654             return new Socket();
655         }
656 
657         /**
658          * Creates a new Socket object.
659          *
660          * @param host
661          *            the host
662          * @param port
663          *            the port
664          *
665          * @return the socket
666          *
667          * @throws IOException
668          *             Signals that an I/O exception has occurred.
669          */
670         public Socket createSocket(String host, int port) throws IOException {
671             return new Socket(host, port);
672         }
673     }
674 
675     /**
676      * Cascade one level with argument matchers.
677      *
678      * @param sf
679      *            the sf
680      *
681      * @throws Exception
682      *             the exception
683      */
684     @Test
685     void cascadeOneLevelWithArgumentMatchers(@Mocked final SocketFactory sf) throws Exception {
686         new Expectations() {
687             {
688                 sf.createSocket(anyString, 80);
689                 result = null;
690             }
691         };
692 
693         assertNull(sf.createSocket("expected", 80));
694         assertNotNull(sf.createSocket("unexpected", 8080));
695     }
696 
697     /**
698      * Record and verify one level deep.
699      *
700      * @param sf
701      *            the sf
702      *
703      * @throws Exception
704      *             the exception
705      */
706     @Test
707     void recordAndVerifyOneLevelDeep(@Mocked final SocketFactory sf) throws Exception {
708         final OutputStream out = new ByteArrayOutputStream();
709 
710         new Expectations() {
711             {
712                 sf.createSocket().getOutputStream();
713                 result = out;
714             }
715         };
716 
717         assertSame(out, sf.createSocket().getOutputStream());
718     }
719 
720     /**
721      * Record and verify on two cascading mocks of the same type.
722      *
723      * @param sf1
724      *            the sf 1
725      * @param sf2
726      *            the sf 2
727      *
728      * @throws Exception
729      *             the exception
730      */
731     @Test
732     void recordAndVerifyOnTwoCascadingMocksOfTheSameType(@Mocked final SocketFactory sf1,
733             @Mocked final SocketFactory sf2) throws Exception {
734         final OutputStream out1 = new ByteArrayOutputStream();
735         final OutputStream out2 = new ByteArrayOutputStream();
736 
737         new Expectations() {
738             {
739                 sf1.createSocket().getOutputStream();
740                 result = out1;
741                 sf2.createSocket().getOutputStream();
742                 result = out2;
743             }
744         };
745 
746         assertSame(out1, sf1.createSocket().getOutputStream());
747         assertSame(out2, sf2.createSocket().getOutputStream());
748 
749         new VerificationsInOrder() {
750             {
751                 sf1.createSocket().getOutputStream();
752                 sf2.createSocket().getOutputStream();
753             }
754         };
755     }
756 
757     /**
758      * Record and verify same invocation on mocks returned from invocations with different arguments.
759      *
760      * @param sf
761      *            the sf
762      *
763      * @throws Exception
764      *             the exception
765      */
766     @Test
767     void recordAndVerifySameInvocationOnMocksReturnedFromInvocationsWithDifferentArguments(
768             @Mocked final SocketFactory sf) throws Exception {
769         new Expectations() {
770             {
771                 sf.createSocket().getPort();
772                 result = 1;
773                 sf.createSocket("first", 80).getPort();
774                 result = 2;
775                 sf.createSocket("second", 80).getPort();
776                 result = 3;
777                 sf.createSocket(anyString, 81).getPort();
778                 result = 4;
779             }
780         };
781 
782         assertEquals(1, sf.createSocket().getPort());
783         assertEquals(2, sf.createSocket("first", 80).getPort());
784         assertEquals(3, sf.createSocket("second", 80).getPort());
785         assertEquals(4, sf.createSocket("third", 81).getPort());
786 
787         new VerificationsInOrder() {
788             {
789                 sf.createSocket().getPort();
790                 times = 1;
791                 sf.createSocket("first", 80).getPort();
792                 sf.createSocket("second", 80).getPort();
793                 sf.createSocket(anyString, 81).getPort();
794                 maxTimes = 1;
795                 sf.createSocket("fourth", -1);
796                 times = 0;
797             }
798         };
799     }
800 
801     /**
802      * Cascade on inherited method.
803      *
804      * @param sc
805      *            the sc
806      */
807     @Test
808     void cascadeOnInheritedMethod(@Mocked SocketChannel sc) {
809         assertNotNull(sc.provider());
810     }
811 
812     /**
813      * Record and verify with mixed cascade levels.
814      *
815      * @param sf
816      *            the sf
817      *
818      * @throws Exception
819      *             the exception
820      */
821     @Test
822     void recordAndVerifyWithMixedCascadeLevels(@Mocked final SocketFactory sf) throws Exception {
823         new Expectations() {
824             {
825                 sf.createSocket("first", 80).getKeepAlive();
826                 result = true;
827                 sf.createSocket("second", anyInt).getChannel().close();
828                 times = 1;
829             }
830         };
831 
832         sf.createSocket("second", 80).getChannel().close();
833         assertTrue(sf.createSocket("first", 80).getKeepAlive());
834         sf.createSocket("first", 8080).getChannel().provider().openPipe();
835 
836         new Verifications() {
837             {
838                 sf.createSocket("first", 8080).getChannel().provider().openPipe();
839             }
840         };
841     }
842 
843     // Cascading other Java SE types ///////////////////////////////////////////////////////////////////////////////////
844 
845     /**
846      * The Class SomeClass.
847      */
848     static class SomeClass {
849         /**
850          * Do something.
851          *
852          * @return the future
853          */
854         Future<Foo> doSomething() {
855             return null;
856         }
857     }
858 
859     /**
860      * Cascade A future.
861      *
862      * @param mock
863      *            the mock
864      *
865      * @throws Exception
866      *             the exception
867      */
868     @Test
869     void cascadeAFuture(@Mocked SomeClass mock) throws Exception {
870         Future<Foo> f = mock.doSomething();
871         Foo foo = f.get();
872 
873         assertNotNull(foo);
874     }
875 
876     // Other tests /////////////////////////////////////////////////////////////////////////////////////////////////////
877 
878     /**
879      * Record expectation on cascaded mock.
880      *
881      * @param foo
882      *            the foo
883      * @param mockBar
884      *            the mock bar
885      */
886     @Test
887     void recordExpectationOnCascadedMock(@Mocked Foo foo, @Mocked final Bar mockBar) {
888         new Expectations() {
889             {
890                 mockBar.doSomething();
891                 times = 1;
892                 result = 123;
893             }
894         };
895 
896         Bar bar = foo.getBar();
897         assertEquals(123, bar.doSomething());
898     }
899 
900     /**
901      * Override two cascaded mocks of the same type.
902      *
903      * @param foo1
904      *            the foo 1
905      * @param foo2
906      *            the foo 2
907      * @param mockBar1
908      *            the mock bar 1
909      * @param mockBar2
910      *            the mock bar 2
911      */
912     @Test
913     void overrideTwoCascadedMocksOfTheSameType(@Mocked final Foo foo1, @Mocked final Foo foo2,
914             @Mocked final Bar mockBar1, @Mocked final Bar mockBar2) {
915         new Expectations() {
916             {
917                 foo1.getBar();
918                 result = mockBar1;
919                 foo2.getBar();
920                 result = mockBar2;
921                 mockBar1.doSomething();
922                 mockBar2.doSomething();
923             }
924         };
925 
926         Bar bar1 = foo1.getBar();
927         Bar bar2 = foo2.getBar();
928         bar1.doSomething();
929         bar2.doSomething();
930     }
931 
932     /**
933      * Override two cascaded mocks of the same type but replay in different order.
934      *
935      * @param foo1
936      *            the foo 1
937      * @param foo2
938      *            the foo 2
939      * @param mockBar1
940      *            the mock bar 1
941      * @param mockBar2
942      *            the mock bar 2
943      */
944     @Test
945     void overrideTwoCascadedMocksOfTheSameTypeButReplayInDifferentOrder(@Mocked final Foo foo1, @Mocked final Foo foo2,
946             @Injectable final Bar mockBar1, @Mocked final Bar mockBar2) {
947         assertThrows(MissingInvocation.class, () -> {
948             new Expectations() {
949                 {
950                     foo1.getBar();
951                     result = mockBar1;
952                     foo2.getBar();
953                     result = mockBar2;
954                 }
955             };
956 
957             Bar bar1 = foo1.getBar();
958             Bar bar2 = foo2.getBar();
959             bar2.doSomething();
960             bar1.doSomething();
961 
962             new VerificationsInOrder() {
963                 {
964                     mockBar1.doSomething();
965                     mockBar2.doSomething();
966                 }
967             };
968         });
969     }
970 
971     /**
972      * Cascaded enum.
973      *
974      * @param mock
975      *            the mock
976      */
977     @Test
978     void cascadedEnum(@Mocked final Foo mock) {
979         new Expectations() {
980             {
981                 mock.getBar().getEnum();
982                 result = AnEnum.Second;
983             }
984         };
985 
986         assertEquals(AnEnum.Second, mock.getBar().getEnum());
987     }
988 
989     /**
990      * Cascaded enum returning consecutive values through result field.
991      *
992      * @param mock
993      *            the mock
994      */
995     @Test
996     void cascadedEnumReturningConsecutiveValuesThroughResultField(@Mocked final Foo mock) {
997         new Expectations() {
998             {
999                 mock.getBar().getEnum();
1000                 result = AnEnum.First;
1001                 result = AnEnum.Second;
1002                 result = AnEnum.Third;
1003             }
1004         };
1005 
1006         assertSame(AnEnum.First, mock.getBar().getEnum());
1007         assertSame(AnEnum.Second, mock.getBar().getEnum());
1008         assertSame(AnEnum.Third, mock.getBar().getEnum());
1009     }
1010 
1011     /**
1012      * Cascaded enum returning consecutive values through returns method.
1013      *
1014      * @param mock
1015      *            the mock
1016      */
1017     @Test
1018     void cascadedEnumReturningConsecutiveValuesThroughReturnsMethod(@Mocked final Foo mock) {
1019         new Expectations() {
1020             {
1021                 mock.getBar().getEnum();
1022                 returns(AnEnum.First, AnEnum.Second, AnEnum.Third);
1023             }
1024         };
1025 
1026         assertSame(AnEnum.First, mock.getBar().getEnum());
1027         assertSame(AnEnum.Second, mock.getBar().getEnum());
1028         assertSame(AnEnum.Third, mock.getBar().getEnum());
1029     }
1030 
1031     /**
1032      * Override last cascaded object with non mocked instance.
1033      *
1034      * @param foo
1035      *            the foo
1036      */
1037     @Test
1038     void overrideLastCascadedObjectWithNonMockedInstance(@Mocked final Foo foo) {
1039         final Date newDate = new Date(123);
1040         assertEquals(123, newDate.getTime());
1041 
1042         new Expectations() {
1043             {
1044                 foo.getBar().getBaz().getDate();
1045                 result = newDate;
1046             }
1047         };
1048 
1049         assertSame(newDate, new Foo().getBar().getBaz().getDate());
1050         assertEquals(123, newDate.getTime());
1051     }
1052 
1053     /**
1054      * Return declared mocked instance from multi level cascading.
1055      *
1056      * @param mockedDate
1057      *            the mocked date
1058      * @param foo
1059      *            the foo
1060      */
1061     @Test
1062     void returnDeclaredMockedInstanceFromMultiLevelCascading(@Mocked Date mockedDate, @Mocked Foo foo) {
1063         Date newDate = new Date(123);
1064         assertEquals(0, newDate.getTime());
1065 
1066         Date cascadedDate = new Foo().getBar().getBaz().getDate();
1067 
1068         assertSame(mockedDate, cascadedDate);
1069         assertEquals(0, newDate.getTime());
1070         assertEquals(0, mockedDate.getTime());
1071     }
1072 
1073     /**
1074      * Return injectable mock instance from multi level cascading.
1075      *
1076      * @param mockDate
1077      *            the mock date
1078      * @param foo
1079      *            the foo
1080      */
1081     @Test
1082     void returnInjectableMockInstanceFromMultiLevelCascading(@Injectable Date mockDate, @Mocked Foo foo) {
1083         Date newDate = new Date(123);
1084         assertEquals(123, newDate.getTime());
1085 
1086         Date cascadedDate = new Foo().getBar().getBaz().getDate();
1087 
1088         assertSame(mockDate, cascadedDate);
1089         assertEquals(123, newDate.getTime());
1090         assertEquals(0, mockDate.getTime());
1091     }
1092 
1093     /**
1094      * The Class Factory.
1095      */
1096     static class Factory {
1097         /**
1098          * Creates the.
1099          *
1100          * @return the factory
1101          */
1102         static Factory create() {
1103             return null;
1104         }
1105     }
1106 
1107     /**
1108      * The Class Client.
1109      */
1110     static class Client {
1111         /**
1112          * Gets the other client.
1113          *
1114          * @return the other client
1115          */
1116         OtherClient getOtherClient() {
1117             return null;
1118         }
1119     }
1120 
1121     /**
1122      * The Class OtherClient.
1123      */
1124     static class OtherClient {
1125         /** The Constant F. */
1126         static final Factory F = Factory.create();
1127     }
1128 
1129     /**
1130      * Cascade during static initialization of cascading class.
1131      *
1132      * @param mock1
1133      *            the mock 1
1134      * @param mock2
1135      *            the mock 2
1136      */
1137     @Test
1138     void cascadeDuringStaticInitializationOfCascadingClass(@Mocked Factory mock1, @Mocked Client mock2) {
1139         assertNotNull(mock2.getOtherClient());
1140         assertNotNull(OtherClient.F);
1141     }
1142 
1143     /**
1144      * The Interface LevelZero.
1145      */
1146     public interface LevelZero {
1147         /**
1148          * Gets the foo.
1149          *
1150          * @return the foo
1151          */
1152         Runnable getFoo();
1153     }
1154 
1155     /**
1156      * The Interface LevelOne.
1157      */
1158     public interface LevelOne extends LevelZero {
1159     }
1160 
1161     /**
1162      * The Interface LevelTwo.
1163      */
1164     public interface LevelTwo extends LevelOne {
1165     }
1166 
1167     /**
1168      * Creates the cascaded mock from method defined two levels up an interface hierarchy.
1169      *
1170      * @param mock
1171      *            the mock
1172      */
1173     @Test
1174     void createCascadedMockFromMethodDefinedTwoLevelsUpAnInterfaceHierarchy(@Mocked LevelTwo mock) {
1175         assertNotNull(mock.getFoo());
1176     }
1177 
1178     /**
1179      * The Class AbstractClass.
1180      */
1181     public abstract static class AbstractClass implements LevelZero {
1182     }
1183 
1184     /**
1185      * Cascade type returned from interface implemented by abstract class.
1186      *
1187      * @param mock
1188      *            the mock
1189      */
1190     @Test
1191     void cascadeTypeReturnedFromInterfaceImplementedByAbstractClass(@Mocked AbstractClass mock) {
1192         Runnable foo = mock.getFoo();
1193         assertNotNull(foo);
1194     }
1195 
1196     /**
1197      * Produce different cascaded instances of same interface from different invocations.
1198      *
1199      * @param bar
1200      *            the bar
1201      */
1202     @Test
1203     void produceDifferentCascadedInstancesOfSameInterfaceFromDifferentInvocations(@Mocked Bar bar) {
1204         Baz cascaded1 = bar.getBaz(1);
1205         Baz cascaded2 = bar.getBaz(2);
1206         Baz cascaded3 = bar.getBaz(1);
1207 
1208         assertSame(cascaded1, cascaded3);
1209         assertNotSame(cascaded1, cascaded2);
1210     }
1211 
1212     /**
1213      * Cascade from java management API.
1214      *
1215      * @param mngmntFactory
1216      *            the mngmnt factory
1217      */
1218     @Test
1219     void cascadeFromJavaManagementAPI(@Mocked ManagementFactory mngmntFactory) {
1220         CompilationMXBean compilation = ManagementFactory.getCompilationMXBean();
1221 
1222         assertNotNull(compilation);
1223         assertNull(compilation.getName());
1224     }
1225 
1226     /**
1227      * The Interface AnInterface.
1228      */
1229     public interface AnInterface {
1230         /**
1231          * Gets the package private class.
1232          *
1233          * @return the package private class
1234          */
1235         NonPublicTestedClass getPackagePrivateClass();
1236     }
1237 
1238     /**
1239      * Cascade from method in public interface returning package private type.
1240      *
1241      * @param mock
1242      *            the mock
1243      */
1244     @Test
1245     void cascadeFromMethodInPublicInterfaceReturningPackagePrivateType(@Mocked AnInterface mock) {
1246         NonPublicTestedClass ret = mock.getPackagePrivateClass();
1247 
1248         assertNull(ret);
1249     }
1250 
1251     /**
1252      * The Class CustomException.
1253      */
1254     public static final class CustomException extends Throwable {
1255 
1256         private static final long serialVersionUID = 1L;
1257     }
1258 
1259     /**
1260      * The Class AClass.
1261      */
1262     static class AClass {
1263         /**
1264          * Gets the exception.
1265          *
1266          * @return the exception
1267          */
1268         CustomException getException() {
1269             return new CustomException();
1270         }
1271     }
1272 
1273     /**
1274      * Cascade from method returning A throwable subclass.
1275      *
1276      * @param mock
1277      *            the mock
1278      */
1279     @Test
1280     void cascadeFromMethodReturningAThrowableSubclass(@Mocked AClass mock) {
1281         CustomException t = mock.getException();
1282 
1283         assertNull(t);
1284     }
1285 
1286     /**
1287      * The Class First.
1288      */
1289     static class First {
1290         /**
1291          * Gets the second.
1292          *
1293          * @param <T>
1294          *            the generic type
1295          * @param aClass
1296          *            the a class
1297          *
1298          * @return the second
1299          */
1300         <T extends Second> T getSecond(@SuppressWarnings("unused") Class<T> aClass) {
1301             return null;
1302         }
1303     }
1304 
1305     /**
1306      * The Class Second.
1307      */
1308     static class Second {
1309         /**
1310          * Gets the something.
1311          *
1312          * @return the something
1313          */
1314         Runnable getSomething() {
1315             return null;
1316         }
1317     }
1318 
1319     /**
1320      * Cascade from method returning type provided by class parameter then from cascaded instance.
1321      *
1322      * @param first
1323      *            the first
1324      */
1325     @Test
1326     void cascadeFromMethodReturningTypeProvidedByClassParameterThenFromCascadedInstance(@Mocked First first) {
1327         Second second = first.getSecond(Second.class);
1328         Runnable runnable = second.getSomething();
1329 
1330         assertNotNull(runnable);
1331     }
1332 
1333 }