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