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 public static int getJdkVersion() {
218 String version = System.getProperty("java.specification.version");
219 if (version.startsWith("1.")) {
220 version = version.substring(2);
221 }
222 return Integer.parseInt(version);
223 }
224
225
226
227
228
229
230
231
232
233
234
235
236 public static int adjustFlushCountForOutputStreamClose(int flushCount) {
237 int result = flushCount;
238 if (getJdkVersion() >= 13) {
239 ++result;
240 }
241 return result;
242 }
243
244
245
246
247
248
249
250
251
252
253
254
255 public static <V> V getResultWithLimitedResources(Callable<V> callable) throws Exception {
256 final FutureTask<V> futureTask = new FutureTask<>(callable);
257 final Thread thread = new Thread(null, futureTask,
258 "LimitedStackSizeThread", MINIMAL_STACK_SIZE);
259 thread.start();
260 return futureTask.get(10, TimeUnit.SECONDS);
261 }
262
263
264
265
266
267
268
269
270
271
272
273 public static <T> T getInternalState(Object instance, String fieldName) {
274 try {
275 final Field field = getClassDeclaredField(instance.getClass(), fieldName);
276 return (T) field.get(instance);
277 }
278 catch (ReflectiveOperationException ex) {
279 final String message = String.format(Locale.ROOT,
280 "Failed to get field '%s' for instance of class '%s'",
281 fieldName, instance.getClass().getSimpleName());
282 throw new IllegalStateException(message, ex);
283 }
284 }
285
286
287
288
289
290
291
292
293
294
295
296 public static <T> T getInternalStaticState(Class<?> clss, String fieldName) {
297 try {
298 final Field field = getClassDeclaredField(clss, fieldName);
299 return (T) field.get(null);
300 }
301 catch (ReflectiveOperationException ex) {
302 final String message = String.format(Locale.ROOT,
303 "Failed to get static field '%s' for class '%s'",
304 fieldName, clss);
305 throw new IllegalStateException(message, ex);
306 }
307 }
308
309
310
311
312
313
314
315
316
317
318 public static void setInternalState(Object instance, String fieldName, Object value) {
319 try {
320 final Field field = getClassDeclaredField(instance.getClass(), fieldName);
321 field.set(instance, value);
322 }
323 catch (ReflectiveOperationException ex) {
324 final String message = String.format(Locale.ROOT,
325 "Failed to set field '%s' for instance of class '%s'",
326 fieldName, instance.getClass().getSimpleName());
327 throw new IllegalStateException(message, ex);
328 }
329 }
330
331
332
333
334
335
336
337
338
339
340
341
342
343 public static <T> T invokeMethod(Object instance,
344 String methodToExecute, Object... arguments) throws ReflectiveOperationException {
345 final Class<?> clss = instance.getClass();
346 final Method method = getClassDeclaredMethod(clss, methodToExecute, arguments.length);
347 return (T) method.invoke(instance, arguments);
348 }
349
350
351
352
353
354
355
356
357
358
359
360
361
362 public static <T> T invokeStaticMethod(Class<?> clss,
363 String methodToExecute, Object... arguments) throws ReflectiveOperationException {
364 final Method method = getClassDeclaredMethod(clss, methodToExecute, arguments.length);
365 return (T) method.invoke(null, arguments);
366 }
367
368
369
370
371
372
373
374
375
376
377
378 public static <T> Class<T> getInnerClassType(Class<?> declaringClass, String name)
379 throws ClassNotFoundException {
380 return (Class<T>) Class.forName(declaringClass.getName() + "$" + name);
381 }
382
383
384
385
386
387
388
389
390
391 public static <T extends Throwable> T getExpectedThrowable(Class<T> expectedType,
392 Executable executable,
393 String message) {
394 return assertThrows(expectedType, executable, message);
395 }
396
397
398
399
400
401
402
403
404 public static <T extends Throwable> T getExpectedThrowable(Class<T> expectedType,
405 Executable executable) {
406 return assertThrows(expectedType, executable);
407 }
408
409 }