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 org.junit.jupiter.api.Assertions.assertNotNull;
9   import static org.junit.jupiter.api.Assertions.assertNull;
10  import static org.junit.jupiter.api.Assertions.assertSame;
11  
12  import java.io.Serializable;
13  import java.util.HashMap;
14  import java.util.List;
15  import java.util.Map;
16  import java.util.concurrent.Callable;
17  
18  import mockit.integration.junit5.JMockitExtension;
19  
20  import org.junit.jupiter.api.Test;
21  import org.junit.jupiter.api.extension.ExtendWith;
22  
23  /**
24   * The Class TestedClassWithGenericsTest.
25   */
26  @ExtendWith(JMockitExtension.class)
27  class TestedClassWithGenericsTest {
28  
29      /**
30       * The Interface Collaborator.
31       *
32       * @param <T>
33       *            the generic type
34       */
35      public interface Collaborator<T> {
36          /**
37           * Gets the value.
38           *
39           * @return the value
40           */
41          T getValue();
42      }
43  
44      /**
45       * The Class SUTWithUnboundedTypeParameter.
46       *
47       * @param <T>
48       *            the generic type
49       */
50      static class SUTWithUnboundedTypeParameter<T> {
51  
52          /** The value. */
53          T value;
54  
55          /** The collaborator. */
56          final Collaborator<T> collaborator;
57  
58          /** The collaborators. */
59          final Iterable<Collaborator<T>> collaborators;
60  
61          Map<T, ?> values;
62  
63          /** The action 1. */
64          Callable<T> action1;
65  
66          /** The action 2. */
67          Callable<?> action2;
68  
69          /**
70           * Instantiates a new SUT with unbounded type parameter.
71           *
72           * @param c
73           *            the c
74           */
75          @SuppressWarnings("unused")
76          SUTWithUnboundedTypeParameter(Collaborator<T> c) {
77              collaborator = c;
78              collaborators = null;
79          }
80  
81          /**
82           * Instantiates a new SUT with unbounded type parameter.
83           *
84           * @param collaborators
85           *            the collaborators
86           * @param action
87           *            the action
88           */
89          @SuppressWarnings("unused")
90          SUTWithUnboundedTypeParameter(Iterable<Collaborator<T>> collaborators, Callable<String> action) {
91              collaborator = null;
92              this.collaborators = collaborators;
93              action2 = action;
94          }
95  
96          <V extends CharSequence & Serializable> SUTWithUnboundedTypeParameter(Map<T, V> values, Callable<?> action) {
97              collaborator = null;
98              collaborators = null;
99              this.values = values;
100             action2 = action;
101         }
102     }
103 
104     /** The tested 1. */
105     @Tested
106     SUTWithUnboundedTypeParameter<Integer> tested1;
107 
108     /** The number to inject. */
109     @Injectable
110     final Integer numberToInject = 123;
111 
112     /** The mock collaborator. */
113     @Injectable
114     Collaborator<Integer> mockCollaborator;
115 
116     /**
117      * Use SUT created with constructor of single generic parameter and with generic field injected from concrete
118      * injectables.
119      */
120     @Test
121     void useSUTCreatedWithConstructorOfSingleGenericParameterAndWithGenericFieldInjectedFromConcreteInjectables() {
122         assertSame(mockCollaborator, tested1.collaborator);
123         assertNull(tested1.collaborators);
124         assertSame(numberToInject, tested1.value);
125         assertNull(tested1.action1);
126         assertNull(tested1.action2);
127         assertNull(tested1.values);
128     }
129 
130     /**
131      * Use SUT instantiated with constructor having multiple generic parameters.
132      *
133      * @param collaborators
134      *            the collaborators
135      * @param mockAction1
136      *            the mock action 1
137      * @param action1
138      *            the action 1
139      */
140     @Test
141     void useSUTInstantiatedWithConstructorHavingMultipleGenericParameters(
142             @Injectable Iterable<Collaborator<Integer>> collaborators, @Injectable Callable<String> mockAction1,
143             @Injectable Callable<Integer> action1) {
144         assertNull(tested1.collaborator);
145         assertSame(collaborators, tested1.collaborators);
146         assertSame(mockAction1, tested1.action2);
147         assertSame(action1, tested1.action1);
148         assertSame(numberToInject, tested1.value);
149         assertNull(tested1.values);
150     }
151 
152     /**
153      * Use SUT instantiated with generic constructor parameters injected from concrete injectables.
154      *
155      * @param mockCollaborators
156      *            the mock collaborators
157      * @param mockAction
158      *            the mock action
159      */
160     @Test
161     void useSUTInstantiatedWithGenericConstructorParametersInjectedFromConcreteInjectables(
162             @Injectable Iterable<Collaborator<Integer>> mockCollaborators, @Injectable Callable<String> mockAction) {
163         assertNull(tested1.collaborator);
164         assertSame(mockCollaborators, tested1.collaborators);
165         assertNull(tested1.action1);
166         assertSame(mockAction, tested1.action2);
167         assertSame(numberToInject, tested1.value);
168         assertNull(tested1.values);
169     }
170 
171     /**
172      * The Class SUTWithGenericConstructor.
173      *
174      * @param <T>
175      *            the generic type
176      */
177     static class SUTWithGenericConstructor<T> {
178 
179         /** The values. */
180         final Map<T, ?> values;
181 
182         /**
183          * Instantiates a new SUT with generic constructor.
184          *
185          * @param <V>
186          *            the value type
187          * @param values
188          *            the values
189          */
190         @SuppressWarnings("unused")
191         <V extends CharSequence & Serializable> SUTWithGenericConstructor(Map<T, V> values) {
192             this.values = values;
193         }
194     }
195 
196     /** The map values. */
197     @Tested
198     final Map<Integer, String> mapValues = new HashMap<>();
199 
200     /** The tested 8. */
201     @Tested
202     SUTWithGenericConstructor<Integer> tested8;
203 
204     /**
205      * Use SUT instantiated with generic constructor.
206      */
207     @Test
208     void useSUTInstantiatedWithGenericConstructor() {
209         assertSame(mapValues, tested8.values);
210     }
211 
212     @Test
213     public void useSUTInstantiatedWithGenericConstructor(@Injectable Callable<?> mockAction,
214             @Injectable Map<Integer, String> mockValues) {
215         assertNull(tested1.collaborator);
216         assertNull(tested1.collaborators);
217         assertSame(mockValues, tested1.values);
218         assertNull(tested1.action1);
219         assertSame(mockAction, tested1.action2);
220         assertSame(numberToInject, tested1.value);
221     }
222 
223     /**
224      * The Class GenericClass.
225      *
226      * @param <T>
227      *            the generic type
228      */
229     static class GenericClass<T> {
230         /** The value. */
231         T value;
232     }
233 
234     /**
235      * The Class SUTWithBoundedTypeParameter.
236      *
237      * @param <N>
238      *            the number type
239      * @param <C>
240      *            the generic type
241      */
242     static class SUTWithBoundedTypeParameter<N extends Number, C extends CharSequence> {
243 
244         /** The text value. */
245         C textValue;
246 
247         /** The number value. */
248         N numberValue;
249 
250         /** The collaborator. */
251         GenericClass<N> collaborator;
252 
253         /** The action. */
254         Callable<C> action;
255     }
256 
257     /** The tested 2. */
258     @Tested
259     SUTWithBoundedTypeParameter<Integer, String> tested2;
260 
261     /** The tested 3. */
262     @Tested
263     SUTWithBoundedTypeParameter<Number, CharSequence> tested3;
264 
265     /** The tested 4. */
266     @Tested
267     SUTWithBoundedTypeParameter<?, ?> tested4;
268 
269     /** The tested 5. */
270     @Tested
271     SUTWithBoundedTypeParameter<Long, StringBuilder> tested5;
272 
273     /**
274      * Use SUT declared with type bound.
275      *
276      * @param name
277      *            the name
278      * @param textAction
279      *            the text action
280      * @param collaborator
281      *            the collaborator
282      */
283     @Test
284     void useSUTDeclaredWithTypeBound(@Injectable("test") String name, @Injectable Callable<String> textAction,
285             @Injectable GenericClass<? extends Number> collaborator) {
286         assertSame(numberToInject, tested2.numberValue);
287         assertSame(name, tested2.textValue);
288         assertSame(collaborator, tested2.collaborator);
289         assertSame(textAction, tested2.action);
290 
291         assertSame(numberToInject, tested3.numberValue);
292         assertSame(name, tested3.textValue);
293         assertSame(collaborator, tested3.collaborator);
294         assertSame(textAction, tested3.action);
295 
296         assertSame(numberToInject, tested4.numberValue);
297         assertSame(name, tested4.textValue);
298         assertSame(collaborator, tested4.collaborator);
299         assertSame(textAction, tested4.action);
300 
301         assertNull(tested5.numberValue);
302         assertNull(tested5.textValue);
303         assertSame(collaborator, tested5.collaborator);
304         assertNull(tested5.action);
305     }
306 
307     /**
308      * Use SUT declared with type bound having non matching injectable with wildcard.
309      *
310      * @param action
311      *            the action
312      */
313     @Test
314     void useSUTDeclaredWithTypeBoundHavingNonMatchingInjectableWithWildcard(
315             @Injectable Callable<? extends Number> action) {
316         assertNull(tested2.action);
317         assertNull(tested3.action);
318         assertNull(tested4.action);
319         assertNull(tested5.action);
320     }
321 
322     /**
323      * The Class Base.
324      *
325      * @param <B>
326      *            the generic type
327      */
328     static class Base<B> {
329         /** The dep. */
330         B dep;
331     }
332 
333     /**
334      * The Class Derived.
335      *
336      * @param <D>
337      *            the generic type
338      */
339     static class Derived<D> extends Base<D> {
340     }
341 
342     /**
343      * The Class Concrete.
344      */
345     static final class Concrete extends Derived<Dep> {
346     }
347 
348     /**
349      * The Interface Dep.
350      */
351     public interface Dep {
352     }
353 
354     /** The dep. */
355     @Injectable
356     final Dep dep = new Dep() {
357     };
358 
359     /** The sut. */
360     @Tested
361     Concrete sut;
362 
363     /**
364      * Use SUT class extending generic base class which extends another generic base class containing A generic
365      * dependency.
366      */
367     @Test
368     void useSUTClassExtendingGenericBaseClassWhichExtendsAnotherGenericBaseClassContainingAGenericDependency() {
369         assertSame(dep, sut.dep);
370     }
371 
372     /**
373      * The Class AnotherDep.
374      */
375     public static class AnotherDep {
376     }
377 
378     /**
379      * The Class Concrete2.
380      */
381     static class Concrete2 extends Base<AnotherDep> {
382     }
383 
384     /** The sut 2. */
385     @Tested(fullyInitialized = true)
386     Concrete2 sut2;
387 
388     /**
389      * Use fully initialized SUT class extending generic base class.
390      */
391     @Test
392     void useFullyInitializedSUTClassExtendingGenericBaseClass() {
393         AnotherDep anotherDep = sut2.dep;
394         assertNotNull(anotherDep);
395     }
396 
397     /**
398      * The Class Concrete3.
399      */
400     static class Concrete3 extends Derived<AnotherDep> {
401     }
402 
403     /** The sut 3. */
404     @Tested(fullyInitialized = true)
405     Concrete3 sut3;
406 
407     /**
408      * Use fully initialized SUT class extending generic class which extends another generic class.
409      */
410     @Test
411     void useFullyInitializedSUTClassExtendingGenericClassWhichExtendsAnotherGenericClass() {
412         AnotherDep anotherDep = sut3.dep;
413         assertNotNull(anotherDep);
414     }
415 
416     /**
417      * The Class TestedClassWithConstructorParameterOfGenericType.
418      */
419     static class TestedClassWithConstructorParameterOfGenericType {
420 
421         /** The a class. */
422         private final Class<?> aClass;
423 
424         /**
425          * Instantiates a new tested class with constructor parameter of generic type.
426          *
427          * @param aClass
428          *            the a class
429          */
430         TestedClassWithConstructorParameterOfGenericType(Class<?> aClass) {
431             this.aClass = aClass;
432         }
433     }
434 
435     /** The a class. */
436     @Tested
437     final Class<?> aClass = Long.class;
438 
439     /** The tested 6. */
440     @Tested(fullyInitialized = true)
441     TestedClassWithConstructorParameterOfGenericType tested6;
442 
443     /**
444      * Verify instantiation of class with constructor parameter of generic type.
445      */
446     @Test
447     void verifyInstantiationOfClassWithConstructorParameterOfGenericType() {
448         assertSame(aClass, tested6.aClass);
449     }
450 
451     /**
452      * The Class GenericClassWithDependencyUsingTypeParameter.
453      *
454      * @param <T>
455      *            the generic type
456      */
457     static class GenericClassWithDependencyUsingTypeParameter<T> {
458         /** The dependency. */
459         GenericClass<T> dependency;
460     }
461 
462     /** The dependency. */
463     @Tested
464     final GenericClass<String> dependency = new GenericClass<>();
465 
466     /** The tested 7. */
467     @Tested(fullyInitialized = true)
468     GenericClassWithDependencyUsingTypeParameter<String> tested7;
469 
470     /**
471      * Verify instantiation of generic class with dependency using type parameter.
472      */
473     @Test
474     void verifyInstantiationOfGenericClassWithDependencyUsingTypeParameter() {
475         assertSame(dependency, tested7.dependency);
476     }
477 
478     /**
479      * The Interface Interface.
480      */
481     public interface Interface {
482     }
483 
484     /**
485      * The Class Implementation.
486      */
487     static class Implementation implements Interface {
488     }
489 
490     /**
491      * The Class Derived2.
492      */
493     static class Derived2 extends Base<Interface> {
494     }
495 
496     /** The impl. */
497     @Tested
498     Implementation impl;
499 
500     /** The tested. */
501     @Tested(fullyInitialized = true)
502     Derived2 tested;
503 
504     /**
505      * Use tested object of implementation type for type variable in generic base class.
506      */
507     @Test
508     void useTestedObjectOfImplementationTypeForTypeVariableInGenericBaseClass() {
509         assertSame(impl, tested.dep);
510     }
511 
512     /**
513      * The Class ClassWithFieldOfGenericTypeContainingGenericArray.
514      */
515     static class ClassWithFieldOfGenericTypeContainingGenericArray {
516         /** The n. */
517         @SuppressWarnings("unused")
518         int n;
519         /** The list. */
520         List<Comparable<?>[]> list;
521     }
522 
523     /**
524      * Instantiate object containing generic type field with generic array element.
525      *
526      * @param t
527      *            the t
528      */
529     @Test
530     void instantiateObjectContainingGenericTypeFieldWithGenericArrayElement(
531             @Tested ClassWithFieldOfGenericTypeContainingGenericArray t) {
532         assertNotNull(t);
533     }
534 }