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