/***************************************************************** * 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.cayenne.exp; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.cayenne.exp.parser.ASTLike; import org.apache.cayenne.exp.parser.ASTLikeIgnoreCase; import org.apache.cayenne.exp.parser.ASTTrim; import org.junit.Before; import org.junit.Test; public class ExpressionFactoryTest { private TstTraversalHandler handler; @Before public void before() throws Exception { handler = new TstTraversalHandler(); } @Test(expected = ExpressionException.class) public void testExpressionOfBadType() throws Exception { // non existing type int badType = -50; ExpressionFactory.expressionOfType(badType); } @Test public void testBetweenExp() throws Exception { Object v1 = new Object(); Object v2 = new Object(); Expression exp = ExpressionFactory.betweenExp("abc", v1, v2); assertEquals(Expression.BETWEEN, exp.getType()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.OBJ_PATH, path.getType()); } @Test public void testBetweenDbExp() throws Exception { Object v1 = new Object(); Object v2 = new Object(); Expression exp = ExpressionFactory.betweenDbExp("abc", v1, v2); assertEquals(Expression.BETWEEN, exp.getType()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.DB_PATH, path.getType()); } @Test public void testNotBetweenExp() throws Exception { Object v1 = new Object(); Object v2 = new Object(); Expression exp = ExpressionFactory.notBetweenExp("abc", v1, v2); assertEquals(Expression.NOT_BETWEEN, exp.getType()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.OBJ_PATH, path.getType()); } @Test public void testNotBetweenDbExp() throws Exception { Object v1 = new Object(); Object v2 = new Object(); Expression exp = ExpressionFactory.notBetweenDbExp("abc", v1, v2); assertEquals(Expression.NOT_BETWEEN, exp.getType()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.DB_PATH, path.getType()); } @Test public void testGreaterExp() throws Exception { Object v = new Object(); Expression exp = ExpressionFactory.greaterExp("abc", v); assertEquals(Expression.GREATER_THAN, exp.getType()); } @Test public void testGreaterDbExp() throws Exception { Object v = new Object(); Expression exp = ExpressionFactory.greaterDbExp("abc", v); assertEquals(Expression.GREATER_THAN, exp.getType()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.DB_PATH, path.getType()); } @Test public void testGreaterOrEqualExp() throws Exception { Object v = new Object(); Expression exp = ExpressionFactory.greaterOrEqualExp("abc", v); assertEquals(Expression.GREATER_THAN_EQUAL_TO, exp.getType()); } @Test public void testGreaterOrEqualDbExp() throws Exception { Object v = new Object(); Expression exp = ExpressionFactory.greaterOrEqualDbExp("abc", v); assertEquals(Expression.GREATER_THAN_EQUAL_TO, exp.getType()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.DB_PATH, path.getType()); } @Test public void testLessExp() throws Exception { Object v = new Object(); Expression exp = ExpressionFactory.lessExp("abc", v); assertEquals(Expression.LESS_THAN, exp.getType()); } @Test public void testLessDbExp() throws Exception { Object v = new Object(); Expression exp = ExpressionFactory.lessDbExp("abc", v); assertEquals(Expression.LESS_THAN, exp.getType()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.DB_PATH, path.getType()); } @Test public void testLessOrEqualExp() throws Exception { Object v = new Object(); Expression exp = ExpressionFactory.lessOrEqualExp("abc", v); assertEquals(Expression.LESS_THAN_EQUAL_TO, exp.getType()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.OBJ_PATH, path.getType()); } @Test public void testLessOrEqualDbExp() throws Exception { Object v = new Object(); Expression exp = ExpressionFactory.lessOrEqualDbExp("abc", v); assertEquals(Expression.LESS_THAN_EQUAL_TO, exp.getType()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.DB_PATH, path.getType()); } @Test public void testInExp1() throws Exception { Expression exp = ExpressionFactory.inExp("abc", "a", "b"); assertEquals(Expression.IN, exp.getType()); } @Test public void testInExp2() throws Exception { List<Object> v = new ArrayList<>(); v.add("a"); v.add("b"); Expression exp = ExpressionFactory.inExp("abc", v); assertEquals(Expression.IN, exp.getType()); } @Test public void testInExp3() throws Exception { List<Object> v = new ArrayList<>(); Expression exp = ExpressionFactory.inExp("abc", v); assertEquals(Expression.FALSE, exp.getType()); } @Test public void testLikeExp() throws Exception { String v = "abc"; Expression exp = ExpressionFactory.likeExp("abc", v); assertEquals(Expression.LIKE, exp.getType()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.OBJ_PATH, path.getType()); } @Test public void testLikeDbExp() throws Exception { String v = "abc"; Expression exp = ExpressionFactory.likeDbExp("abc", v); assertEquals(Expression.LIKE, exp.getType()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.DB_PATH, path.getType()); } @Test public void testLikeExpEscape() throws Exception { String v = "abc"; Expression exp = ExpressionFactory.likeExp("=abc", v, '='); assertEquals(Expression.LIKE, exp.getType()); assertEquals('=', ((ASTLike) exp).getEscapeChar()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.OBJ_PATH, path.getType()); } @Test public void testLikeIgnoreCaseExp() throws Exception { String v = "abc"; Expression exp = ExpressionFactory.likeIgnoreCaseExp("abc", v); assertEquals(Expression.LIKE_IGNORE_CASE, exp.getType()); assertEquals(0, ((ASTLikeIgnoreCase) exp).getEscapeChar()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.OBJ_PATH, path.getType()); } @Test public void testLikeIgnoreCaseExpEscape() throws Exception { String v = "abc"; Expression exp = ExpressionFactory.likeIgnoreCaseExp("=abc", v, '='); assertEquals(Expression.LIKE_IGNORE_CASE, exp.getType()); assertEquals('=', ((ASTLikeIgnoreCase) exp).getEscapeChar()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.OBJ_PATH, path.getType()); } @Test public void testLikeIgnoreCaseDbExp() throws Exception { String v = "abc"; Expression exp = ExpressionFactory.likeIgnoreCaseDbExp("abc", v); assertEquals(Expression.LIKE_IGNORE_CASE, exp.getType()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.DB_PATH, path.getType()); } @Test public void testNotLikeIgnoreCaseExp() throws Exception { String v = "abc"; Expression exp = ExpressionFactory.notLikeIgnoreCaseExp("abc", v); assertEquals(Expression.NOT_LIKE_IGNORE_CASE, exp.getType()); } // testing CAY-941 bug @Test public void testLikeExpNull() throws Exception { Expression exp = ExpressionFactory.likeExp("abc", null); assertEquals(Expression.LIKE, exp.getType()); Expression path = (Expression) exp.getOperand(0); assertEquals(Expression.OBJ_PATH, path.getType()); assertNull(exp.getOperand(1)); } @Test public void testMatchAllExp() throws Exception { // create expressions and check the counts, // leaf count should be (2N) : 2 leafs for each pair // node count should be (2N + 1) for nodes with more than 1 pair // and 2N for a single pair : 2 nodes for each pair + 1 list node // where N is map size // check for N in (1..3) for (int n = 1; n <= 3; n++) { Map<String, Object> map = new HashMap<>(); // populate map for (int i = 1; i <= n; i++) { map.put("k" + i, "v" + i); } Expression exp = ExpressionFactory.matchAllExp(map, Expression.LESS_THAN); assertNotNull(exp); handler.traverseExpression(exp); // assert statistics handler.assertConsistency(); assertEquals("Failed: " + exp, 2 * n, handler.getLeafs()); assertEquals("Failed: " + exp, n < 2 ? 2 * n : 2 * n + 1, handler.getNodeCount()); } } @Test public void testJoinExp() throws Exception { // create expressions and check the counts, // leaf count should be (2N) : 2 leafs for each expression // node count should be N > 1 ? 2 * N + 1 : 2 * N // where N is map size // check for N in (1..5) for (int n = 1; n <= 5; n++) { Collection<Expression> list = new ArrayList<>(); // populate map for (int i = 1; i <= n; i++) { list.add(ExpressionFactory.matchExp(("k" + i), "v" + i)); } Expression exp = ExpressionFactory.joinExp(Expression.AND, list); assertNotNull(exp); handler.traverseExpression(exp); // assert statistics handler.assertConsistency(); assertEquals("Failed: " + exp, 2 * n, handler.getLeafs()); assertEquals("Failed: " + exp, n > 1 ? 2 * n + 1 : 2 * n, handler.getNodeCount()); } } @Test public void testAnd_Collection() { Expression e1 = ExpressionFactory.matchExp("a", 1); Expression e2 = ExpressionFactory.matchExp("b", 2); Expression e3 = ExpressionFactory.matchExp("c", "C"); Collection<Expression> c = Arrays.asList(e1, e2, e3); Expression e = ExpressionFactory.and(c); assertEquals("(a = 1) and (b = 2) and (c = \"C\")", e.toString()); } @Test public void testAnd_Collection_OneElement() { Expression e1 = ExpressionFactory.matchExp("a", 1); Collection<Expression> c = Collections.singletonList(e1); Expression e = ExpressionFactory.and(c); assertEquals("a = 1", e.toString()); } @Test public void testAnd_Collection_Empty() { Expression e = ExpressionFactory.and(Collections.<Expression> emptyList()); // hmm... is this really a valid return value? assertNull(e); } @Test public void testAnd_Vararg() { Expression e1 = ExpressionFactory.matchExp("a", 1); Expression e2 = ExpressionFactory.matchExp("b", 2); Expression e3 = ExpressionFactory.matchExp("c", "C"); Expression e = ExpressionFactory.and(e1, e2, e3); assertEquals("(a = 1) and (b = 2) and (c = \"C\")", e.toString()); } @Test public void testAnd_Vararg_OneElement() { Expression e1 = ExpressionFactory.matchExp("a", 1); Expression e = ExpressionFactory.and(e1); assertEquals("a = 1", e.toString()); } @Test public void testAnd_Vararg_Empty() { Expression e = ExpressionFactory.and(); // hmm... is this really a valid return value? assertNull(e); } @Test public void testOr_Collection() { Expression e1 = ExpressionFactory.matchExp("a", 1); Expression e2 = ExpressionFactory.matchExp("b", 2); Expression e3 = ExpressionFactory.matchExp("c", "C"); Collection<Expression> c = Arrays.asList(e1, e2, e3); Expression e = ExpressionFactory.or(c); assertEquals("(a = 1) or (b = 2) or (c = \"C\")", e.toString()); } @Test public void testOr_Vararg() { Expression e1 = ExpressionFactory.matchExp("a", 1); Expression e2 = ExpressionFactory.matchExp("b", 2); Expression e3 = ExpressionFactory.matchExp("c", "C"); Expression e = ExpressionFactory.or(e1, e2, e3); assertEquals("(a = 1) or (b = 2) or (c = \"C\")", e.toString()); } @Test public void testExp_Long() { Expression e = ExpressionFactory.exp("216201000180L"); assertEquals(216201000180L, e.evaluate(new Object())); } @Test public void testExp_Path() { Expression e1 = ExpressionFactory.exp("object.path"); assertEquals(Expression.OBJ_PATH, e1.getType()); Expression e2 = ExpressionFactory.exp("db:object.path"); assertEquals(Expression.DB_PATH, e2.getType()); Expression e3 = ExpressionFactory.exp("object+.path"); assertEquals(Expression.OBJ_PATH, e3.getType()); Expression e4 = ExpressionFactory.exp("db:object.path+"); assertEquals(Expression.DB_PATH, e4.getType()); } @Test public void testExp_Scalar() { Expression e1 = ExpressionFactory.exp("a = 'abc'"); assertEquals("abc", e1.getOperand(1)); } @Test public void testExp_Enum() { Expression e1 = ExpressionFactory.exp("a = enum:org.apache.cayenne.exp.ExpEnum1.ONE"); assertEquals(ExpEnum1.ONE, e1.getOperand(1)); Expression e2 = ExpressionFactory.exp("a = enum:org.apache.cayenne.exp.ExpEnum1.TWO"); assertEquals(ExpEnum1.TWO, e2.getOperand(1)); Expression e3 = ExpressionFactory.exp("a = enum:org.apache.cayenne.exp.ExpEnum1.THREE"); assertEquals(ExpEnum1.THREE, e3.getOperand(1)); } @Test(expected = ExpressionException.class) public void testExp_EnumInvalid1() { ExpressionFactory.exp("a = enum:org.apache.cayenne.exp.ExpEnum1.BOGUS"); } @Test(expected = ExpressionException.class) public void testExp_EnumInvalid2() { ExpressionFactory.exp("a = enum:BOGUS"); } @Test public void testExp_Vararg_InAsValues() { Expression e = ExpressionFactory.exp("k1 in ($ap, $bp)", "a", "b"); assertEquals("k1 in (\"a\", \"b\")", e.toString()); } @Test public void testPathExp() { assertEquals("abc.xyz", ExpressionFactory.pathExp("abc.xyz").toString()); } @Test public void testDbPathExp() { assertEquals("db:abc.xyz", ExpressionFactory.dbPathExp("abc.xyz").toString()); } @Test public void testFuncExp() { Expression e = ExpressionFactory.exp("trim(abc.xyz)"); assertEquals(ASTTrim.class, e.getClass()); } // CAY-2081 @Test(expected = ExpressionException.class) public void testExceptionInParse() { ExpressionFactory.exp("name like %32_65415'"); } }