From 3ae614fc269e45ba4af09c77a339b39c0650fe4b Mon Sep 17 00:00:00 2001 From: Pinaki Poddar Date: Thu, 30 Jul 2009 19:56:52 +0000 Subject: [PATCH] OPENJPA-1013: Add tests for multiselect() git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@799432 13f79535-47bb-0310-9956-ffa450edef68 --- .../persistence/criteria/CriteriaTest.java | 4 +- .../openjpa/persistence/criteria/Person.java | 8 + .../criteria/results/TestMultiselect.java | 277 ++++++++++++++++++ 3 files changed, 287 insertions(+), 2 deletions(-) create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestMultiselect.java diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/CriteriaTest.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/CriteriaTest.java index 651a1cbbd..4947a3853 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/CriteriaTest.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/CriteriaTest.java @@ -59,8 +59,8 @@ public abstract class CriteriaTest extends TestCase { protected static OpenJPAEntityManagerFactorySPI emf; protected static SQLAuditor auditor; - CriteriaBuilder cb; - EntityManager em; + protected CriteriaBuilder cb; + protected EntityManager em; protected static Class[] CLASSES = { Account.class, diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/Person.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/Person.java index 8b05cc7de..1b392d118 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/Person.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/Person.java @@ -38,6 +38,14 @@ public class Person { @ElementCollection private Set nickNames; + + protected Person() { + this("?"); + } + + public Person(String name) { + setName(name); + } public int getId() { return id; diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestMultiselect.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestMultiselect.java new file mode 100644 index 000000000..b1c1bbd64 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestMultiselect.java @@ -0,0 +1,277 @@ +/* + * 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.openjpa.persistence.criteria.results; + +import java.lang.reflect.Array; +import java.util.List; + +import javax.persistence.PersistenceException; +import javax.persistence.Tuple; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.apache.openjpa.persistence.criteria.CriteriaTest; +import org.apache.openjpa.persistence.criteria.Person; +import org.apache.openjpa.persistence.criteria.Person_; +import org.apache.openjpa.persistence.test.AllowFailure; + + +/** + * Test variations of {@link CriteriaQuery#multiselect(java.util.List)} arguments. + * + * @author Pinaki Poddar + * + */ + +@AllowFailure(value=true, message="Tests:16 Errors:1 Failure:7") +public class TestMultiselect extends CriteriaTest { + private static final Class[] CLASSES = {Person.class}; + private static boolean initialized = false; + + @Override + public void setUp() { + super.setUp(); + if (!initialized) { + createData(); + initialized = true; + } + } + + @Override + protected Class[] getDomainClasses() { + return CLASSES; + } + + void createData() { + em.getTransaction().begin(); + Person p = new Person("Test Result Shape"); + em.persist(p); + em.getTransaction().commit(); + } + + /** + * If the type of the criteria query is CriteriaQuery + * (i.e., a criteria query object created by either the + * createTupleQuery method or by passing a Tuple class argument + * to the createQuery method), a Tuple object corresponding to + * the elements of the list passed to the multiselect method + * will be instantiated and returned for each row that results + * from the query execution. + * */ + + public void testTupleQuery() { + CriteriaQuery q = cb.createTupleQuery(); + Root p = q.from(Person.class); + q.multiselect(p.get(Person_.name), p.get(Person_.id)); + + assertResult(q, Tuple.class); + } + + public void testTupleQueryExplicit() { + CriteriaQuery q = cb.createQuery(Tuple.class); + Root p = q.from(Person.class); + q.multiselect(p.get(Person_.name), p.get(Person_.id)); + + assertResult(q, Tuple.class); + } + + //======================================================================= + + /** + * If the type of the criteria query is CriteriaQuery for + * some user-defined class X (i.e., a criteria query object + * created by passing a X class argument to the createQuery + * method), then the elements of the list passed to the + * multiselect method will be passed to the X constructor and + * an instance of type X will be returned for each row. + */ + public void testUserResultQueryWithExplictProjectionOfConstructorArguments() { + CriteriaQuery q = cb.createQuery(Person.class); + Root p = q.from(Person.class); + q.multiselect(p.get(Person_.name)); + + assertResult(q, Person.class); + } + + public void testUserResultQueryWithImplicitProjection() { + CriteriaQuery q = cb.createQuery(Person.class); + Root p = q.from(Person.class); + + assertResult(q, Person.class); + } + + public void testUserResultQueryWithMismatchProjectionOfConstructorArguments() { + CriteriaQuery q = cb.createQuery(Person.class); + Root p = q.from(Person.class); + q.multiselect(p.get(Person_.name), p.get(Person_.id)); + + fail("Person has no constrcutor with (name,id)", q); + } + + // ====================================================================== + /** + * If the type of the criteria query is CriteriaQuery for + * some class X, an instance of type X[] will be returned for + * each row. The elements of the array will correspond to the + * elements of the list passed to the multiselect method. + */ + + public void testUserClassArray() { + CriteriaQuery q = cb.createQuery(Person[].class); + Root p = q.from(Person.class); + q.multiselect(p,p); + + assertResult(q, Person[].class, Person.class, Person.class); + } + + public void testBasicClassArray() { + CriteriaQuery q = cb.createQuery(String[].class); + Root p = q.from(Person.class); + q.multiselect(p.get(Person_.name), p.get(Person_.name)); + + assertResult(q, String[].class); + } + + public void testTupleArray() { + CriteriaQuery q = cb.createQuery(Tuple[].class); + Root p = q.from(Person.class); + q.multiselect(p.get(Person_.name), p.get(Person_.name)); + + assertResult(q, Tuple[].class); + } +// ================================================================= + /** + * If the type of the criteria query is CriteriaQuery + * or if the criteria query was created without specifying a + * type, and the list passed to the multiselect method contains + * only a single element, an instance of type Object will be + * returned for each row. + */ + public void testSingleObject() { + CriteriaQuery q = cb.createQuery(Object.class); + Root p = q.from(Person.class); + q.multiselect(p); + + assertResult(q, Object.class); + } + + public void testSingleObjectViaConstructor() { + CriteriaQuery q = cb.createQuery(Object.class); + Root p = q.from(Person.class); + q.multiselect(cb.construct(Person.class, p.get(Person_.name))); + + assertResult(q, Object.class); + } + + public void testSingleObjectAsProperty() { + CriteriaQuery q = cb.createQuery(Object.class); + Root p = q.from(Person.class); + q.multiselect(p.get(Person_.name)); + + assertResult(q, Object.class); + } + + public void testSingleObjectImplicit() { + CriteriaQuery q = cb.createQuery(); + Root p = q.from(Person.class); + q.multiselect(p); + + assertResult(q, Object.class); + } + + public void testSingleObjectViaConstructorImplicit() { + CriteriaQuery q = cb.createQuery(); + Root p = q.from(Person.class); + q.multiselect(cb.construct(Person.class, p.get(Person_.name))); + + assertResult(q, Object.class); + } + + public void testSingleObjectAsPropertyImplicit() { + CriteriaQuery q = cb.createQuery(); + Root p = q.from(Person.class); + q.multiselect(p.get(Person_.name)); + + assertResult(q, Object.class); + } + +// ================================================================================ + /** + * If the type of the criteria query is CriteriaQuery + * or if the criteria query was created without specifying a + * type, and the list passed to the multiselect method contains + * more than one element, an instance of type Object[] will be + * instantiated and returned for each row. The elements of the + * array will correspond to the elements of the list passed to + * the multiselect method. + */ + public void testSingleObjectMultipleProjections() { + CriteriaQuery q = cb.createQuery(Object.class); + Root p = q.from(Person.class); + q.multiselect(p.get(Person_.name), p.get(Person_.id)); + + assertResult(q, Object[].class, String.class, Integer.class); + } + + public void testSingleObjectMultipleProjectionsAndConstructor() { + CriteriaQuery q = cb.createQuery(Object.class); + Root p = q.from(Person.class); + q.multiselect(cb.construct(Person.class, p.get(Person_.name)), p.get(Person_.id), p.get(Person_.name)); + + assertResult(q, Object[].class, Person.class, Integer.class, String.class); + } + + /** + * An element of the list passed to the multiselect method + * must not be a tuple- or array-valued compound selection item. + */ + + +// =============== assertions by result types ======================== + + void assertResult(CriteriaQuery q, Class resultClass) { + assertResult(q, resultClass, (Class[])null); + } + /** + * Assert the query result elements by their types + */ + void assertResult(CriteriaQuery q, Class resultClass, Class... arrayElementClasses) { + List result = em.createQuery(q).getResultList(); + assertFalse(result.isEmpty()); + for (Object row : result) { + assertTrue(row.getClass() + " does not match actual result " + resultClass, resultClass.isInstance(row)); + if (resultClass.isArray() && arrayElementClasses != null) { + for (int i = 0; i < arrayElementClasses.length; i++) { + Object element = Array.get(row, i); + assertTrue(i + "-th array element " + arrayElementClasses[i] + " does not match actual result " + + element.getClass(), arrayElementClasses[i].isInstance(element)); + } + } + } + } + + void fail(String msg, CriteriaQuery q) { + try { + em.createQuery(q).getResultList(); + fail("Expected to fail " + msg); + } catch (PersistenceException e) { + // this is an expected exception + } + } +}