public function testQuery()
 {
     $this->assertTokens("AVG(user.id) as Avg, count(id), (id + 10) / 2\n" . "from UserGroup\n" . "where (id in (1, \$1) or id >= \$2) and (name like \"%'ы'%\") " . "order by id desc", array(OqlToken::make('avg', 'AVG', OqlToken::AGGREGATE_FUNCTION, 1, 0), OqlToken::make('(', '(', OqlToken::PARENTHESES, 1, 3), OqlToken::make('user.id', 'user.id', OqlToken::IDENTIFIER, 1, 4), OqlToken::make(')', ')', OqlToken::PARENTHESES, 1, 11), OqlToken::make('as', 'as', OqlToken::KEYWORD, 1, 13), OqlToken::make('avg', 'Avg', OqlToken::AGGREGATE_FUNCTION, 1, 16), OqlToken::make(',', ',', OqlToken::PUNCTUATION, 1, 19), OqlToken::make('count', 'count', OqlToken::AGGREGATE_FUNCTION, 1, 21), OqlToken::make('(', '(', OqlToken::PARENTHESES, 1, 26), OqlToken::make('id', 'id', OqlToken::IDENTIFIER, 1, 27), OqlToken::make(')', ')', OqlToken::PARENTHESES, 1, 29), OqlToken::make(',', ',', OqlToken::PUNCTUATION, 1, 30), OqlToken::make('(', '(', OqlToken::PARENTHESES, 1, 32), OqlToken::make('id', 'id', OqlToken::IDENTIFIER, 1, 33), OqlToken::make('+', '+', OqlToken::ARITHMETIC_OPERATOR, 1, 36), OqlToken::make(10.0, '10', OqlToken::NUMBER, 1, 38), OqlToken::make(')', ')', OqlToken::PARENTHESES, 1, 40), OqlToken::make('/', '/', OqlToken::ARITHMETIC_OPERATOR, 1, 42), OqlToken::make(2.0, '2', OqlToken::NUMBER, 1, 44), OqlToken::make('from', 'from', OqlToken::KEYWORD, 2, 0), OqlToken::make('UserGroup', 'UserGroup', OqlToken::IDENTIFIER, 2, 5), OqlToken::make('where', 'where', OqlToken::KEYWORD, 3, 0), OqlToken::make('(', '(', OqlToken::PARENTHESES, 3, 6), OqlToken::make('id', 'id', OqlToken::IDENTIFIER, 3, 7), OqlToken::make('in', 'in', OqlToken::KEYWORD, 3, 10), OqlToken::make('(', '(', OqlToken::PARENTHESES, 3, 13), OqlToken::make(1.0, '1', OqlToken::NUMBER, 3, 14), OqlToken::make(',', ',', OqlToken::PUNCTUATION, 3, 15), OqlToken::make(1, '$1', OqlToken::SUBSTITUTION, 3, 17), OqlToken::make(')', ')', OqlToken::PARENTHESES, 3, 19), OqlToken::make('or', 'or', OqlToken::KEYWORD, 3, 21), OqlToken::make('id', 'id', OqlToken::IDENTIFIER, 3, 24), OqlToken::make('>=', '>=', OqlToken::COMPARISON_OPERATOR, 3, 27), OqlToken::make(2, '$2', OqlToken::SUBSTITUTION, 3, 30), OqlToken::make(')', ')', OqlToken::PARENTHESES, 3, 32), OqlToken::make('and', 'and', OqlToken::KEYWORD, 3, 34), OqlToken::make('(', '(', OqlToken::PARENTHESES, 3, 38), OqlToken::make('name', 'name', OqlToken::IDENTIFIER, 3, 39), OqlToken::make('like', 'like', OqlToken::KEYWORD, 3, 44), OqlToken::make('%\'ы\'%', '"%\'ы\'%"', OqlToken::STRING, 3, 49), OqlToken::make(')', ')', OqlToken::PARENTHESES, 3, 56), OqlToken::make('order by', 'order by', OqlToken::KEYWORD, 3, 58), OqlToken::make('id', 'id', OqlToken::IDENTIFIER, 3, 67), OqlToken::make('desc', 'desc', OqlToken::KEYWORD, 3, 70)));
 }
 /**
  * @return OqlTokenizer
  **/
 private function tokenize($string)
 {
     Assert::isString($string);
     $maxMultibyteDelta = strlen($string) - mb_strlen($string);
     $isMultibyte = $maxMultibyteDelta > 0;
     $pattern = '/(' . implode(')|(', self::$masks) . ')/is';
     if ($isMultibyte) {
         $pattern .= 'u';
     }
     preg_match_all($pattern, $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
     $line = 1;
     $lineStart = 0;
     $multibyteDelta = 0;
     foreach ($matches as $match) {
         $type = count($match) - 1;
         $offset = $match[0][1] - $multibyteDelta;
         if ($type == OqlToken::NEW_LINE) {
             $line++;
             $lineStart = $offset + 1;
             continue;
         }
         $value = $match[0][0];
         $position = $offset - $lineStart;
         $this->tokens[] = OqlToken::make($this->importTokenValue($value, $type), $value, $type, $line, $position);
         if ($type == OqlToken::KEYWORD && ($pos = strpos($value, "\n")) !== false) {
             $line++;
             $lineStart = $offset + $pos + 1;
         }
         if ($isMultibyte && $type == OqlToken::STRING) {
             $multibyteDelta += strlen($value) - mb_strlen($value);
             if ($multibyteDelta >= $maxMultibyteDelta) {
                 $isMultibyte = false;
             }
         }
     }
     $this->tokensCount = count($this->tokens);
     return $this;
 }