1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.internal.utils;
21
22 import static org.junit.jupiter.api.Assertions.assertThrows;
23
24 import java.io.OutputStream;
25 import java.lang.reflect.Constructor;
26 import java.lang.reflect.Field;
27 import java.lang.reflect.Method;
28 import java.lang.reflect.Modifier;
29 import java.util.Arrays;
30 import java.util.Locale;
31 import java.util.Optional;
32 import java.util.Set;
33 import java.util.concurrent.Callable;
34 import java.util.concurrent.FutureTask;
35 import java.util.concurrent.TimeUnit;
36 import java.util.function.Predicate;
37 import java.util.stream.Stream;
38
39 import org.junit.jupiter.api.function.Executable;
40
41 import com.puppycrawl.tools.checkstyle.AbstractAutomaticBean;
42 import com.puppycrawl.tools.checkstyle.PackageNamesLoader;
43 import com.puppycrawl.tools.checkstyle.PackageObjectFactory;
44 import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent;
45 import com.puppycrawl.tools.checkstyle.TreeWalkerFilter;
46 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
47 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
48 import com.puppycrawl.tools.checkstyle.api.DetailAST;
49
50 public final class TestUtil {
51
52
53
54
55
56
57
58
59
60 private static final int MINIMAL_STACK_SIZE = 147456;
61
62 private TestUtil() {
63 }
64
65
66
67
68
69
70
71 public static boolean isUtilsClassHasPrivateConstructor(final Class<?> utilClass)
72 throws ReflectiveOperationException {
73 final Constructor<?> constructor = utilClass.getDeclaredConstructor();
74 final boolean result = Modifier.isPrivate(constructor.getModifiers());
75 constructor.setAccessible(true);
76 constructor.newInstance();
77 return result;
78 }
79
80
81
82
83
84
85
86
87 public static Field getClassDeclaredField(Class<?> clss, String fieldName) {
88 return Stream.<Class<?>>iterate(clss, Class::getSuperclass)
89 .flatMap(cls -> Arrays.stream(cls.getDeclaredFields()))
90 .filter(field -> fieldName.equals(field.getName()))
91 .findFirst()
92 .map(field -> {
93 field.setAccessible(true);
94 return field;
95 })
96 .orElseThrow(() -> {
97 return new IllegalStateException(String.format(Locale.ROOT,
98 "Field '%s' not found in '%s'", fieldName, clss.getCanonicalName()));
99 });
100 }
101
102
103
104
105
106
107
108
109
110 public static Method getClassDeclaredMethod(Class<?> clss, String methodName, int parameters) {
111 return Stream.<Class<?>>iterate(clss, Class::getSuperclass)
112 .flatMap(cls -> Arrays.stream(cls.getDeclaredMethods()))
113 .filter(method -> {
114 return methodName.equals(method.getName())
115 && parameters == method.getParameterCount();
116 })
117 .findFirst()
118 .map(method -> {
119 method.setAccessible(true);
120 return method;
121 })
122 .orElseThrow(() -> {
123 return new IllegalStateException(String.format(Locale.ROOT,
124 "Method '%s' with %d parameters not found in '%s'",
125 methodName, parameters, clss.getCanonicalName()));
126 });
127 }
128
129
130
131
132
133
134
135
136
137
138 public static boolean isStatefulFieldClearedDuringBeginTree(AbstractCheck check,
139 DetailAST astToVisit,
140 String fieldName,
141 Predicate<Object> isClear) {
142 check.beginTree(astToVisit);
143 check.visitToken(astToVisit);
144 check.beginTree(null);
145 return isClear.test(getInternalState(check, fieldName));
146 }
147
148
149
150
151
152
153
154
155
156
157
158 public static boolean isStatefulFieldClearedDuringLocalSetup(
159 TreeWalkerFilter filter, TreeWalkerAuditEvent event,
160 String fieldName, Predicate<Object> isClear) throws Exception {
161 filter.accept(event);
162 invokeMethod(filter, "finishLocalSetup");
163 final Field resultField = getClassDeclaredField(filter.getClass(), fieldName);
164 return isClear.test(resultField.get(filter));
165 }
166
167
168
169
170
171
172 public static PackageObjectFactory getPackageObjectFactory() throws CheckstyleException {
173 final ClassLoader cl = TestUtil.class.getClassLoader();
174 final Set<String> packageNames = PackageNamesLoader.getPackageNames(cl);
175 return new PackageObjectFactory(packageNames, cl);
176 }
177
178
179
180
181
182
183
184
185
186 public static Optional<DetailAST> findTokenInAstByPredicate(DetailAST root,
187 Predicate<DetailAST> predicate) {
188 DetailAST curNode = root;
189 while (!predicate.test(curNode)) {
190 DetailAST toVisit = curNode.getFirstChild();
191 while (curNode != null && toVisit == null) {
192 toVisit = curNode.getNextSibling();
193 if (toVisit == null) {
194 curNode = curNode.getParent();
195 }
196 }
197
198 if (curNode == toVisit || curNode == root.getParent()) {
199 curNode = null;
200 break;
201 }
202
203 curNode = toVisit;
204 }
205 return Optional.ofNullable(curNode);
206 }
207
208
209
210
211
212
213
214
215
216
217
218 public static int getJdkVersion() {
219 String version = System.getProperty("java.specification.version");
220 if (version.startsWith("1.")) {
221 version = version.substring(2);
222 }
223 return Integer.parseInt(version);
224 }
225
226
227
228
229
230
231
232
233
234
235
236
237
238 public static int adjustFlushCountForOutputStreamClose(int flushCount) {
239 int result = flushCount;
240 if (getJdkVersion() >= 13) {
241 ++result;
242 }
243 return result;
244 }
245
246
247
248
249
250
251
252
253
254
255
256
257 public static <V> V getResultWithLimitedResources(Callable<V> callable) throws Exception {
258 final FutureTask<V> futureTask = new FutureTask<>(callable);
259 final Thread thread = new Thread(null, futureTask,
260 "LimitedStackSizeThread", MINIMAL_STACK_SIZE);
261 thread.start();
262 return futureTask.get(10, TimeUnit.SECONDS);
263 }
264
265
266
267
268
269
270
271
272
273
274
275 public static <T> T getInternalState(Object instance, String fieldName) {
276 try {
277 final Field field = getClassDeclaredField(instance.getClass(), fieldName);
278 return (T) field.get(instance);
279 }
280 catch (ReflectiveOperationException ex) {
281 final String message = String.format(Locale.ROOT,
282 "Failed to get field '%s' for instance of class '%s'",
283 fieldName, instance.getClass().getSimpleName());
284 throw new IllegalStateException(message, ex);
285 }
286 }
287
288
289
290
291
292
293
294
295
296
297
298 public static <T> T getInternalStaticState(Class<?> clss, String fieldName) {
299 try {
300 final Field field = getClassDeclaredField(clss, fieldName);
301 return (T) field.get(null);
302 }
303 catch (ReflectiveOperationException ex) {
304 final String message = String.format(Locale.ROOT,
305 "Failed to get static field '%s' for class '%s'",
306 fieldName, clss);
307 throw new IllegalStateException(message, ex);
308 }
309 }
310
311
312
313
314
315
316
317
318
319
320 public static void setInternalState(Object instance, String fieldName, Object value) {
321 try {
322 final Field field = getClassDeclaredField(instance.getClass(), fieldName);
323 field.set(instance, value);
324 }
325 catch (ReflectiveOperationException ex) {
326 final String message = String.format(Locale.ROOT,
327 "Failed to set field '%s' for instance of class '%s'",
328 fieldName, instance.getClass().getSimpleName());
329 throw new IllegalStateException(message, ex);
330 }
331 }
332
333
334
335
336
337
338
339
340
341
342
343
344
345 public static <T> T invokeMethod(Object instance,
346 String methodToExecute, Object... arguments) throws ReflectiveOperationException {
347 final Class<?> clss = instance.getClass();
348 final Method method = getClassDeclaredMethod(clss, methodToExecute, arguments.length);
349 return (T) method.invoke(instance, arguments);
350 }
351
352
353
354
355
356
357
358
359
360
361
362
363
364 public static <T> T invokeStaticMethod(Class<?> clss,
365 String methodToExecute, Object... arguments) throws ReflectiveOperationException {
366 final Method method = getClassDeclaredMethod(clss, methodToExecute, arguments.length);
367 return (T) method.invoke(null, arguments);
368 }
369
370
371
372
373
374
375
376
377
378
379
380 public static <T> Class<T> getInnerClassType(Class<?> declaringClass, String name)
381 throws ClassNotFoundException {
382 return (Class<T>) Class.forName(declaringClass.getName() + "$" + name);
383 }
384
385
386
387
388
389
390
391
392
393 public static <T extends Throwable> T getExpectedThrowable(Class<T> expectedType,
394 Executable executable,
395 String message) {
396 return assertThrows(expectedType, executable, message);
397 }
398
399
400
401
402
403
404
405
406 public static <T extends Throwable> T getExpectedThrowable(Class<T> expectedType,
407 Executable executable) {
408 return assertThrows(expectedType, executable);
409 }
410
411 }