| //////////////////////////////////////////////////////////////////////////////// |
| // checkstyle: Checks Java source code for adherence to a set of rules. |
| // Copyright (C) 2001-2017 the original author or authors. |
| // |
| // This library is free software; you can redistribute it and/or |
| // modify it under the terms of the GNU Lesser General Public |
| // License as published by the Free Software Foundation; either |
| // version 2.1 of the License, or (at your option) any later version. |
| // |
| // This library is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| // Lesser General Public License for more details. |
| // |
| // You should have received a copy of the GNU Lesser General Public |
| // License along with this library; if not, write to the Free Software |
| // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| package com.puppycrawl.tools.checkstyle.grammars; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import java.io.File; |
| import java.io.InputStream; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.nio.charset.StandardCharsets; |
| import java.util.Arrays; |
| |
| import org.junit.Test; |
| |
| import antlr.NoViableAltForCharException; |
| import antlr.ParserSharedInputState; |
| import antlr.SemanticException; |
| import antlr.TokenBuffer; |
| import com.puppycrawl.tools.checkstyle.AbstractTreeTestSupport; |
| import com.puppycrawl.tools.checkstyle.AstTreeStringPrinter; |
| import com.puppycrawl.tools.checkstyle.api.FileText; |
| |
| public class AstRegressionTest extends AbstractTreeTestSupport { |
| @Override |
| protected String getPackageLocation() { |
| return "com/puppycrawl/tools/checkstyle/grammars"; |
| } |
| |
| @Test |
| public void testClassAstTree1() throws Exception { |
| verifyAst(getPath("InputRegressionJavaClass1Ast.txt"), |
| getPath("InputRegressionJavaClass1.java")); |
| } |
| |
| @Test |
| public void testClassAstTree2() throws Exception { |
| verifyAst(getPath("InputRegressionJavaClass2Ast.txt"), |
| getPath("InputRegressionJavaClass2.java")); |
| } |
| |
| @Test |
| public void testJava8ClassAstTree1() throws Exception { |
| verifyAst(getPath("InputRegressionJava8Class1Ast.txt"), |
| getPath("InputRegressionJava8Class1.java")); |
| } |
| |
| @Test |
| public void testInterfaceAstTree1() throws Exception { |
| verifyAst(getPath("InputRegressionJavaInterface1Ast.txt"), |
| getPath("InputRegressionJavaInterface1.java")); |
| } |
| |
| @Test |
| public void testInterfaceAstTree2() throws Exception { |
| verifyAst(getPath("InputRegressionJavaInterface2Ast.txt"), |
| getPath("InputRegressionJavaInterface2.java")); |
| } |
| |
| @Test |
| public void testJava8InterfaceAstTree1() throws Exception { |
| verifyAst(getPath("InputRegressionJava8Interface1Ast.txt"), |
| getPath("InputRegressionJava8Interface1.java")); |
| } |
| |
| @Test |
| public void testEnumAstTree1() throws Exception { |
| verifyAst(getPath("InputRegressionJavaEnum1Ast.txt"), |
| getPath("InputRegressionJavaEnum1.java")); |
| } |
| |
| @Test |
| public void testEnumAstTree2() throws Exception { |
| verifyAst(getPath("InputRegressionJavaEnum2Ast.txt"), |
| getPath("InputRegressionJavaEnum2.java")); |
| } |
| |
| @Test |
| public void testAnnotationAstTree1() throws Exception { |
| verifyAst(getPath("InputRegressionJavaAnnotation1Ast.txt"), |
| getPath("InputRegressionJavaAnnotation1.java")); |
| } |
| |
| @Test |
| public void testUnusedConstructors1() throws Exception { |
| final Class<?> clss = GeneratedJavaLexer.class; |
| final Constructor<?> constructor = clss.getDeclaredConstructor(InputStream.class); |
| |
| assertNotNull("InputStream should not be null", |
| constructor.newInstance((InputStream) null)); |
| } |
| |
| @Test |
| public void testUnusedConstructors2() throws Exception { |
| final Class<?> clss = GeneratedJavaRecognizer.class; |
| final Constructor<?> constructor = clss |
| .getDeclaredConstructor(ParserSharedInputState.class); |
| |
| assertNotNull("ParserSharedInputState should not be null", |
| constructor.newInstance((ParserSharedInputState) null)); |
| } |
| |
| @Test |
| public void testUnusedConstructors3() throws Exception { |
| final Class<?> clss = GeneratedJavaRecognizer.class; |
| final Constructor<?> constructor = clss.getDeclaredConstructor(TokenBuffer.class); |
| |
| assertNotNull("TokenBuffer should not be null", |
| constructor.newInstance((TokenBuffer) null)); |
| } |
| |
| @Test |
| public void testCustomAstTree() throws Exception { |
| verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "\t"); |
| verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "\r\n"); |
| verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "\n"); |
| verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "\r\r"); |
| verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "\r"); |
| verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "\u000c\f"); |
| verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "// \n", |
| AstTreeStringPrinter.PrintOptions.WITH_COMMENTS); |
| verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "// \r", |
| AstTreeStringPrinter.PrintOptions.WITH_COMMENTS); |
| verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "// \r\n", |
| AstTreeStringPrinter.PrintOptions.WITH_COMMENTS); |
| verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "/* \n */", |
| AstTreeStringPrinter.PrintOptions.WITH_COMMENTS); |
| verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "/* \r\n */", |
| AstTreeStringPrinter.PrintOptions.WITH_COMMENTS); |
| verifyAstRaw(getPath("InputRegressionEmptyAst.txt"), "/* \r" + "\u0000\u0000" + " */", |
| AstTreeStringPrinter.PrintOptions.WITH_COMMENTS); |
| } |
| |
| @Test |
| public void testNewlineCr() throws Exception { |
| verifyAst(getPath("InputNewlineCrAtEndOfFileAst.txt"), |
| getPath("InputAstRegressionNewlineCrAtEndOfFile.java"), |
| AstTreeStringPrinter.PrintOptions.WITH_COMMENTS); |
| } |
| |
| @Test |
| public void testImpossibleExceptions() throws Exception { |
| AssertGeneratedJavaLexer.verifyFail("mSTD_ESC", 'a'); |
| AssertGeneratedJavaLexer.verifyFail("mSTD_ESC", '0', (char) 0xFFFF); |
| AssertGeneratedJavaLexer.verifyFail("mSTD_ESC", '4', (char) 0xFFFF); |
| AssertGeneratedJavaLexer.verifyFail("mCHAR_LITERAL", '\'', '\''); |
| AssertGeneratedJavaLexer.verifyFail("mHEX_DIGIT", ';'); |
| AssertGeneratedJavaLexer.verifyFail("mEXPONENT", ';'); |
| AssertGeneratedJavaLexer.verifyFail("mBINARY_DIGIT", '2'); |
| AssertGeneratedJavaLexer.verifyFail("mSIGNED_INTEGER", 'a'); |
| AssertGeneratedJavaLexer.verifyFail("mID_START", '%'); |
| AssertGeneratedJavaLexer.verifyFail("mID_START", (char) 0xBF); |
| AssertGeneratedJavaLexer.verifyFailNoGuessing("mID_START", (char) 0xBF); |
| AssertGeneratedJavaLexer.verifyFail("mID_PART", '%'); |
| AssertGeneratedJavaLexer.verifyFail("mID_PART", (char) 0xBF); |
| AssertGeneratedJavaLexer.verifyFailNoGuessing("mID_PART", (char) 0xBF); |
| AssertGeneratedJavaLexer.verifyFail("mESC", '\\', 'a'); |
| AssertGeneratedJavaLexer.verifyFail("mLONG_LITERAL", '0', ';'); |
| AssertGeneratedJavaLexer.verifyFail("mLONG_LITERAL", '1', ';'); |
| AssertGeneratedJavaLexer.verifyFail("mLONG_LITERAL", ';'); |
| AssertGeneratedJavaLexer.verifyFail("mINT_LITERAL", ';'); |
| AssertGeneratedJavaLexer.verifyFail("mHEX_DOUBLE_LITERAL", '0', 'a'); |
| AssertGeneratedJavaLexer.verifyFail("mHEX_FLOAT_LITERAL", '0', 'a'); |
| } |
| |
| @Test |
| public void testImpossibleValid() throws Exception { |
| AssertGeneratedJavaLexer.verifyPass("mSTD_ESC", 'n'); |
| AssertGeneratedJavaLexer.verifyPass("mELLIPSIS", '.', '.', '.'); |
| AssertGeneratedJavaLexer.verifyPass("mDOT", '.'); |
| AssertGeneratedJavaLexer.verifyPass("mBINARY_EXPONENT", 'p', '0', ';'); |
| AssertGeneratedJavaLexer.verifyPass("mHEX_DIGIT", '0'); |
| AssertGeneratedJavaLexer.verifyPass("mEXPONENT", 'e', '0', ';'); |
| AssertGeneratedJavaLexer.verifyPass("mBINARY_DIGIT", '0'); |
| AssertGeneratedJavaLexer.verifyPass("mSIGNED_INTEGER", '0', ';'); |
| AssertGeneratedJavaLexer.verifyPass("mWS", ' ', ';'); |
| AssertGeneratedJavaLexer.verifyPass("mID_START", '$'); |
| AssertGeneratedJavaLexer.verifyPass("mID_PART", '$'); |
| AssertGeneratedJavaLexer.verifyPass("mESC", '\\', '\\'); |
| AssertGeneratedJavaLexer.verifyPass("mLONG_LITERAL", '1', 'L'); |
| AssertGeneratedJavaLexer.verifyPass("mINT_LITERAL", '0', ';'); |
| AssertGeneratedJavaLexer.verifyPass("mFLOAT_LITERAL", '0', 'f'); |
| AssertGeneratedJavaLexer.verifyPass("mDOUBLE_LITERAL", '0', 'd'); |
| AssertGeneratedJavaLexer.verifyPass("mHEX_FLOAT_LITERAL", '0', 'x', '2', '_', '4', '.', |
| '4', '4', '.', '4', 'P', '4', ';'); |
| AssertGeneratedJavaLexer.verifyPass("mHEX_DOUBLE_LITERAL", '0', 'x', '2', '_', '4', '.', |
| '4', '4', '.', '4', 'P', '4', 'D', ';'); |
| } |
| |
| private static void verifyAstRaw(String expectedTextPrintFileName, String actualJava) |
| throws Exception { |
| verifyAstRaw(expectedTextPrintFileName, actualJava, |
| AstTreeStringPrinter.PrintOptions.WITHOUT_COMMENTS); |
| } |
| |
| private static void verifyAstRaw(String expectedTextPrintFileName, String actualJava, |
| AstTreeStringPrinter.PrintOptions withComments) throws Exception { |
| final File expectedFile = new File(expectedTextPrintFileName); |
| final String expectedContents = new FileText(expectedFile, System.getProperty( |
| "file.encoding", StandardCharsets.UTF_8.name())) |
| .getFullText().toString().replace("\r", ""); |
| |
| final FileText actualFileContents = new FileText(new File(""), |
| Arrays.asList(actualJava.split("\\n|\\r\\n?"))); |
| final String actualContents = AstTreeStringPrinter.printAst(actualFileContents, |
| withComments); |
| |
| assertEquals("Generated AST from Java code should match pre-defined AST", expectedContents, |
| actualContents); |
| } |
| |
| private static final class AssertGeneratedJavaLexer extends GeneratedJavaLexer { |
| private int laPosition; |
| private char[] laResults; |
| |
| private AssertGeneratedJavaLexer() { |
| super((InputStream) null); |
| } |
| |
| public static void verifyFailNoGuessing(String methodName, char... laResults) |
| throws Exception { |
| verify(methodName, false, 0, laResults); |
| } |
| |
| public static void verifyPass(String methodName, char... laResults) throws Exception { |
| verify(methodName, true, 1, laResults); |
| } |
| |
| public static void verifyFail(String methodName, char... laResults) throws Exception { |
| verify(methodName, false, 1, laResults); |
| } |
| |
| private static void verify(String methodName, boolean expectPass, int guessing, |
| char... laResults) throws Exception { |
| final AssertGeneratedJavaLexer instance = new AssertGeneratedJavaLexer(); |
| instance.laPosition = 0; |
| instance.laResults = laResults.clone(); |
| instance.inputState.guessing = guessing; |
| |
| final Method method = GeneratedJavaLexer.class.getDeclaredMethod(methodName, |
| boolean.class); |
| boolean exception; |
| |
| try { |
| method.invoke(instance, true); |
| exception = false; |
| } |
| catch (InvocationTargetException ex) { |
| if (expectPass) { |
| throw ex; |
| } |
| |
| final Class<?> clss = ex.getTargetException().getClass(); |
| if (clss != NoViableAltForCharException.class |
| && clss != SemanticException.class) { |
| throw ex; |
| } |
| exception = true; |
| } |
| |
| if (expectPass) { |
| assertFalse("Call to GeneratedJavaLexer." + methodName |
| + " resulted in an exception", exception); |
| } |
| else { |
| assertTrue("Call to GeneratedJavaLexer." + methodName |
| + " did not result in an exception", exception); |
| } |
| } |
| |
| @Override |
| public char LA(int i) { |
| return laResults[laPosition + i - 1]; |
| } |
| |
| @Override |
| public void consume() { |
| laPosition++; |
| } |
| |
| @Override |
| public int mark() { |
| return 1; |
| } |
| } |
| } |