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.internal.state;
7   
8   import edu.umd.cs.findbugs.annotations.NonNull;
9   import edu.umd.cs.findbugs.annotations.Nullable;
10  
11  import mockit.internal.expectations.RecordAndReplayExecution;
12  import mockit.internal.expectations.mocking.FieldTypeRedefinitions;
13  import mockit.internal.expectations.state.ExecutingTest;
14  import mockit.internal.faking.FakeClasses;
15  import mockit.internal.faking.FakeStates;
16  import mockit.internal.injection.TestedClassInstantiations;
17  import mockit.internal.util.StackTrace;
18  
19  /**
20   * A singleton which stores several data structures which in turn hold global state for individual test methods, test
21   * classes, and for the test run as a whole.
22   */
23  public final class TestRun {
24      private static final TestRun INSTANCE = new TestRun();
25  
26      private TestRun() {
27      }
28  
29      // Fields with global state
30      // ////////////////////////////////////////////////////////////////////////////////////////////////////////////
31  
32      private static final ThreadLocal<Integer> noMockingCount = new ThreadLocal<>() {
33          @Override
34          protected Integer initialValue() {
35              return 0;
36          }
37  
38          @Override
39          public void set(Integer valueToAdd) {
40              super.set(get() + valueToAdd);
41          }
42      };
43  
44      // Used only by the Coverage tool:
45      private int testId;
46  
47      @Nullable
48      private Class<?> currentTestClass;
49      @Nullable
50      private Object currentTestInstance;
51      @Nullable
52      private FieldTypeRedefinitions fieldTypeRedefinitions;
53      @Nullable
54      private TestedClassInstantiations testedClassInstantiations;
55  
56      @NonNull
57      private final MockFixture mockFixture = new MockFixture();
58  
59      @NonNull
60      private final ExecutingTest executingTest = new ExecutingTest();
61      @NonNull
62      private final FakeClasses fakeClasses = new FakeClasses();
63  
64      // Static "getters" for global state
65      // ///////////////////////////////////////////////////////////////////////////////////////////////////
66  
67      public static boolean isInsideNoMockingZone() {
68          return noMockingCount.get() > 0;
69      }
70  
71      @Nullable
72      public static Class<?> getCurrentTestClass() {
73          return INSTANCE.currentTestClass;
74      }
75  
76      @Nullable
77      public static Object getCurrentTestInstance() {
78          return INSTANCE.currentTestInstance;
79      }
80  
81      public static int getTestId() {
82          return INSTANCE.testId;
83      }
84  
85      @Nullable
86      public static FieldTypeRedefinitions getFieldTypeRedefinitions() {
87          return INSTANCE.fieldTypeRedefinitions;
88      }
89  
90      @Nullable
91      public static TestedClassInstantiations getTestedClassInstantiations() {
92          return INSTANCE.testedClassInstantiations;
93      }
94  
95      @NonNull
96      public static MockFixture mockFixture() {
97          return INSTANCE.mockFixture;
98      }
99  
100     @NonNull
101     public static ExecutingTest getExecutingTest() {
102         return INSTANCE.executingTest;
103     }
104 
105     @Nullable
106     public static RecordAndReplayExecution getRecordAndReplayForRunningTest() {
107         return INSTANCE.executingTest.getCurrentRecordAndReplay();
108     }
109 
110     @NonNull
111     public static RecordAndReplayExecution getOrCreateRecordAndReplayForRunningTest() {
112         return INSTANCE.executingTest.getOrCreateRecordAndReplay();
113     }
114 
115     @NonNull
116     public static RecordAndReplayExecution getRecordAndReplayForVerifications() {
117         return INSTANCE.executingTest.getRecordAndReplayForVerifications();
118     }
119 
120     @NonNull
121     public static FakeClasses getFakeClasses() {
122         return INSTANCE.fakeClasses;
123     }
124 
125     @NonNull
126     public static FakeStates getFakeStates() {
127         return INSTANCE.fakeClasses.fakeStates;
128     }
129 
130     // Static "mutators" for global state
131     // //////////////////////////////////////////////////////////////////////////////////////////////////
132 
133     public static void setCurrentTestClass(@Nullable Class<?> testClass) {
134         INSTANCE.currentTestClass = testClass;
135     }
136 
137     public static void prepareForNextTest() {
138         INSTANCE.testId++;
139         INSTANCE.executingTest.setRecordAndReplay(null);
140     }
141 
142     public static void enterNoMockingZone() {
143         noMockingCount.set(1);
144     }
145 
146     public static void exitNoMockingZone() {
147         noMockingCount.set(-1);
148     }
149 
150     public static void clearNoMockingZone() {
151         noMockingCount.remove();
152     }
153 
154     public static void clearCurrentTestInstance() {
155         INSTANCE.currentTestInstance = null;
156     }
157 
158     public static void setRunningIndividualTest(@NonNull Object testInstance) {
159         INSTANCE.currentTestInstance = testInstance;
160     }
161 
162     public static void setFieldTypeRedefinitions(@Nullable FieldTypeRedefinitions redefinitions) {
163         INSTANCE.fieldTypeRedefinitions = redefinitions;
164     }
165 
166     public static void setTestedClassInstantiations(@Nullable TestedClassInstantiations testedClassInstantiations) {
167         INSTANCE.testedClassInstantiations = testedClassInstantiations;
168     }
169 
170     public static void finishCurrentTestExecution() {
171         INSTANCE.executingTest.finishExecution();
172     }
173 
174     // Methods to be called only from generated bytecode or from the ClassLoadingBridge
175     // ////////////////////////////////////////////////////
176 
177     @SuppressWarnings({ "StaticMethodOnlyUsedInOneClass", "SimplifiableIfStatement" })
178     public static boolean updateFakeState(@NonNull String fakeClassDesc, @Nullable Object mockedInstance,
179             int fakeStateIndex) {
180         Object fake = getFake(fakeClassDesc, mockedInstance);
181 
182         if (fake == null) {
183             return false;
184         }
185 
186         if (fakeStateIndex < 0) {
187             return true;
188         }
189 
190         return getFakeStates().updateFakeState(fake, fakeStateIndex);
191     }
192 
193     @Nullable
194     public static Object getFake(@NonNull String fakeClassDesc, @Nullable Object mockedInstance) {
195         return INSTANCE.fakeClasses.getFake(fakeClassDesc, mockedInstance);
196     }
197 
198     // Other methods ///////////////////////////////////////////////////////////////////////////////////////////////////
199 
200     public static void ensureThatClassIsInitialized(@NonNull Class<?> aClass) {
201         boolean previousFlag = INSTANCE.executingTest.setShouldIgnoreMockingCallbacks(true);
202 
203         try {
204             Class.forName(aClass.getName(), true, aClass.getClassLoader());
205         } catch (ClassNotFoundException ignore) {
206         } catch (LinkageError e) {
207             StackTrace.filterStackTrace(e);
208             e.printStackTrace();
209         } finally {
210             INSTANCE.executingTest.setShouldIgnoreMockingCallbacks(previousFlag);
211         }
212     }
213 
214     /**
215      * Determines whether the current thread is executing inside a test method or inside an assertThrows() call.
216      *
217      * @return {@code true} if so; {@code false} otherwise
218      */
219     public static boolean isInsideTestMethodOrAssertThrows() {
220         // 1. No options passed to getInstance() (Fastest)
221         // 2. Uses stream().anyMatch() to stop searching as soon as the frame is found (Short-circuiting)
222         return StackWalker.getInstance()
223                 .walk(stream -> stream.anyMatch(frame -> "org.junit.jupiter.api.Assertions".equals(frame.getClassName())
224                         && "assertThrows".equals(frame.getMethodName())));
225     }
226 
227 }