1
2
3
4
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.assertSame;
14
15 import java.io.Serializable;
16 import java.lang.reflect.Type;
17 import java.util.Dictionary;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.concurrent.Callable;
21
22 import mockit.integration.junit5.JMockitExtension;
23
24 import org.junit.jupiter.api.Test;
25 import org.junit.jupiter.api.extension.ExtendWith;
26
27
28
29
30 @ExtendWith(JMockitExtension.class)
31 class GenericMockedTypesTest {
32
33
34 @Mocked
35 Callable<Integer> mock2;
36
37
38
39
40
41
42
43
44
45
46 @Test
47 void mockGenericInterfaces(@Mocked final Callable<?> mock1) throws Exception {
48 new Expectations() {
49 {
50 mock1.call();
51 result = "mocked";
52 mock2.call();
53 result = 123;
54 }
55 };
56
57 assertEquals("mocked", mock1.call());
58 assertEquals(123, mock2.call().intValue());
59 }
60
61
62
63
64
65
66
67 @Test
68 void obtainGenericSuperclassFromClassGeneratedForNonGenericInterface(@Mocked Runnable mock) {
69 Class<?> generatedClass = mock.getClass();
70 Type genericSuperClass = generatedClass.getGenericSuperclass();
71
72
73
74 assertSame(Object.class, genericSuperClass);
75 }
76
77
78
79
80
81
82
83 @Test
84 void mockGenericAbstractClass(@Mocked final Dictionary<Integer, String> mock) {
85 new Expectations() {
86 {
87 mock.put(123, "test");
88 result = "mocked";
89 }
90 };
91
92 assertEquals("mocked", mock.put(123, "test"));
93 }
94
95 @Test
96 public void mockRawMapInterface(@SuppressWarnings("rawtypes") @Mocked final Map rawMap) {
97 new Expectations() {
98 {
99 rawMap.get("test");
100 result = new Object();
101 }
102 };
103
104 Object value = rawMap.get("test");
105 assertNotNull(value);
106 }
107
108
109
110
111 public interface InterfaceWithMethodParametersMixingGenericTypesAndArrays {
112
113
114
115
116
117
118
119
120
121
122
123 <T> void doSomething(int[] i, T b);
124
125
126
127
128
129
130
131
132
133 void doSomething(Callable<int[]> pc, int[] ii);
134
135
136
137
138
139
140
141
142
143
144
145
146
147 void doSomething(Callable<String> pc, int[] i, boolean[] currencies, int[] ii);
148 }
149
150
151
152
153
154
155
156 @Test
157 void mockMethodsHavingGenericsAndArrays(@Mocked InterfaceWithMethodParametersMixingGenericTypesAndArrays mock) {
158 mock.doSomething((Callable<int[]>) null, new int[] { 1, 2 });
159 mock.doSomething(null, new int[] { 1, 2 }, null, new int[] { 3, 4, 5 });
160 }
161
162
163
164
165 public interface NonGenericInterfaceWithGenericMethods {
166
167
168
169
170
171
172
173
174
175 <T> T genericMethodWithUnboundedReturnType();
176
177
178
179
180
181
182
183
184
185 <T extends CharSequence> T genericMethodWithBoundedReturnType();
186 }
187
188
189
190
191
192
193
194 @Test
195 void resultFromGenericMethodsOfNonGenericInterface(@Mocked final NonGenericInterfaceWithGenericMethods mock) {
196 new Expectations() {
197 {
198 mock.genericMethodWithUnboundedReturnType();
199 result = 123;
200 mock.genericMethodWithBoundedReturnType();
201 result = "test";
202 }
203 };
204
205 Object v1 = mock.genericMethodWithUnboundedReturnType();
206 assertEquals(123, v1);
207
208 Object v2 = mock.genericMethodWithBoundedReturnType();
209 assertEquals("test", v2);
210 }
211
212
213
214
215 static class Item implements Serializable {
216
217 private static final long serialVersionUID = 1L;
218 }
219
220
221
222
223
224
225
226 static class GenericContainer<T extends Serializable> {
227
228
229
230
231
232 final T getItem() {
233 return null;
234 }
235 }
236
237
238
239
240
241
242
243 @Test
244 void createFirstLevelCascadedMockFromTypeParameter(@Mocked GenericContainer<Item> mockContainer) {
245 Serializable mock = mockContainer.getItem();
246
247 assertSame(Item.class, mock.getClass());
248 }
249
250
251
252
253 static class Factory1 {
254
255
256
257
258
259 static GenericContainer<Item> getContainer() {
260 return null;
261 }
262 }
263
264
265
266
267
268
269
270
271 @Test
272 void createSecondLevelCascadedMockFromTypeParameterInGenericMethodResolvedFromFirstLevelReturnType(
273 @Mocked Factory1 mockFactory) {
274 GenericContainer<Item> mockContainer = Factory1.getContainer();
275 Serializable cascadedMock = mockContainer.getItem();
276
277 assertNotNull(cascadedMock);
278 assertSame(Item.class, cascadedMock.getClass());
279 }
280
281
282
283
284 static class ConcreteContainer extends GenericContainer<Item> {
285 }
286
287
288
289
290 static class Factory2 {
291
292
293
294
295
296 ConcreteContainer getContainer() {
297 return null;
298 }
299 }
300
301
302
303
304
305
306
307 @Test
308 void createSecondLevelCascadedMockFromTypeParameterInBaseTypeOfMethodReturn(@Mocked Factory2 mockFactory) {
309 ConcreteContainer mockContainer = mockFactory.getContainer();
310 Serializable cascadedMock = mockContainer.getItem();
311
312 assertSame(Item.class, cascadedMock.getClass());
313 }
314
315
316
317
318 static class Collaborator {
319
320
321
322
323
324 Runnable doSomething() {
325 return null;
326 }
327 }
328
329
330
331
332 static class Collaborator2 {
333 }
334
335
336
337
338
339
340
341
342
343 @Test
344 void cascadingClassWithNameStartingWithAnotherMockedClass(@Mocked final Collaborator regularMock,
345 @Mocked Collaborator2 cascadingMock) {
346 new Expectations() {
347 {
348 regularMock.doSomething();
349 }
350 };
351
352 assertNotNull(regularMock.doSomething());
353 }
354
355
356
357
358
359
360
361 public interface InterfaceWithBoundedTypeParameter<T extends Runnable> {
362
363
364
365
366
367 T getFoo();
368 }
369
370
371
372
373
374
375
376 @Test
377 void createCascadedMockFromGenericInterfaceMethodWhichReturnsBoundedTypeParameter(
378 @Mocked InterfaceWithBoundedTypeParameter<?> mock) {
379 Runnable foo = mock.getFoo();
380 assertNotNull(foo);
381 foo.run();
382 }
383
384
385
386
387
388
389
390 public interface InterfaceWhichExtendsInterfaceWithBoundedTypeParameter<T extends Runnable>
391 extends InterfaceWithBoundedTypeParameter<T> {
392 }
393
394
395
396
397
398
399
400 @Test
401 void createCascadedMockFromGenericMethodDefinedInSuperInterfaceWithBoundedTypeParameter(
402 @Mocked InterfaceWhichExtendsInterfaceWithBoundedTypeParameter<?> mock) {
403 Runnable foo = mock.getFoo();
404 assertNotNull(foo);
405 foo.run();
406 }
407
408
409
410
411 static class Abc {
412 }
413
414
415
416
417
418
419
420 static class GenericBase<T> {
421
422
423
424
425
426 T doSomething() {
427 return null;
428 }
429 }
430
431
432
433
434
435
436
437 static class GenericSubclass<T> extends GenericBase<T> {
438
439
440
441
442
443 T getAbc() {
444 return null;
445 }
446 }
447
448
449
450
451
452
453
454 @Test
455 void createCascadedMockFromGenericSubclassHavingSameTypeParameterNameAsBaseClass(
456 @Mocked GenericSubclass<Abc> mock) {
457 Abc abc = mock.getAbc();
458 assertNotNull(abc);
459 }
460
461
462
463
464
465
466
467 @Test
468 void mockGenericClassHavingTypeArgumentOfArrayType(@Mocked GenericBase<String[]> mock) {
469 String[] result = mock.doSomething();
470
471 assertEquals(0, result.length);
472 }
473
474
475
476
477
478
479
480 @Test
481 void mockGenericClassHavingTypeArgumentOfArrayTypeWithPrimitiveComponent(@Mocked GenericBase<int[]> mock) {
482 int[] result = mock.doSomething();
483
484 assertEquals(0, result.length);
485 }
486
487
488
489
490
491
492
493 @Test
494 void mockGenericClassHavingTypeArgumentOfArrayTypeWith2DPrimitiveComponent(@Mocked GenericBase<int[][]> mock) {
495 int[][] result = mock.doSomething();
496
497 assertEquals(0, result.length);
498 }
499
500
501
502
503
504
505
506 @Test
507 void mockGenericClassHavingTypeArgumentOfArrayTypeWithGenericComponent(@Mocked GenericBase<List<?>[]> mock) {
508 List<?>[] result = mock.doSomething();
509
510 assertEquals(0, result.length);
511 }
512
513
514
515
516 static final class DerivedClass extends GenericBase<Number[]> {
517 }
518
519
520
521
522
523
524
525 @Test
526 void mockClassExtendingAGenericBaseClassHavingTypeArgumentOfArrayType(@Mocked DerivedClass mock) {
527 Number[] result = mock.doSomething();
528
529 assertEquals(0, result.length);
530 }
531
532
533
534
535
536
537
538 public interface BaseGenericInterface<V> {
539
540
541
542
543
544 V doSomething();
545 }
546
547
548
549
550
551
552
553 public interface DerivedGenericInterface<V> extends BaseGenericInterface<List<V>> {
554
555
556
557
558
559 V doSomethingElse();
560 }
561
562
563
564
565
566
567
568
569 @Test
570 void recordGenericInterfaceMethodWithReturnTypeGivenByTypeParameterDependentOnAnotherTypeParameterOfSameName(
571 @Mocked final DerivedGenericInterface<String> dep) {
572 final List<String> values = asList("a", "b");
573
574 new Expectations() {
575 {
576 dep.doSomething();
577 result = values;
578 dep.doSomethingElse();
579 result = "Abc";
580 }
581 };
582
583 List<String> resultFromBase = dep.doSomething();
584 String resultFromSub = dep.doSomethingElse();
585
586 assertSame(values, resultFromBase);
587 assertEquals("Abc", resultFromSub);
588 }
589
590
591
592
593
594
595
596 @Test
597 void mockGenericTypeWithGenericMultiDimensionalArrayTypeArgument(@Mocked GenericBase<List<?>[][]> mock) {
598 List<?>[][] result = mock.doSomething();
599
600 assertEquals(0, result.length);
601 }
602
603
604
605
606
607
608
609 public interface BaseInterface<T> {
610
611
612
613
614
615
616 void doSomething(T t);
617 }
618
619
620
621
622 public interface SubInterface extends BaseInterface<String> {
623
624
625
626
627
628
629
630 @SuppressWarnings("AbstractMethodOverridesAbstractMethod")
631 @Override
632 void doSomething(String s);
633 }
634
635
636
637
638
639
640
641 @Test
642 void invokeGenericBaseInterfaceMethodThatIsOverriddenInMockedSubInterface(@Mocked final SubInterface mock) {
643 @SuppressWarnings("UnnecessaryLocalVariable")
644 BaseInterface<String> base = mock;
645 base.doSomething("test");
646
647 new Verifications() {
648 {
649 mock.doSomething("test");
650 }
651 };
652 }
653
654
655
656
657
658
659
660 public static class Outer<T> {
661
662
663
664
665 public abstract class Inner {
666
667
668
669
670
671 public abstract T getSomeValue();
672 }
673
674
675
676
677 public abstract class SubInner extends Inner {
678 }
679 }
680
681
682
683
684
685
686
687 @Test
688 void mockInnerClassWhichUsesTypeVariableOfOuterClass(@Mocked Outer<String>.Inner mock) {
689 String in = mock.getSomeValue();
690 assertNull(in);
691 }
692
693
694
695
696
697
698
699 @Test
700 void mockAbstractSubClassOfInnerClassWhichUsesTypeVariableOfOuterClass(@Mocked Outer<String>.SubInner mock) {
701 String in = mock.getSomeValue();
702 assertNull(in);
703 }
704
705
706
707
708 static class T1 {
709 }
710
711
712
713
714 static class T2 {
715 }
716
717
718
719
720
721
722
723
724
725 @Test
726 void cascadeFromGenericMethodOfSecondMockedGenericTypeHavingDifferentParameterTypeFromFirstMockedType(
727 @Mocked GenericBase<T1> mock1, @Mocked GenericBase<T2> mock3) {
728 T2 r = mock3.doSomething();
729 assertNotNull(r);
730 }
731
732
733
734
735 static class AClass {
736
737
738
739
740
741
742
743
744
745 <R> R genericMethod() {
746 return null;
747 }
748
749
750
751
752
753
754
755
756
757
758
759 <R> R genericMethodWithParameter(R value) {
760 return value;
761 }
762
763
764
765
766
767
768
769
770
771
772
773
774
775 <R, S> R genericMethodWithTwoTypeParameters(@SuppressWarnings("unused") S s) {
776 return null;
777 }
778 }
779
780
781
782
783
784
785
786 @Test
787 void returnNullFromGenericMethod(@Mocked AClass mock) {
788 String test1 = mock.genericMethod();
789 String test2 = mock.genericMethodWithParameter("test2");
790 String test3 = mock.genericMethodWithTwoTypeParameters(1);
791
792 assertNull(test1);
793 assertNull(test2);
794 assertNull(test3);
795 }
796 }