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.grammar;
21
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertNotNull;
25 import static org.junit.Assert.assertTrue;
26
27 import java.io.File;
28 import java.io.InputStream;
29 import java.lang.reflect.Constructor;
30 import java.lang.reflect.InvocationTargetException;
31 import java.lang.reflect.Method;
32 import java.nio.charset.StandardCharsets;
33 import java.util.Arrays;
34
35 import org.junit.Test;
36
37 import antlr.NoViableAltForCharException;
38 import antlr.ParserSharedInputState;
39 import antlr.SemanticException;
40 import antlr.TokenBuffer;
41 import com.puppycrawl.tools.checkstyle.AbstractTreeTestSupport;
42 import com.puppycrawl.tools.checkstyle.AstTreeStringPrinter;
43 import com.puppycrawl.tools.checkstyle.JavaParser;
44 import com.puppycrawl.tools.checkstyle.api.FileText;
45
46 public class AstRegressionTest extends AbstractTreeTestSupport {
47
48 @Override
49 protected String getPackageLocation() {
50 return "com/puppycrawl/tools/checkstyle/grammar";
51 }
52
53 @Test
54 public void testClassAstTree1() throws Exception {
55 verifyAst(getPath("InputRegressionJavaClass1Ast.txt"),
56 getPath("InputRegressionJavaClass1.java"));
57 }
58
59 @Test
60 public void testClassAstTree2() throws Exception {
61 verifyAst(getPath("InputRegressionJavaClass2Ast.txt"),
62 getPath("InputRegressionJavaClass2.java"));
63 }
64
65 @Test
66 public void testJava8ClassAstTree1() throws Exception {
67 verifyAst(getPath("InputRegressionJava8Class1Ast.txt"),
68 getPath("InputRegressionJava8Class1.java"));
69 }
70
71 @Test
72 public void testInputSemicolonBetweenImports() throws Exception {
73 verifyAst(getPath("InputSemicolonBetweenImportsAst.txt"),
74 getNonCompilablePath("InputSemicolonBetweenImports.java"));
75 }
76
77 @Test
78 public void testInterfaceAstTree1() throws Exception {
79 verifyAst(getPath("InputRegressionJavaInterface1Ast.txt"),
80 getPath("InputRegressionJavaInterface1.java"));
81 }
82
83 @Test
84 public void testInterfaceAstTree2() throws Exception {
85 verifyAst(getPath("InputRegressionJavaInterface2Ast.txt"),
86 getPath("InputRegressionJavaInterface2.java"));
87 }
88
89 @Test
90 public void testJava8InterfaceAstTree1() throws Exception {
91 verifyAst(getPath("InputRegressionJava8Interface1Ast.txt"),
92 getPath("InputRegressionJava8Interface1.java"));
93 }
94
95 @Test
96 public void testEnumAstTree1() throws Exception {
97 verifyAst(getPath("InputRegressionJavaEnum1Ast.txt"),
98 getPath("InputRegressionJavaEnum1.java"));
99 }
100
101 @Test
102 public void testEnumAstTree2() throws Exception {
103 verifyAst(getPath("InputRegressionJavaEnum2Ast.txt"),
104 getPath("InputRegressionJavaEnum2.java"));
105 }
106
107 @Test
108 public void testAnnotationAstTree1() throws Exception {
109 verifyAst(getPath("InputRegressionJavaAnnotation1Ast.txt"),
110 getPath("InputRegressionJavaAnnotation1.java"));
111 }
112
113 @Test
114 public void testTypecast() throws Exception {
115 verifyAst(getPath("InputRegressionJavaTypecastAst.txt"),
116 getPath("InputRegressionJavaTypecast.java"));
117 }
118
119 @Test
120 public void testUnusedConstructors1() throws Exception {
121 final Class<?> clss = GeneratedJavaLexer.class;
122 final Constructor<?> constructor = clss.getDeclaredConstructor(InputStream.class);
123
124 assertNotNull("InputStream should not be null",
125 constructor.newInstance(new Object[] {null}));
126 }
127
128 @Test
129 public void testUnusedConstructors2() throws Exception {
130 final Class<?> clss = GeneratedJavaRecognizer.class;
131 final Constructor<?> constructor = clss
132 .getDeclaredConstructor(ParserSharedInputState.class);
133
134 assertNotNull("ParserSharedInputState should not be null",
135 constructor.newInstance(new Object[] {null}));
136 }
137
138 @Test
139 public void testUnusedConstructors3() throws Exception {
140 final Class<?> clss = GeneratedJavaRecognizer.class;
141 final Constructor<?> constructor = clss.getDeclaredConstructor(TokenBuffer.class);
142
143 assertNotNull("TokenBuffer should not be null",
144 constructor.newInstance(new Object[] {null}));
145 }
146
147 @Test
148 public void testCustomAstTree() throws Exception {
149 verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "\t");
150 verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "\r\n");
151 verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "\n");
152 verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "\r\r");
153 verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "\r");
154 verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "\u000c\f");
155 verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "// \n",
156 JavaParser.Options.WITH_COMMENTS);
157 verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "// \r",
158 JavaParser.Options.WITH_COMMENTS);
159 verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "// \r\n",
160 JavaParser.Options.WITH_COMMENTS);
161 verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "/* \n */",
162 JavaParser.Options.WITH_COMMENTS);
163 verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "/* \r\n */",
164 JavaParser.Options.WITH_COMMENTS);
165 verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "/* \r" + "\u0000\u0000" + " */",
166 JavaParser.Options.WITH_COMMENTS);
167 }
168
169 @Test
170 public void testNewlineCr() throws Exception {
171 verifyAst(getPath("InputNewlineCrAtEndOfFileAst.txt"),
172 getPath("InputAstRegressionNewlineCrAtEndOfFile.java"),
173 JavaParser.Options.WITH_COMMENTS);
174 }
175
176 @Test
177 public void testImpossibleExceptions() throws Exception {
178 AssertGeneratedJavaLexer.verifyFail("mSTD_ESC", 'a');
179 AssertGeneratedJavaLexer.verifyFail("mSTD_ESC", '0', (char) 0xFFFF);
180 AssertGeneratedJavaLexer.verifyFail("mSTD_ESC", '4', (char) 0xFFFF);
181 AssertGeneratedJavaLexer.verifyFail("mCHAR_LITERAL", '\'', '\'');
182 AssertGeneratedJavaLexer.verifyFail("mHEX_DIGIT", ';');
183 AssertGeneratedJavaLexer.verifyFail("mEXPONENT", ';');
184 AssertGeneratedJavaLexer.verifyFail("mBINARY_DIGIT", '2');
185 AssertGeneratedJavaLexer.verifyFail("mSIGNED_INTEGER", 'a');
186 AssertGeneratedJavaLexer.verifyFail("mID_START", '%');
187 AssertGeneratedJavaLexer.verifyFail("mID_START", (char) 0xBF);
188 AssertGeneratedJavaLexer.verifyFailNoGuessing("mID_START", (char) 0xBF);
189 AssertGeneratedJavaLexer.verifyFail("mID_PART", '%');
190 AssertGeneratedJavaLexer.verifyFail("mID_PART", (char) 0xBF);
191 AssertGeneratedJavaLexer.verifyFailNoGuessing("mID_PART", (char) 0xBF);
192 AssertGeneratedJavaLexer.verifyFail("mESC", '\\', 'a');
193 AssertGeneratedJavaLexer.verifyFail("mLONG_LITERAL", '0', ';');
194 AssertGeneratedJavaLexer.verifyFail("mLONG_LITERAL", '1', ';');
195 AssertGeneratedJavaLexer.verifyFail("mLONG_LITERAL", ';');
196 AssertGeneratedJavaLexer.verifyFail("mINT_LITERAL", ';');
197 AssertGeneratedJavaLexer.verifyFail("mHEX_DOUBLE_LITERAL", '0', 'a');
198 AssertGeneratedJavaLexer.verifyFail("mHEX_FLOAT_LITERAL", '0', 'a');
199 }
200
201 @Test
202 public void testImpossibleValid() throws Exception {
203 AssertGeneratedJavaLexer.verifyPass("mSTD_ESC", 'n');
204 AssertGeneratedJavaLexer.verifyPass("mELLIPSIS", '.', '.', '.');
205 AssertGeneratedJavaLexer.verifyPass("mDOT", '.');
206 AssertGeneratedJavaLexer.verifyPass("mBINARY_EXPONENT", 'p', '0', ';');
207 AssertGeneratedJavaLexer.verifyPass("mHEX_DIGIT", '0');
208 AssertGeneratedJavaLexer.verifyPass("mEXPONENT", 'e', '0', ';');
209 AssertGeneratedJavaLexer.verifyPass("mBINARY_DIGIT", '0');
210 AssertGeneratedJavaLexer.verifyPass("mSIGNED_INTEGER", '0', ';');
211 AssertGeneratedJavaLexer.verifyPass("mWS", ' ', ';');
212 AssertGeneratedJavaLexer.verifyPass("mID_START", '$');
213 AssertGeneratedJavaLexer.verifyPass("mID_PART", '$');
214 AssertGeneratedJavaLexer.verifyPass("mESC", '\\', '\\');
215 AssertGeneratedJavaLexer.verifyPass("mLONG_LITERAL", '1', 'L');
216 AssertGeneratedJavaLexer.verifyPass("mINT_LITERAL", '0', ';');
217 AssertGeneratedJavaLexer.verifyPass("mFLOAT_LITERAL", '0', 'f');
218 AssertGeneratedJavaLexer.verifyPass("mDOUBLE_LITERAL", '0', 'd');
219 AssertGeneratedJavaLexer.verifyPass("mHEX_FLOAT_LITERAL", '0', 'x', '2', '_', '4', '.',
220 '4', '4', '.', '4', 'P', '4', ';');
221 AssertGeneratedJavaLexer.verifyPass("mHEX_DOUBLE_LITERAL", '0', 'x', '2', '_', '4', '.',
222 '4', '4', '.', '4', 'P', '4', 'D', ';');
223 }
224
225 private static void verifyAstRaw(String expectedTextPrintFileName, String actualJava)
226 throws Exception {
227 verifyAstRaw(expectedTextPrintFileName, actualJava, JavaParser.Options.WITHOUT_COMMENTS);
228 }
229
230 private static void verifyAstRaw(String expectedTextPrintFileName, String actualJava,
231 JavaParser.Options withComments) throws Exception {
232 final File expectedFile = new File(expectedTextPrintFileName);
233 final String expectedContents = new FileText(expectedFile, System.getProperty(
234 "file.encoding", StandardCharsets.UTF_8.name()))
235 .getFullText().toString().replace("\r", "");
236
237 final FileText actualFileContents = new FileText(new File(""),
238 Arrays.asList(actualJava.split("\\n|\\r\\n?")));
239 final String actualContents = AstTreeStringPrinter.printAst(actualFileContents,
240 withComments);
241
242 assertEquals("Generated AST from Java code should match pre-defined AST", expectedContents,
243 actualContents);
244 }
245
246 private static final class AssertGeneratedJavaLexer extends GeneratedJavaLexer {
247
248 private int laPosition;
249 private char[] laResults;
250
251 private AssertGeneratedJavaLexer() {
252 super((InputStream) null);
253 }
254
255 public static void verifyFailNoGuessing(String methodName, char... laResults)
256 throws Exception {
257 verify(methodName, false, 0, laResults);
258 }
259
260 public static void verifyPass(String methodName, char... laResults) throws Exception {
261 verify(methodName, true, 1, laResults);
262 }
263
264 public static void verifyFail(String methodName, char... laResults) throws Exception {
265 verify(methodName, false, 1, laResults);
266 }
267
268 private static void verify(String methodName, boolean expectPass, int guessing,
269 char... laResults) throws Exception {
270 final AssertGeneratedJavaLexer instance = new AssertGeneratedJavaLexer();
271 instance.laPosition = 0;
272 instance.laResults = laResults.clone();
273 instance.inputState.guessing = guessing;
274
275 final Method method = GeneratedJavaLexer.class.getDeclaredMethod(methodName,
276 boolean.class);
277 boolean exception;
278
279 try {
280 method.invoke(instance, true);
281 exception = false;
282 }
283 catch (InvocationTargetException ex) {
284 if (expectPass) {
285 throw ex;
286 }
287
288 final Class<?> clss = ex.getTargetException().getClass();
289 if (clss != NoViableAltForCharException.class
290 && clss != SemanticException.class) {
291 throw ex;
292 }
293 exception = true;
294 }
295
296 if (expectPass) {
297 assertFalse("Call to GeneratedJavaLexer." + methodName
298 + " resulted in an exception", exception);
299 }
300 else {
301 assertTrue("Call to GeneratedJavaLexer." + methodName
302 + " did not result in an exception", exception);
303 }
304 }
305
306 @Override
307 public char LA(int i) {
308 return laResults[laPosition + i - 1];
309 }
310
311 @Override
312 public void consume() {
313 laPosition++;
314 }
315
316 @Override
317 public int mark() {
318 return 1;
319 }
320
321 }
322
323 }