/* * Licensed to CRATE Technology GmbH ("Crate") under one or more contributor * license agreements. See the NOTICE file distributed with this work for * additional information regarding copyright ownership. Crate 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. * * However, if you have executed another commercial license agreement * with Crate these terms will supersede the license and you may use the * software solely pursuant to the terms of the relevant commercial agreement. */ package io.crate.operation.operator; import io.crate.analyze.symbol.Literal; import io.crate.operation.scalar.AbstractScalarFunctionsTest; import org.junit.Test; import static io.crate.operation.operator.LikeOperator.DEFAULT_ESCAPE; import static io.crate.testing.SymbolMatchers.isLiteral; public class LikeOperatorTest extends AbstractScalarFunctionsTest { @Test public void testNormalizeSymbolEqual() { assertNormalize("'foo' like 'foo'", isLiteral(true)); assertNormalize("'notFoo' like 'foo'", isLiteral(false)); } @Test public void testPatternIsNoLiteral() throws Exception { assertEvaluate("name like timezone", false, Literal.of("foo"), Literal.of("bar")); assertEvaluate("name like name", true, Literal.of("foo"), Literal.of("foo")); } @Test public void testNormalizeSymbolLikeZeroOrMore() { // Following tests: wildcard: '%' ... zero or more characters (0...N) assertNormalize("'foobar' like '%bar'", isLiteral(true)); assertNormalize("'bar' like '%bar'", isLiteral(true)); assertNormalize("'ar' like '%bar'", isLiteral(false)); assertNormalize("'foobar' like 'foo%'", isLiteral(true)); assertNormalize("'foo' like 'foo%'", isLiteral(true)); assertNormalize("'fo' like 'foo%'", isLiteral(false)); assertNormalize("'foobar' like '%oob%'", isLiteral(true)); } @Test public void testNormalizeSymbolLikeExactlyOne() { // Following tests: wildcard: '_' ... any single character (exactly one) assertNormalize("'bar' like '_ar'", isLiteral(true)); assertNormalize("'bar' like '_bar'", isLiteral(false)); assertNormalize("'foo' like 'fo_'", isLiteral(true)); assertNormalize("'foo' like 'foo_'", isLiteral(false)); assertNormalize("'foo' like '_o_'", isLiteral(true)); assertNormalize("'foobar' like '_foobar_'", isLiteral(false)); } // Following tests: mixed wildcards: @Test public void testNormalizeSymbolLikeMixed() { assertNormalize("'foobar' like '%o_ar'", isLiteral(true)); assertNormalize("'foobar' like '%a_'", isLiteral(true)); assertNormalize("'foobar' like '%o_a%'", isLiteral(true)); assertNormalize("'Lorem ipsum dolor...' like '%i%m%'", isLiteral(true)); assertNormalize("'Lorem ipsum dolor...' like '%%%sum%%'", isLiteral(true)); assertNormalize("'Lorem ipsum dolor...' like '%i%m'", isLiteral(false)); } // Following tests: escaping wildcards @Test public void testExpressionToRegexExactlyOne() { String expression = "fo_bar"; assertEquals("^fo.bar$", LikeOperator.patternToRegex(expression, DEFAULT_ESCAPE, true)); } @Test public void testLikeOnMultilineStatement() throws Exception { String stmt = "SELECT date_trunc('day', ts), sum(num_steps) as num_steps, count(*) as num_records \n" + "FROM steps\n" + "WHERE month_partition = '201409'\n" + "GROUP BY 1 ORDER BY 1 DESC limit 100"; assertEvaluate("name like ' SELECT%'", false, Literal.of(stmt)); assertEvaluate("name like 'SELECT%'", true, Literal.of(stmt)); assertEvaluate("name like 'SELECT date_trunc%'", true, Literal.of(stmt)); assertEvaluate("name like '% date_trunc%'", true, Literal.of(stmt)); } @Test public void testExpressionToRegexZeroOrMore() { String expression = "fo%bar"; assertEquals("^fo.*bar$", LikeOperator.patternToRegex(expression, DEFAULT_ESCAPE, true)); } @Test public void testExpressionToRegexEscapingPercent() { String expression = "fo\\%bar"; assertEquals("^fo%bar$", LikeOperator.patternToRegex(expression, DEFAULT_ESCAPE, true)); } @Test public void testExpressionToRegexEscapingUnderline() { String expression = "fo\\_bar"; assertEquals("^fo_bar$", LikeOperator.patternToRegex(expression, DEFAULT_ESCAPE, true)); } @Test public void testExpressionToRegexEscaping() { String expression = "fo\\\\_bar"; assertEquals("^fo\\\\.bar$", LikeOperator.patternToRegex(expression, DEFAULT_ESCAPE, true)); } @Test public void testExpressionToRegexEscapingMutli() { String expression = "%%\\%sum%%"; assertEquals("^.*.*%sum.*.*$", LikeOperator.patternToRegex(expression, DEFAULT_ESCAPE, true)); } @Test public void testExpressionToRegexMaliciousPatterns() { String expression = "fo(ooo)o[asdf]o\\bar^$.*"; assertEquals("^fo\\(ooo\\)o\\[asdf\\]obar\\^\\$\\.\\*$", LikeOperator.patternToRegex(expression, DEFAULT_ESCAPE, true)); } @Test public void testLikeOperator() { assertEvaluate("'foobarbaz' like 'foo%baz'", true); assertEvaluate("'foobarbaz' like 'foo_baz'", false); assertEvaluate("'characters' like 'charac%'", true); assertEvaluate("'foobarbaz' like name", null, Literal.NULL); assertEvaluate("name like 'foobarbaz'", null, Literal.NULL); } }