View Javadoc
1   /*
2    * Copyright (c) 2006 JMockit developers
3    * This file is subject to the terms of the MIT license (see LICENSE.txt).
4    */
5   package mockit;
6   
7   import static org.junit.jupiter.api.Assertions.assertEquals;
8   import static org.junit.jupiter.api.Assertions.assertTrue;
9   import static org.junit.jupiter.api.Assertions.fail;
10  
11  import java.util.Collection;
12  import java.util.Collections;
13  import java.util.List;
14  
15  import org.junit.jupiter.api.Test;
16  
17  public final class MockUpForGenericsTest {
18      // Mock-ups for generic classes/methods ////////////////////////////////////////////////////////////////////////////
19  
20      public static final class Collaborator {
21          public <N extends Number> N genericMethod(@SuppressWarnings("UnusedParameters") N n) {
22              return null;
23          }
24      }
25  
26      @Test
27      public void mockGenericMethod() {
28          new MockUp<Collaborator>() {
29              @Mock
30              <T extends Number> T genericMethod(T t) {
31                  return t;
32              }
33  
34              // This also works (same erasure):
35              // @Mock Number genericMethod(Number t) { return t; }
36          };
37  
38          Integer n = new Collaborator().genericMethod(123);
39          assertEquals(123, n.intValue());
40  
41          Long l = new Collaborator().genericMethod(45L);
42          assertEquals(45L, l.longValue());
43  
44          Short s = new Collaborator().genericMethod((short) 6);
45          assertEquals(6, s.shortValue());
46  
47          Double d = new Collaborator().genericMethod(0.5);
48          assertEquals(0.5, d, 0);
49      }
50  
51      @SuppressWarnings("UnusedParameters")
52      public static final class GenericClass<T1, T2> {
53          public void aMethod(T1 t) {
54              throw new RuntimeException("t=" + t);
55          }
56  
57          public int anotherMethod(T1 t, int i, T2 p) {
58              return 2 * i;
59          }
60  
61          public int anotherMethod(Integer t, int i, String p) {
62              return -2 * i;
63          }
64      }
65  
66      @Test
67      public void mockGenericClassWithUnspecifiedTypeArguments() {
68          new MockUp<GenericClass<?, ?>>() {
69              @Mock
70              void aMethod(Object o) {
71                  StringBuilder s = (StringBuilder) o;
72                  s.setLength(0);
73                  s.append("mock");
74                  s.toString();
75              }
76  
77              @Mock
78              int anotherMethod(Object o, int i, Object list) {
79                  assertTrue(o instanceof StringBuilder);
80                  // noinspection unchecked
81                  assertEquals(0, ((Collection<String>) list).size());
82                  return -i;
83              }
84          };
85  
86          StringBuilder s = new StringBuilder("test");
87          GenericClass<StringBuilder, List<String>> g = new GenericClass<>();
88  
89          g.aMethod(s);
90          int r1 = g.anotherMethod(new StringBuilder("test"), 58, Collections.<String> emptyList());
91          int r2 = g.anotherMethod(123, 65, "abc");
92  
93          assertEquals("mock", s.toString());
94          assertEquals(-58, r1);
95          assertEquals(-130, r2);
96      }
97  
98      @Test
99      public void mockBothGenericAndNonGenericMethodsInGenericClass() {
100         new MockUp<GenericClass<String, Boolean>>() {
101             @Mock
102             int anotherMethod(Integer t, int i, String p) {
103                 return 2;
104             }
105 
106             @Mock
107             int anotherMethod(String t, int i, Boolean p) {
108                 return 1;
109             }
110         };
111 
112         GenericClass<String, Boolean> o = new GenericClass<>();
113         assertEquals(1, o.anotherMethod("generic", 1, true));
114         assertEquals(2, o.anotherMethod(123, 2, "non generic"));
115     }
116 
117     static class GenericBaseClass<T, U> {
118         public U find(@SuppressWarnings("UnusedParameters") T id) {
119             return null;
120         }
121     }
122 
123     @Test
124     public void mockGenericMethodWithMockMethodHavingParameterTypesMatchingTypeArguments() {
125         new MockUp<GenericBaseClass<String, Integer>>() {
126             @Mock
127             Integer find(String id) {
128                 return id.hashCode();
129             }
130         };
131 
132         int i = new GenericBaseClass<String, Integer>().find("test");
133         assertEquals("test".hashCode(), i);
134     }
135 
136     @Test
137     public void cannotCallGenericMethodWhenSomeMockMethodExpectsDifferentTypes() {
138         new MockUp<GenericBaseClass<String, Integer>>() {
139             @Mock
140             Integer find(String id) {
141                 return 1;
142             }
143         };
144 
145         try {
146             new GenericBaseClass<Integer, String>().find(1);
147             fail();
148         } catch (IllegalArgumentException e) {
149             assertTrue(e.getMessage().startsWith("Failure to invoke method: "));
150         }
151     }
152 
153     static class NonGenericSuperclass extends GenericBaseClass<Integer, String> {
154     }
155 
156     final class NonGenericSubclass extends NonGenericSuperclass {
157     }
158 
159     @Test
160     public void mockGenericMethodFromInstantiationOfNonGenericSubclass() {
161         new MockUp<NonGenericSubclass>() {
162             @Mock
163             String find(Integer id) {
164                 return "mocked" + id;
165             }
166         };
167 
168         String s = new NonGenericSubclass().find(1);
169         assertEquals("mocked1", s);
170     }
171 
172     static class GenericSuperclass<I> extends GenericBaseClass<I, String> {
173     }
174 
175     final class AnotherNonGenericSubclass extends GenericSuperclass<Integer> {
176     }
177 
178     @Test
179     public void mockGenericMethodFromInstantiationOfNonGenericSubclassWhichExtendsAGenericIntermediateSuperclass() {
180         new MockUp<AnotherNonGenericSubclass>() {
181             @Mock
182             String find(Integer id) {
183                 return "mocked" + id;
184             }
185         };
186 
187         String s = new AnotherNonGenericSubclass().find(1);
188         assertEquals("mocked1", s);
189     }
190 
191     @SuppressWarnings("UnusedParameters")
192     public static class NonGenericClassWithGenericMethods {
193         public static <T> T staticMethod(Class<T> cls, String s) {
194             throw new RuntimeException();
195         }
196 
197         public <C> void instanceMethod(Class<C> cls, String s) {
198             throw new RuntimeException();
199         }
200 
201         public final <N extends Number> void instanceMethod(Class<N> cls) {
202             throw new RuntimeException();
203         }
204     }
205 
206     @Test
207     public void mockGenericMethodsOfNonGenericClass() {
208         new MockUp<NonGenericClassWithGenericMethods>() {
209             @Mock
210             <T> T staticMethod(Class<T> cls, String s) {
211                 return null;
212             }
213 
214             @Mock
215             <C> void instanceMethod(Class<C> cls, String s) {
216             }
217 
218             @Mock
219             void instanceMethod(Class<?> cls) {
220             }
221         };
222 
223         new NonGenericClassWithGenericMethods().instanceMethod(Integer.class);
224         NonGenericClassWithGenericMethods.staticMethod(Collaborator.class, "test1");
225         new NonGenericClassWithGenericMethods().instanceMethod(Byte.class, "test2");
226     }
227 
228     // Mock-ups for generic interfaces /////////////////////////////////////////////////////////////////////////////////
229 
230     public interface GenericInterface<T> {
231         void method(T t);
232     }
233 
234     @Test
235     public void mockGenericInterfaceMethodWithMockMethodHavingParameterOfTypeObject() {
236         GenericInterface<Boolean> mock = new MockUp<GenericInterface<Boolean>>() {
237             @Mock
238             void method(Object b) {
239                 assertTrue((Boolean) b);
240             }
241         }.getMockInstance();
242 
243         mock.method(true);
244     }
245 
246     public interface NonGenericSubInterface extends GenericInterface<Long> {
247     }
248 
249     @Test
250     public void mockMethodOfSubInterfaceWithGenericTypeArgument() {
251         NonGenericSubInterface mock = new MockUp<NonGenericSubInterface>() {
252             @Mock
253             void method(Long l) {
254                 assertTrue(l > 0);
255             }
256         }.getMockInstance();
257 
258         mock.method(123L);
259     }
260 
261     @Test
262     public void mockGenericInterfaceMethod() {
263         Comparable<Integer> cmp = new MockUp<Comparable<Integer>>() {
264             @Mock
265             int compareTo(Integer i) {
266                 assertEquals(123, i.intValue());
267                 return 2;
268             }
269         }.getMockInstance();
270 
271         assertEquals(2, cmp.compareTo(123));
272     }
273 }