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 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   * The Class GenericMockedTypesTest.
29   */
30  @ExtendWith(JMockitExtension.class)
31  class GenericMockedTypesTest {
32  
33      /** The mock 2. */
34      @Mocked
35      Callable<Integer> mock2;
36  
37      /**
38       * Mock generic interfaces.
39       *
40       * @param mock1
41       *            the mock 1
42       *
43       * @throws Exception
44       *             the exception
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       * Obtain generic superclass from class generated for non generic interface.
63       *
64       * @param mock
65       *            the mock
66       */
67      @Test
68      void obtainGenericSuperclassFromClassGeneratedForNonGenericInterface(@Mocked Runnable mock) {
69          Class<?> generatedClass = mock.getClass();
70          Type genericSuperClass = generatedClass.getGenericSuperclass();
71  
72          // At one time, a "GenericSignatureFormatError: Signature Parse error: expected a class type
73          // Remaining input: nullLjava/lang/Runnable;" would occur.
74          assertSame(Object.class, genericSuperClass);
75      }
76  
77      /**
78       * Mock generic abstract class.
79       *
80       * @param mock
81       *            the mock
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      * The Interface InterfaceWithMethodParametersMixingGenericTypesAndArrays.
110      */
111     public interface InterfaceWithMethodParametersMixingGenericTypesAndArrays {
112 
113         /**
114          * Do something.
115          *
116          * @param <T>
117          *            the generic type
118          * @param i
119          *            the i
120          * @param b
121          *            the b
122          */
123         <T> void doSomething(int[] i, T b);
124 
125         /**
126          * Do something.
127          *
128          * @param pc
129          *            the pc
130          * @param ii
131          *            the ii
132          */
133         void doSomething(Callable<int[]> pc, int[] ii);
134 
135         /**
136          * Do something.
137          *
138          * @param pc
139          *            the pc
140          * @param i
141          *            the i
142          * @param currencies
143          *            the currencies
144          * @param ii
145          *            the ii
146          */
147         void doSomething(Callable<String> pc, int[] i, boolean[] currencies, int[] ii);
148     }
149 
150     /**
151      * Mock methods having generics and arrays.
152      *
153      * @param mock
154      *            the mock
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      * The Interface NonGenericInterfaceWithGenericMethods.
164      */
165     public interface NonGenericInterfaceWithGenericMethods {
166 
167         /**
168          * Generic method with unbounded return type.
169          *
170          * @param <T>
171          *            the generic type
172          *
173          * @return the t
174          */
175         <T> T genericMethodWithUnboundedReturnType();
176 
177         /**
178          * Generic method with bounded return type.
179          *
180          * @param <T>
181          *            the generic type
182          *
183          * @return the t
184          */
185         <T extends CharSequence> T genericMethodWithBoundedReturnType();
186     }
187 
188     /**
189      * Result from generic methods of non generic interface.
190      *
191      * @param mock
192      *            the mock
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      * The Class Item.
214      */
215     static class Item implements Serializable {
216 
217         private static final long serialVersionUID = 1L;
218     }
219 
220     /**
221      * The Class GenericContainer.
222      *
223      * @param <T>
224      *            the generic type
225      */
226     static class GenericContainer<T extends Serializable> {
227         /**
228          * Gets the item.
229          *
230          * @return the item
231          */
232         final T getItem() {
233             return null;
234         }
235     }
236 
237     /**
238      * Creates the first level cascaded mock from type parameter.
239      *
240      * @param mockContainer
241      *            the mock container
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      * The Class Factory1.
252      */
253     static class Factory1 {
254         /**
255          * Gets the container.
256          *
257          * @return the container
258          */
259         static GenericContainer<Item> getContainer() {
260             return null;
261         }
262     }
263 
264     /**
265      * Creates the second level cascaded mock from type parameter in generic method resolved from first level return
266      * type.
267      *
268      * @param mockFactory
269      *            the mock factory
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      * The Class ConcreteContainer.
283      */
284     static class ConcreteContainer extends GenericContainer<Item> {
285     }
286 
287     /**
288      * The Class Factory2.
289      */
290     static class Factory2 {
291         /**
292          * Gets the container.
293          *
294          * @return the container
295          */
296         ConcreteContainer getContainer() {
297             return null;
298         }
299     }
300 
301     /**
302      * Creates the second level cascaded mock from type parameter in base type of method return.
303      *
304      * @param mockFactory
305      *            the mock factory
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      * The Class Collaborator.
317      */
318     static class Collaborator {
319         /**
320          * Do something.
321          *
322          * @return the runnable
323          */
324         Runnable doSomething() {
325             return null;
326         }
327     }
328 
329     /**
330      * The Class Collaborator2.
331      */
332     static class Collaborator2 {
333     }
334 
335     /**
336      * Cascading class with name starting with another mocked class.
337      *
338      * @param regularMock
339      *            the regular mock
340      * @param cascadingMock
341      *            the cascading mock
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      * The Interface InterfaceWithBoundedTypeParameter.
357      *
358      * @param <T>
359      *            the generic type
360      */
361     public interface InterfaceWithBoundedTypeParameter<T extends Runnable> {
362         /**
363          * Gets the foo.
364          *
365          * @return the foo
366          */
367         T getFoo();
368     }
369 
370     /**
371      * Creates the cascaded mock from generic interface method which returns bounded type parameter.
372      *
373      * @param mock
374      *            the mock
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      * The Interface InterfaceWhichExtendsInterfaceWithBoundedTypeParameter.
386      *
387      * @param <T>
388      *            the generic type
389      */
390     public interface InterfaceWhichExtendsInterfaceWithBoundedTypeParameter<T extends Runnable>
391             extends InterfaceWithBoundedTypeParameter<T> {
392     }
393 
394     /**
395      * Creates the cascaded mock from generic method defined in super interface with bounded type parameter.
396      *
397      * @param mock
398      *            the mock
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      * The Class Abc.
410      */
411     static class Abc {
412     }
413 
414     /**
415      * The Class GenericBase.
416      *
417      * @param <T>
418      *            the generic type
419      */
420     static class GenericBase<T> {
421         /**
422          * Do something.
423          *
424          * @return the t
425          */
426         T doSomething() {
427             return null;
428         }
429     }
430 
431     /**
432      * The Class GenericSubclass.
433      *
434      * @param <T>
435      *            the generic type
436      */
437     static class GenericSubclass<T> extends GenericBase<T> {
438         /**
439          * Gets the abc.
440          *
441          * @return the abc
442          */
443         T getAbc() {
444             return null;
445         }
446     }
447 
448     /**
449      * Creates the cascaded mock from generic subclass having same type parameter name as base class.
450      *
451      * @param mock
452      *            the mock
453      */
454     @Test
455     void createCascadedMockFromGenericSubclassHavingSameTypeParameterNameAsBaseClass(
456             @Mocked GenericSubclass<Abc> mock) {
457         Abc abc = mock.getAbc();
458         assertNotNull(abc);
459     }
460 
461     /**
462      * Mock generic class having type argument of array type.
463      *
464      * @param mock
465      *            the mock
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      * Mock generic class having type argument of array type with primitive component.
476      *
477      * @param mock
478      *            the mock
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      * Mock generic class having type argument of array type with 2 D primitive component.
489      *
490      * @param mock
491      *            the mock
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      * Mock generic class having type argument of array type with generic component.
502      *
503      * @param mock
504      *            the mock
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      * The Class DerivedClass.
515      */
516     static final class DerivedClass extends GenericBase<Number[]> {
517     }
518 
519     /**
520      * Mock class extending A generic base class having type argument of array type.
521      *
522      * @param mock
523      *            the mock
524      */
525     @Test
526     void mockClassExtendingAGenericBaseClassHavingTypeArgumentOfArrayType(@Mocked DerivedClass mock) {
527         Number[] result = mock.doSomething();
528 
529         assertEquals(0, result.length);
530     }
531 
532     /**
533      * The Interface BaseGenericInterface.
534      *
535      * @param <V>
536      *            the value type
537      */
538     public interface BaseGenericInterface<V> {
539         /**
540          * Do something.
541          *
542          * @return the v
543          */
544         V doSomething();
545     }
546 
547     /**
548      * The Interface DerivedGenericInterface.
549      *
550      * @param <V>
551      *            the value type
552      */
553     public interface DerivedGenericInterface<V> extends BaseGenericInterface<List<V>> {
554         /**
555          * Do something else.
556          *
557          * @return the v
558          */
559         V doSomethingElse();
560     }
561 
562     /**
563      * Record generic interface method with return type given by type parameter dependent on another type parameter of
564      * same name.
565      *
566      * @param dep
567      *            the dep
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      * Mock generic type with generic multi dimensional array type argument.
592      *
593      * @param mock
594      *            the mock
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      * The Interface BaseInterface.
605      *
606      * @param <T>
607      *            the generic type
608      */
609     public interface BaseInterface<T> {
610         /**
611          * Do something.
612          *
613          * @param t
614          *            the t
615          */
616         void doSomething(T t);
617     }
618 
619     /**
620      * The Interface SubInterface.
621      */
622     public interface SubInterface extends BaseInterface<String> {
623 
624         /**
625          * Do something.
626          *
627          * @param s
628          *            the s
629          */
630         @SuppressWarnings("AbstractMethodOverridesAbstractMethod")
631         @Override
632         void doSomething(String s);
633     }
634 
635     /**
636      * Invoke generic base interface method that is overridden in mocked sub interface.
637      *
638      * @param mock
639      *            the mock
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      * The Class Outer.
656      *
657      * @param <T>
658      *            the generic type
659      */
660     public static class Outer<T> {
661 
662         /**
663          * The Class Inner.
664          */
665         public abstract class Inner {
666             /**
667              * Gets the some value.
668              *
669              * @return the some value
670              */
671             public abstract T getSomeValue();
672         }
673 
674         /**
675          * The Class SubInner.
676          */
677         public abstract class SubInner extends Inner {
678         }
679     }
680 
681     /**
682      * Mock inner class which uses type variable of outer class.
683      *
684      * @param mock
685      *            the mock
686      */
687     @Test
688     void mockInnerClassWhichUsesTypeVariableOfOuterClass(@Mocked Outer<String>.Inner mock) {
689         String in = mock.getSomeValue();
690         assertNull(in);
691     }
692 
693     /**
694      * Mock abstract sub class of inner class which uses type variable of outer class.
695      *
696      * @param mock
697      *            the mock
698      */
699     @Test
700     void mockAbstractSubClassOfInnerClassWhichUsesTypeVariableOfOuterClass(@Mocked Outer<String>.SubInner mock) {
701         String in = mock.getSomeValue();
702         assertNull(in);
703     }
704 
705     /**
706      * The Class T1.
707      */
708     static class T1 {
709     }
710 
711     /**
712      * The Class T2.
713      */
714     static class T2 {
715     }
716 
717     /**
718      * Cascade from generic method of second mocked generic type having different parameter type from first mocked type.
719      *
720      * @param mock1
721      *            the mock 1
722      * @param mock3
723      *            the mock 3
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      * The Class AClass.
734      */
735     static class AClass {
736 
737         /**
738          * Generic method.
739          *
740          * @param <R>
741          *            the generic type
742          *
743          * @return the r
744          */
745         <R> R genericMethod() {
746             return null;
747         }
748 
749         /**
750          * Generic method with parameter.
751          *
752          * @param <R>
753          *            the generic type
754          * @param value
755          *            the value
756          *
757          * @return the r
758          */
759         <R> R genericMethodWithParameter(R value) {
760             return value;
761         }
762 
763         /**
764          * Generic method with two type parameters.
765          *
766          * @param <R>
767          *            the generic type
768          * @param <S>
769          *            the generic type
770          * @param s
771          *            the s
772          *
773          * @return the r
774          */
775         <R, S> R genericMethodWithTwoTypeParameters(@SuppressWarnings("unused") S s) {
776             return null;
777         }
778     }
779 
780     /**
781      * Return null from generic method.
782      *
783      * @param mock
784      *            the mock
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 }