1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2019 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.utils;
21  
22  import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.findTokenInAstByPredicate;
23  import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.isUtilsClassHasPrivateConstructor;
24  import static org.junit.Assert.assertEquals;
25  import static org.junit.Assert.assertFalse;
26  import static org.junit.Assert.assertTrue;
27  import static org.junit.Assert.fail;
28  
29  import java.io.File;
30  import java.util.Arrays;
31  import java.util.HashSet;
32  import java.util.List;
33  import java.util.Optional;
34  import java.util.Set;
35  
36  import org.junit.Test;
37  
38  import com.puppycrawl.tools.checkstyle.AbstractPathTestSupport;
39  import com.puppycrawl.tools.checkstyle.JavaParser;
40  import com.puppycrawl.tools.checkstyle.api.DetailAST;
41  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
42  import com.puppycrawl.tools.checkstyle.checks.naming.AccessModifier;
43  
44  public class CheckUtilTest extends AbstractPathTestSupport {
45  
46      @Override
47      protected String getPackageLocation() {
48          return "com/puppycrawl/tools/checkstyle/utils/checkutil";
49      }
50  
51      @Test
52      public void testIsProperUtilsClass() throws ReflectiveOperationException {
53          assertTrue("Constructor is not private",
54                  isUtilsClassHasPrivateConstructor(CheckUtil.class, true));
55      }
56  
57      @Test
58      public void testParseDoubleWithIncorrectToken() {
59          final double parsedDouble = CheckUtil.parseDouble("1_02", TokenTypes.ASSIGN);
60          assertEquals("Invalid parse result", Double.NaN, parsedDouble, 0.0);
61      }
62  
63      @Test
64      public void testElseWithCurly() {
65          final DetailAST ast = new DetailAST();
66          ast.setType(TokenTypes.ASSIGN);
67          ast.setText("ASSIGN");
68          assertFalse("Invalid elseIf check result 'ASSIGN' is not 'else if'",
69                  CheckUtil.isElseIf(ast));
70  
71          final DetailAST parentAst = new DetailAST();
72          parentAst.setType(TokenTypes.LCURLY);
73          parentAst.setText("LCURLY");
74  
75          final DetailAST ifAst = new DetailAST();
76          ifAst.setType(TokenTypes.LITERAL_IF);
77          ifAst.setText("IF");
78          parentAst.addChild(ifAst);
79  
80          assertFalse("Invalid elseIf check result: 'IF' is not 'else if'",
81                  CheckUtil.isElseIf(ifAst));
82  
83          final DetailAST parentAst2 = new DetailAST();
84          parentAst2.setType(TokenTypes.SLIST);
85          parentAst2.setText("SLIST");
86  
87          parentAst2.addChild(ifAst);
88  
89          assertFalse("Invalid elseIf check result: 'SLIST' is not 'else if'",
90                  CheckUtil.isElseIf(ifAst));
91  
92          final DetailAST elseAst = new DetailAST();
93          elseAst.setType(TokenTypes.LITERAL_ELSE);
94  
95          elseAst.setFirstChild(ifAst);
96          assertTrue("Invalid elseIf check result", CheckUtil.isElseIf(ifAst));
97      }
98  
99      @Test
100     public void testEquals() {
101         final DetailAST litStatic = new DetailAST();
102         litStatic.setType(TokenTypes.LITERAL_STATIC);
103 
104         final DetailAST modifiers = new DetailAST();
105         modifiers.setType(TokenTypes.MODIFIERS);
106         modifiers.addChild(litStatic);
107 
108         final DetailAST metDef = new DetailAST();
109         metDef.setType(TokenTypes.METHOD_DEF);
110         metDef.addChild(modifiers);
111 
112         assertFalse("Invalid result: ast is not equals method",
113                 CheckUtil.isEqualsMethod(metDef));
114 
115         metDef.removeChildren();
116 
117         final DetailAST metName = new DetailAST();
118         metName.setType(TokenTypes.IDENT);
119         metName.setText("equals");
120         metDef.addChild(metName);
121 
122         final DetailAST modifiers2 = new DetailAST();
123         modifiers2.setType(TokenTypes.MODIFIERS);
124         metDef.addChild(modifiers2);
125 
126         final DetailAST parameter1 = new DetailAST();
127         final DetailAST parameter2 = new DetailAST();
128 
129         final DetailAST parameters = new DetailAST();
130         parameters.setType(TokenTypes.PARAMETERS);
131 
132         parameters.addChild(parameter2);
133 
134         parameters.addChild(parameter1);
135         metDef.addChild(parameters);
136 
137         assertFalse("Invalid result: ast is not equals method",
138                 CheckUtil.isEqualsMethod(metDef));
139     }
140 
141     @Test
142     public void testGetAccessModifierFromModifiersTokenWrongTokenType() {
143         final DetailAST modifiers = new DetailAST();
144         modifiers.setType(TokenTypes.METHOD_DEF);
145 
146         try {
147             CheckUtil.getAccessModifierFromModifiersToken(modifiers);
148             fail(IllegalArgumentException.class.getSimpleName() + " was expected.");
149         }
150         catch (IllegalArgumentException exc) {
151             final String expectedExceptionMsg = "expected non-null AST-token with type 'MODIFIERS'";
152             final String actualExceptionMsg = exc.getMessage();
153             assertEquals("Invalid exception message", expectedExceptionMsg, actualExceptionMsg);
154         }
155     }
156 
157     @Test
158     public void testGetAccessModifierFromModifiersTokenWithNullParameter() {
159         try {
160             CheckUtil.getAccessModifierFromModifiersToken(null);
161             fail(IllegalArgumentException.class.getSimpleName() + " was expected.");
162         }
163         catch (IllegalArgumentException exc) {
164             final String expectedExceptionMsg = "expected non-null AST-token with type 'MODIFIERS'";
165             final String actualExceptionMsg = exc.getMessage();
166             assertEquals("Invalid exception message", expectedExceptionMsg, actualExceptionMsg);
167         }
168     }
169 
170     @Test
171     public void testCreateFullType() throws Exception {
172         final DetailAST typeNode = getNodeFromFile(TokenTypes.TYPE);
173 
174         assertEquals("Invalid full type", "Map[13x12]",
175                 CheckUtil.createFullType(typeNode).toString());
176     }
177 
178     @Test
179     public void testCreateFullTypeOfArray() throws Exception {
180         final DetailAST arrayTypeNode = getNodeFromFile(TokenTypes.VARIABLE_DEF)
181                 .getNextSibling().getFirstChild().getNextSibling();
182 
183         assertEquals("Invalid full type", "int[14x14]",
184                 CheckUtil.createFullType(arrayTypeNode).toString());
185     }
186 
187     @Test
188     public void testGetTypeParameterNames() throws Exception {
189         final DetailAST parameterizedClassNode = getNodeFromFile(TokenTypes.CLASS_DEF);
190         final List<String> expected = Arrays.asList("V", "C");
191 
192         assertEquals("Invalid type parameters",
193                 expected, CheckUtil.getTypeParameterNames(parameterizedClassNode));
194     }
195 
196     @Test
197     public void testGetTypeParameters() throws Exception {
198         final DetailAST parameterizedClassNode = getNodeFromFile(TokenTypes.CLASS_DEF);
199         final DetailAST firstTypeParameter =
200                 getNode(parameterizedClassNode, TokenTypes.TYPE_PARAMETER);
201         final List<DetailAST> expected = Arrays.asList(firstTypeParameter,
202                 firstTypeParameter.getNextSibling().getNextSibling());
203 
204         assertEquals("Invalid type parameters", expected,
205                 CheckUtil.getTypeParameters(parameterizedClassNode));
206     }
207 
208     @Test
209     public void testIsEqualsMethod() throws Exception {
210         final DetailAST equalsMethodNode = getNodeFromFile(TokenTypes.METHOD_DEF);
211         final DetailAST someOtherMethod = equalsMethodNode.getNextSibling();
212 
213         assertTrue("Invalid result: AST provided is not equals method",
214                 CheckUtil.isEqualsMethod(equalsMethodNode));
215         assertFalse("Invalid result: AST provided is equals method",
216                 CheckUtil.isEqualsMethod(someOtherMethod));
217     }
218 
219     @Test
220     public void testIsElseIf() throws Exception {
221         final DetailAST targetMethodNode = getNodeFromFile(TokenTypes.METHOD_DEF).getNextSibling();
222         final DetailAST firstElseNode = getNode(targetMethodNode, TokenTypes.LITERAL_ELSE);
223         final DetailAST ifElseWithCurlyBraces = firstElseNode.getFirstChild().getFirstChild();
224         final DetailAST ifElse = getNode(firstElseNode.getParent().getNextSibling(),
225                 TokenTypes.LITERAL_ELSE).getFirstChild();
226         final DetailAST ifWithoutElse =
227                 firstElseNode.getParent().getNextSibling().getNextSibling();
228 
229         assertTrue("Invalid result: AST provided is not else if with curly",
230                 CheckUtil.isElseIf(ifElseWithCurlyBraces));
231         assertTrue("Invalid result: AST provided is not else if with curly",
232                 CheckUtil.isElseIf(ifElse));
233         assertFalse("Invalid result: AST provided is else if with curly",
234                 CheckUtil.isElseIf(ifWithoutElse));
235     }
236 
237     @Test
238     public void testIsNonVoidMethod() throws Exception {
239         final DetailAST nonVoidMethod = getNodeFromFile(TokenTypes.METHOD_DEF);
240         final DetailAST voidMethod = nonVoidMethod.getNextSibling();
241 
242         assertTrue("Invalid result: AST provided is void method",
243                 CheckUtil.isNonVoidMethod(nonVoidMethod));
244         assertFalse("Invalid result: AST provided is non void method",
245                 CheckUtil.isNonVoidMethod(voidMethod));
246     }
247 
248     @Test
249     public void testIsGetterMethod() throws Exception {
250         final DetailAST notGetterMethod = getNodeFromFile(TokenTypes.METHOD_DEF);
251         final DetailAST getterMethod = notGetterMethod.getNextSibling().getNextSibling();
252 
253         assertTrue("Invalid result: AST provided is getter method",
254                 CheckUtil.isGetterMethod(getterMethod));
255         assertFalse("Invalid result: AST provided is not getter method",
256                 CheckUtil.isGetterMethod(notGetterMethod));
257     }
258 
259     @Test
260     public void testIsSetterMethod() throws Exception {
261         final DetailAST firstClassMethod = getNodeFromFile(TokenTypes.METHOD_DEF);
262         final DetailAST setterMethod =
263                 firstClassMethod.getNextSibling().getNextSibling().getNextSibling();
264         final DetailAST notSetterMethod = setterMethod.getNextSibling();
265 
266         assertTrue("Invalid result: AST provided is setter method",
267                 CheckUtil.isSetterMethod(setterMethod));
268         assertFalse("Invalid result: AST provided is not setter method",
269                 CheckUtil.isSetterMethod(notSetterMethod));
270     }
271 
272     @Test
273     public void testGetAccessModifierFromModifiersToken() throws Exception {
274         final DetailAST privateVariable = getNodeFromFile(TokenTypes.VARIABLE_DEF);
275         final DetailAST protectedVariable = privateVariable.getNextSibling();
276         final DetailAST publicVariable = protectedVariable.getNextSibling();
277         final DetailAST packageVariable = publicVariable.getNextSibling();
278 
279         assertEquals("Invalid access modifier", AccessModifier.PRIVATE,
280                 CheckUtil.getAccessModifierFromModifiersToken(privateVariable.getFirstChild()));
281         assertEquals("Invalid access modifier", AccessModifier.PROTECTED,
282                 CheckUtil.getAccessModifierFromModifiersToken(protectedVariable.getFirstChild()));
283         assertEquals("Invalid access modifier", AccessModifier.PUBLIC,
284                 CheckUtil.getAccessModifierFromModifiersToken(publicVariable.getFirstChild()));
285         assertEquals("Invalid access modifier", AccessModifier.PACKAGE,
286                 CheckUtil.getAccessModifierFromModifiersToken(packageVariable.getFirstChild()));
287     }
288 
289     @Test
290     public void testGetFirstNode() throws Exception {
291         final DetailAST classDef = getNodeFromFile(TokenTypes.CLASS_DEF);
292 
293         assertEquals("Invalid first node", classDef.getFirstChild().getFirstChild(),
294                 CheckUtil.getFirstNode(classDef));
295     }
296 
297     @Test
298     public void testGetFirstNode1() {
299         final DetailAST child = new DetailAST();
300         child.setLineNo(5);
301         child.setColumnNo(6);
302 
303         final DetailAST root = new DetailAST();
304         root.setLineNo(5);
305         root.setColumnNo(6);
306 
307         root.addChild(child);
308 
309         assertEquals("Unexpected node", root, CheckUtil.getFirstNode(root));
310     }
311 
312     @Test
313     public void testGetFirstNode2() {
314         final DetailAST child = new DetailAST();
315         child.setLineNo(6);
316         child.setColumnNo(5);
317 
318         final DetailAST root = new DetailAST();
319         root.setLineNo(5);
320         root.setColumnNo(6);
321 
322         root.addChild(child);
323 
324         assertEquals("Unexpected node", root, CheckUtil.getFirstNode(root));
325     }
326 
327     @Test
328     public void testIsReceiverParameter() throws Exception {
329         final DetailAST objBlock = getNodeFromFile(TokenTypes.OBJBLOCK);
330         final DetailAST methodWithReceiverParameter = objBlock.getLastChild().getPreviousSibling();
331         final DetailAST receiverParameter =
332                 getNode(methodWithReceiverParameter, TokenTypes.PARAMETER_DEF);
333         final DetailAST simpleParameter =
334                 receiverParameter.getNextSibling().getNextSibling();
335 
336         assertTrue("Invalid result: parameter provided is receiver parameter",
337                 CheckUtil.isReceiverParameter(receiverParameter));
338         assertFalse("Invalid result: parameter provided is not receiver parameter",
339                 CheckUtil.isReceiverParameter(simpleParameter));
340     }
341 
342     @Test
343     public void testParseDoubleFloatingPointValues() {
344         assertEquals("Invalid parse result", -0.05,
345                 CheckUtil.parseDouble("-0.05f", TokenTypes.NUM_FLOAT), 0);
346         assertEquals("Invalid parse result", 10.0,
347                 CheckUtil.parseDouble("10.0", TokenTypes.NUM_DOUBLE), 0);
348         assertEquals("Invalid parse result", 1230,
349                 CheckUtil.parseDouble("1.23e3", TokenTypes.NUM_DOUBLE), 0);
350         assertEquals("Invalid parse result", -321,
351                 CheckUtil.parseDouble("-3.21E2", TokenTypes.NUM_DOUBLE), 0);
352         assertEquals("Invalid parse result", -0.0,
353                 CheckUtil.parseDouble("-0.0", TokenTypes.NUM_DOUBLE), 0);
354         assertEquals("Invalid parse result", Double.NaN,
355                 CheckUtil.parseDouble("NaN", TokenTypes.NUM_DOUBLE), 0);
356     }
357 
358     @Test
359     public void testParseDoubleIntegerValues() {
360         assertEquals("Invalid parse result", 0.0,
361                 CheckUtil.parseDouble("0L", TokenTypes.NUM_LONG), 0);
362         assertEquals("Invalid parse result", 0b101,
363                 CheckUtil.parseDouble("0B101", TokenTypes.NUM_INT), 0);
364         assertEquals("Invalid parse result", 289_775_941,
365                 CheckUtil.parseDouble("0b10001010001011010000101000101L", TokenTypes.NUM_LONG), 0);
366         assertEquals("Invalid parse result", 1.0,
367                 CheckUtil.parseDouble("1", TokenTypes.NUM_INT), 0);
368         assertEquals("Invalid parse result", 8.0,
369                 CheckUtil.parseDouble("8L", TokenTypes.NUM_LONG), 0);
370         assertEquals("Invalid parse result", -2.147_483_648E10,
371                 CheckUtil.parseDouble("-21474836480", TokenTypes.NUM_LONG), 0);
372         assertEquals("Invalid parse result", -2,
373                 CheckUtil.parseDouble("-2", TokenTypes.NUM_INT), 0);
374         assertEquals("Invalid parse result", -1,
375                 CheckUtil.parseDouble("0xffffffff", TokenTypes.NUM_INT), 0);
376         assertEquals("Invalid parse result", 2915.0,
377                 CheckUtil.parseDouble("0x0B63", TokenTypes.NUM_INT), 0);
378         assertEquals("Invalid parse result", 2.147_483_647E10,
379                 CheckUtil.parseDouble("21474836470", TokenTypes.NUM_LONG), 0);
380         assertEquals("Invalid parse result", 59.0,
381                 CheckUtil.parseDouble("073l", TokenTypes.NUM_LONG), 0);
382     }
383 
384     @Test
385     public void testParseClassNames() {
386         final Set<String> actual = CheckUtil.parseClassNames(
387                 "I.am.class.name.with.dot.in.the.end.", "ClassOnly", "my.Class");
388         final Set<String> expected = new HashSet<>();
389         expected.add("I.am.class.name.with.dot.in.the.end.");
390         expected.add("ClassOnly");
391         expected.add("my.Class");
392         expected.add("Class");
393         assertEquals("Result is not expected", expected, actual);
394     }
395 
396     private DetailAST getNodeFromFile(int type) throws Exception {
397         return getNode(JavaParser.parseFile(new File(getPath("InputCheckUtilTest.java")),
398             JavaParser.Options.WITH_COMMENTS), type);
399     }
400 
401     private static DetailAST getNode(DetailAST root, int type) {
402         final Optional<DetailAST> node = findTokenInAstByPredicate(root,
403             ast -> ast.getType() == type);
404 
405         if (!node.isPresent()) {
406             fail("Cannot find node of specified type: " + type);
407         }
408 
409         return node.get();
410     }
411 
412 }