/** * Copyright (c) 2005-2013 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ package org.python.pydev.parser; import java.io.File; import java.util.Iterator; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.python.pydev.core.IGrammarVersionProvider; import org.python.pydev.core.IPythonNature; import org.python.pydev.core.MisconfigurationException; import org.python.pydev.parser.PyParser.ParserInfo; import org.python.pydev.parser.jython.ParseException; import org.python.pydev.parser.jython.SimpleNode; import org.python.pydev.parser.jython.Token; import org.python.pydev.parser.jython.TokenMgrError; import org.python.pydev.shared_core.callbacks.ICallback; import org.python.pydev.shared_core.io.FileUtils; import org.python.pydev.shared_core.parsing.BaseParser.ParseOutput; import org.python.pydev.shared_core.structure.Tuple; import junit.framework.TestCase; public class PyParserTestBase extends TestCase { protected static PyParser parser; private static int defaultVersion; protected static IGrammarVersionProvider versionProvider = new IGrammarVersionProvider() { @Override public int getGrammarVersion() { return defaultVersion; } @Override public AdditionalGrammarVersionsToCheck getAdditionalGrammarVersions() throws MisconfigurationException { return null; } }; /** * @param defaultVersion the defaultVersion to set */ protected static void setDefaultVersion(int defaultVersion) { PyParserTestBase.defaultVersion = defaultVersion; } /** * @return the defaultVersion */ protected static int getDefaultVersion() { return defaultVersion; } @Override protected void setUp() throws Exception { PyParser.ACCEPT_NULL_INPUT_EDITOR = true; PyParser.ENABLE_TRACING = true; ParseException.verboseExceptions = true; parser = new PyParser(versionProvider); setDefaultVersion(IPythonNature.LATEST_GRAMMAR_VERSION); super.setUp(); } @Override protected void tearDown() throws Exception { PyParser.ACCEPT_NULL_INPUT_EDITOR = false; PyParser.ENABLE_TRACING = false; super.tearDown(); } /** * @param s * @return */ protected static SimpleNode parseLegalDocStr(String s, Object... additionalErrInfo) { Document doc = new Document(s); //by default always use the last version for parsing return parseLegalDoc(doc, additionalErrInfo, parser); } protected SimpleNode parseLegalDoc(IDocument doc, Object[] additionalErrInfo) { return parseLegalDoc(doc, additionalErrInfo, parser); } protected Throwable parseILegalDocStr(String s) { return parseILegalDoc(new Document(s), true); } protected Throwable parseILegalDocStrWithoutTree(String s) { return parseILegalDoc(new Document(s), false); } protected Throwable parseILegalDoc(IDocument doc) { return parseILegalDoc(doc, true); } protected Throwable parseILegalDoc(IDocument doc, boolean generateTree) { ParseOutput objects; try { objects = PyParser.reparseDocument(new ParserInfo(doc, parser.getGrammarVersion(), generateTree, null)); } catch (MisconfigurationException e) { throw new RuntimeException(e); } Throwable err = objects.error; if (err == null) { fail("Expected a ParseException and the doc was successfully parsed."); } if (!(err instanceof ParseException) && !(err instanceof TokenMgrError)) { fail("Expected a ParseException and received:" + err.getClass()); } return err; } protected Tuple<SimpleNode, Throwable> parseILegalDocSuccessfully(String doc) { ParseOutput ret = parseILegalDocSuccessfully(new Document(doc)); return new Tuple<SimpleNode, Throwable>((SimpleNode) ret.ast, ret.error); } protected ParseOutput parseILegalDocSuccessfully(IDocument doc) { parser.setDocument(doc, false, null); ParseOutput objects = parser.reparseDocument(); Throwable err = objects.error; if (err == null) { fail("Expected a ParseException and the doc was successfully parsed."); } if (!(err instanceof ParseException) && !(err instanceof TokenMgrError)) { fail("Expected a ParseException and received:" + err.getClass()); } if (objects.ast == null) { fail("Expected the ast to be generated with the parse. Error: " + objects.error.getMessage()); } return objects; } protected void parseLegalDocStrWithoutTree(String s, Object... additionalErrInfo) { try { parseLegalDoc(new Document(s), additionalErrInfo, parser.getGrammarVersion(), false); } catch (MisconfigurationException e) { throw new RuntimeException(e); } } protected static SimpleNode parseLegalDoc(IDocument doc, Object[] additionalErrInfo, PyParser parser) { try { return parseLegalDoc(doc, additionalErrInfo, parser.getGrammarVersion(), true); } catch (MisconfigurationException e) { throw new RuntimeException(e); } } /** * @param additionalErrInfo can be used to add additional errors to the fail message if the doc is not parseable * @param parser the parser to be used to do the parsing. */ protected static SimpleNode parseLegalDoc(IDocument doc, Object[] additionalErrInfo, int grammarVersion, boolean generateTree) { ParseOutput objects = PyParser.reparseDocument(new ParserInfo(doc, grammarVersion, generateTree, null)); Object err = objects.error; if (err != null) { String s = ""; for (int i = 0; i < additionalErrInfo.length; i++) { s += additionalErrInfo[i]; } if (err instanceof ParseException) { ParseException parseErr = (ParseException) err; parseErr.printStackTrace(); Token token = parseErr.currentToken; if (token != null) { fail("Expected no error, received: " + parseErr.getMessage() + "\n" + s + "\nline:" + token.beginLine + "\ncol:" + token.beginColumn); } } fail("Expected no error, received:\n" + err + "\n" + s); } if (generateTree) { if (objects.ast == null) { String s = ""; for (int i = 0; i < additionalErrInfo.length; i++) { s += additionalErrInfo[i]; } fail("AST not generated! " + s); } } return (SimpleNode) objects.ast; } public void testEmpty() throws Throwable { } protected void parseFilesInDir(File dir, boolean recursive) { parseFilesInDir(dir, recursive, true); } /** * @param dir the directory that should have .py files found and parsed. */ protected void parseFilesInDir(File dir, boolean recursive, boolean generateTree) { assertTrue("Directory " + dir + " does not exist", dir.exists()); assertTrue(dir.isDirectory()); File[] files = dir.listFiles(); for (int i = 0; i < files.length; i++) { File f = files[i]; String name = f.getName().toLowerCase(); if (name.endsWith(".py")) { //Used for stress-testing: parsing all files in Python installation. // try { // if(name.equals("func_syntax_error.py")){ // continue; // } // if(name.equals("badsyntax_nocaret.py")){ // continue; // } // if(name.equals("py3_test_grammar.py") && parser.getGrammarVersion() < IPythonNature.GRAMMAR_PYTHON_VERSION_3_0){ // continue; // } // String absolute = f.getAbsolutePath().toLowerCase(); // if(absolute.contains("pylint") && absolute.contains("test")){ // continue; // } // if(absolute.contains("port_v3")){ // continue; // } // } catch (MisconfigurationException e) { // throw new RuntimeException(e); // } if (generateTree) { parseLegalDocStr(FileUtils.getFileContents(f), f); } else { parseLegalDocStrWithoutTree(FileUtils.getFileContents(f), f); } } else if (recursive && f.isDirectory()) { parseFilesInDir(f, recursive, generateTree); } } } /** * The parameter passed in the callback is an integer with the version of the grammar. * @param iCallback * @throws Throwable */ public void checkWithAllGrammars(ICallback<Boolean, Integer> iCallback) throws Throwable { for (Iterator<Integer> it = IGrammarVersionProvider.grammarVersions.iterator(); it.hasNext();) { //try with all the grammars final Integer i = it.next(); boolean prev = PyParser.DEBUG_SHOW_PARSE_ERRORS; // Uncomment the following line to get debug info // We leave it off by default because it generates significant (MBs+) of // output which causes Travis CI to reject the build for having too many // logs // PyParser.DEBUG_SHOW_PARSE_ERRORS = true; // Uncomment the following lines to test only the specific grammar // if(i != IGrammarVersionProvider.GRAMMAR_PYTHON_VERSION_2_4){ // continue; // } setDefaultVersion(i); try { iCallback.call(i); } catch (Throwable e) { System.out.println("\nFound error while parsing with version: " + IGrammarVersionProvider.grammarVersionToRep.get(i)); throw e; } finally { PyParser.DEBUG_SHOW_PARSE_ERRORS = prev; } } } }