View Javadoc
1   package mockit;
2   
3   import static org.junit.jupiter.api.Assertions.assertEquals;
4   import static org.junit.jupiter.api.Assertions.assertFalse;
5   import static org.junit.jupiter.api.Assertions.assertNotNull;
6   import static org.junit.jupiter.api.Assertions.assertSame;
7   import static org.junit.jupiter.api.Assertions.assertThrows;
8   import static org.junit.jupiter.api.Assertions.assertTrue;
9   
10  import java.awt.Panel;
11  import java.lang.reflect.Constructor;
12  import java.rmi.RMISecurityException;
13  import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
14  
15  import javax.accessibility.AccessibleContext;
16  import javax.sound.midi.Patch;
17  import javax.swing.SwingUtilities;
18  import javax.swing.plaf.basic.BasicColorChooserUI;
19  
20  import org.junit.jupiter.api.AfterAll;
21  import org.junit.jupiter.api.Test;
22  
23  /**
24   * The Class FakingTest.
25   */
26  final class FakingTest {
27  
28      /**
29       * Attempt to apply fake without the target type.
30       */
31      @Test
32      public void attemptToApplyFakeWithoutTheTargetType() {
33          Throwable throwable = assertThrows(IllegalArgumentException.class, () -> {
34              new MockUp() {
35              };
36          });
37          assertEquals("No target type", throwable.getMessage());
38      }
39  
40      // Fakes for classes
41      // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
42  
43      /**
44       * Fake A class.
45       */
46      @Test
47      void fakeAClass() {
48          new MockUp<Panel>() {
49              @Mock
50              int getComponentCount() {
51                  return 123;
52              }
53          };
54  
55          assertEquals(123, new Panel().getComponentCount());
56      }
57  
58      /**
59       * The Class Main.
60       */
61      static final class Main {
62  
63          /** The Constant atomicCount. */
64          static final AtomicIntegerFieldUpdater<Main> atomicCount = AtomicIntegerFieldUpdater.newUpdater(Main.class,
65                  "count");
66  
67          /** The count. */
68          volatile int count;
69  
70          /** The max. */
71          int max = 2;
72  
73          /**
74           * Increment.
75           *
76           * @return true, if successful
77           */
78          boolean increment() {
79              while (true) {
80                  int currentCount = count;
81  
82                  if (currentCount >= max) {
83                      return false;
84                  }
85  
86                  if (atomicCount.compareAndSet(this, currentCount, currentCount + 1)) {
87                      return true;
88                  }
89              }
90          }
91      }
92  
93      /**
94       * Fake A given class.
95       */
96      @Test
97      void fakeAGivenClass() {
98          final Main main = new Main();
99  
100         new MockUp<AtomicIntegerFieldUpdater<?>>(Main.atomicCount.getClass()) {
101             boolean second;
102 
103             @Mock
104             public boolean compareAndSet(Object obj, int expect, int update) {
105                 assertSame(main, obj);
106                 assertEquals(0, expect);
107                 assertEquals(1, update);
108 
109                 if (second) {
110                     return true;
111                 }
112 
113                 second = true;
114                 return false;
115             }
116         };
117 
118         assertTrue(main.increment());
119     }
120 
121     /**
122      * Attempt to fake given class but pass null.
123      */
124     @Test
125     public void attemptToFakeGivenClassButPassNull() {
126         Class<?> clazz = null;
127         assertThrows(NullPointerException.class, () -> {
128             new MockUp<Panel>(clazz) {
129             };
130         });
131     }
132 
133     /**
134      * The Class FakeForGivenClass.
135      */
136     @SuppressWarnings("rawtypes")
137     static class FakeForGivenClass extends MockUp {
138 
139         /**
140          * Instantiates a new fake for given class.
141          */
142         @SuppressWarnings("unchecked")
143         FakeForGivenClass() {
144             super(Panel.class);
145         }
146 
147         /**
148          * Gets the name.
149          *
150          * @return the name
151          */
152         @Mock
153         String getName() {
154             return "mock";
155         }
156     }
157 
158     /**
159      * Fake given class using named fake.
160      */
161     @Test
162     void fakeGivenClassUsingNamedFake() {
163         new FakeForGivenClass();
164 
165         String s = new Panel().getName();
166 
167         assertEquals("mock", s);
168     }
169 
170     // Fakes for other situations
171     // //////////////////////////////////////////////////////////////////////////////////////////////////////////
172 
173     /**
174      * Attempt to fake class and interface at once.
175      *
176      * @param <M>
177      *            the generic type
178      */
179     @Test
180     public <M extends Panel & Runnable> void attemptToFakeClassAndInterfaceAtOnce() {
181         Throwable throwable = assertThrows(RuntimeException.class, () -> {
182             new MockUp<M>() {
183                 @Mock
184                 String getName() {
185                     return "";
186                 }
187 
188                 @Mock
189                 void run() {
190                 }
191             };
192         });
193         // Java 11 gets null pointer instead of IllegalArgumentException
194         if (throwable.getMessage() != null) {
195             assertEquals("java.awt.Panel is not an interface", throwable.getMessage());
196         }
197     }
198 
199     /**
200      * Fake using invocation parameters.
201      */
202     @Test
203     void fakeUsingInvocationParameters() {
204         new MockUp<Panel>() {
205             @Mock
206             void $init(Invocation inv) {
207                 Panel it = inv.getInvokedInstance();
208                 assertNotNull(it);
209             }
210 
211             @Mock
212             int getBaseline(Invocation inv, int w, int h) {
213                 return inv.proceed();
214             }
215         };
216 
217         int i = new Panel().getBaseline(20, 15);
218 
219         assertEquals(-1, i);
220     }
221 
222     /**
223      * The Class PublicNamedFakeWithNoInvocationParameters.
224      */
225     public static class PublicNamedFakeWithNoInvocationParameters extends MockUp<Panel> {
226 
227         /** The executed. */
228         boolean executed;
229 
230         /**
231          * $init.
232          */
233         @Mock
234         public void $init() {
235             executed = true;
236         }
237 
238         /**
239          * Gets the name.
240          *
241          * @return the name
242          */
243         @Mock
244         public String getName() {
245             return "test";
246         }
247     }
248 
249     /**
250      * Public named fake with no invocation parameter.
251      */
252     @Test
253     void publicNamedFakeWithNoInvocationParameter() {
254         PublicNamedFakeWithNoInvocationParameters fake = new PublicNamedFakeWithNoInvocationParameters();
255 
256         Panel applet = new Panel();
257         assertTrue(fake.executed);
258 
259         String name = applet.getName();
260         assertEquals("test", name);
261     }
262 
263     /**
264      * Faking of annotated class.
265      *
266      * @throws Exception
267      *             the exception
268      */
269     @Test
270     @SuppressWarnings("deprecation")
271     void fakingOfAnnotatedClass() throws Exception {
272         new MockUp<RMISecurityException>() {
273             @Mock
274             void $init(String s) {
275                 assertNotNull(s);
276             }
277         };
278 
279         assertTrue(RMISecurityException.class.isAnnotationPresent(Deprecated.class));
280 
281         Constructor<RMISecurityException> aConstructor = RMISecurityException.class
282                 .getDeclaredConstructor(String.class);
283         assertTrue(aConstructor.isAnnotationPresent(Deprecated.class));
284 
285         Deprecated deprecated = aConstructor.getAnnotation(Deprecated.class);
286         assertNotNull(deprecated);
287     }
288 
289     /**
290      * Fake same class twice using separate fakes.
291      */
292     @Test
293     void fakeSameClassTwiceUsingSeparateFakes() {
294         Panel a = new Panel();
295 
296         class Fake1 extends MockUp<Panel> {
297             @Mock
298             void addNotify() {
299             }
300         }
301         new Fake1();
302         a.addNotify();
303 
304         new MockUp<Panel>() {
305             @Mock
306             AccessibleContext getAccessibleContext() {
307                 return null;
308             }
309         };
310         a.addNotify(); // still faked
311         a.getAccessibleContext();
312     }
313 
314     /**
315      * Fake constructor of inner class.
316      */
317     @Test
318     void fakeConstructorOfInnerClass() {
319         final BasicColorChooserUI outer = new BasicColorChooserUI();
320         final boolean[] constructed = { false };
321 
322         new MockUp<BasicColorChooserUI.PropertyHandler>() {
323             @Mock
324             void $init(BasicColorChooserUI o) {
325                 assertSame(outer, o);
326                 constructed[0] = true;
327             }
328         };
329 
330         outer.new PropertyHandler();
331         assertTrue(constructed[0]);
332     }
333 
334     /**
335      * Call fake method from AWT event dispatching thread.
336      *
337      * @throws Exception
338      *             the exception
339      */
340     @Test
341     void callFakeMethodFromAWTEventDispatchingThread() throws Exception {
342         new MockUp<Panel>() {
343             @Mock
344             int getComponentCount() {
345                 return 10;
346             }
347         };
348 
349         SwingUtilities.invokeAndWait(() -> {
350             int i = new Panel().getComponentCount();
351             assertEquals(10, i);
352         });
353     }
354 
355     /**
356      * The Class JRESubclass.
357      */
358     static final class JRESubclass extends Patch {
359         /**
360          * Instantiates a new JRE subclass.
361          *
362          * @param i
363          *            the i
364          * @param j
365          *            the j
366          */
367         JRESubclass(int i, int j) {
368             super(i, j);
369         }
370     }
371 
372     /**
373      * Anonymous fake for JRE subclass having fake method for JRE method.
374      */
375     @Test
376     void anonymousFakeForJRESubclassHavingFakeMethodForJREMethod() {
377         new MockUp<JRESubclass>() {
378             @Mock
379             int getBank() {
380                 return 123;
381             }
382         };
383 
384         Patch t = new JRESubclass(1, 2);
385         int i = t.getBank();
386 
387         assertEquals(123, i);
388     }
389 
390     /** The fake torn down. */
391     static Boolean fakeTornDown;
392 
393     /**
394      * The Class FakeWithActionOnTearDown.
395      */
396     static final class FakeWithActionOnTearDown extends MockUp<Panel> {
397         @Override
398         protected void onTearDown() {
399             fakeTornDown = true;
400         }
401     }
402 
403     /**
404      * Perform action on fake tear down.
405      */
406     @Test
407     void performActionOnFakeTearDown() {
408         fakeTornDown = false;
409         new FakeWithActionOnTearDown();
410         assertFalse(fakeTornDown);
411     }
412 
413     /**
414      * Verify fake applied in test was torn down.
415      */
416     @AfterAll
417     static void verifyFakeAppliedInTestWasTornDown() {
418         assertTrue(fakeTornDown == null || fakeTornDown);
419     }
420 
421     /**
422      * Fake varargs method with proceeding fake method which passes replacement arguments.
423      */
424     @Test
425     void fakeVarargsMethodWithProceedingFakeMethodWhichPassesReplacementArguments() {
426         new MockUp<ProcessBuilder>() {
427             @Mock
428             ProcessBuilder command(Invocation inv, String... command) {
429                 String[] newArgs = { "replaced" };
430                 return inv.proceed((Object) newArgs);
431             }
432         };
433 
434         new ProcessBuilder().command("test", "something");
435     }
436 }