Repository: cayenne
Updated Branches:
  refs/heads/master eb0373e81 -> 60c556675


http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/OrderingTranslatorIT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/OrderingTranslatorIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/OrderingTranslatorIT.java
deleted file mode 100644
index 0aff229..0000000
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/OrderingTranslatorIT.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*****************************************************************
- *   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.access.translator.select;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.Arrays;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.access.DataNode;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.exp.ExpressionFactory;
-import org.apache.cayenne.exp.FunctionExpressionFactory;
-import org.apache.cayenne.query.Ordering;
-import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.query.SortOrder;
-import org.apache.cayenne.testdo.testmap.Artist;
-import org.apache.cayenne.unit.di.server.CayenneProjects;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.ServerCaseDataSourceFactory;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-import org.junit.Test;
-
-@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
-public class OrderingTranslatorIT extends ServerCase {
-
-       @Inject
-       private DataNode node;
-
-       @Inject
-       private ServerCaseDataSourceFactory dataSourceFactory;
-
-       /**
-        * Tests ascending ordering on string attribute.
-        */
-       @Test
-       public void testAppendPart1() throws Exception {
-               Ordering o1 = new Ordering("artistName", SortOrder.ASCENDING);
-               doTestAppendPart("ta.ARTIST_NAME", o1);
-       }
-
-       /**
-        * Tests descending ordering on string attribute.
-        */
-       @Test
-       public void testAppendPart2() throws Exception {
-               Ordering o1 = new Ordering("artistName", SortOrder.DESCENDING);
-               doTestAppendPart("ta.ARTIST_NAME DESC", o1);
-       }
-
-       @Test
-       public void testAppendPart3() throws Exception {
-
-               Ordering o1 = new Ordering("artistName", SortOrder.DESCENDING);
-               Ordering o2 = new Ordering("paintingArray.estimatedPrice", 
SortOrder.ASCENDING);
-
-               doTestAppendPart("ta.ARTIST_NAME DESC, ta.ESTIMATED_PRICE", o1, 
o2);
-       }
-
-       /**
-        * Tests ascending case-insensitive ordering on string attribute.
-        */
-       @Test
-       public void testAppendPart4() throws Exception {
-               Ordering o1 = new Ordering("artistName", 
SortOrder.ASCENDING_INSENSITIVE);
-               doTestAppendPart("UPPER(ta.ARTIST_NAME)", o1);
-       }
-
-       @Test
-       public void testAppendPart5() throws Exception {
-
-               Ordering o1 = new Ordering("artistName", 
SortOrder.DESCENDING_INSENSITIVE);
-               Ordering o2 = new Ordering("paintingArray.estimatedPrice", 
SortOrder.ASCENDING);
-
-               doTestAppendPart("UPPER(ta.ARTIST_NAME) DESC, 
ta.ESTIMATED_PRICE", o1, o2);
-       }
-
-       @Test
-       public void testAppendPart6() throws Exception {
-               Ordering o1 = new Ordering("artistName", 
SortOrder.ASCENDING_INSENSITIVE);
-               Ordering o2 = new Ordering("paintingArray.estimatedPrice", 
SortOrder.ASCENDING_INSENSITIVE);
-
-               doTestAppendPart("UPPER(ta.ARTIST_NAME), 
UPPER(ta.ESTIMATED_PRICE)", o1, o2);
-       }
-
-       @Test
-       public void testAppendFunctionExpression1() throws Exception {
-               Ordering o1 = new 
Ordering(FunctionExpressionFactory.absExp("paintingArray.estimatedPrice"));
-
-               doTestAppendPart("ABS(ta.ESTIMATED_PRICE)", o1);
-       }
-
-       @Test
-       public void testAppendFunctionExpression2() throws Exception {
-               Ordering o1 = new 
Ordering(FunctionExpressionFactory.countExp(ExpressionFactory.pathExp("dateOfBirth")),
 SortOrder.ASCENDING_INSENSITIVE);
-               Ordering o2 = new 
Ordering(FunctionExpressionFactory.sqrtExp("paintingArray.estimatedPrice"), 
SortOrder.DESCENDING);
-
-               doTestAppendPart("UPPER(COUNT(ta.DATE_OF_BIRTH)), 
SQRT(ta.ESTIMATED_PRICE) DESC", o1, o2);
-       }
-
-       @Test(expected = CayenneRuntimeException.class)
-       public void testAppendIllegalExpression() throws Exception {
-               Ordering o1 = new 
Ordering(ExpressionFactory.and(ExpressionFactory.expTrue(), 
ExpressionFactory.expFalse()));
-               // should throw exception
-               doTestAppendPart("TRUE AND FALSE", o1);
-       }
-
-       private void doTestAppendPart(String expectedSQL, Ordering... 
orderings) {
-
-               SelectQuery<Artist> q = SelectQuery.query(Artist.class);
-               q.addOrderings(Arrays.asList(orderings));
-
-               TstQueryAssembler assembler = new TstQueryAssembler(q, 
node.getAdapter(), node.getEntityResolver());
-               StringBuilder out = new StringBuilder();
-               String translated = new 
OrderingTranslator(assembler).appendPart(out).toString();
-
-               assertEquals(expectedSQL, translated);
-       }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/PathComponentsTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/PathComponentsTest.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/PathComponentsTest.java
new file mode 100644
index 0000000..89e9a57
--- /dev/null
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/PathComponentsTest.java
@@ -0,0 +1,77 @@
+/*****************************************************************
+ *   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.access.translator.select;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * @since 4.1
+ */
+public class PathComponentsTest {
+
+    private PathComponents components1;
+    private PathComponents components2;
+    private PathComponents components3;
+
+    @Before
+    public void setUp() {
+        components1 = new PathComponents("a");
+        components2 = new PathComponents("a+.bcd");
+        components3 = new PathComponents("a.bc.defg");
+    }
+
+    @Test
+    public void size() {
+        assertEquals(1, components1.size());
+        assertEquals(2, components2.size());
+        assertEquals(3, components3.size());
+    }
+
+    @Test
+    public void getLast() {
+        assertEquals("a", components1.getLast());
+        assertEquals("bcd", components2.getLast());
+        assertEquals("defg", components3.getLast());
+    }
+
+    @Test
+    public void getParent() {
+        assertEquals("", components1.getParent());
+        assertEquals("a+", components2.getParent());
+        assertEquals("a.bc", components3.getParent());
+    }
+
+    @Test
+    public void getAll() {
+        assertArrayEquals(new String[]{"a"}, components1.getAll());
+        assertArrayEquals(new String[]{"a+", "bcd"}, components2.getAll());
+        assertArrayEquals(new String[]{"a", "bc", "defg"}, 
components3.getAll());
+    }
+
+    @Test
+    public void getPath() {
+        assertEquals("a", components1.getPath());
+        assertEquals("a+.bcd", components2.getPath());
+        assertEquals("a.bc.defg", components3.getPath());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslationStageTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslationStageTest.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslationStageTest.java
new file mode 100644
index 0000000..9b56c81
--- /dev/null
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslationStageTest.java
@@ -0,0 +1,89 @@
+/*****************************************************************
+ *   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.access.translator.select;
+
+import org.apache.cayenne.access.sqlbuilder.sqltree.ColumnNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.Node;
+import org.apache.cayenne.access.sqlbuilder.sqltree.OpExpressionNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.ValueNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.WhereNode;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.*;
+
+/**
+ * @since 4.2
+ */
+public class QualifierTranslationStageTest {
+
+    private TranslatorContext context;
+
+    @Before
+    public void prepareContext() {
+        DbEntity dbEntity = new DbEntity();
+        dbEntity.setName("mock");
+        DbAttribute dbAttribute = new DbAttribute();
+        dbAttribute.setName("path");
+        dbEntity.addAttribute(dbAttribute);
+
+        TranslatableQueryWrapper wrapper = new MockQueryWrapperBuilder()
+                .withQualifier(ExpressionFactory.greaterOrEqualDbExp("path", 
10))
+                .withMetaData(new MockQueryMetadataBuilder()
+                        .withDbEntity(dbEntity)
+                        .build())
+                .build();
+        context = new MockTranslatorContext(wrapper);
+    }
+
+    @Test
+    public void perform() {
+        QualifierTranslationStage stage = new QualifierTranslationStage();
+        stage.perform(context);
+
+        Node select = context.getSelectBuilder().build();
+
+        // Content of "select" node:
+        //
+        //      Where
+        //        |
+        //   OpExpression
+        //    /        \
+        // Column     Value
+
+        assertEquals(1, select.getChildrenCount());
+        assertThat(select.getChild(0), instanceOf(WhereNode.class));
+        Node op = select.getChild(0).getChild(0);
+        assertThat(op, instanceOf(OpExpressionNode.class));
+        assertEquals(">=", ((OpExpressionNode)op).getOp());
+        assertEquals(2, op.getChildrenCount());
+        assertThat(op.getChild(0), instanceOf(ColumnNode.class));
+        assertThat(op.getChild(1), instanceOf(ValueNode.class));
+
+        ColumnNode columnNode = (ColumnNode)op.getChild(0);
+        ValueNode valueNode = (ValueNode)op.getChild(1);
+        assertEquals("path", columnNode.getColumn());
+        assertEquals(10, valueNode.getValue());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslatorIT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslatorIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslatorIT.java
deleted file mode 100644
index 2f2c71d..0000000
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslatorIT.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*****************************************************************
- *   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.access.translator.select;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import java.util.Arrays;
-
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.access.DataNode;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.exp.Expression;
-import org.apache.cayenne.exp.ExpressionFactory;
-import org.apache.cayenne.query.MockQuery;
-import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.testdo.testmap.Artist;
-import org.apache.cayenne.testdo.testmap.Exhibit;
-import org.apache.cayenne.testdo.testmap.Gallery;
-import org.apache.cayenne.testdo.testmap.Painting;
-import org.apache.cayenne.unit.di.server.CayenneProjects;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.ServerCaseDataSourceFactory;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-import org.junit.Test;
-
-@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
-public class QualifierTranslatorIT extends ServerCase {
-
-       @Inject
-       private DataNode node;
-
-       @Inject
-       private ServerCaseDataSourceFactory dataSourceFactory;
-
-       // TODO: not an integration test; extract into *Test
-       @Test
-       public void testNonQualifiedQuery() {
-               TstQueryAssembler qa = new TstQueryAssembler(new MockQuery(), 
node.getAdapter(), node.getEntityResolver());
-
-               try {
-                       new QualifierTranslator(qa).appendPart(new 
StringBuilder());
-                       fail();
-               } catch (ClassCastException ccex) {
-                       // exception expected
-               }
-       }
-
-       // TODO: not an integration test; extract into *Test
-       @Test
-       public void testNullQualifier() {
-               TstQueryAssembler qa = new TstQueryAssembler(new 
SelectQuery<>(), node.getAdapter(),
-                               node.getEntityResolver());
-
-               StringBuilder out = new StringBuilder();
-               new QualifierTranslator(qa).appendPart(out);
-               assertEquals(0, out.length());
-       }
-
-       @Test
-       public void testBinary_In1() {
-               doExpressionTest(Exhibit.class, "toGallery.galleryName in 
('g1', 'g2', 'g3')", "ta.GALLERY_NAME IN (?, ?, ?)");
-       }
-
-       @Test
-       public void testBinary_In2() {
-               Expression exp = 
ExpressionFactory.inExp("toGallery.galleryName",
-                               Arrays.asList("g1", "g2", "g3"));
-               doExpressionTest(Exhibit.class, exp, "ta.GALLERY_NAME IN (?, ?, 
?)");
-       }
-
-       @Test
-       public void testBinary_In3() {
-               Expression exp = 
ExpressionFactory.inExp("toGallery.galleryName", "g1", "g2", "g3");
-               doExpressionTest(Exhibit.class, exp, "ta.GALLERY_NAME IN (?, ?, 
?)");
-       }
-
-       @Test
-       public void testBinary_Like() {
-               doExpressionTest(Exhibit.class, "toGallery.galleryName like 
'a%'", "ta.GALLERY_NAME LIKE ?");
-       }
-
-       @Test
-       public void testBinary_LikeIgnoreCase() {
-               doExpressionTest(Exhibit.class, "toGallery.galleryName 
likeIgnoreCase 'a%'",
-                               "UPPER(ta.GALLERY_NAME) LIKE UPPER(?)");
-       }
-
-       @Test
-       public void testBinary_IsNull() {
-               doExpressionTest(Exhibit.class, "toGallery.galleryName = null", 
"ta.GALLERY_NAME IS NULL");
-       }
-
-       @Test
-       public void testBinary_IsNotNull() {
-               doExpressionTest(Exhibit.class, "toGallery.galleryName != 
null", "ta.GALLERY_NAME IS NOT NULL");
-       }
-
-       @Test
-       public void testTernary_Between() {
-               doExpressionTest(Painting.class, "estimatedPrice between 3000 
and 15000", "ta.ESTIMATED_PRICE BETWEEN ? AND ?");
-       }
-
-       @Test
-       public void testExtras() {
-               ObjectId oid1 = new ObjectId("Gallery", "GALLERY_ID", 1);
-               ObjectId oid2 = new ObjectId("Gallery", "GALLERY_ID", 2);
-               Gallery g1 = new Gallery();
-               Gallery g2 = new Gallery();
-               g1.setObjectId(oid1);
-               g2.setObjectId(oid2);
-
-               Expression e1 = ExpressionFactory.matchExp("toGallery", g1);
-               Expression e2 = 
e1.orExp(ExpressionFactory.matchExp("toGallery", g2));
-
-               doExpressionTest(Exhibit.class, e2, "(ta.GALLERY_ID = ?) OR 
(ta.GALLERY_ID = ?)");
-       }
-
-       @Test
-       public void testTrim() {
-               doExpressionTest(Artist.class, 
Artist.ARTIST_NAME.trim().like("P%"),
-                               "TRIM(ta.ARTIST_NAME) LIKE ?");
-       }
-
-       @Test
-       public void testConcat() {
-               doExpressionTest(Artist.class, 
Artist.ARTIST_NAME.concat(Artist.DATE_OF_BIRTH).like("P%"),
-                               "CONCAT(ta.ARTIST_NAME, ta.DATE_OF_BIRTH) LIKE 
?");
-       }
-
-       private void doExpressionTest(Class<?> queryType, String qualifier, 
String expectedSQL) {
-               doExpressionTest(queryType, ExpressionFactory.exp(qualifier), 
expectedSQL);
-       }
-
-       private void doExpressionTest(Class<?> queryType, Expression qualifier, 
String expectedSQL) {
-
-               SelectQuery<?> q = new SelectQuery<>(queryType);
-               q.setQualifier(qualifier);
-
-               TstQueryAssembler qa = new TstQueryAssembler(q, 
node.getAdapter(), node.getEntityResolver());
-
-               StringBuilder out = new StringBuilder();
-               String translated = new 
QualifierTranslator(qa).appendPart(out).toString();
-               assertEquals(expectedSQL, translated);
-
-       }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslatorTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslatorTest.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslatorTest.java
new file mode 100644
index 0000000..1f78ae0
--- /dev/null
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QualifierTranslatorTest.java
@@ -0,0 +1,524 @@
+/*****************************************************************
+ *   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.access.translator.select;
+
+import java.util.Arrays;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.access.sqlbuilder.sqltree.BetweenNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.BitwiseNotNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.ColumnNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.EqualNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.FunctionNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.InNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.LikeNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.Node;
+import org.apache.cayenne.access.sqlbuilder.sqltree.NotEqualNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.NotNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.OpExpressionNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.SelectNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.TextNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.ValueNode;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.parser.ASTAsterisk;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.query.ObjectSelect;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.*;
+
+/**
+ * @since 4.2
+ */
+public class QualifierTranslatorTest {
+
+    private QualifierTranslator translator;
+
+    @Before
+    public void prepareTranslator() {
+        DbEntity dbEntity = new DbEntity();
+        dbEntity.setName("mock");
+
+        DbAttribute dbAttributeA = new DbAttribute();
+        dbAttributeA.setName("a");
+        dbEntity.addAttribute(dbAttributeA);
+
+        DbAttribute dbAttributeB = new DbAttribute();
+        dbAttributeB.setName("b");
+        dbAttributeB.setPrimaryKey(true);
+        dbEntity.addAttribute(dbAttributeB);
+
+        ObjEntity entity = new ObjEntity();
+        entity.setName("mock");
+        ObjAttribute attribute = new ObjAttribute();
+        attribute.setName("a");
+        attribute.setDbAttributePath("a");
+        entity.addAttribute(attribute);
+        entity.setDbEntity(dbEntity);
+
+        DataMap dataMap = new DataMap();
+        dataMap.addDbEntity(dbEntity);
+        dataMap.addObjEntity(entity);
+
+        EntityResolver resolver = new EntityResolver();
+        resolver.addDataMap(dataMap);
+
+        TranslatableQueryWrapper wrapper = new MockQueryWrapperBuilder()
+                .withMetaData(new MockQueryMetadataBuilder()
+                        .withDbEntity(dbEntity)
+                        .withObjEntity(entity)
+                        .build())
+                .build();
+        TranslatorContext context = new MockTranslatorContext(wrapper, 
resolver);
+        translator = new QualifierTranslator(context);
+    }
+
+    @Test
+    public void translateNull() {
+        assertNull(translator.translate((Expression)null));
+        assertNull(translator.translate((Property<?>)null));
+    }
+
+    @Test
+    public void translateIn() {
+        {
+            Node in = translate("db:a in (1,2)");
+            assertThat(in, instanceOf(InNode.class));
+            assertEquals(2, in.getChildrenCount());
+            assertFalse(((InNode) in).isNot());
+            assertThat(in.getChild(0), instanceOf(ColumnNode.class));
+            assertThat(in.getChild(1), instanceOf(ValueNode.class));
+            assertEquals("a", ((ColumnNode) in.getChild(0)).getColumn());
+            assertArrayEquals(new Object[]{1, 2}, (Object[]) ((ValueNode) 
in.getChild(1)).getValue());
+        }
+
+        {
+            Node in = translator.translate(ExpressionFactory.inExp("a", 
Arrays.asList(1, 2, 3)));
+            assertThat(in, instanceOf(InNode.class));
+            assertEquals(2, in.getChildrenCount());
+            assertFalse(((InNode) in).isNot());
+            assertThat(in.getChild(0), instanceOf(ColumnNode.class));
+            assertThat(in.getChild(1), instanceOf(ValueNode.class));
+            assertEquals("a", ((ColumnNode) in.getChild(0)).getColumn());
+            assertArrayEquals(new Object[]{1, 2, 3}, (Object[]) ((ValueNode) 
in.getChild(1)).getValue());
+        }
+
+        {
+            Node notIn = translate("db:a not in (1,2)");
+            assertThat(notIn, instanceOf(InNode.class));
+            assertEquals(2, notIn.getChildrenCount());
+            assertTrue(((InNode) notIn).isNot());
+            assertThat(notIn.getChild(0), instanceOf(ColumnNode.class));
+            assertThat(notIn.getChild(1), instanceOf(ValueNode.class));
+            assertEquals("a", ((ColumnNode) notIn.getChild(0)).getColumn());
+            assertArrayEquals(new Object[]{1, 2}, (Object[]) ((ValueNode) 
notIn.getChild(1)).getValue());
+        }
+
+    }
+
+    @Test
+    public void translateBetween() {
+        {
+            Node between = translate("db:a between 1 and 5");
+            assertThat(between, instanceOf(BetweenNode.class));
+            assertEquals(3, between.getChildrenCount());
+            assertFalse(((BetweenNode) between).isNot());
+            assertThat(between.getChild(0), instanceOf(ColumnNode.class));
+            assertThat(between.getChild(1), instanceOf(ValueNode.class));
+            assertThat(between.getChild(2), instanceOf(ValueNode.class));
+        }
+
+        {
+            Node notBetween = translate("db:b not between 2 and 6");
+            assertThat(notBetween, instanceOf(BetweenNode.class));
+            assertEquals(3, notBetween.getChildrenCount());
+            assertTrue(((BetweenNode) notBetween).isNot());
+            assertThat(notBetween.getChild(0), instanceOf(ColumnNode.class));
+            assertThat(notBetween.getChild(1), instanceOf(ValueNode.class));
+            assertThat(notBetween.getChild(2), instanceOf(ValueNode.class));
+        }
+    }
+
+    @Test
+    public void translateNot() {
+        Node not = translate("not true");
+        assertThat(not, instanceOf(NotNode.class));
+        assertEquals(1, not.getChildrenCount());
+        assertThat(not.getChild(0), instanceOf(TextNode.class));
+        assertEquals(" 1=1", ((TextNode)not.getChild(0)).getText());
+    }
+
+    @Test
+    public void translateBitwiseNot() {
+        Node not = translate("~123");
+        assertThat(not, instanceOf(BitwiseNotNode.class));
+        assertEquals(1, not.getChildrenCount());
+        assertThat(not.getChild(0), instanceOf(ValueNode.class));
+        assertEquals(123, ((ValueNode)not.getChild(0)).getValue());
+    }
+
+    @Test
+    public void translateEqual() {
+        {
+            Node eq = translate("db:a = 123");
+            assertThat(eq, instanceOf(EqualNode.class));
+            assertEquals(2, eq.getChildrenCount());
+            assertThat(eq.getChild(0), instanceOf(ColumnNode.class));
+            assertThat(eq.getChild(1), instanceOf(ValueNode.class));
+            assertEquals("a", ((ColumnNode) eq.getChild(0)).getColumn());
+            assertEquals(123, ((ValueNode) eq.getChild(1)).getValue());
+        }
+
+        {
+            Node neq = translate("db:b != 321");
+            assertThat(neq, instanceOf(NotEqualNode.class));
+            assertEquals(2, neq.getChildrenCount());
+            assertThat(neq.getChild(0), instanceOf(ColumnNode.class));
+            assertThat(neq.getChild(1), instanceOf(ValueNode.class));
+            assertEquals("b", ((ColumnNode) neq.getChild(0)).getColumn());
+            assertEquals(321, ((ValueNode) neq.getChild(1)).getValue());
+        }
+    }
+
+    @Test
+    public void translateLike() {
+        {
+            // no support for escape char in exp parser
+            Node like = translator.translate(ExpressionFactory.likeExp("a", 
"abc", '~'));
+            assertThat(like, instanceOf(LikeNode.class));
+            assertEquals('~', ((LikeNode) like).getEscape());
+            assertFalse(((LikeNode) like).isIgnoreCase());
+            assertFalse(((LikeNode) like).isNot());
+            assertEquals(2, like.getChildrenCount());
+            assertThat(like.getChild(0), instanceOf(ColumnNode.class));
+            assertThat(like.getChild(1), instanceOf(ValueNode.class));
+            assertEquals("a", ((ColumnNode) like.getChild(0)).getColumn());
+            assertEquals("abc", ((ValueNode) like.getChild(1)).getValue());
+        }
+
+        {
+            Node notLike = translate("db:a not like 'abc'");
+            assertThat(notLike, instanceOf(LikeNode.class));
+            assertEquals(0, ((LikeNode) notLike).getEscape());
+            assertFalse(((LikeNode) notLike).isIgnoreCase());
+            assertTrue(((LikeNode) notLike).isNot());
+            assertEquals(2, notLike.getChildrenCount());
+            assertThat(notLike.getChild(0), instanceOf(ColumnNode.class));
+            assertThat(notLike.getChild(1), instanceOf(ValueNode.class));
+            assertEquals("a", ((ColumnNode) notLike.getChild(0)).getColumn());
+            assertEquals("abc", ((ValueNode) notLike.getChild(1)).getValue());
+        }
+
+        {
+            Node likeIgnoreCase = translate("db:a likeIgnoreCase 'abc'");
+            assertThat(likeIgnoreCase, instanceOf(LikeNode.class));
+            assertEquals(0, ((LikeNode) likeIgnoreCase).getEscape());
+            assertTrue(((LikeNode) likeIgnoreCase).isIgnoreCase());
+            assertFalse(((LikeNode) likeIgnoreCase).isNot());
+            assertEquals(2, likeIgnoreCase.getChildrenCount());
+            assertThat(likeIgnoreCase.getChild(0), 
instanceOf(ColumnNode.class));
+            assertThat(likeIgnoreCase.getChild(1), 
instanceOf(ValueNode.class));
+            assertEquals("a", ((ColumnNode) 
likeIgnoreCase.getChild(0)).getColumn());
+            assertEquals("abc", ((ValueNode) 
likeIgnoreCase.getChild(1)).getValue());
+        }
+
+        {
+            Node notLikeIgnoreCase = translate("db:a not likeIgnoreCase 
'abc'");
+            assertThat(notLikeIgnoreCase, instanceOf(LikeNode.class));
+            assertEquals(0, ((LikeNode) notLikeIgnoreCase).getEscape());
+            assertTrue(((LikeNode) notLikeIgnoreCase).isIgnoreCase());
+            assertTrue(((LikeNode) notLikeIgnoreCase).isNot());
+            assertEquals(2, notLikeIgnoreCase.getChildrenCount());
+            assertThat(notLikeIgnoreCase.getChild(0), 
instanceOf(ColumnNode.class));
+            assertThat(notLikeIgnoreCase.getChild(1), 
instanceOf(ValueNode.class));
+            assertEquals("a", ((ColumnNode) 
notLikeIgnoreCase.getChild(0)).getColumn());
+            assertEquals("abc", ((ValueNode) 
notLikeIgnoreCase.getChild(1)).getValue());
+        }
+    }
+
+    @Test
+    public void translateFunctionCall() {
+        {
+            Node function = translate("trim(a)");
+            assertThat(function, instanceOf(FunctionNode.class));
+            assertEquals("TRIM", ((FunctionNode) function).getFunctionName());
+            assertNull(((FunctionNode) function).getAlias());
+            assertEquals(1, function.getChildrenCount());
+            assertThat(function.getChild(0), instanceOf(ColumnNode.class));
+            assertEquals("a", ((ColumnNode) function.getChild(0)).getColumn());
+        }
+
+        {
+            Node function = translate("year(a)");
+            assertThat(function, instanceOf(FunctionNode.class));
+            assertEquals("YEAR", ((FunctionNode) function).getFunctionName());
+            assertNull(((FunctionNode) function).getAlias());
+            assertEquals(1, function.getChildrenCount());
+            assertThat(function.getChild(0), instanceOf(ColumnNode.class));
+            assertEquals("a", ((ColumnNode) function.getChild(0)).getColumn());
+        }
+    }
+
+    @Test
+    public void translateMathExp() {
+        {
+            Node op = translate("1 + 2");
+            assertThat(op, instanceOf(OpExpressionNode.class));
+            assertEquals("+", ((OpExpressionNode)op).getOp());
+            assertEquals(2, op.getChildrenCount());
+        }
+
+        {
+            Node op = translate("1 - 2");
+            assertThat(op, instanceOf(OpExpressionNode.class));
+            assertEquals("-", ((OpExpressionNode)op).getOp());
+            assertEquals(2, op.getChildrenCount());
+        }
+
+        {
+            Node op = translate("1 / 2");
+            assertThat(op, instanceOf(OpExpressionNode.class));
+            assertEquals("/", ((OpExpressionNode)op).getOp());
+            assertEquals(2, op.getChildrenCount());
+        }
+
+        {
+            Node op = translate("1 * 2");
+            assertThat(op, instanceOf(OpExpressionNode.class));
+            assertEquals("*", ((OpExpressionNode)op).getOp());
+            assertEquals(2, op.getChildrenCount());
+        }
+
+        {
+            Node op = translate("-2");
+            assertThat(op, instanceOf(OpExpressionNode.class));
+            assertEquals("-", ((OpExpressionNode)op).getOp());
+            assertEquals(1, op.getChildrenCount());
+        }
+
+        {
+            Node op = translate("1 & 2");
+            assertThat(op, instanceOf(OpExpressionNode.class));
+            assertEquals("&", ((OpExpressionNode)op).getOp());
+            assertEquals(2, op.getChildrenCount());
+        }
+
+        {
+            Node op = translate("1 | 2");
+            assertThat(op, instanceOf(OpExpressionNode.class));
+            assertEquals("|", ((OpExpressionNode)op).getOp());
+            assertEquals(2, op.getChildrenCount());
+        }
+
+        {
+            Node op = translate("1 ^ 2");
+            assertThat(op, instanceOf(OpExpressionNode.class));
+            assertEquals("^", ((OpExpressionNode)op).getOp());
+            assertEquals(2, op.getChildrenCount());
+        }
+
+        {
+            Node op = translate("1 << 2");
+            assertThat(op, instanceOf(OpExpressionNode.class));
+            assertEquals("<<", ((OpExpressionNode)op).getOp());
+            assertEquals(2, op.getChildrenCount());
+        }
+
+        {
+            Node op = translate("1 >> 2");
+            assertThat(op, instanceOf(OpExpressionNode.class));
+            assertEquals(">>", ((OpExpressionNode)op).getOp());
+            assertEquals(2, op.getChildrenCount());
+        }
+
+    }
+
+    @Test
+    public void translateComparision() {
+        {
+            Node op = translate("a < 2");
+            assertThat(op, instanceOf(OpExpressionNode.class));
+            assertEquals("<", ((OpExpressionNode)op).getOp());
+            assertEquals(2, op.getChildrenCount());
+        }
+
+        {
+            Node op = translate("a > 2");
+            assertThat(op, instanceOf(OpExpressionNode.class));
+            assertEquals(">", ((OpExpressionNode)op).getOp());
+            assertEquals(2, op.getChildrenCount());
+        }
+
+        {
+            Node op = translate("a <= 2");
+            assertThat(op, instanceOf(OpExpressionNode.class));
+            assertEquals("<=", ((OpExpressionNode)op).getOp());
+            assertEquals(2, op.getChildrenCount());
+        }
+
+        {
+            Node op = translate("a >= 2");
+            assertThat(op, instanceOf(OpExpressionNode.class));
+            assertEquals(">=", ((OpExpressionNode)op).getOp());
+            assertEquals(2, op.getChildrenCount());
+        }
+    }
+
+    @Test
+    public void translateConst() {
+        {
+            Node op = translate("true");
+            assertThat(op, instanceOf(TextNode.class));
+            assertEquals(" 1=1", ((TextNode)op).getText());
+            assertEquals(0, op.getChildrenCount());
+        }
+
+        {
+            Node op = translate("false");
+            assertThat(op, instanceOf(TextNode.class));
+            assertEquals(" 1=0", ((TextNode)op).getText());
+            assertEquals(0, op.getChildrenCount());
+        }
+
+        {
+            Node op = translator.translate(new ASTAsterisk());
+            assertThat(op, instanceOf(TextNode.class));
+            assertEquals(" *", ((TextNode)op).getText());
+            assertEquals(0, op.getChildrenCount());
+        }
+    }
+
+    @Test
+    public void translateExists() {
+        Node exists = 
translator.translate(ExpressionFactory.exists(ObjectSelect.dbQuery("mock")));
+        assertThat(exists, instanceOf(FunctionNode.class));
+        assertEquals("EXISTS", ((FunctionNode) exists).getFunctionName());
+        assertEquals(1, exists.getChildrenCount());
+        assertThat(exists.getChild(0), instanceOf(SelectNode.class));
+    }
+
+    @Test
+    public void translateFullObject() {
+        Node fullObj = translator.translate(ExpressionFactory.fullObjectExp());
+        assertThat(fullObj, instanceOf(ColumnNode.class));
+        ColumnNode columnNode = (ColumnNode)fullObj;
+        assertEquals("b", columnNode.getColumn());
+    }
+
+    @Test(expected = CayenneRuntimeException.class)
+    public void translateEnclosingObject() {
+        // can't translate enclosing exp not in nested query
+        
translator.translate(ExpressionFactory.enclosingObjectExp(ExpressionFactory.dbPathExp("a")));
+    }
+
+    @Test
+    public void translateAnd() {
+        Node and = translate("true and false");
+        assertNotNull(and);
+        assertThat(and, instanceOf(OpExpressionNode.class));
+        assertEquals("AND", ((OpExpressionNode)and).getOp());
+        assertEquals(2, and.getChildrenCount());
+        assertThat(and.getChild(0), instanceOf(TextNode.class));
+        assertEquals(" 1=1", ((TextNode)and.getChild(0)).getText());
+        assertThat(and.getChild(1), instanceOf(TextNode.class));
+        assertEquals(" 1=0", ((TextNode)and.getChild(1)).getText());
+    }
+
+    @Test
+    public void translateOr() {
+        Node or = translate("true or false");
+        assertNotNull(or);
+        assertThat(or, instanceOf(OpExpressionNode.class));
+        assertEquals("OR", ((OpExpressionNode)or).getOp());
+        assertEquals(2, or.getChildrenCount());
+        assertThat(or.getChild(0), instanceOf(TextNode.class));
+        assertThat(or.getChild(1), instanceOf(TextNode.class));
+    }
+
+    @Test
+    public void translateComplexExp() {
+        Node result = translate("(a >= 1 + 2 / 3 << 4) and (db:b != true)");
+
+        {
+            assertNotNull(result);
+            assertThat(result, instanceOf(OpExpressionNode.class));
+            assertEquals("AND", ((OpExpressionNode) result).getOp());
+            assertEquals(2, result.getChildrenCount());
+            assertThat(result.getChild(0), instanceOf(OpExpressionNode.class));
+            assertThat(result.getChild(1), instanceOf(NotEqualNode.class));
+        }
+
+        {
+            OpExpressionNode left = (OpExpressionNode) result.getChild(0);
+            assertEquals(">=", left.getOp());
+            assertEquals(2, left.getChildrenCount());
+            assertThat(left.getChild(0), instanceOf(ColumnNode.class));
+            assertEquals("a", ((ColumnNode)left.getChild(0)).getColumn());
+            assertThat(left.getChild(1), instanceOf(OpExpressionNode.class));
+            {
+                OpExpressionNode shift = (OpExpressionNode)left.getChild(1);
+                assertEquals("<<", shift.getOp());
+                assertThat(shift.getChild(0), 
instanceOf(OpExpressionNode.class));
+                {
+                    OpExpressionNode plus = 
(OpExpressionNode)shift.getChild(0);
+                    assertEquals("+", plus.getOp());
+                    assertEquals(2, plus.getChildrenCount());
+                    assertThat(plus.getChild(0), instanceOf(ValueNode.class));
+                    assertEquals(1, ((ValueNode)plus.getChild(0)).getValue());
+                    assertThat(plus.getChild(1), 
instanceOf(OpExpressionNode.class));
+                    {
+                        OpExpressionNode div = 
(OpExpressionNode)plus.getChild(1);
+                        assertEquals("/", div.getOp());
+                        assertEquals(2, div.getChildrenCount());
+                        assertThat(div.getChild(0), 
instanceOf(ValueNode.class));
+                        assertEquals(2, 
((ValueNode)div.getChild(0)).getValue());
+                        assertThat(div.getChild(0), 
instanceOf(ValueNode.class));
+                        assertEquals(3, 
((ValueNode)div.getChild(1)).getValue());
+                    }
+                }
+                assertThat(shift.getChild(1), instanceOf(ValueNode.class));
+                assertEquals(4, ((ValueNode)shift.getChild(1)).getValue());
+            }
+        }
+
+        {
+            NotEqualNode right = (NotEqualNode) result.getChild(1);
+            assertEquals(2, right.getChildrenCount());
+            assertThat(right.getChild(0), instanceOf(ColumnNode.class));
+            assertEquals("b", ((ColumnNode)right.getChild(0)).getColumn());
+            assertThat(right.getChild(1), instanceOf(ValueNode.class));
+            assertEquals(Boolean.TRUE, 
((ValueNode)right.getChild(1)).getValue());
+        }
+    }
+
+    private Node translate(String s) {
+        return translator.translate(ExpressionFactory.exp(s));
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QueryAssemblerIT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QueryAssemblerIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QueryAssemblerIT.java
deleted file mode 100644
index 05c51e6..0000000
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/QueryAssemblerIT.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*****************************************************************
- *   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.access.translator.select;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import org.apache.cayenne.access.DataNode;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.unit.di.server.CayenneProjects;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-import org.junit.Before;
-import org.junit.Test;
-
-@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
-public class QueryAssemblerIT extends ServerCase {
-
-       @Inject
-       private DataNode node;
-
-       private TstQueryAssembler qa;
-
-       @Before
-       public void setUp() throws Exception {
-               this.qa = new TstQueryAssembler(new SelectQuery<Object>(), 
node.getAdapter(), node.getEntityResolver());
-       }
-
-       @Test
-       public void testGetQuery() throws Exception {
-               assertNotNull(qa.getQuery());
-       }
-
-       @Test
-       public void testAddToParamList() throws Exception {
-
-               assertEquals(0, qa.getBindings().length);
-
-               qa.addToParamList(new DbAttribute(), new Object());
-               assertEquals(1, qa.getBindings().length);
-       }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/TstQueryAssembler.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/TstQueryAssembler.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/TstQueryAssembler.java
deleted file mode 100644
index 72a3803..0000000
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/TstQueryAssembler.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*****************************************************************
- *   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.access.translator.select;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.cayenne.dba.DbAdapter;
-import org.apache.cayenne.exp.Expression;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.EntityResolver;
-import org.apache.cayenne.map.JoinType;
-import org.apache.cayenne.query.Query;
-
-public class TstQueryAssembler extends QueryAssembler {
-
-       protected List<DbRelationship> dbRels;
-
-       public TstQueryAssembler(Query q, DbAdapter adapter, EntityResolver 
resolver) {
-               super(q, adapter, resolver);
-               dbRels = new ArrayList<DbRelationship>();
-       }
-
-       @Override
-       public void dbRelationshipAdded(DbRelationship relationship, JoinType 
joinType, String joinSplitAlias) {
-               dbRels.add(relationship);
-       }
-
-       @Override
-       public String getCurrentAlias() {
-               return "ta";
-       }
-
-       @Override
-       public void resetJoinStack() {
-               // noop
-       }
-
-       @Override
-       public boolean supportsTableAliases() {
-               return true;
-       }
-
-       @Override
-       public String getAliasForExpression(Expression exp) {
-               return null;
-       }
-
-       @Override
-       protected void doTranslate() {
-               this.sql = "SELECT * FROM ARTIST";
-       }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
index e73402d..8c2bdd5 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
@@ -167,7 +167,7 @@ public class PathAliasesIT extends ServerCase {
         List<Object[]> artistAndPaintingCount = 
ObjectSelect.columnQuery(Artist.class, Artist.ARTIST_NAME, 
Artist.PAINTING_ARRAY.count())
                 .having(Artist.PAINTING_ARRAY.alias("p1").count().lt(5L))
                 .select(context);
-        assertEquals(4, artistAndPaintingCount.size());
+        assertEquals(19, artistAndPaintingCount.size());
         assertTrue((Long)artistAndPaintingCount.get(0)[1] < 5);
     }
 
@@ -296,7 +296,7 @@ public class PathAliasesIT extends ServerCase {
         List<Object[]> artistAndPaintingCount = 
ObjectSelect.columnQuery(Artist.class, Artist.ARTIST_NAME, 
Artist.PAINTING_ARRAY.count())
                 .having(PropertyFactory.createBase(e1, 
Number.class).count().lt(5L))
                 .select(context);
-        assertEquals(4, artistAndPaintingCount.size());
+        assertEquals(19, artistAndPaintingCount.size());
         assertTrue((Long)artistAndPaintingCount.get(0)[1] < 5);
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java 
b/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java
index a0b2486..cbd2e03 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java
@@ -56,6 +56,7 @@ import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 
+import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.junit.Assert.*;
 
 /**
@@ -492,6 +493,7 @@ public class ColumnSelectIT extends ServerCase {
                 PropertyFactory.createSelf(Artist.class)
         ).select(context);
         assertEquals(21, result.size());
+
         for(Object[] next : result) {
             long count = (Long)next[0];
             Artist artist = (Artist)next[1];
@@ -502,12 +504,12 @@ public class ColumnSelectIT extends ServerCase {
             Artist artist3 = (Artist)next[6];
 
             assertTrue(paintingTitle.startsWith("painting"));
-            assertTrue(count == 4L || count == 5L);
             assertEquals("tate modern", galleryName);
             assertEquals(PersistenceState.COMMITTED, 
artist.getPersistenceState());
             assertEquals(PersistenceState.COMMITTED, 
artist2.getPersistenceState());
             assertEquals(PersistenceState.COMMITTED, 
artist3.getPersistenceState());
             assertEquals(artistName, artist.getArtistName());
+            assertTrue(count == 4L || count == 5L);
         }
     }
 
@@ -607,7 +609,7 @@ public class ColumnSelectIT extends ServerCase {
                 .pageSize(10)
                 .select(context);
         assertNotNull(a);
-        assertEquals(5, a.size());
+        assertEquals(20, a.size());
         int idx = 0;
         for(Object[] next : a) {
             assertNotNull(next);
@@ -655,7 +657,7 @@ public class ColumnSelectIT extends ServerCase {
                 .pageSize(10)
                 .select(context);
         assertNotNull(a);
-        assertEquals(5, a.size());
+        assertEquals(20, a.size());
         int idx = 0;
         for(Object[] next : a) {
             assertNotNull(next);
@@ -673,14 +675,17 @@ public class ColumnSelectIT extends ServerCase {
                 .columns(Artist.ARTIST_NAME, artistFull, 
Artist.PAINTING_ARRAY.flat())
                 .pageSize(10)
                 .select(context);
+
         assertNotNull(a);
-        assertEquals(21, a.size());
+        assertEquals(36, a.size());
         int idx = 0;
         for(Object[] next : a) {
             assertNotNull(next);
             assertEquals("" + idx, String.class, next[0].getClass());
             assertEquals("" + idx, Artist.class, next[1].getClass());
-            assertEquals("" + idx, Painting.class, next[2].getClass());
+            if(next[2] != null) {
+                assertEquals("" + idx, Painting.class, next[2].getClass());
+            }
             idx++;
         }
     }
@@ -728,9 +733,9 @@ public class ColumnSelectIT extends ServerCase {
     private void checkPrefetchResults(List<Object[]> result) {
         assertEquals(21, result.size());
         for(Object[] next : result) {
-            assertTrue(next[0] instanceof Artist);
-            assertTrue(next[1] instanceof java.util.Date);
-            assertTrue(next[2] instanceof String);
+            assertThat(next[0], instanceOf(Artist.class));
+            assertThat(next[1], instanceOf(java.util.Date.class));
+            assertThat(next[2], instanceOf(String.class));
             Artist artist = (Artist)next[0];
             assertEquals(PersistenceState.COMMITTED, 
artist.getPersistenceState());
 
@@ -777,7 +782,7 @@ public class ColumnSelectIT extends ServerCase {
     }
 
     private void checkAggregatePrefetchResults(List<Object[]> result) {
-        assertEquals(5, result.size());
+        assertEquals(20, result.size());
         for(Object[] next : result) {
             assertTrue(next[0] instanceof Artist);
             assertTrue(next[1] instanceof Long);
@@ -847,7 +852,7 @@ public class ColumnSelectIT extends ServerCase {
         List<Object[]> result = ObjectSelect.query(Artist.class)
                 .columns(artistProperty, Artist.ARTIST_NAME, 
Artist.PAINTING_ARRAY.count())
                 .select(context);
-        assertEquals(5, result.size());
+        assertEquals(20, result.size());
 
         for(Object[] next : result) {
             assertTrue(next[0] instanceof Artist);
@@ -898,15 +903,19 @@ public class ColumnSelectIT extends ServerCase {
         List<Object[]> result = ObjectSelect.query(Artist.class)
                 .columns(artistProperty, Artist.PAINTING_ARRAY.flat(), 
Artist.PAINTING_ARRAY.dot(Painting.TO_GALLERY))
                 .select(context);
-        assertEquals(21, result.size());
+        assertEquals(36, result.size());
 
         for(Object[] next : result) {
             assertTrue(next[0] instanceof Artist);
-            assertTrue(next[1] instanceof Painting);
-            assertTrue(next[2] instanceof Gallery);
             assertEquals(PersistenceState.COMMITTED, 
((Artist)next[0]).getPersistenceState());
-            assertEquals(PersistenceState.COMMITTED, 
((Painting)(next[1])).getPersistenceState());
-            assertEquals(PersistenceState.COMMITTED, 
((Gallery)(next[2])).getPersistenceState());
+            if(next[1] != null) {
+                assertTrue(next[1] instanceof Painting);
+                assertEquals(PersistenceState.COMMITTED, 
((Painting)(next[1])).getPersistenceState());
+            }
+            if(next[2] != null) {
+                assertTrue(next[2] instanceof Gallery);
+                assertEquals(PersistenceState.COMMITTED, ((Gallery) 
(next[2])).getPersistenceState());
+            }
         }
     }
 
@@ -918,24 +927,29 @@ public class ColumnSelectIT extends ServerCase {
         assertEquals(21, result.size());
     }
 
-    @Test(expected = CayenneRuntimeException.class)
+    @Test
     public void testSelfPropertyInOrderBy() {
         EntityProperty<Artist> artistProperty = 
PropertyFactory.createSelf(Artist.class);
-        ObjectSelect.query(Artist.class)
+        List<Artist> artists = ObjectSelect.query(Artist.class)
                 .column(artistProperty)
                 .orderBy(artistProperty.desc())
                 .select(context);
+        assertEquals(20, artists.size());
+        assertEquals("artist20", artists.get(0).getArtistName());
+        assertEquals("artist1", artists.get(19).getArtistName());
     }
 
-    @Test(expected = CayenneRuntimeException.class)
+    @Test
     public void testSelfPropertyInWhere() {
         Artist artist = ObjectSelect.query(Artist.class).selectFirst(context);
         EntityProperty<Artist> artistProperty = 
PropertyFactory.createSelf(Artist.class);
-        List<Artist> result = ObjectSelect.query(Artist.class)
+        Artist selectedArtist = ObjectSelect.query(Artist.class)
                 .column(artistProperty)
                 .where(artistProperty.eq(artist))
-                .select(context);
-        assertNotNull(result);
+                .orderBy(artistProperty.asc())
+                .selectOne(context);
+        assertNotNull(selectedArtist);
+        assertEquals(artist.getArtistName(), selectedArtist.getArtistName());
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/test/java/org/apache/cayenne/unit/IngresUnitDbAdapter.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/unit/IngresUnitDbAdapter.java 
b/cayenne-server/src/test/java/org/apache/cayenne/unit/IngresUnitDbAdapter.java
index aa043ec..279b096 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/unit/IngresUnitDbAdapter.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/unit/IngresUnitDbAdapter.java
@@ -21,6 +21,9 @@ package org.apache.cayenne.unit;
 
 import org.apache.cayenne.dba.DbAdapter;
 
+/**
+ * Ingress doesn't support sorting by an aggregate expression (ORDER BY 
COUNT(some_field))
+ */
 public class IngresUnitDbAdapter extends UnitDbAdapter {
 
     public IngresUnitDbAdapter(DbAdapter adapter) {
@@ -51,4 +54,9 @@ public class IngresUnitDbAdapter extends UnitDbAdapter {
     public boolean supportsSelectBooleanExpression() {
         return false;
     }
+
+    @Override
+    public boolean isLowerCaseNames() {
+        return true;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/test/java/org/apache/cayenne/util/ArrayUtilTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/util/ArrayUtilTest.java 
b/cayenne-server/src/test/java/org/apache/cayenne/util/ArrayUtilTest.java
new file mode 100644
index 0000000..8b159b1
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/util/ArrayUtilTest.java
@@ -0,0 +1,354 @@
+/*****************************************************************
+ *   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.util;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * @since 4.1
+ */
+public class ArrayUtilTest {
+
+    @Test
+    public void sliceIntArray() {
+        int[] array = {1, 2, 3, 4, 5, 6, 7};
+
+        int[][] result = ArrayUtil.sliceArray(array, 2);
+
+        assertEquals(4, result.length);
+        assertArrayEquals(new int[]{1, 2}, result[0]);
+        assertArrayEquals(new int[]{3, 4}, result[1]);
+        assertArrayEquals(new int[]{5, 6}, result[2]);
+        assertArrayEquals(new int[]{7},    result[3]);
+
+        int[][] result2 = ArrayUtil.sliceArray(array, 4);
+
+        assertEquals(2, result2.length);
+        assertArrayEquals(new int[]{1, 2, 3, 4}, result2[0]);
+        assertArrayEquals(new int[]{5, 6, 7}, result2[1]);
+
+        int[][] result3 = ArrayUtil.sliceArray(array, 7);
+
+        assertEquals(1, result3.length);
+        assertArrayEquals(array, result3[0]);
+
+        int[][] result4 = ArrayUtil.sliceArray(array, 10);
+
+        assertEquals(1, result4.length);
+        assertArrayEquals(array, result4[0]);
+
+        int[] array2 = {1, 2, 3, 4, 5, 6, 7, 8};
+        int[][] result5 = ArrayUtil.sliceArray(array2, 4);
+
+        assertEquals(2, result5.length);
+        assertArrayEquals(new int[]{1, 2, 3, 4}, result5[0]);
+        assertArrayEquals(new int[]{5, 6, 7, 8}, result5[1]);
+    }
+
+    @Test
+    public void sliceLongArray() {
+        long[] array = {1, 2, 3, 4, 5, 6, 7};
+
+        long[][] result = ArrayUtil.sliceArray(array, 2);
+
+        assertEquals(4, result.length);
+        assertArrayEquals(new long[]{1, 2}, result[0]);
+        assertArrayEquals(new long[]{3, 4}, result[1]);
+        assertArrayEquals(new long[]{5, 6}, result[2]);
+        assertArrayEquals(new long[]{7},    result[3]);
+
+        long[][] result2 = ArrayUtil.sliceArray(array, 4);
+
+        assertEquals(2, result2.length);
+        assertArrayEquals(new long[]{1, 2, 3, 4}, result2[0]);
+        assertArrayEquals(new long[]{5, 6, 7}, result2[1]);
+
+        long[][] result3 = ArrayUtil.sliceArray(array, 7);
+
+        assertEquals(1, result3.length);
+        assertArrayEquals(array, result3[0]);
+
+        long[][] result4 = ArrayUtil.sliceArray(array, 10);
+
+        assertEquals(1, result4.length);
+        assertArrayEquals(array, result4[0]);
+
+        long[] array2 = {1, 2, 3, 4, 5, 6, 7, 8};
+        long[][] result5 = ArrayUtil.sliceArray(array2, 4);
+
+        assertEquals(2, result5.length);
+        assertArrayEquals(new long[]{1, 2, 3, 4}, result5[0]);
+        assertArrayEquals(new long[]{5, 6, 7, 8}, result5[1]);
+    }
+
+    @Test
+    public void sliceFloatArray() {
+        float[] array = {1, 2, 3, 4, 5, 6, 7};
+
+        float[][] result = ArrayUtil.sliceArray(array, 2);
+
+        assertEquals(4, result.length);
+        assertArrayEquals(new float[]{1, 2}, result[0], 0.000001f);
+        assertArrayEquals(new float[]{3, 4}, result[1], 0.000001f);
+        assertArrayEquals(new float[]{5, 6}, result[2], 0.000001f);
+        assertArrayEquals(new float[]{7},    result[3], 0.000001f);
+
+        float[][] result2 = ArrayUtil.sliceArray(array, 4);
+
+        assertEquals(2, result2.length);
+        assertArrayEquals(new float[]{1, 2, 3, 4}, result2[0], 0.000001f);
+        assertArrayEquals(new float[]{5, 6, 7}, result2[1], 0.000001f);
+
+        float[][] result3 = ArrayUtil.sliceArray(array, 7);
+
+        assertEquals(1, result3.length);
+        assertArrayEquals(array, result3[0], 0.000001f);
+
+        float[][] result4 = ArrayUtil.sliceArray(array, 10);
+
+        assertEquals(1, result4.length);
+        assertArrayEquals(array, result4[0], 0.000001f);
+
+        float[] array2 = {1, 2, 3, 4, 5, 6, 7, 8};
+        float[][] result5 = ArrayUtil.sliceArray(array2, 4);
+
+        assertEquals(2, result5.length);
+        assertArrayEquals(new float[]{1, 2, 3, 4}, result5[0], 0.000001f);
+        assertArrayEquals(new float[]{5, 6, 7, 8}, result5[1], 0.000001f);
+    }
+
+    @Test
+    public void sliceDoubleArray() {
+        double[] array = {1, 2, 3, 4, 5, 6, 7};
+
+        double[][] result = ArrayUtil.sliceArray(array, 2);
+
+        assertEquals(4, result.length);
+        assertArrayEquals(new double[]{1, 2}, result[0], 0.000001);
+        assertArrayEquals(new double[]{3, 4}, result[1], 0.000001);
+        assertArrayEquals(new double[]{5, 6}, result[2], 0.000001);
+        assertArrayEquals(new double[]{7},    result[3], 0.000001);
+
+        double[][] result2 = ArrayUtil.sliceArray(array, 4);
+
+        assertEquals(2, result2.length);
+        assertArrayEquals(new double[]{1, 2, 3, 4}, result2[0], 0.000001);
+        assertArrayEquals(new double[]{5, 6, 7}, result2[1], 0.000001);
+
+        double[][] result3 = ArrayUtil.sliceArray(array, 7);
+
+        assertEquals(1, result3.length);
+        assertArrayEquals(array, result3[0], 0.000001);
+
+        double[][] result4 = ArrayUtil.sliceArray(array, 10);
+
+        assertEquals(1, result4.length);
+        assertArrayEquals(array, result4[0], 0.000001);
+
+        double[] array2 = {1, 2, 3, 4, 5, 6, 7, 8};
+        double[][] result5 = ArrayUtil.sliceArray(array2, 4);
+
+        assertEquals(2, result5.length);
+        assertArrayEquals(new double[]{1, 2, 3, 4}, result5[0], 0.000001);
+        assertArrayEquals(new double[]{5, 6, 7, 8}, result5[1], 0.000001);
+    }
+
+    @Test
+    public void sliceCharArray() {
+        char[] array = {1, 2, 3, 4, 5, 6, 7};
+
+        char[][] result = ArrayUtil.sliceArray(array, 2);
+
+        assertEquals(4, result.length);
+        assertArrayEquals(new char[]{1, 2}, result[0]);
+        assertArrayEquals(new char[]{3, 4}, result[1]);
+        assertArrayEquals(new char[]{5, 6}, result[2]);
+        assertArrayEquals(new char[]{7},    result[3]);
+
+        char[][] result2 = ArrayUtil.sliceArray(array, 4);
+
+        assertEquals(2, result2.length);
+        assertArrayEquals(new char[]{1, 2, 3, 4}, result2[0]);
+        assertArrayEquals(new char[]{5, 6, 7}, result2[1]);
+
+        char[][] result3 = ArrayUtil.sliceArray(array, 7);
+
+        assertEquals(1, result3.length);
+        assertArrayEquals(array, result3[0]);
+
+        char[][] result4 = ArrayUtil.sliceArray(array, 10);
+
+        assertEquals(1, result4.length);
+        assertArrayEquals(array, result4[0]);
+
+        char[] array2 = {1, 2, 3, 4, 5, 6, 7, 8};
+        char[][] result5 = ArrayUtil.sliceArray(array2, 4);
+
+        assertEquals(2, result5.length);
+        assertArrayEquals(new char[]{1, 2, 3, 4}, result5[0]);
+        assertArrayEquals(new char[]{5, 6, 7, 8}, result5[1]);
+    }
+
+    @Test
+    public void sliceShortArray() {
+        short[] array = {1, 2, 3, 4, 5, 6, 7};
+
+        short[][] result = ArrayUtil.sliceArray(array, 2);
+
+        assertEquals(4, result.length);
+        assertArrayEquals(new short[]{1, 2}, result[0]);
+        assertArrayEquals(new short[]{3, 4}, result[1]);
+        assertArrayEquals(new short[]{5, 6}, result[2]);
+        assertArrayEquals(new short[]{7},    result[3]);
+
+        short[][] result2 = ArrayUtil.sliceArray(array, 4);
+
+        assertEquals(2, result2.length);
+        assertArrayEquals(new short[]{1, 2, 3, 4}, result2[0]);
+        assertArrayEquals(new short[]{5, 6, 7}, result2[1]);
+
+        short[][] result3 = ArrayUtil.sliceArray(array, 7);
+
+        assertEquals(1, result3.length);
+        assertArrayEquals(array, result3[0]);
+
+        short[][] result4 = ArrayUtil.sliceArray(array, 10);
+
+        assertEquals(1, result4.length);
+        assertArrayEquals(array, result4[0]);
+
+        short[] array2 = {1, 2, 3, 4, 5, 6, 7, 8};
+        short[][] result5 = ArrayUtil.sliceArray(array2, 4);
+
+        assertEquals(2, result5.length);
+        assertArrayEquals(new short[]{1, 2, 3, 4}, result5[0]);
+        assertArrayEquals(new short[]{5, 6, 7, 8}, result5[1]);
+    }
+
+    @Test
+    public void sliceByteArray() {
+        byte[] array = {1, 2, 3, 4, 5, 6, 7};
+
+        byte[][] result = ArrayUtil.sliceArray(array, 2);
+
+        assertEquals(4, result.length);
+        assertArrayEquals(new byte[]{1, 2}, result[0]);
+        assertArrayEquals(new byte[]{3, 4}, result[1]);
+        assertArrayEquals(new byte[]{5, 6}, result[2]);
+        assertArrayEquals(new byte[]{7},    result[3]);
+
+        byte[][] result2 = ArrayUtil.sliceArray(array, 4);
+
+        assertEquals(2, result2.length);
+        assertArrayEquals(new byte[]{1, 2, 3, 4}, result2[0]);
+        assertArrayEquals(new byte[]{5, 6, 7}, result2[1]);
+
+        byte[][] result3 = ArrayUtil.sliceArray(array, 7);
+
+        assertEquals(1, result3.length);
+        assertArrayEquals(array, result3[0]);
+
+        byte[][] result4 = ArrayUtil.sliceArray(array, 10);
+
+        assertEquals(1, result4.length);
+        assertArrayEquals(array, result4[0]);
+
+        byte[] array2 = {1, 2, 3, 4, 5, 6, 7, 8};
+        byte[][] result5 = ArrayUtil.sliceArray(array2, 4);
+
+        assertEquals(2, result5.length);
+        assertArrayEquals(new byte[]{1, 2, 3, 4}, result5[0]);
+        assertArrayEquals(new byte[]{5, 6, 7, 8}, result5[1]);
+    }
+
+    @Test
+    public void sliceBooleanArray() {
+        boolean[] array = {true, true, false, true, false, false, true};
+
+        boolean[][] result = ArrayUtil.sliceArray(array, 2);
+
+        assertEquals(4, result.length);
+        assertArrayEquals(new boolean[]{true, true}, result[0]);
+        assertArrayEquals(new boolean[]{false, true}, result[1]);
+        assertArrayEquals(new boolean[]{false, false}, result[2]);
+        assertArrayEquals(new boolean[]{true},    result[3]);
+
+        boolean[][] result2 = ArrayUtil.sliceArray(array, 4);
+
+        assertEquals(2, result2.length);
+        assertArrayEquals(new boolean[]{true, true, false, true}, result2[0]);
+        assertArrayEquals(new boolean[]{false, false, true}, result2[1]);
+
+        boolean[][] result3 = ArrayUtil.sliceArray(array, 7);
+
+        assertEquals(1, result3.length);
+        assertArrayEquals(array, result3[0]);
+
+        boolean[][] result4 = ArrayUtil.sliceArray(array, 10);
+
+        assertEquals(1, result4.length);
+        assertArrayEquals(array, result4[0]);
+
+        boolean[] array2 = {true, true, false, true, false, false, true, 
false};
+        boolean[][] result5 = ArrayUtil.sliceArray(array2, 4);
+
+        assertEquals(2, result5.length);
+        assertArrayEquals(new boolean[]{true, true, false, true}, result5[0]);
+        assertArrayEquals(new boolean[]{false, false, true, false}, 
result5[1]);
+    }
+
+    @Test
+    public void sliceObjectArray() {
+        Object[] array = {1, 2, 3, 4, 5, 6, 7};
+
+        Object[][] result = ArrayUtil.sliceArray(array, 2);
+
+        assertEquals(4, result.length);
+        assertArrayEquals(new Object[]{1, 2}, result[0]);
+        assertArrayEquals(new Object[]{3, 4}, result[1]);
+        assertArrayEquals(new Object[]{5, 6}, result[2]);
+        assertArrayEquals(new Object[]{7},    result[3]);
+
+        Object[][] result2 = ArrayUtil.sliceArray(array, 4);
+
+        assertEquals(2, result2.length);
+        assertArrayEquals(new Object[]{1, 2, 3, 4}, result2[0]);
+        assertArrayEquals(new Object[]{5, 6, 7}, result2[1]);
+
+        Object[][] result3 = ArrayUtil.sliceArray(array, 7);
+
+        assertEquals(1, result3.length);
+        assertArrayEquals(array, result3[0]);
+
+        Object[][] result4 = ArrayUtil.sliceArray(array, 10);
+
+        assertEquals(1, result4.length);
+        assertArrayEquals(array, result4[0]);
+
+        Object[] array2 = {1, 2, 3, 4, 5, 6, 7, 8};
+        Object[][] result5 = ArrayUtil.sliceArray(array2, 4);
+
+        assertEquals(2, result5.length);
+        assertArrayEquals(new Object[]{1, 2, 3, 4}, result5[0]);
+        assertArrayEquals(new Object[]{5, 6, 7, 8}, result5[1]);
+    }
+}
\ No newline at end of file

Reply via email to