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