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.cassandra.cql3;
  
  import org.junit.Test;
  
  import org.antlr.runtime.ANTLRStringStream;
  import org.antlr.runtime.BaseRecognizer;
  import org.antlr.runtime.CharStream;
  import org.antlr.runtime.CommonTokenStream;
  import org.antlr.runtime.RecognitionException;
  import org.antlr.runtime.TokenStream;
  import org.apache.cassandra.cql3.statements.PropertyDefinitions;
  
  import static org.junit.Assert.*;
  
  public class CqlParserTest
  {
      @Test
      public void testAddErrorListener() throws Exception
      {
          SyntaxErrorCounter firstCounter = new SyntaxErrorCounter();
          SyntaxErrorCounter secondCounter = new SyntaxErrorCounter();
  
          CharStream stream = new ANTLRStringStream("SELECT * FORM FROM test");
          CqlLexer lexer = new CqlLexer(stream);
  
          TokenStream tokenStream = new CommonTokenStream(lexer);
          CqlParser parser = new CqlParser(tokenStream);
          parser.addErrorListener(firstCounter);
          parser.addErrorListener(secondCounter);
  
          // By default CqlParser should recover from the syntax error by removing FORM
          // but as recoverFromMismatchedToken and recover have been overloaded, it will not
          // and the returned ParsedStatement will be null.
          assertNull(parser.query());
  
          // Only one error must be reported (mismatched: FORM).
          assertEquals(1, firstCounter.count);
          assertEquals(1, secondCounter.count);
      }
  
      @Test
      public void testRemoveErrorListener() throws Exception
      {
          SyntaxErrorCounter firstCounter = new SyntaxErrorCounter();
          SyntaxErrorCounter secondCounter = new SyntaxErrorCounter();
  
          CharStream stream = new ANTLRStringStream("SELECT * FORM test;");
          CqlLexer lexer = new CqlLexer(stream);
  
          TokenStream tokenStream = new CommonTokenStream(lexer);
          CqlParser parser = new CqlParser(tokenStream);
          parser.addErrorListener(firstCounter);
          parser.addErrorListener(secondCounter);
          parser.removeErrorListener(secondCounter);
  
          parser.query();
  
          assertEquals(1, firstCounter.count);
          assertEquals(0, secondCounter.count);
      }
  
      @Test
      public void testDuplicateProperties() throws Exception
      {
          parseAndCountErrors("properties = { 'foo' : 'value1', 'bar': 'value2' };", 0, (p) -> p.properties(new PropertyDefinitions()));
          parseAndCountErrors("properties = { 'foo' : 'value1', 'foo': 'value2' };", 1, (p) -> p.properties(new PropertyDefinitions()));
          parseAndCountErrors("foo = 'value1' AND bar = 'value2' };", 0, (p) -> p.properties(new PropertyDefinitions()));
          parseAndCountErrors("foo = 'value1' AND foo = 'value2' };", 1, (p) -> p.properties(new PropertyDefinitions()));
      }
  
      private void parseAndCountErrors(String cql, int expectedErrors, ParserOperation operation) throws RecognitionException
      {
          SyntaxErrorCounter counter = new SyntaxErrorCounter();
          CharStream stream = new ANTLRStringStream(cql);
          CqlLexer lexer = new CqlLexer(stream);
          TokenStream tokenStream = new CommonTokenStream(lexer);
          CqlParser parser = new CqlParser(tokenStream);
          parser.addErrorListener(counter);
  
          operation.perform(parser);
  
          assertEquals(expectedErrors, counter.count);
      }
  
      @FunctionalInterface
      private interface ParserOperation
      {
          void perform(CqlParser cqlParser) throws RecognitionException;
      }
  
      private static final class SyntaxErrorCounter implements ErrorListener
      {
          private int count;
  
          @Override
          public void syntaxError(BaseRecognizer recognizer, String[] tokenNames, RecognitionException e)
          {
              count++;
          }
  
          @Override
          public void syntaxError(BaseRecognizer recognizer, String errorMsg)
          {
              count++;
          }
      }
  }
  