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.assertTrue;
15  
16  import java.io.Serializable;
17  import java.util.Date;
18  import java.util.List;
19  
20  import mockit.integration.junit5.JMockitExtension;
21  
22  import org.junit.jupiter.api.BeforeEach;
23  import org.junit.jupiter.api.MethodOrderer.MethodName;
24  import org.junit.jupiter.api.Test;
25  import org.junit.jupiter.api.TestMethodOrder;
26  import org.junit.jupiter.api.extension.ExtendWith;
27  
28  /**
29   * The Class CascadingFieldTest.
30   */
31  @ExtendWith(JMockitExtension.class)
32  @TestMethodOrder(MethodName.class)
33  class CascadingFieldTest {
34  
35      /**
36       * The Class Foo.
37       */
38      static class Foo {
39  
40          /**
41           * Gets the bar.
42           *
43           * @return the bar
44           */
45          Bar getBar() {
46              return null;
47          }
48  
49          /**
50           * Global bar.
51           *
52           * @return the bar
53           */
54          static Bar globalBar() {
55              return null;
56          }
57  
58          /**
59           * Do something.
60           *
61           * @param s
62           *            the s
63           */
64          void doSomething(String s) {
65              throw new RuntimeException(s);
66          }
67  
68          /**
69           * Gets the int value.
70           *
71           * @return the int value
72           */
73          int getIntValue() {
74              return 1;
75          }
76  
77          /**
78           * Gets the boolean value.
79           *
80           * @return the boolean value
81           */
82          Boolean getBooleanValue() {
83              return true;
84          }
85  
86          /**
87           * Gets the string value.
88           *
89           * @return the string value
90           */
91          String getStringValue() {
92              return "abc";
93          }
94  
95          /**
96           * Gets the date.
97           *
98           * @return the date
99           */
100         public final Date getDate() {
101             return null;
102         }
103 
104         /**
105          * Gets the list.
106          *
107          * @return the list
108          */
109         final List<Integer> getList() {
110             return null;
111         }
112     }
113 
114     /**
115      * The Class Bar.
116      */
117     static class Bar {
118 
119         /**
120          * Instantiates a new bar.
121          */
122         Bar() {
123             throw new RuntimeException();
124         }
125 
126         /**
127          * Do something.
128          *
129          * @return the int
130          */
131         int doSomething() {
132             return 1;
133         }
134 
135         /**
136          * Checks if is done.
137          *
138          * @return true, if is done
139          */
140         boolean isDone() {
141             return false;
142         }
143 
144         /**
145          * Gets the short.
146          *
147          * @return the short
148          */
149         Short getShort() {
150             return 1;
151         }
152 
153         /**
154          * Gets the list.
155          *
156          * @return the list
157          */
158         List<?> getList() {
159             return null;
160         }
161 
162         /**
163          * Gets the baz.
164          *
165          * @return the baz
166          */
167         Baz getBaz() {
168             return null;
169         }
170 
171         /**
172          * Gets the task.
173          *
174          * @return the task
175          */
176         Runnable getTask() {
177             return null;
178         }
179     }
180 
181     /**
182      * The Class Baz.
183      */
184     static final class Baz {
185 
186         /** The e. */
187         final E e;
188 
189         /**
190          * Instantiates a new baz.
191          *
192          * @param e
193          *            the e
194          */
195         Baz(E e) {
196             this.e = e;
197         }
198 
199         /**
200          * Gets the e.
201          *
202          * @return the e
203          */
204         E getE() {
205             return e;
206         }
207 
208         /**
209          * Do something.
210          */
211         void doSomething() {
212         }
213     }
214 
215     /**
216      * The Enum E.
217      */
218     public enum E {
219         /** The a. */
220         A,
221         /** The b. */
222         B
223     }
224 
225     /**
226      * The Interface A.
227      */
228     public interface A {
229         /**
230          * Gets the b.
231          *
232          * @return the b
233          */
234         B getB();
235     }
236 
237     /**
238      * The Interface B.
239      */
240     public interface B {
241         /**
242          * Gets the c.
243          *
244          * @return the c
245          */
246         C getC();
247     }
248 
249     /**
250      * The Interface C.
251      */
252     public interface C {
253     }
254 
255     /** The foo. */
256     @Mocked
257     Foo foo;
258 
259     /** The a. */
260     @Mocked
261     A a;
262 
263     /**
264      * Record common expectations.
265      */
266     @BeforeEach
267     void recordCommonExpectations() {
268         new Expectations() {
269             {
270                 Bar bar = foo.getBar();
271                 minTimes = 0;
272                 bar.isDone();
273                 result = true;
274                 minTimes = 0;
275             }
276         };
277     }
278 
279     /**
280      * Obtain cascaded instances at all levels.
281      */
282     @Test
283     void obtainCascadedInstancesAtAllLevels() {
284         assertNotNull(foo.getBar());
285         assertNotNull(foo.getBar().getList());
286         assertNotNull(foo.getBar().getBaz());
287         assertNotNull(foo.getBar().getTask());
288 
289         B b = a.getB();
290         assertNotNull(b);
291         assertNotNull(b.getC());
292     }
293 
294     /**
295      * Obtain cascaded instances at all levels again.
296      */
297     @Test
298     void obtainCascadedInstancesAtAllLevelsAgain() {
299         Bar bar = foo.getBar();
300         assertNotNull(bar);
301         assertNotNull(bar.getList());
302         assertNotNull(bar.getBaz());
303         assertNotNull(bar.getTask());
304 
305         assertNotNull(a.getB());
306         assertNotNull(a.getB().getC());
307     }
308 
309     /**
310      * Cascade one level.
311      */
312     @Test
313     void cascadeOneLevel() {
314         assertTrue(foo.getBar().isDone());
315         assertEquals(0, foo.getBar().doSomething());
316         assertEquals(0, Foo.globalBar().doSomething());
317         assertNotSame(foo.getBar(), Foo.globalBar());
318         assertEquals(0, foo.getBar().getShort().intValue());
319 
320         foo.doSomething("test");
321         assertEquals(0, foo.getIntValue());
322         assertFalse(foo.getBooleanValue());
323         assertNull(foo.getStringValue());
324         assertNotNull(foo.getDate());
325         assertTrue(foo.getList().isEmpty());
326 
327         new Verifications() {
328             {
329                 foo.doSomething(anyString);
330             }
331         };
332     }
333 
334     /**
335      * Exercise cascading mock again.
336      */
337     @Test
338     void exerciseCascadingMockAgain() {
339         assertTrue(foo.getBar().isDone());
340     }
341 
342     /**
343      * Record unambiguous expectations producing different cascaded instances.
344      *
345      * @param foo1
346      *            the foo 1
347      * @param foo2
348      *            the foo 2
349      */
350     @Test
351     void recordUnambiguousExpectationsProducingDifferentCascadedInstances(@Mocked final Foo foo1,
352             @Mocked final Foo foo2) {
353         new Expectations() {
354             {
355                 Date c1 = foo1.getDate();
356                 Date c2 = foo2.getDate();
357                 assertNotSame(c1, c2);
358             }
359         };
360 
361         Date d1 = foo1.getDate();
362         Date d2 = foo2.getDate();
363         assertNotSame(d1, d2);
364     }
365 
366     /**
367      * Record ambiguous expectations on instance method producing the same cascaded instance.
368      */
369     @Test
370     void recordAmbiguousExpectationsOnInstanceMethodProducingTheSameCascadedInstance() {
371         new Expectations() {
372             {
373                 Bar c1 = foo.getBar();
374                 Bar c2 = foo.getBar();
375                 assertSame(c1, c2);
376             }
377         };
378 
379         Bar b1 = foo.getBar();
380         Bar b2 = foo.getBar();
381         assertSame(b1, b2);
382     }
383 
384     /**
385      * Record ambiguous expectations on static method producing the same cascaded instance.
386      */
387     @Test
388     void recordAmbiguousExpectationsOnStaticMethodProducingTheSameCascadedInstance() {
389         new Expectations() {
390             {
391                 Bar c1 = Foo.globalBar();
392                 Bar c2 = Foo.globalBar();
393                 assertSame(c1, c2);
394             }
395         };
396 
397         Bar b1 = Foo.globalBar();
398         Bar b2 = Foo.globalBar();
399         assertSame(b1, b2);
400     }
401 
402     /**
403      * Record ambiguous expectation with multiple cascading candidates followed by expectation recorded on first
404      * candidate.
405      *
406      * @param bar1
407      *            the bar 1
408      * @param bar2
409      *            the bar 2
410      */
411     @Test
412     void recordAmbiguousExpectationWithMultipleCascadingCandidatesFollowedByExpectationRecordedOnFirstCandidate(
413             @Injectable final Bar bar1, @Injectable Bar bar2) {
414         new Expectations() {
415             {
416                 foo.getBar();
417                 bar1.doSomething();
418             }
419         };
420 
421         foo.getBar();
422         bar1.doSomething();
423     }
424 
425     /**
426      * The Class AnotherFoo.
427      */
428     static final class AnotherFoo {
429         /**
430          * Gets the bar.
431          *
432          * @return the bar
433          */
434         Bar getBar() {
435             return null;
436         }
437     }
438 
439     /** The another foo. */
440     @Mocked
441     AnotherFoo anotherFoo;
442 
443     /**
444      * Cascading mock field.
445      */
446     @Test
447     void cascadingMockField() {
448         new Expectations() {
449             {
450                 anotherFoo.getBar().doSomething();
451                 result = 123;
452             }
453         };
454 
455         assertEquals(123, new AnotherFoo().getBar().doSomething());
456     }
457 
458     /**
459      * Cascading instance accessed from delegate method.
460      */
461     @Test
462     void cascadingInstanceAccessedFromDelegateMethod() {
463         new Expectations() {
464             {
465                 foo.getIntValue();
466                 result = new Delegate<Object>() {
467                     @Mock
468                     int delegate() {
469                         return foo.getBar().doSomething();
470                     }
471                 };
472             }
473         };
474 
475         assertEquals(0, foo.getIntValue());
476     }
477 
478     /** The baz creator and consumer. */
479     @Mocked
480     BazCreatorAndConsumer bazCreatorAndConsumer;
481 
482     /**
483      * The Class BazCreatorAndConsumer.
484      */
485     static class BazCreatorAndConsumer {
486 
487         /**
488          * Creates the.
489          *
490          * @return the baz
491          */
492         Baz create() {
493             return null;
494         }
495 
496         /**
497          * Consume.
498          *
499          * @param arg
500          *            the arg
501          */
502         void consume(Baz arg) {
503             arg.toString();
504         }
505     }
506 
507     /**
508      * Call method on non cascaded instance from custom argument matcher with cascaded instance also created.
509      */
510     @Test
511     void callMethodOnNonCascadedInstanceFromCustomArgumentMatcherWithCascadedInstanceAlsoCreated() {
512         Baz nonCascadedInstance = new Baz(E.A);
513         Baz cascadedInstance = bazCreatorAndConsumer.create();
514         assertNotSame(nonCascadedInstance, cascadedInstance);
515 
516         bazCreatorAndConsumer.consume(nonCascadedInstance);
517 
518         new Verifications() {
519             {
520                 bazCreatorAndConsumer.consume(with(new Delegate<Baz>() {
521                     @SuppressWarnings("unused")
522                     boolean matches(Baz actual) {
523                         return actual.getE() == E.A;
524                     }
525                 }));
526             }
527         };
528     }
529 
530     // Tests for cascaded instances obtained from generic methods //////////////////////////////////////////////////////
531 
532     /**
533      * The Class GenericBaseClass1.
534      *
535      * @param <T>
536      *            the generic type
537      */
538     static class GenericBaseClass1<T> {
539         /**
540          * Gets the value.
541          *
542          * @return the value
543          */
544         T getValue() {
545             return null;
546         }
547     }
548 
549     /**
550      * Cascade generic method from specialized generic class.
551      *
552      * @param mock
553      *            the mock
554      */
555     @Test
556     void cascadeGenericMethodFromSpecializedGenericClass(@Mocked GenericBaseClass1<C> mock) {
557         C value = mock.getValue();
558         assertNotNull(value);
559     }
560 
561     /**
562      * The Class ConcreteSubclass1.
563      */
564     static class ConcreteSubclass1 extends GenericBaseClass1<A> {
565     }
566 
567     /**
568      * Cascade generic method of concrete subclass which extends generic class.
569      *
570      * @param mock
571      *            the mock
572      */
573     @Test
574     void cascadeGenericMethodOfConcreteSubclassWhichExtendsGenericClass(@Mocked final ConcreteSubclass1 mock) {
575         new Expectations() {
576             {
577                 mock.getValue().getB().getC();
578                 result = new C() {
579                 };
580             }
581         };
582 
583         A value = mock.getValue();
584         assertNotNull(value);
585         B b = value.getB();
586         assertNotNull(b);
587         assertNotNull(b.getC());
588 
589         new FullVerifications() {
590             {
591                 mock.getValue().getB().getC();
592             }
593         };
594     }
595 
596     /**
597      * The Interface Ab.
598      */
599     interface Ab extends A {
600     }
601 
602     /**
603      * The Class GenericBaseClass2.
604      *
605      * @param <T>
606      *            the generic type
607      */
608     static class GenericBaseClass2<T extends A> {
609         /**
610          * Gets the value.
611          *
612          * @return the value
613          */
614         T getValue() {
615             return null;
616         }
617     }
618 
619     /**
620      * The Class ConcreteSubclass2.
621      */
622     static class ConcreteSubclass2 extends GenericBaseClass2<Ab> {
623     }
624 
625     /**
626      * Cascade generic method of subclass which extends generic class with upper bound using interface.
627      *
628      * @param mock
629      *            the mock
630      */
631     @Test
632     void cascadeGenericMethodOfSubclassWhichExtendsGenericClassWithUpperBoundUsingInterface(
633             @Mocked final ConcreteSubclass2 mock) {
634         Ab value = mock.getValue();
635         assertNotNull(value);
636         value.getB().getC();
637 
638         new Verifications() {
639             {
640                 mock.getValue().getB().getC();
641                 times = 1;
642             }
643         };
644     }
645 
646     /**
647      * Cascade generic method of subclass which extends generic class with upper bound only in verification block.
648      *
649      * @param mock
650      *            the mock
651      */
652     @Test
653     void cascadeGenericMethodOfSubclassWhichExtendsGenericClassWithUpperBoundOnlyInVerificationBlock(
654             @Mocked final ConcreteSubclass2 mock) {
655         new FullVerifications() {
656             {
657                 Ab value = mock.getValue();
658                 times = 0;
659                 B b = value.getB();
660                 times = 0;
661                 b.getC();
662                 times = 0;
663             }
664         };
665     }
666 
667     /**
668      * The Class Action.
669      */
670     static final class Action implements A {
671         @Override
672         public B getB() {
673             return null;
674         }
675     }
676 
677     /**
678      * The Class ActionHolder.
679      */
680     static final class ActionHolder extends GenericBaseClass2<Action> {
681     }
682 
683     /**
684      * Cascade generic method of subclass which extends generic class with upper bound using class.
685      *
686      * @param mock
687      *            the mock
688      */
689     @Test
690     void cascadeGenericMethodOfSubclassWhichExtendsGenericClassWithUpperBoundUsingClass(
691             @Mocked final ActionHolder mock) {
692         new Expectations() {
693             {
694                 mock.getValue().getB().getC();
695             }
696         };
697 
698         mock.getValue().getB().getC();
699     }
700 
701     /**
702      * The Class Base.
703      *
704      * @param <T>
705      *            the generic type
706      */
707     static class Base<T extends Serializable> {
708         /**
709          * Value.
710          *
711          * @return the t
712          */
713         @SuppressWarnings("unchecked")
714         T value() {
715             return (T) Long.valueOf(123);
716         }
717     }
718 
719     /**
720      * The Class Derived1.
721      */
722     static class Derived1 extends Base<Long> {
723     }
724 
725     /**
726      * The Class Derived2.
727      */
728     static class Derived2 extends Base<Long> {
729     }
730 
731     /**
732      * The Interface Factory1.
733      */
734     interface Factory1 {
735         /**
736          * Gets the 1.
737          *
738          * @return the 1
739          */
740         Derived1 get1();
741     }
742 
743     /**
744      * The Interface Factory2.
745      */
746     interface Factory2 {
747         /**
748          * Gets the 2.
749          *
750          * @return the 2
751          */
752         Derived2 get2();
753     }
754 
755     /** The factory 1. */
756     @Mocked
757     Factory1 factory1;
758 
759     /** The factory 2. */
760     @Mocked
761     Factory2 factory2;
762 
763     /**
764      * Use subclass mocked through cascading.
765      */
766     @Test
767     void useSubclassMockedThroughCascading() {
768         Derived1 d1 = factory1.get1(); // cascade-mocks Derived1 (per-instance)
769         Long v1 = d1.value();
770         assertNull(v1);
771 
772         Long v2 = new Derived1().value(); // new instance, not mocked
773         assertEquals(123, v2.longValue());
774     }
775 
776     /**
777      * Use subclass previously mocked through cascading while mocking sibling subclass.
778      *
779      * @param d2
780      *            the d 2
781      */
782     @Test
783     void useSubclassPreviouslyMockedThroughCascadingWhileMockingSiblingSubclass(@Injectable Derived2 d2) {
784         Long v1 = new Derived1().value();
785         assertEquals(123, v1.longValue());
786 
787         Long v2 = d2.value();
788         assertNull(v2);
789 
790         Long v3 = new Derived2().value();
791         assertEquals(123, v3.longValue());
792     }
793 }