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.assertNotNull;
10 import static org.junit.jupiter.api.Assertions.assertNotSame;
11 import static org.junit.jupiter.api.Assertions.assertNull;
12 import static org.junit.jupiter.api.Assertions.assertSame;
13
14 import java.io.Serializable;
15 import java.util.Date;
16 import java.util.List;
17 import java.util.concurrent.Callable;
18
19 import mockit.integration.junit5.JMockitExtension;
20
21 import org.junit.jupiter.api.MethodOrderer.MethodName;
22 import org.junit.jupiter.api.Test;
23 import org.junit.jupiter.api.TestMethodOrder;
24 import org.junit.jupiter.api.extension.ExtendWith;
25
26 /**
27 * The Class CascadingWithGenericsTest.
28 */
29 @ExtendWith(JMockitExtension.class)
30 @TestMethodOrder(MethodName.class)
31 class CascadingWithGenericsTest {
32
33 /**
34 * The Class Foo.
35 */
36 static class Foo {
37
38 /**
39 * Return type with wildcard.
40 *
41 * @return the callable
42 */
43 Callable<?> returnTypeWithWildcard() {
44 return null;
45 }
46
47 /**
48 * Return type with bounded type variable.
49 *
50 * @param <RT>
51 * the generic type
52 *
53 * @return the rt
54 */
55 <RT extends Baz> RT returnTypeWithBoundedTypeVariable() {
56 return null;
57 }
58
59 /**
60 * Generic method with non mockable bounded type variable and class parameter.
61 *
62 * @param <N>
63 * the number type
64 * @param c
65 * the c
66 *
67 * @return the n
68 */
69 <N extends Number> N genericMethodWithNonMockableBoundedTypeVariableAndClassParameter(
70 @SuppressWarnings("unused") Class<N> c) {
71 return null;
72 }
73
74 /**
75 * Generic method with bounded type variable and class parameter.
76 *
77 * @param <RT>
78 * the generic type
79 * @param cl
80 * the cl
81 *
82 * @return the rt
83 */
84 <RT extends Bar> RT genericMethodWithBoundedTypeVariableAndClassParameter(
85 @SuppressWarnings("unused") Class<RT> cl) {
86 return null;
87 }
88
89 /**
90 * Return type with multiple type variables.
91 *
92 * @param <T1>
93 * the generic type
94 * @param <T2>
95 * the generic type
96 *
97 * @return the pair
98 */
99 <T1 extends Baz, T2 extends List<? extends Number>> Pair<T1, T2> returnTypeWithMultipleTypeVariables() {
100 return null;
101 }
102
103 /**
104 * Return generic type with type argument.
105 *
106 * @return the callable
107 */
108 Callable<Baz> returnGenericTypeWithTypeArgument() {
109 return null;
110 }
111
112 /**
113 * Bar.
114 *
115 * @return the bar
116 */
117 Bar bar() {
118 return null;
119 }
120 }
121
122 /**
123 * The Interface Pair.
124 *
125 * @param <K>
126 * the key type
127 * @param <V>
128 * the value type
129 */
130 @SuppressWarnings("unused")
131 public interface Pair<K, V> {
132 }
133
134 /**
135 * The Class Bar.
136 */
137 static class Bar {
138
139 /**
140 * Instantiates a new bar.
141 */
142 Bar() {
143 throw new RuntimeException();
144 }
145
146 /**
147 * Do something.
148 *
149 * @return the int
150 */
151 int doSomething() {
152 return 1;
153 }
154
155 /**
156 * Static method.
157 *
158 * @return the string
159 */
160 static String staticMethod() {
161 return "notMocked";
162 }
163 }
164
165 /**
166 * The Class SubBar.
167 */
168 static final class SubBar extends Bar {
169 }
170
171 /**
172 * The Interface Baz.
173 */
174 public interface Baz {
175 /**
176 * Gets the date.
177 *
178 * @return the date
179 */
180 Date getDate();
181 }
182
183 /**
184 * Cascade one level during replay.
185 *
186 * @param foo
187 * the foo
188 */
189 @Test
190 void cascadeOneLevelDuringReplay(@Mocked Foo foo) {
191 assertNotNull(foo.returnTypeWithWildcard());
192 assertNotNull(foo.returnTypeWithBoundedTypeVariable());
193
194 Pair<Baz, List<Integer>> x = foo.returnTypeWithMultipleTypeVariables();
195 assertNotNull(x);
196 }
197
198 /**
199 * Cascade one level during record.
200 *
201 * @param action
202 * the action
203 * @param mockFoo
204 * the mock foo
205 */
206 @Test
207 void cascadeOneLevelDuringRecord(@Mocked Callable<String> action, @Mocked Foo mockFoo) {
208 Foo foo = new Foo();
209 Callable<?> cascaded = foo.returnTypeWithWildcard();
210
211 assertSame(action, cascaded);
212 }
213
214 /**
215 * Cascade two levels during record.
216 *
217 * @param mockFoo
218 * the mock foo
219 */
220 @Test
221 void cascadeTwoLevelsDuringRecord(@Mocked final Foo mockFoo) {
222 final Date now = new Date();
223
224 new Expectations() {
225 {
226 mockFoo.returnTypeWithBoundedTypeVariable().getDate();
227 result = now;
228 }
229 };
230
231 Foo foo = new Foo();
232 assertSame(now, foo.returnTypeWithBoundedTypeVariable().getDate());
233 }
234
235 /**
236 * The Class GenericFoo.
237 *
238 * @param <T>
239 * the generic type
240 * @param <U>
241 * the generic type
242 */
243 static class GenericFoo<T, U extends Bar> {
244
245 /**
246 * Return type with unbounded type variable.
247 *
248 * @return the t
249 */
250 T returnTypeWithUnboundedTypeVariable() {
251 return null;
252 }
253
254 /**
255 * Return type with bounded type variable.
256 *
257 * @return the u
258 */
259 U returnTypeWithBoundedTypeVariable() {
260 return null;
261 }
262 }
263
264 /**
265 * Cascade generic methods.
266 *
267 * @param foo
268 * the foo
269 */
270 @Test
271 void cascadeGenericMethods(@Mocked GenericFoo<Baz, SubBar> foo) {
272 Baz t = foo.returnTypeWithUnboundedTypeVariable();
273 assertNotNull(t);
274
275 SubBar u = foo.returnTypeWithBoundedTypeVariable();
276 assertNotNull(u);
277 }
278
279 /**
280 * The Class A.
281 */
282 static class A {
283 /**
284 * Gets the b.
285 *
286 * @return the b
287 */
288 B<?> getB() {
289 return null;
290 }
291 }
292
293 /**
294 * The Class B.
295 *
296 * @param <T>
297 * the generic type
298 */
299 static class B<T> {
300 /**
301 * Gets the value.
302 *
303 * @return the value
304 */
305 T getValue() {
306 return null;
307 }
308 }
309
310 /**
311 * Cascade on method returning A parameterized class with A generic method.
312 *
313 * @param a
314 * the a
315 */
316 @Test
317 void cascadeOnMethodReturningAParameterizedClassWithAGenericMethod(@Injectable final A a) {
318 new Expectations() {
319 {
320 a.getB().getValue();
321 result = "test";
322 }
323 };
324
325 assertEquals("test", a.getB().getValue());
326 }
327
328 /**
329 * The Class C.
330 *
331 * @param <T>
332 * the generic type
333 */
334 @SuppressWarnings("unused")
335 static class C<T> {
336 }
337
338 /**
339 * The Class D.
340 */
341 static class D extends C<Foo> {
342 /**
343 * Do something.
344 *
345 * @param <T>
346 * the generic type
347 *
348 * @return the t
349 */
350 <T extends Bar> T doSomething() {
351 return null;
352 }
353 }
354
355 /**
356 * Cascade from generic method using type parameter of same name as type parameter from base class.
357 *
358 * @param mock
359 * the mock
360 */
361 @Test
362 void cascadeFromGenericMethodUsingTypeParameterOfSameNameAsTypeParameterFromBaseClass(@Mocked D mock) {
363 Bar cascaded = mock.doSomething();
364
365 assertNotNull(cascaded);
366 }
367
368 /**
369 * The Class Factory.
370 */
371 static class Factory {
372
373 /**
374 * Bar.
375 *
376 * @param <T>
377 * the generic type
378 *
379 * @return the t
380 */
381 static <T extends Bar> T bar() {
382 return null;
383 }
384
385 /**
386 * Bar.
387 *
388 * @param <T>
389 * the generic type
390 * @param c
391 * the c
392 *
393 * @return the t
394 */
395 static <T extends Bar> T bar(@SuppressWarnings("UnusedParameters") Class<T> c) {
396 return null;
397 }
398
399 /**
400 * Static init.
401 *
402 * @return the with static init
403 */
404 WithStaticInit staticInit() {
405 return null;
406 }
407 }
408
409 /**
410 * The Class WithStaticInit.
411 */
412 static class WithStaticInit {
413
414 /** The Constant T. */
415 static final Bar T = Factory.bar();
416
417 /** The Constant S. */
418 static final SubBar S = Factory.bar(SubBar.class);
419 }
420
421 /**
422 * Cascade during static initialization of cascaded class.
423 *
424 * @param mock
425 * the mock
426 */
427 @Test
428 void cascadeDuringStaticInitializationOfCascadedClass(@Mocked Factory mock) {
429 assertNotNull(mock.staticInit());
430 assertNotNull(WithStaticInit.T);
431 assertNotNull(WithStaticInit.S);
432 }
433
434 /**
435 * Cascade from generic method where concrete return type is given by class parameter but is not mockable.
436 *
437 * @param foo
438 * the foo
439 */
440 @Test
441 void cascadeFromGenericMethodWhereConcreteReturnTypeIsGivenByClassParameterButIsNotMockable(@Mocked Foo foo) {
442 Integer n = foo.genericMethodWithNonMockableBoundedTypeVariableAndClassParameter(Integer.class);
443
444 assertNotNull(n);
445 }
446
447 /**
448 * Cascade from generic method where concrete return type is given by class parameter.
449 *
450 * @param foo
451 * the foo
452 */
453 @Test
454 void cascadeFromGenericMethodWhereConcreteReturnTypeIsGivenByClassParameter(@Mocked Foo foo) {
455 SubBar subBar = foo.genericMethodWithBoundedTypeVariableAndClassParameter(SubBar.class);
456
457 assertNotNull(subBar);
458 }
459
460 /**
461 * Cascade from generic method whose return type comes from parameter on owner type.
462 *
463 * @param foo
464 * the foo
465 * @param cascadedBaz
466 * the cascaded baz
467 *
468 * @throws Exception
469 * the exception
470 */
471 @Test
472 void cascadeFromGenericMethodWhoseReturnTypeComesFromParameterOnOwnerType(@Mocked Foo foo,
473 @Mocked final Baz cascadedBaz) throws Exception {
474 final Date date = new Date();
475 new Expectations() {
476 {
477 cascadedBaz.getDate();
478 result = date;
479 }
480 };
481
482 Callable<Baz> callable = foo.returnGenericTypeWithTypeArgument();
483 Baz baz = callable.call();
484
485 assertSame(cascadedBaz, baz);
486 assertSame(date, baz.getDate());
487 }
488
489 /**
490 * The Interface GenericInterface.
491 *
492 * @param <T>
493 * the generic type
494 */
495 public interface GenericInterface<T> {
496 /**
497 * Save.
498 *
499 * @param <S>
500 * the generic type
501 * @param entity
502 * the entity
503 *
504 * @return the s
505 */
506 <S extends T> S save(S entity);
507 }
508
509 /**
510 * The Interface ConcreteInterface.
511 */
512 public interface ConcreteInterface extends GenericInterface<Foo> {
513 }
514
515 /**
516 * Cascading from generic method whose type parameter extends another.
517 *
518 * @param mock
519 * the mock
520 */
521 @Test
522 void cascadingFromGenericMethodWhoseTypeParameterExtendsAnother(@Mocked ConcreteInterface mock) {
523 Foo value = new Foo();
524
525 Foo saved = mock.save(value);
526
527 assertNotNull(saved);
528 assertNotSame(value, saved);
529 }
530
531 /**
532 * The Interface GenericInterfaceWithBoundedTypeParameter.
533 *
534 * @param <B>
535 * the generic type
536 */
537 public interface GenericInterfaceWithBoundedTypeParameter<B extends Serializable> {
538 /**
539 * Gets the.
540 *
541 * @param id
542 * the id
543 *
544 * @return the b
545 */
546 B get(int id);
547 }
548
549 /**
550 * Cascade from method returning A type variable.
551 *
552 * @param <T>
553 * the generic type
554 * @param mock
555 * the mock
556 */
557 @Test
558 <T extends Serializable> void cascadeFromMethodReturningATypeVariable(
559 @Mocked final GenericInterfaceWithBoundedTypeParameter<T> mock) {
560 new Expectations() {
561 {
562 mock.get(1);
563 result = "test";
564 mock.get(2);
565 result = null;
566 }
567 };
568
569 assertEquals("test", mock.get(1));
570 assertNull(mock.get(2));
571 }
572
573 /**
574 * The Class TypeWithUnusedTypeParameterInGenericMethod.
575 */
576 static class TypeWithUnusedTypeParameterInGenericMethod {
577 /**
578 * Foo.
579 *
580 * @param <U>
581 * the generic type
582 *
583 * @return the foo
584 */
585 @SuppressWarnings("unused")
586 <U> Foo foo() {
587 return null;
588 }
589 }
590
591 /**
592 * Cascade from method having unused type parameter.
593 *
594 * @param mock
595 * the mock
596 */
597 @Test
598 void cascadeFromMethodHavingUnusedTypeParameter(@Mocked TypeWithUnusedTypeParameterInGenericMethod mock) {
599 Foo foo = mock.foo();
600 Bar bar = foo.bar();
601 assertNotNull(bar);
602 }
603
604 /**
605 * Cascade from generic method whose return type resolves to another generic type.
606 *
607 * @param mock
608 * the mock
609 */
610 @Test
611 void cascadeFromGenericMethodWhoseReturnTypeResolvesToAnotherGenericType(@Mocked B<C<?>> mock) {
612 C<?> c = mock.getValue();
613
614 assertNotNull(c);
615 }
616
617 /**
618 * The Interface BaseGenericInterface.
619 *
620 * @param <B>
621 * the generic type
622 */
623 public interface BaseGenericInterface<B> {
624 /**
625 * Generic method.
626 *
627 * @return the b
628 */
629 B genericMethod();
630 }
631
632 /**
633 * The Interface GenericSubInterface.
634 *
635 * @param <S>
636 * the generic type
637 */
638 public interface GenericSubInterface<S> extends BaseGenericInterface<S> {
639 }
640
641 /**
642 * The Interface NonGenericInterface.
643 */
644 public interface NonGenericInterface extends GenericSubInterface<Bar> {
645 }
646
647 /**
648 * Cascade from generic method defined two levels deep in inheritance hierarchy.
649 *
650 * @param mock
651 * the mock
652 */
653 @Test
654 void cascadeFromGenericMethodDefinedTwoLevelsDeepInInheritanceHierarchy(@Mocked NonGenericInterface mock) {
655 Bar cascadedResult = mock.genericMethod();
656
657 assertNotNull(cascadedResult);
658 }
659
660 /**
661 * The Interface NonPublicInterfaceWithGenericMethod.
662 */
663 interface NonPublicInterfaceWithGenericMethod {
664 /**
665 * Do something.
666 *
667 * @param <T>
668 * the generic type
669 *
670 * @return the t
671 */
672 <T extends Runnable> T doSomething();
673 }
674
675 /**
676 * Cascade from generic method of non public interface.
677 *
678 * @param mock
679 * the mock
680 */
681 @Test
682 void cascadeFromGenericMethodOfNonPublicInterface(@Mocked NonPublicInterfaceWithGenericMethod mock) {
683 Runnable result = mock.doSomething();
684
685 assertNotNull(result);
686 }
687
688 /**
689 * The Interface FactoryInterface.
690 */
691 public interface FactoryInterface {
692 /**
693 * Generic with class.
694 *
695 * @param <T>
696 * the generic type
697 * @param type
698 * the type
699 *
700 * @return the t
701 */
702 <T> T genericWithClass(Class<T> type);
703 }
704
705 /**
706 * Cascade from generic method with class parameter of mocked interface.
707 *
708 * @param mock
709 * the mock
710 */
711 @Test
712 void cascadeFromGenericMethodWithClassParameterOfMockedInterface(@Mocked FactoryInterface mock) {
713 Foo cascaded = mock.genericWithClass(Foo.class);
714
715 assertNotNull(cascaded);
716 }
717
718 /**
719 * The Class Outer.
720 *
721 * @param <T>
722 * the generic type
723 */
724 @SuppressWarnings("unused")
725 static class Outer<T> {
726 /**
727 * The Class Inner.
728 */
729 class Inner {
730 }
731 }
732
733 /**
734 * The Class Client.
735 */
736 static class Client {
737 /**
738 * Do something.
739 *
740 * @return the outer. inner
741 */
742 Outer<String>.Inner doSomething() {
743 return null;
744 }
745 }
746
747 /**
748 * Cascade from method returning inner instance of generic class.
749 *
750 * @param mock
751 * the mock
752 */
753 @Test
754 void cascadeFromMethodReturningInnerInstanceOfGenericClass(@Mocked final Client mock) {
755 final Outer<?>.Inner innerInstance = new Outer().new Inner();
756
757 new Expectations() {
758 {
759 mock.doSomething();
760 result = innerInstance;
761 }
762 };
763
764 assertSame(innerInstance, mock.doSomething());
765 }
766
767 /**
768 * The Class SubB.
769 *
770 * @param <T>
771 * the generic type
772 */
773 static class SubB<T> extends B<T> {
774 }
775
776 /**
777 * The Class ClassWithMethodReturningGenericClassInstance.
778 */
779 static class ClassWithMethodReturningGenericClassInstance {
780 /**
781 * Do something.
782 *
783 * @return the sub B
784 */
785 SubB<C<?>> doSomething() {
786 return null;
787 }
788 }
789
790 /**
791 * Cascade from method returning instance of generic subclass then from generic method of generic base class.
792 *
793 * @param mock
794 * the mock
795 */
796 @Test
797 void cascadeFromMethodReturningInstanceOfGenericSubclassThenFromGenericMethodOfGenericBaseClass(
798 @Mocked ClassWithMethodReturningGenericClassInstance mock) {
799 SubB<C<?>> cascade1 = mock.doSomething();
800 C<?> cascade2 = cascade1.getValue();
801
802 assertNotNull(cascade2);
803 }
804
805 /**
806 * The Interface InterfaceWithGenericMethod.
807 *
808 * @param <T>
809 * the generic type
810 */
811 public interface InterfaceWithGenericMethod<T> {
812 /**
813 * Generic method.
814 *
815 * @return the t
816 */
817 @SuppressWarnings("unused")
818 T genericMethod();
819 }
820
821 /**
822 * The Class BaseClass.
823 */
824 static class BaseClass {
825 /**
826 * Generic method.
827 *
828 * @return the bar
829 */
830 public Bar genericMethod() {
831 return null;
832 }
833 }
834
835 /**
836 * The Class SubClass.
837 */
838 static class SubClass extends BaseClass implements InterfaceWithGenericMethod<Bar> {
839 }
840
841 /**
842 * Cascade from generic interface method implemented in base class of mocked sub class.
843 *
844 * @param mock
845 * the mock
846 */
847 @Test
848 void cascadeFromGenericInterfaceMethodImplementedInBaseClassOfMockedSubClass(@Mocked SubClass mock) {
849 Bar cascaded = mock.genericMethod();
850 assertNotNull(cascaded);
851 }
852 }