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.ambari.server.api.predicate;
  
  import static org.junit.Assert.assertArrayEquals;
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.fail;
  
  import java.util.ArrayList;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Set;
  
  import org.junit.Test;
  
  /**
   * QueryLexer unit tests
   */
  public class QueryLexerTest {
  
    @Test
    public void testTokens_simple() throws InvalidQueryException {
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "a"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
      listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "&"));
      listTokens.add(new Token(Token.TYPE.BRACKET_OPEN, "("));
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "<="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "b"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "2"));
      listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "|"));
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, ">"));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "c"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "3"));
      listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("a=1&(b<=2|c>3)");
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testTokens_multipleBrackets() throws InvalidQueryException {
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "<"));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "a"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
      listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "&"));
      listTokens.add(new Token(Token.TYPE.BRACKET_OPEN, "("));
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "<="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "b"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "2"));
      listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "&"));
      listTokens.add(new Token(Token.TYPE.BRACKET_OPEN, "("));
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, ">="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "c"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "3"));
      listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "|"));
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "!="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "d"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "4"));
      listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
      listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("a<1&(b<=2&(c>=3|d!=4))");
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testUnaryNot() throws Exception {
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("!foo<5");
  
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.LOGICAL_UNARY_OPERATOR, "!"));
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "<"));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "5"));
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testInOperator() throws Exception {
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("foo.in(one, two, 3)");
  
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC, ".in("));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "one, two, 3"));
      listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testIsEmptyOperator() throws Exception {
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("category1.isEmpty()");
  
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC, ".isEmpty("));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "category1"));
      listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testTokens_ignoreFieldsSyntax___noPredicate() throws InvalidQueryException {
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("fields=foo,bar");
      assertEquals(0, tokens.length);
    }
  
    @Test
    public void testTokens_ignoreFieldsSyntax___fieldsFirst() throws InvalidQueryException {
  
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("fields=foo,bar&foo=1");
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testTokens_ignoreFieldsSyntax___fieldsLast() throws InvalidQueryException {
  
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("foo=1&fields=foo,bar");
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testTokens_ignoreFormatSyntax___noPredicate() throws InvalidQueryException {
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("format=default");
      assertEquals(0, tokens.length);
    }
  
    @Test
    public void testTokens_ignoreFormatSyntax___formatFirst() throws InvalidQueryException {
  
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("format=default&foo=1");
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testTokens_ignoreFormatSyntax___formatLast() throws InvalidQueryException {
  
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("foo=1&format=foo");
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testTokens_ignoreUnderscoreSyntax___noPredicate() throws InvalidQueryException {
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("_=1");
      assertEquals(0, tokens.length);
    }
  
    @Test
    public void testTokens_ignoreUnderscoreSyntax___fieldsFirst() throws InvalidQueryException {
  
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("_=111111&foo=1");
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testTokens_ignoreUnderscoreSyntax___fieldsLast() throws InvalidQueryException {
  
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("foo=1&_=11111");
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testTokens_ignore__multipleIgnoreFields() throws InvalidQueryException {
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("fields=a/b&foo=1&_=5555555");
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testTokens_ignore__multipleConsecutiveIgnoreFields() throws InvalidQueryException {
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("foo=1&fields=a/b&_=5555555");
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testTokens_ignore__multipleConsecutiveIgnoreFields2() throws InvalidQueryException {
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("fields=a/b&_=5555555&foo=1");
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testTokens_ignore__fieldsMiddle() throws InvalidQueryException {
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
      listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "&"));
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "bar"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "2"));
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("foo=1&fields=a/b&bar=2");
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testTokens_ignore__fieldsMiddle2() throws InvalidQueryException {
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
      listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "&"));
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "bar"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "2"));
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("foo=1&fields=a/b,c&_=123&bar=2");
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testTokens_ignore__userDefined() throws InvalidQueryException {
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
      listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "&"));
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "bar"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "2"));
  
      QueryLexer lexer = new QueryLexer();
      Set<String> propertiesToIgnore = new HashSet<>();
      propertiesToIgnore.add("ignore1");
      propertiesToIgnore.add("otherIgnore");
      propertiesToIgnore.add("ba");
      propertiesToIgnore.add("ple");
  
      Token[] tokens = lexer.tokens("ba=gone&foo=1&ignore1=pleaseIgnoreMe&fields=a/b&bar=2&otherIgnore=byebye",
          propertiesToIgnore);
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testTokens_invalidRelationalOp() {
      try {
        new QueryLexer().tokens("foo=1&bar|5");
        fail("Expected InvalidQueryException due to invalid relational op");
      } catch (InvalidQueryException e) {
        //expected
      }
    }
  
    @Test
    public void testTokens_invalidLogicalOp() {
      try {
        new QueryLexer().tokens("foo=1<5=2");
        fail("Expected InvalidQueryException due to invalid logical op");
      } catch (InvalidQueryException e) {
        //expected
      }
    }
  
    @Test
    public void testTokens_invalidLogicalOp2() {
      try {
        new QueryLexer().tokens("foo=1&&5=2");
        fail("Expected InvalidQueryException due to invalid logical op");
      } catch (InvalidQueryException e) {
        //expected
      }
    }
  
    @Test
    public void testTokens_matchesRegexp_simple() throws InvalidQueryException {
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC, ".matches("));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "StackConfigurations/property_type"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "(.*USER.*)|(.*GROUP.*)"));
      listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("StackConfigurations/property_type.matches((.*USER.*)|(.*GROUP.*))");
  
      assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test
    public void testTokens_matchesRegexp() throws InvalidQueryException {
      List<Token> listTokens = new ArrayList<>();
      listTokens.add(new Token(Token.TYPE.BRACKET_OPEN, "("));
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC, ".matches("));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "StackConfigurations/property_type"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "(([^=])|=|!=),.in(&).*USER.*.isEmpty(a).matches(b)"));
      listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
      listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "|"));
      listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC, ".matches("));
      listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "StackConfigurations/property_type"));
      listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "fields format to from .*GROUP.*"));
      listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
      listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
  
      QueryLexer lexer = new QueryLexer();
      Token[] tokens = lexer.tokens("(StackConfigurations/property_type.matches((([^=])|=|!=),.in(&).*USER.*" +
          ".isEmpty(a).matches(b))|StackConfigurations/property_type.matches(fields format to from .*GROUP.*))");
  
      assertArrayEquals("All characters between \".matches(\" and corresponding closing \")\" bracket should " +
          "come to VALUE_OPERAND.", listTokens.toArray(new Token[listTokens.size()]), tokens);
    }
  
    @Test(expected = InvalidQueryException.class)
    public void testTokens_matchesRegexpInvalidQuery() throws InvalidQueryException {
      QueryLexer lexer = new QueryLexer();
      lexer.tokens("StackConfigurations/property_type.matches((.*USER.*)|(.*GROUP.*)");
    }
  
    @Test(expected = InvalidQueryException.class)
    public void testTokens_matchesRegexpInvalidQuery2() throws InvalidQueryException {
      QueryLexer lexer = new QueryLexer();
      lexer.tokens("StackConfigurations/property_type.matches((.*USER.*)|(.*GROUP.*)|StackConfigurations/property_type.matches(.*GROUP.*)");
    }
  }
  