View Javadoc
1   package mockit;
2   
3   import static org.junit.jupiter.api.Assertions.assertEquals;
4   import static org.junit.jupiter.api.Assertions.assertTrue;
5   import static org.junit.jupiter.api.Assertions.fail;
6   
7   import java.util.Collection;
8   import java.util.Collections;
9   import java.util.List;
10  
11  import org.junit.jupiter.api.Test;
12  
13  /**
14   * The Class FakeForGenericsTest.
15   */
16  final class FakeForGenericsTest {
17  
18      /**
19       * The Class Collaborator.
20       */
21      public static final class Collaborator {
22  
23          /**
24           * Generic method.
25           *
26           * @param <N>
27           *            the number type
28           * @param n
29           *            the n
30           *
31           * @return the n
32           */
33          public <N extends Number> N genericMethod(@SuppressWarnings("UnusedParameters") N n) {
34              return null;
35          }
36      }
37  
38      /**
39       * Fake generic method.
40       */
41      @Test
42      void fakeGenericMethod() {
43          new MockUp<Collaborator>() {
44              @Mock
45              <T extends Number> T genericMethod(T t) {
46                  return t;
47              }
48  
49              // This also works (same erasure):
50              // @Mock Number genericMethod(Number t) { return t; }
51          };
52  
53          Integer n = new Collaborator().genericMethod(123);
54          assertEquals(123, n.intValue());
55  
56          Long l = new Collaborator().genericMethod(45L);
57          assertEquals(45L, l.longValue());
58  
59          Short s = new Collaborator().genericMethod((short) 6);
60          assertEquals(6, s.shortValue());
61  
62          Double d = new Collaborator().genericMethod(0.5);
63          assertEquals(0.5, d, 0);
64      }
65  
66      /**
67       * The Class GenericClass.
68       *
69       * @param <T1>
70       *            the generic type
71       * @param <T2>
72       *            the generic type
73       */
74      @SuppressWarnings("UnusedParameters")
75      public static final class GenericClass<T1, T2> {
76  
77          /**
78           * A method.
79           *
80           * @param t
81           *            the t
82           */
83          public void aMethod(T1 t) {
84              throw new RuntimeException("t=" + t);
85          }
86  
87          /**
88           * Another method.
89           *
90           * @param t
91           *            the t
92           * @param i
93           *            the i
94           * @param p
95           *            the p
96           *
97           * @return the int
98           */
99          public int anotherMethod(T1 t, int i, T2 p) {
100             return 2 * i;
101         }
102 
103         /**
104          * Another method.
105          *
106          * @param t
107          *            the t
108          * @param i
109          *            the i
110          * @param p
111          *            the p
112          *
113          * @return the int
114          */
115         public int anotherMethod(Integer t, int i, String p) {
116             return -2 * i;
117         }
118     }
119 
120     /**
121      * Fake generic class with unspecified type arguments.
122      */
123     @Test
124     void fakeGenericClassWithUnspecifiedTypeArguments() {
125         new MockUp<GenericClass<?, ?>>() {
126             @Mock
127             void aMethod(Object o) {
128                 StringBuilder s = (StringBuilder) o;
129                 s.setLength(0);
130                 s.append("fake");
131                 s.toString();
132             }
133 
134             @Mock
135             int anotherMethod(Object o, int i, Object list) {
136                 assertTrue(o instanceof StringBuilder);
137                 // noinspection unchecked
138                 assertEquals(0, ((Collection<String>) list).size());
139                 return -i;
140             }
141         };
142 
143         StringBuilder s = new StringBuilder("test");
144         GenericClass<StringBuilder, List<String>> g = new GenericClass<>();
145 
146         g.aMethod(s);
147         int r1 = g.anotherMethod(new StringBuilder("test"), 58, Collections.<String> emptyList());
148         int r2 = g.anotherMethod(123, 65, "abc");
149 
150         assertEquals("fake", s.toString());
151         assertEquals(-58, r1);
152         assertEquals(-130, r2);
153     }
154 
155     /**
156      * Fake both generic and non generic methods in generic class.
157      */
158     @Test
159     void fakeBothGenericAndNonGenericMethodsInGenericClass() {
160         new MockUp<GenericClass<String, Boolean>>() {
161             @Mock
162             int anotherMethod(Integer t, int i, String p) {
163                 return 2;
164             }
165 
166             @Mock
167             int anotherMethod(String t, int i, Boolean p) {
168                 return 1;
169             }
170         };
171 
172         GenericClass<String, Boolean> o = new GenericClass<>();
173         assertEquals(1, o.anotherMethod("generic", 1, true));
174         assertEquals(2, o.anotherMethod(123, 2, "non generic"));
175     }
176 
177     /**
178      * The Class GenericBaseClass.
179      *
180      * @param <T>
181      *            the generic type
182      * @param <U>
183      *            the generic type
184      */
185     static class GenericBaseClass<T, U> {
186         /**
187          * Find.
188          *
189          * @param id
190          *            the id
191          *
192          * @return the u
193          */
194         public U find(@SuppressWarnings("UnusedParameters") T id) {
195             return null;
196         }
197     }
198 
199     /**
200      * Fake generic method with fake method having parameter types matching type arguments.
201      */
202     @Test
203     void fakeGenericMethodWithFakeMethodHavingParameterTypesMatchingTypeArguments() {
204         new MockUp<GenericBaseClass<String, Integer>>() {
205             @Mock
206             Integer find(String id) {
207                 return id.hashCode();
208             }
209         };
210 
211         int i = new GenericBaseClass<String, Integer>().find("test");
212         assertEquals("test".hashCode(), i);
213     }
214 
215     /**
216      * Cannot call generic method when some fake method expects different types.
217      */
218     @Test
219     void cannotCallGenericMethodWhenSomeFakeMethodExpectsDifferentTypes() {
220         new MockUp<GenericBaseClass<String, Integer>>() {
221             @Mock
222             Integer find(String id) {
223                 return 1;
224             }
225         };
226 
227         try {
228             new GenericBaseClass<Integer, String>().find(1);
229             fail();
230         } catch (IllegalArgumentException e) {
231             assertTrue(e.getMessage().startsWith("Failure to invoke method: "));
232         }
233     }
234 
235     /**
236      * The Class NonGenericSuperclass.
237      */
238     static class NonGenericSuperclass extends GenericBaseClass<Integer, String> {
239     }
240 
241     /**
242      * The Class NonGenericSubclass.
243      */
244     static final class NonGenericSubclass extends NonGenericSuperclass {
245     }
246 
247     /**
248      * Fake generic method from instantiation of non generic subclass.
249      */
250     @Test
251     void fakeGenericMethodFromInstantiationOfNonGenericSubclass() {
252         new MockUp<NonGenericSubclass>() {
253             @Mock
254             String find(Integer id) {
255                 return "faked" + id;
256             }
257         };
258 
259         String s = new NonGenericSubclass().find(1);
260         assertEquals("faked1", s);
261     }
262 
263     /**
264      * The Class GenericSuperclass.
265      *
266      * @param <I>
267      *            the generic type
268      */
269     static class GenericSuperclass<I> extends GenericBaseClass<I, String> {
270     }
271 
272     /**
273      * The Class AnotherNonGenericSubclass.
274      */
275     static final class AnotherNonGenericSubclass extends GenericSuperclass<Integer> {
276     }
277 
278     /**
279      * Fake generic method from instantiation of non generic subclass which extends A generic intermediate superclass.
280      */
281     @Test
282     void fakeGenericMethodFromInstantiationOfNonGenericSubclassWhichExtendsAGenericIntermediateSuperclass() {
283         new MockUp<AnotherNonGenericSubclass>() {
284             @Mock
285             String find(Integer id) {
286                 return "faked" + id;
287             }
288         };
289 
290         String s = new AnotherNonGenericSubclass().find(1);
291         assertEquals("faked1", s);
292     }
293 
294     /**
295      * The Class NonGenericClassWithGenericMethods.
296      */
297     @SuppressWarnings("UnusedParameters")
298     public static class NonGenericClassWithGenericMethods {
299 
300         /**
301          * Static method.
302          *
303          * @param <T>
304          *            the generic type
305          * @param cls
306          *            the cls
307          * @param s
308          *            the s
309          *
310          * @return the t
311          */
312         public static <T> T staticMethod(Class<T> cls, String s) {
313             throw new RuntimeException();
314         }
315 
316         /**
317          * Instance method.
318          *
319          * @param <C>
320          *            the generic type
321          * @param cls
322          *            the cls
323          * @param s
324          *            the s
325          */
326         public <C> void instanceMethod(Class<C> cls, String s) {
327             throw new RuntimeException();
328         }
329 
330         /**
331          * Instance method.
332          *
333          * @param <N>
334          *            the number type
335          * @param cls
336          *            the cls
337          */
338         public final <N extends Number> void instanceMethod(Class<N> cls) {
339             throw new RuntimeException();
340         }
341     }
342 
343     /**
344      * Fake generic methods of non generic class.
345      */
346     @Test
347     void fakeGenericMethodsOfNonGenericClass() {
348         new MockUp<NonGenericClassWithGenericMethods>() {
349             @Mock
350             <T> T staticMethod(Class<T> cls, String s) {
351                 return null;
352             }
353 
354             @Mock
355             <C> void instanceMethod(Class<C> cls, String s) {
356             }
357 
358             @Mock
359             void instanceMethod(Class<?> cls) {
360             }
361         };
362 
363         new NonGenericClassWithGenericMethods().instanceMethod(Integer.class);
364         NonGenericClassWithGenericMethods.staticMethod(Collaborator.class, "test1");
365         new NonGenericClassWithGenericMethods().instanceMethod(Byte.class, "test2");
366     }
367 }