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