content: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied.  See the License for the
   * specific language governing permissions and limitations
   * under the License.
   */
  package org.apache.chemistry.opencmis.server.support.query;
  
  import static org.junit.Assert.fail;
  
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Method;
  
  import org.antlr.runtime.ANTLRStringStream;
  import org.antlr.runtime.BaseRecognizer;
  import org.antlr.runtime.CharStream;
  import org.antlr.runtime.CommonTokenStream;
  import org.antlr.runtime.Lexer;
  import org.antlr.runtime.Token;
  import org.antlr.runtime.TokenStream;
  import org.antlr.runtime.tree.CommonTree;
  import org.antlr.stringtemplate.StringTemplate;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  /**
   * This class is clone of org.antlr.gunit.gUnitBase class adapted to Java style
   * Because the original class can't deal with composite grammar this is a
   * replacement working around this antlr bug.
   * 
   */
  public class AbstractParserTest {
  
      private static final Logger log = LoggerFactory.getLogger(AbstractParserTest.class);
  
      protected String superGrammarName;
      protected String baseLexerName;
      Class<?> lexer;
      Class<?> parser;
      protected String treeParserPath;
  
      protected void setUp(Class<?> lexerClass, Class<?> parserClass, String baseGrammar, String baseLexer) {
          lexer = lexerClass;
          parser = parserClass;
          this.superGrammarName = baseGrammar;
          this.baseLexerName = baseLexer;
      }
  
      protected void tearDown() {
      }
  
      protected void testLexerOk(String rule, String statement) {
          // test input: "a"
          try {
              Object retval = execLexer(rule, statement);
              log.debug("testing rule " + rule + " parsed to: " + retval);
          } catch (Exception e) {
              fail("testing rule " + rule + ": " + e.toString());
          }
      }
  
      protected void testLexerFail(String rule, String statement) {
          // test input: "a"
          try {
              Object retval = execLexer(rule, statement);
              fail("testing rule should fail " + rule);
          } catch (Exception e) {
              log.debug("testing rule " + rule + " parsed with exception: " + e);
          }
      }
  
      protected void testParserOk(String rule, String statement) {
          try {
              Object retval = execParser(rule, statement);
              log.debug("testing rule " + rule + " parsed to: " + retval);
          } catch (Exception e) {
              fail("testing rule " + rule + " failed: " + e.toString());
          }
      }
  
      protected void testParserFail(String rule, String statement) {
          try {
              Object retval = execParser(rule, statement);
              fail("testing rule should fail " + rule);
          } catch (Exception e) {
              log.debug("testing rule " + rule + " failed: " + e.toString());
          }
      }
  
      protected void testParser(String rule, String statement, String expectedResult) {
          try {
              Object actual = execParser(rule, statement);
              log.debug("testing rule " + rule + " parsed to: " + actual);
          } catch (Exception e) {
              fail("testing rule " + rule + " failed: " + e);
          }
      }
  
      // Invoke target lexer.rule
      public String execLexer(String testRuleName, String testInput) throws Exception {
          String result = null;
          CharStream input;
          /** Set up ANTLR input stream based on input source, file or String */
          input = new ANTLRStringStream(testInput);
  
          /** Use Reflection to create instances of lexer and parser */
          Class<?>[] lexArgTypes = new Class[] { CharStream.class }; // assign
                                                                     // type to
                                                                     // lexer's
                                                                     // args
          Constructor<?> lexConstructor = lexer.getConstructor(lexArgTypes);
          Object[] lexArgs = new Object[] { input }; // assign value to lexer's
                                                     // args
          Object lexObj = lexConstructor.newInstance(lexArgs); // makes new
                                                               // instance of
                                                               // lexer
          Method ruleName = null;
  
          try {
              ruleName = lexer.getMethod("m" + testRuleName, new Class[0]);
          } catch (NoSuchMethodException e) {
              // try superclass lexers
              Class<?> lexerSuper = Class.forName(lexer.getName() + "_" + baseLexerName);
              ruleName = lexerSuper.getMethod("m" + testRuleName, new Class[0]);
              lexArgTypes = new Class[] { CharStream.class, CmisQlStrictLexer.class };
              lexArgs = new Object[] { input, lexObj };
              lexConstructor = lexerSuper.getConstructor(lexArgTypes);
              lexObj = lexConstructor.newInstance(lexArgs);
          }
          /** Invoke lexer rule, and get the current index in CharStream */
          ruleName.invoke(lexObj, new Object[0]);
          Method ruleName2 = lexer.getMethod("getCharIndex", new Class[0]);
          int currentIndex = (Integer) ruleName2.invoke(lexObj, new Object[0]);
          if (currentIndex != input.size()) {
              throw new RuntimeException("extra text found, '" + input.substring(currentIndex, input.size() - 1) + "'");
              // System.out.println("extra text found, '"+input.substring(currentIndex,
              // input.size()-1)+"'");
          }
  
          return result;
      }
  
      // Invoke target parser.rule
      public Object execParser(String testRuleName, String testInput) throws Exception {
          String result = null;
          CharStream input;
          /** Set up ANTLR input stream based on input source, file or String */
          input = new ANTLRStringStream(testInput);
  
          /** Use Reflection to create instances of lexer and parser */
          // assign type to lexer's args
          Class<?>[] lexArgTypes = new Class[] { CharStream.class };
          Constructor<?> lexConstructor = lexer.getConstructor(lexArgTypes);
  
          // assign value to lexer's args
          Object[] lexArgs = new Object[] { input };
  
          // makes new instance of lexer
          Object lexObj = lexConstructor.newInstance(lexArgs);
  
          CommonTokenStream tokens = new CommonTokenStream((Lexer) lexObj);
          
          // assign type to parser's args
          Class<?>[] parArgTypes = new Class[] { TokenStream.class };
          Constructor<?> parConstructor = parser.getConstructor(parArgTypes);
  
          // assign value to parser's args
          Object[] parArgs = new Object[] { tokens };
  
          // makes new instance of parser
          Object parObj = parConstructor.newInstance(parArgs);
  
          Method ruleName = parser.getMethod(testRuleName);
  
          /** Invoke grammar rule, and store if there is a return value */
          Object ruleReturn = ruleName.invoke(parObj);
  
          /** If rule has return value, determine if it contains an AST or a ST */
          if (ruleReturn != null) {
              if (ruleReturn.getClass().toString().indexOf(testRuleName + "_return") > 0) {
                  try { // NullPointerException may happen here...
                      String classPath = parser.getName();
                      if (null != superGrammarName) {
                          classPath += "_" + superGrammarName;
                      }
                      Class<?> _return = Class.forName(classPath + "$" + testRuleName + "_return");
                      Method[] methods = _return.getDeclaredMethods();
                      for (Method method : methods) {
                          if (method.getName().equals("getTree")) {
                              Method returnName = _return.getMethod("getTree");
                              CommonTree tree = (CommonTree) returnName.invoke(ruleReturn);
                              result = tree.toStringTree();
                          } else if (method.getName().equals("getTemplate")) {
                              Method returnName = _return.getMethod("getTemplate");
                              StringTemplate st = (StringTemplate) returnName.invoke(ruleReturn);
                              result = st.toString();
                          }
                      }
                  } catch (Exception e) {
                      // Note: If any exception occurs, the test is viewed as
                      // failed.
                      throw (e);
                  }
              }
          }
  
          /** Invalid input */
          // Since AntLR 3.3 we have to skip EOF tokens at the end 
          // This requires modification of the default code 
          // if (tokens.index() != tokens.size()) {
          // to
          if (tokens.get(tokens.index()).getType() != Token.EOF) {
              throw new RuntimeException("Invalid input.");
          }
  
          /** Check for syntax errors */
          if (((BaseRecognizer) parObj).getNumberOfSyntaxErrors() > 0) {
              throw new RuntimeException("Syntax error occured");
          }
          return result;
      }
  
  }
  