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;
21  
22  import static org.junit.Assert.assertArrayEquals;
23  import static org.junit.Assert.assertEquals;
24  import static org.junit.Assert.assertFalse;
25  import static org.junit.Assert.assertNull;
26  import static org.junit.Assert.assertTrue;
27  
28  import java.io.File;
29  import java.util.ArrayList;
30  import java.util.Arrays;
31  import java.util.List;
32  import java.util.Optional;
33  
34  import org.junit.Assert;
35  import org.junit.Test;
36  
37  import antlr.NoViableAltException;
38  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
39  import com.puppycrawl.tools.checkstyle.api.DetailAST;
40  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
41  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
42  
43  public class JavaParserTest extends AbstractModuleTestSupport {
44  
45      @Override
46      protected String getPackageLocation() {
47          return "com/puppycrawl/tools/checkstyle/javaparser";
48      }
49  
50      @Test
51      public void testIsProperUtilsClass() throws ReflectiveOperationException {
52          assertTrue("Constructor is not private", TestUtil.isUtilsClassHasPrivateConstructor(
53              JavaParser.class, false));
54      }
55  
56      @Test
57      public void testNullRootWithComments() {
58          assertNull("Invalid return root", JavaParser.appendHiddenCommentNodes(null));
59      }
60  
61      @Test
62      public void testAppendHiddenBlockCommentNodes() throws Exception {
63          final DetailAST root =
64              JavaParser.parseFile(new File(getPath("InputJavaParserHiddenComments.java")),
65                  JavaParser.Options.WITH_COMMENTS);
66  
67          final Optional<DetailAST> blockComment = TestUtil.findTokenInAstByPredicate(root,
68              ast -> ast.getType() == TokenTypes.BLOCK_COMMENT_BEGIN);
69  
70          assertTrue("Block comment should be present", blockComment.isPresent());
71  
72          final DetailAST comment = blockComment.get();
73  
74          assertEquals("Unexpected line number", 3, comment.getLineNo());
75          assertEquals("Unexpected column number", 0, comment.getColumnNo());
76          assertEquals("Unexpected comment content", "/*", comment.getText());
77  
78          final DetailAST commentContent = comment.getFirstChild();
79          final DetailAST commentEnd = comment.getLastChild();
80  
81          assertEquals("Unexpected line number", 3, commentContent.getLineNo());
82          assertEquals("Unexpected column number", 2, commentContent.getColumnNo());
83          assertEquals("Unexpected line number", 9, commentEnd.getLineNo());
84          assertEquals("Unexpected column number", 1, commentEnd.getColumnNo());
85      }
86  
87      @Test
88      public void testAppendHiddenSingleLineCommentNodes() throws Exception {
89          final DetailAST root =
90              JavaParser.parseFile(new File(getPath("InputJavaParserHiddenComments.java")),
91                  JavaParser.Options.WITH_COMMENTS);
92  
93          final Optional<DetailAST> singleLineComment = TestUtil.findTokenInAstByPredicate(root,
94              ast -> ast.getType() == TokenTypes.SINGLE_LINE_COMMENT);
95          assertTrue("Single line comment should be present", singleLineComment.isPresent());
96  
97          final DetailAST comment = singleLineComment.get();
98  
99          assertEquals("Unexpected line number", 13, comment.getLineNo());
100         assertEquals("Unexpected column number", 0, comment.getColumnNo());
101         assertEquals("Unexpected comment content", "//", comment.getText());
102 
103         final DetailAST commentContent = comment.getFirstChild();
104 
105         assertEquals("Unexpected token type", TokenTypes.COMMENT_CONTENT, commentContent.getType());
106         assertEquals("Unexpected line number", 13, commentContent.getLineNo());
107         assertEquals("Unexpected column number", 2, commentContent.getColumnNo());
108         assertTrue("Unexpected comment content",
109             commentContent.getText().startsWith(" inline comment"));
110     }
111 
112     @Test
113     public void testAppendHiddenSingleLineCommentNodes2() throws Exception {
114         final DetailAST root =
115             JavaParser.parseFile(new File(getPath("InputJavaParserHiddenComments2.java")),
116                 JavaParser.Options.WITH_COMMENTS);
117 
118         final Optional<DetailAST> singleLineComment = TestUtil.findTokenInAstByPredicate(root,
119             ast -> ast.getType() == TokenTypes.SINGLE_LINE_COMMENT);
120         assertTrue("Single line comment should be present", singleLineComment.isPresent());
121 
122         final DetailAST comment = singleLineComment.get();
123 
124         assertEquals("Unexpected line number", 1, comment.getLineNo());
125         assertEquals("Unexpected column number", 4, comment.getColumnNo());
126         assertEquals("Unexpected comment content", "//", comment.getText());
127 
128         final DetailAST commentContent = comment.getFirstChild();
129 
130         assertEquals("Unexpected token type", TokenTypes.COMMENT_CONTENT, commentContent.getType());
131         assertEquals("Unexpected line number", 1, commentContent.getLineNo());
132         assertEquals("Unexpected column number", 6, commentContent.getColumnNo());
133         assertTrue("Unexpected comment content",
134             commentContent.getText().startsWith(" indented comment"));
135     }
136 
137     @Test
138     public void testDontAppendCommentNodes() throws Exception {
139         final DetailAST root =
140             JavaParser.parseFile(new File(getPath("InputJavaParserHiddenComments.java")),
141                 JavaParser.Options.WITHOUT_COMMENTS);
142 
143         final Optional<DetailAST> singleLineComment = TestUtil.findTokenInAstByPredicate(root,
144             ast -> ast.getType() == TokenTypes.SINGLE_LINE_COMMENT);
145         assertFalse("Single line comment should be present", singleLineComment.isPresent());
146     }
147 
148     @Test
149     public void testParseException() throws Exception {
150         final File input = new File(getNonCompilablePath("InputJavaParser.java"));
151         try {
152             JavaParser.parseFile(input, JavaParser.Options.WITH_COMMENTS);
153             Assert.fail("exception expected");
154         }
155         catch (CheckstyleException ex) {
156             assertEquals("Invalid exception message",
157                     CheckstyleException.class.getName()
158                             + ": NoViableAltException occurred while parsing file "
159                             + input.getAbsolutePath() + ".",
160                     ex.toString());
161             Assert.assertSame("Invalid class",
162                     NoViableAltException.class, ex.getCause().getClass());
163             assertEquals("Invalid exception message",
164                     input.getAbsolutePath() + ":2:1: unexpected token: classD",
165                     ex.getCause().toString());
166         }
167     }
168 
169     @Test
170     public void testComments() throws Exception {
171         final DetailAST root =
172             JavaParser.parseFile(new File(getPath("InputJavaParserHiddenComments3.java")),
173                 JavaParser.Options.WITH_COMMENTS);
174         final CountComments counter = new CountComments(root);
175 
176         assertArrayEquals("Invalid line comments",
177                 Arrays.asList("1,4", "6,4", "9,0").toArray(),
178                 counter.lineComments.toArray());
179         assertArrayEquals("Invalid block comments",
180                 Arrays.asList("5,4", "8,0").toArray(),
181                 counter.blockComments.toArray());
182     }
183 
184     private static final class CountComments {
185         private final List<String> lineComments = new ArrayList<>();
186         private final List<String> blockComments = new ArrayList<>();
187 
188         /* package */ CountComments(DetailAST root) {
189             forEachChild(root);
190         }
191 
192         private void forEachChild(DetailAST root) {
193             for (DetailAST ast = root; ast != null; ast = ast.getNextSibling()) {
194                 if (ast.getType() == TokenTypes.SINGLE_LINE_COMMENT) {
195                     lineComments.add(ast.getLineNo() + "," + ast.getColumnNo());
196                 }
197                 else if (ast.getType() == TokenTypes.BLOCK_COMMENT_BEGIN) {
198                     blockComments.add(ast.getLineNo() + "," + ast.getColumnNo());
199                 }
200 
201                 forEachChild(ast.getFirstChild());
202             }
203         }
204     }
205 
206 }