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.utils;
21
22 import static com.google.common.truth.Truth.assertWithMessage;
23 import static com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck.MSG_EQUALS_AVOID_NULL;
24 import static com.puppycrawl.tools.checkstyle.checks.coding.MultipleVariableDeclarationsCheck.MSG_MULTIPLE;
25 import static com.puppycrawl.tools.checkstyle.checks.coding.NestedIfDepthCheck.MSG_KEY;
26 import static com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheck.MSG_EXPECTED_TAG;
27 import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.findTokenInAstByPredicate;
28 import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.getExpectedThrowable;
29 import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.isUtilsClassHasPrivateConstructor;
30
31 import java.nio.file.Path;
32 import java.util.Arrays;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Optional;
36 import java.util.Set;
37
38 import org.junit.jupiter.api.Test;
39
40 import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
41 import com.puppycrawl.tools.checkstyle.DetailAstImpl;
42 import com.puppycrawl.tools.checkstyle.JavaParser;
43 import com.puppycrawl.tools.checkstyle.api.DetailAST;
44 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
45 import com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck;
46 import com.puppycrawl.tools.checkstyle.checks.coding.MultipleVariableDeclarationsCheck;
47 import com.puppycrawl.tools.checkstyle.checks.coding.NestedIfDepthCheck;
48 import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheck;
49 import com.puppycrawl.tools.checkstyle.checks.naming.AccessModifierOption;
50
51 public class CheckUtilTest extends AbstractModuleTestSupport {
52
53 @Override
54 public String getPackageLocation() {
55 return "com/puppycrawl/tools/checkstyle/utils/checkutil";
56 }
57
58 @Test
59 public void testIsProperUtilsClass() throws ReflectiveOperationException {
60 assertWithMessage("Constructor is not private")
61 .that(isUtilsClassHasPrivateConstructor(CheckUtil.class))
62 .isTrue();
63 }
64
65 @Test
66 public void testParseDoubleWithIncorrectToken() {
67 final double parsedDouble = CheckUtil.parseDouble("1_02", TokenTypes.ASSIGN);
68 assertWithMessage("Invalid parse result")
69 .that(parsedDouble)
70 .isEqualTo(Double.NaN);
71 }
72
73 @Test
74 public void testEquals() {
75 final DetailAstImpl litStatic = new DetailAstImpl();
76 litStatic.setType(TokenTypes.LITERAL_STATIC);
77
78 final DetailAstImpl modifiers = new DetailAstImpl();
79 modifiers.setType(TokenTypes.MODIFIERS);
80 modifiers.addChild(litStatic);
81
82 final DetailAstImpl metDef = new DetailAstImpl();
83 metDef.setType(TokenTypes.METHOD_DEF);
84 metDef.addChild(modifiers);
85
86 assertWithMessage("Invalid result: ast is not equals method")
87 .that(CheckUtil.isEqualsMethod(metDef))
88 .isFalse();
89
90 metDef.removeChildren();
91
92 final DetailAstImpl metName = new DetailAstImpl();
93 metName.setType(TokenTypes.IDENT);
94 metName.setText("equals");
95 metDef.addChild(metName);
96
97 final DetailAstImpl modifiers2 = new DetailAstImpl();
98 modifiers2.setType(TokenTypes.MODIFIERS);
99 metDef.addChild(modifiers2);
100
101 final DetailAstImpl parameter1 = new DetailAstImpl();
102 final DetailAstImpl parameter2 = new DetailAstImpl();
103
104 final DetailAstImpl parameters = new DetailAstImpl();
105 parameters.setType(TokenTypes.PARAMETERS);
106
107 parameters.addChild(parameter2);
108
109 parameters.addChild(parameter1);
110 metDef.addChild(parameters);
111
112 assertWithMessage("Invalid result: ast is not equals method")
113 .that(CheckUtil.isEqualsMethod(metDef))
114 .isFalse();
115 }
116
117 @Test
118 public void testGetAccessModifierFromModifiersTokenWrongTokenType() {
119 final DetailAstImpl modifiers = new DetailAstImpl();
120 modifiers.setType(TokenTypes.METHOD_DEF);
121
122 final IllegalArgumentException exc =
123 getExpectedThrowable(IllegalArgumentException.class, () -> {
124 CheckUtil.getAccessModifierFromModifiersToken(modifiers);
125 });
126
127 final String expectedExceptionMsg = "expected non-null AST-token with type 'MODIFIERS'";
128 final String actualExceptionMsg = exc.getMessage();
129 assertWithMessage("Invalid exception message")
130 .that(actualExceptionMsg)
131 .isEqualTo(expectedExceptionMsg);
132 }
133
134 @Test
135 public void testGetTypeParameterNames() throws Exception {
136 final DetailAST parameterizedClassNode = getNodeFromFile(TokenTypes.CLASS_DEF);
137 final List<String> expected = Arrays.asList("V", "C");
138 final List<String> actual = CheckUtil.getTypeParameterNames(parameterizedClassNode);
139
140 assertWithMessage("Invalid type parameters")
141 .that(actual)
142 .isEqualTo(expected);
143 }
144
145 @Test
146 public void testGetTypeParameters() throws Exception {
147 final DetailAST parameterizedClassNode = getNodeFromFile(TokenTypes.CLASS_DEF);
148 final DetailAST firstTypeParameter =
149 getNode(parameterizedClassNode, TokenTypes.TYPE_PARAMETER);
150 final List<DetailAST> expected = Arrays.asList(firstTypeParameter,
151 firstTypeParameter.getNextSibling().getNextSibling());
152 final List<DetailAST> actual = CheckUtil.getTypeParameters(parameterizedClassNode);
153
154 assertWithMessage("Invalid type parameters")
155 .that(actual)
156 .isEqualTo(expected);
157 }
158
159 @Test
160 public void testIsEqualsMethod() throws Exception {
161 final DetailAST equalsMethodNode = getNodeFromFile(TokenTypes.METHOD_DEF);
162 final DetailAST someOtherMethod = equalsMethodNode.getNextSibling();
163
164 assertWithMessage("Invalid result: AST provided is not equals method")
165 .that(CheckUtil.isEqualsMethod(equalsMethodNode))
166 .isTrue();
167 assertWithMessage("Invalid result: AST provided is equals method")
168 .that(CheckUtil.isEqualsMethod(someOtherMethod))
169 .isFalse();
170 }
171
172 @Test
173 public void testIsNonVoidMethod() throws Exception {
174 final DetailAST nonVoidMethod = getNodeFromFile(TokenTypes.METHOD_DEF);
175 final DetailAST voidMethod = nonVoidMethod.getNextSibling();
176
177 assertWithMessage("Invalid result: AST provided is void method")
178 .that(CheckUtil.isNonVoidMethod(nonVoidMethod))
179 .isTrue();
180 assertWithMessage("Invalid result: AST provided is non void method")
181 .that(CheckUtil.isNonVoidMethod(voidMethod))
182 .isFalse();
183 }
184
185 @Test
186 public void testGetAccessModifierFromModifiersToken() throws Exception {
187 final DetailAST interfaceDef = getNodeFromFile(TokenTypes.INTERFACE_DEF);
188 final AccessModifierOption modifierInterface = CheckUtil
189 .getAccessModifierFromModifiersToken(interfaceDef
190 .findFirstToken(TokenTypes.OBJBLOCK)
191 .findFirstToken(TokenTypes.METHOD_DEF));
192 assertWithMessage("Invalid access modifier")
193 .that(modifierInterface)
194 .isEqualTo(AccessModifierOption.PUBLIC);
195
196 final DetailAST privateVariable = getNodeFromFile(TokenTypes.VARIABLE_DEF);
197 final AccessModifierOption modifierPrivate =
198 CheckUtil.getAccessModifierFromModifiersToken(privateVariable);
199 assertWithMessage("Invalid access modifier")
200 .that(modifierPrivate)
201 .isEqualTo(AccessModifierOption.PRIVATE);
202
203 final DetailAST protectedVariable = privateVariable.getNextSibling();
204 final AccessModifierOption modifierProtected =
205 CheckUtil.getAccessModifierFromModifiersToken(protectedVariable);
206 assertWithMessage("Invalid access modifier")
207 .that(modifierProtected)
208 .isEqualTo(AccessModifierOption.PROTECTED);
209
210 final DetailAST publicVariable = protectedVariable.getNextSibling();
211 final AccessModifierOption modifierPublic =
212 CheckUtil.getAccessModifierFromModifiersToken(publicVariable);
213 assertWithMessage("Invalid access modifier")
214 .that(modifierPublic)
215 .isEqualTo(AccessModifierOption.PUBLIC);
216
217 final DetailAST packageVariable = publicVariable.getNextSibling();
218 final AccessModifierOption modifierPackage =
219 CheckUtil.getAccessModifierFromModifiersToken(packageVariable);
220 assertWithMessage("Invalid access modifier")
221 .that(modifierPackage)
222 .isEqualTo(AccessModifierOption.PACKAGE);
223
224 final DetailAST enumConstantDefinition = getNodeFromFile(TokenTypes.ENUM_CONSTANT_DEF);
225 final AccessModifierOption modifierEnumConstant = CheckUtil
226 .getAccessModifierFromModifiersToken(enumConstantDefinition);
227 assertWithMessage("Invalid access modifier")
228 .that(modifierEnumConstant)
229 .isEqualTo(AccessModifierOption.PUBLIC);
230 }
231
232 @Test
233 public void testGetFirstNode() throws Exception {
234 final DetailAST classDef = getNodeFromFile(TokenTypes.CLASS_DEF);
235
236 final DetailAST firstChild = classDef.getFirstChild().getFirstChild();
237 final DetailAST firstNode = CheckUtil.getFirstNode(classDef);
238 assertWithMessage("Invalid first node")
239 .that(firstNode)
240 .isEqualTo(firstChild);
241 }
242
243 @Test
244 public void testGetFirstNode1() {
245 final DetailAstImpl child = new DetailAstImpl();
246 child.setLineNo(5);
247 child.setColumnNo(6);
248
249 final DetailAstImpl root = new DetailAstImpl();
250 root.setLineNo(5);
251 root.setColumnNo(6);
252
253 root.addChild(child);
254
255 final DetailAST firstNode = CheckUtil.getFirstNode(root);
256 assertWithMessage("Unexpected node")
257 .that(firstNode)
258 .isEqualTo(root);
259 }
260
261 @Test
262 public void testGetFirstNode2() {
263 final DetailAstImpl child = new DetailAstImpl();
264 child.setLineNo(6);
265 child.setColumnNo(5);
266
267 final DetailAstImpl root = new DetailAstImpl();
268 root.setLineNo(5);
269 root.setColumnNo(6);
270
271 root.addChild(child);
272
273 final DetailAST firstNode = CheckUtil.getFirstNode(root);
274 assertWithMessage("Unexpected node")
275 .that(firstNode)
276 .isEqualTo(root);
277 }
278
279 @Test
280 public void testParseDoubleFloatingPointValues() {
281 assertWithMessage("Invalid parse result")
282 .that(CheckUtil.parseDouble("-0.05f", TokenTypes.NUM_FLOAT))
283 .isEqualTo(-0.05);
284 assertWithMessage("Invalid parse result")
285 .that(CheckUtil.parseDouble("10.0", TokenTypes.NUM_DOUBLE))
286 .isEqualTo(10.0);
287 assertWithMessage("Invalid parse result")
288 .that(CheckUtil.parseDouble("1.23e3", TokenTypes.NUM_DOUBLE))
289 .isEqualTo(1230);
290 assertWithMessage("Invalid parse result")
291 .that(CheckUtil.parseDouble("-3.21E2", TokenTypes.NUM_DOUBLE))
292 .isEqualTo(-321);
293 assertWithMessage("Invalid parse result")
294 .that(CheckUtil.parseDouble("-0.0", TokenTypes.NUM_DOUBLE))
295 .isEqualTo(-0.0);
296 assertWithMessage("Invalid parse result")
297 .that(CheckUtil.parseDouble("NaN", TokenTypes.NUM_DOUBLE))
298 .isEqualTo(Double.NaN);
299 }
300
301 @Test
302 public void testParseDoubleIntegerValues() {
303 assertWithMessage("Invalid parse result")
304 .that(CheckUtil.parseDouble("0L", TokenTypes.NUM_LONG))
305 .isEqualTo(0.0);
306 assertWithMessage("Invalid parse result")
307 .that(CheckUtil.parseDouble("0B101", TokenTypes.NUM_INT))
308 .isEqualTo(0b101);
309 assertWithMessage("Invalid parse result")
310 .that(CheckUtil.parseDouble("0b10001010001011010000101000101L", TokenTypes.NUM_LONG))
311 .isEqualTo(289_775_941);
312 assertWithMessage("Invalid parse result")
313 .that(CheckUtil.parseDouble("1", TokenTypes.NUM_INT))
314 .isEqualTo(1.0);
315 assertWithMessage("Invalid parse result")
316 .that(CheckUtil.parseDouble("8L", TokenTypes.NUM_LONG))
317 .isEqualTo(8.0);
318 assertWithMessage("Invalid parse result")
319 .that(CheckUtil.parseDouble("-21474836480", TokenTypes.NUM_LONG))
320 .isEqualTo(-2.147_483_648e10);
321 assertWithMessage("Invalid parse result")
322 .that(CheckUtil.parseDouble("-2", TokenTypes.NUM_INT))
323 .isEqualTo(-2);
324 assertWithMessage("Invalid parse result")
325 .that(CheckUtil.parseDouble("0xffffffff", TokenTypes.NUM_INT))
326 .isEqualTo(-1);
327 assertWithMessage("Invalid parse result")
328 .that(CheckUtil.parseDouble("0x0B63", TokenTypes.NUM_INT))
329 .isEqualTo(2915.0);
330 assertWithMessage("Invalid parse result")
331 .that(CheckUtil.parseDouble("21474836470", TokenTypes.NUM_LONG))
332 .isEqualTo(2.147_483_647e10);
333 assertWithMessage("Invalid parse result")
334 .that(CheckUtil.parseDouble("073l", TokenTypes.NUM_LONG))
335 .isEqualTo(59.0);
336 }
337
338 @Test
339 public void testParseClassNames() {
340 final Set<String> actual = CheckUtil.parseClassNames(
341 "I.am.class.name.with.dot.in.the.end.", "ClassOnly", "my.Class");
342 final Set<String> expected = new HashSet<>();
343 expected.add("I.am.class.name.with.dot.in.the.end.");
344 expected.add("ClassOnly");
345 expected.add("my.Class");
346 expected.add("Class");
347 assertWithMessage("Result is not expected")
348 .that(actual)
349 .isEqualTo(expected);
350 }
351
352 @Test
353 public void testEqualsAvoidNullCheck() throws Exception {
354
355 final String[] expected = {
356 "14:28: " + getCheckMessage(EqualsAvoidNullCheck.class, MSG_EQUALS_AVOID_NULL),
357 "21:17: " + getCheckMessage(EqualsAvoidNullCheck.class, MSG_EQUALS_AVOID_NULL),
358 };
359 verifyWithInlineConfigParser(
360 getPath("InputCheckUtil1.java"), expected);
361 }
362
363 @Test
364 public void testMultipleVariableDeclarationsCheck() throws Exception {
365 final String[] expected = {
366 "11:5: " + getCheckMessage(MultipleVariableDeclarationsCheck.class, MSG_MULTIPLE),
367 "14:5: " + getCheckMessage(MultipleVariableDeclarationsCheck.class, MSG_MULTIPLE),
368 };
369 verifyWithInlineConfigParser(
370 getPath("InputCheckUtil2.java"),
371 expected);
372 }
373
374 @Test
375 public void testNestedIfDepth() throws Exception {
376 final String[] expected = {
377 "26:17: " + getCheckMessage(NestedIfDepthCheck.class, MSG_KEY, 2, 1),
378 "52:17: " + getCheckMessage(NestedIfDepthCheck.class, MSG_KEY, 2, 1),
379 };
380 verifyWithInlineConfigParser(
381 getPath("InputCheckUtil3.java"), expected);
382 }
383
384 @Test
385 public void testJavaDocMethod() throws Exception {
386 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
387 verifyWithInlineConfigParser(
388 getPath("InputCheckUtil4.java"), expected);
389 }
390
391 @Test
392 public void testJavaDocMethod2() throws Exception {
393 final String[] expected = {
394 "20:25: " + getCheckMessage(JavadocMethodCheck.class,
395 MSG_EXPECTED_TAG, "@param", "i"),
396 };
397 verifyWithInlineConfigParser(
398 getPath("InputCheckUtil5.java"), expected);
399 }
400
401 @Test
402 public void testJavadoc() throws Exception {
403 final String[] expected = {
404 "26:39: " + getCheckMessage(JavadocMethodCheck.class,
405 MSG_EXPECTED_TAG, "@param", "i"),
406 };
407 verifyWithInlineConfigParser(
408 getPath("InputCheckUtil7.java"), expected);
409 }
410
411 private DetailAST getNodeFromFile(int type) throws Exception {
412 final Path path = Path.of(getPath("InputCheckUtilTest.java"));
413 return getNode(JavaParser.parseFile(path.toFile(), JavaParser.Options.WITH_COMMENTS), type);
414 }
415
416
417
418
419
420
421
422
423
424
425 public static DetailAST getNode(Path filePath, int type) throws Exception {
426 return getNode(JavaParser.parseFile(filePath.toFile(),
427 JavaParser.Options.WITH_COMMENTS), type);
428 }
429
430
431
432
433
434
435
436
437 private static DetailAST getNode(DetailAST root, int type) {
438 final Optional<DetailAST> node = findTokenInAstByPredicate(root,
439 ast -> ast.getType() == type);
440
441 assertWithMessage("Cannot find node of specified type: %s", type)
442 .that(node.isPresent())
443 .isTrue();
444
445 return node.orElseThrow();
446 }
447
448 @Test
449 public void testPackageInfo() {
450 final boolean result = CheckUtil.isPackageInfo("/");
451
452 assertWithMessage("Expected isPackageInfo() to return false for ('/')")
453 .that(result)
454 .isFalse();
455 }
456
457 }