/*******************************************************************************
 * Copyright (c) 2005, 2009 SAP. All rights reserved.
 * This program and the accompanying materials are made available under the 
 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
 * which accompanies this distribution. 
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at 
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *     SAP - initial API and implementation
 ******************************************************************************/

package org.eclipse.persistence.testing.tests.wdf.jpa1.query;

import static javax.persistence.FlushModeType.AUTO;
import static javax.persistence.FlushModeType.COMMIT;
import static org.junit.Assert.assertEquals;

import java.sql.SQLException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.FlushModeType;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

import org.eclipse.persistence.testing.framework.wdf.JPAEnvironment;
import org.eclipse.persistence.testing.framework.wdf.ToBeInvestigated;
import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Department;
import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Project;
import org.eclipse.persistence.testing.models.wdf.jpa1.types.BasicTypesFieldAccess;
import org.eclipse.persistence.testing.tests.wdf.jpa1.JPA1Base;
import org.junit.Test;

@SuppressWarnings("unchecked")
public class TestSimpleQuery extends JPA1Base {

    private final Set<Department> ALL_DEPARTMENTS = new HashSet<Department>();
    private final Department dep10 = new Department(10, "ten");
    private final Department dep20 = new Department(20, "twenty");

    private void init() throws SQLException {
        clearAllTables();
        ALL_DEPARTMENTS.add(dep10);
        ALL_DEPARTMENTS.add(dep20);
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            env.beginTransaction(em);
            em.persist(dep10);
            em.persist(dep20);
            env.commitTransactionAndClear(em);
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testSelectAllDepartments() throws SQLException {
        init();
        EntityManager em = getEnvironment().getEntityManager();
        boolean extended = getEnvironment().usesExtendedPC();
        try {
            Query query = em.createQuery("select d from Department d");
            List result = query.getResultList();
            verify(result.size() == 2, "wrong resultcount");
            Iterator iter = result.iterator();
            Set<Department> actualSet = new HashSet<Department>();
            while (iter.hasNext()) {
                Department entity = (Department) iter.next();
                if (extended) {
                    verify(em.contains(entity), "entity manager doesn't contain result read outside transaction");
                } else {
                    verify(!em.contains(entity), "entity manager contains result read outside transaction");
                }
                actualSet.add(entity);
            }
            verify(ALL_DEPARTMENTS.equals(actualSet), "the sets are somehow different");
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testSelectDepartmentByName() throws SQLException {
        init();
        EntityManager em = getEnvironment().getEntityManager();
        boolean extended = getEnvironment().usesExtendedPC();
        try {
            Query query = em.createQuery("select d from Department d where d.name = ?1");
            query.setParameter(1, "twenty");
            List result = query.getResultList();
            Iterator iter = result.iterator();
            verify(iter.hasNext(), "row not found");
            Department entity = (Department) iter.next();
            if (extended) {
                verify(em.contains(entity), "entity manager doesn't contain result read outside transaction");
            } else {
                verify(!em.contains(entity), "entity manager contains result read outside transaction");
            }
            verify(entity.equals(dep20), " got wrong department");
            verify(!iter.hasNext(), "too many rows");
            query = em.createQuery("select distinct d from Department d where d.name = ?1");
            query.setParameter(1, "twenty");
            result = query.getResultList();
            iter = result.iterator();
            verify(iter.hasNext(), "row not found");
            entity = (Department) iter.next();
            if (extended) {
                verify(em.contains(entity), "entity manager doesn't contain result read outside transaction");
            } else {
                verify(!em.contains(entity), "entity manager contains result read outside transaction");
            }
            verify(entity.equals(dep20), " got wrong department");
            verify(!iter.hasNext(), "too many rows");
            query = em.createQuery("select d from Department d where d.name like 'twenty'");
            result = query.getResultList();
            iter = result.iterator();
            verify(iter.hasNext(), "row not found");
            entity = (Department) iter.next();
            if (extended) {
                verify(em.contains(entity), "entity manager doesn't contain result read outside transaction");
            } else {
                verify(!em.contains(entity), "entity manager contains result read outside transaction");
            }
            verify(entity.equals(dep20), " got wrong department");
            verify(!iter.hasNext(), "too many rows");
            query = em.createQuery("select d from Department d where d.name like 'twen%'");
            result = query.getResultList();
            iter = result.iterator();
            verify(iter.hasNext(), "row not found");
            entity = (Department) iter.next();
            if (extended) {
                verify(em.contains(entity), "entity manager doesn't contain result read outside transaction");
            } else {
                verify(!em.contains(entity), "entity manager contains result read outside transaction");
            }
            verify(entity.equals(dep20), " got wrong department");
            verify(!iter.hasNext(), "too many rows");
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testSelectInTransaction() throws SQLException {
        init();
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            env.beginTransaction(em);
            Query query = em.createQuery("select d from Department d");
            List result = query.getResultList();
            verify(result.size() == 2, "wrong resultcount");
            Iterator iter = result.iterator();
            while (iter.hasNext()) {
                Object entity = iter.next();
                verify(em.contains(entity), "entity manager doesn't contain result read inside transaction");
            }
            env.rollbackTransactionAndClear(em);
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testIntIsNull() throws SQLException {
        init();
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            env.beginTransaction(em);
            Project project = new Project(null);
            em.persist(project);
            final int projectId = project.getId().intValue();
            env.commitTransactionAndClear(em);
            Query query = em.createQuery("select p from Project p where p.name IS NULL");
            List result = query.getResultList();
            verify(result.size() == 1, "wrong resultcount");
            Iterator iter = result.iterator();
            while (iter.hasNext()) {
                project = (Project) iter.next();
                verify(project.getId().intValue() == projectId, "wrong project");
            }
            query = em.createQuery("select distinct p from Project p where p.name IS NULL");
            result = query.getResultList();
            verify(result.size() == 1, "wrong resultcount");
            iter = result.iterator();
            while (iter.hasNext()) {
                project = (Project) iter.next();
                verify(project.getId().intValue() == projectId, "wrong project");
            }
        } finally {
            closeEntityManager(em);
        }
    }

    private void verifyComparisonPrepdicateResult(EntityManager em, String txt, int... ids) {
        Query query = em.createQuery(txt);
        List result = query.getResultList();
        Set<Integer> actual = new HashSet<Integer>();
        for (Object object : result) {
            BasicTypesFieldAccess fa = (BasicTypesFieldAccess) object;
            actual.add(new Integer(fa.getId()));
        }
        Set<Integer> expected = new HashSet<Integer>();
        for (int i : ids) {
            expected.add(new Integer(i));
        }
        verify(expected.equals(actual), "expecetd and actual sets are different for query >>" + txt + "<<");
    }

    @Test
    public void testComparisonPrepdicate() throws SQLException {
        init();
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            env.beginTransaction(em);
            BasicTypesFieldAccess fa = new BasicTypesFieldAccess(17);
            fa.setPrimitiveInt(17);
            em.persist(fa);
            fa = new BasicTypesFieldAccess(18);
            fa.setPrimitiveInt(18);
            em.persist(fa);
            fa = new BasicTypesFieldAccess(19);
            fa.setPrimitiveInt(19);
            em.persist(fa);
            fa = new BasicTypesFieldAccess(20);
            fa.setPrimitiveInt(20);
            em.persist(fa);
            env.commitTransactionAndClear(em);
            verifyComparisonPrepdicateResult(em, "Select Object(a) from BasicTypesFieldAccess a where a.primitiveInt = 17", 17);
            verifyComparisonPrepdicateResult(em, "Select Object(a) from BasicTypesFieldAccess a where a.primitiveInt > 17", 18,
                    19, 20);
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testNamedQuery() throws SQLException {
        init();
        EntityManager em = getEnvironment().getEntityManager();
        boolean extended = getEnvironment().usesExtendedPC();
        try {
            Query query = em.createNamedQuery("getDepartmentByName"); // select d from Department d where d.name = ?1
            query.setParameter(1, "twenty");
            List result = query.getResultList();
            Iterator iter = result.iterator();
            verify(iter.hasNext(), "row not found");
            Department entity = (Department) iter.next();
            if (extended) {
                verify(em.contains(entity), "entity manager doesn't contain result read outside transaction");
            } else {
                verify(!em.contains(entity), "entity manager contains result read outside transaction");
            }
            verify(entity.equals(dep20), " got wrong department");
            verify(!iter.hasNext(), "too many rows");
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    @ToBeInvestigated
    public void testUndefinedNamedQuery() throws SQLException {
        init();
        EntityManager em = getEnvironment().getEntityManager();
        try {
            try {
                Query query = em.createNamedQuery("Hutzliputz");
                query.getResultList();
                flop("undefined query created");
            } catch (IllegalArgumentException e) {
            }
            try {
                Query query = em.createNamedQuery(null);
                query.getResultList();
                flop("undefined query created");
            } catch (IllegalArgumentException e) {
            }
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testNamedParameter() throws SQLException {
        init();
        EntityManager em = getEnvironment().getEntityManager();
        boolean extended = getEnvironment().usesExtendedPC();
        try {
            Query query = em.createQuery("select d from Department d where d.name = :name");
            query.setParameter("name", "twenty");
            List result = query.getResultList();
            Iterator iter = result.iterator();
            verify(iter.hasNext(), "row not found");
            Department entity = (Department) iter.next();
            if (extended) {
                verify(em.contains(entity), "entity manager doesn't contain result read outside transaction");
            } else {
                verify(!em.contains(entity), "entity manager contains result read outside transaction");
            }
            verify(entity.equals(dep20), " got wrong department");
            verify(!iter.hasNext(), "too many rows");
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testWrongParameter() throws SQLException {
        init();
        EntityManager em = getEnvironment().getEntityManager();
        try {
            try {
                Query query = em.createQuery("select d from Department d where d.name = :name");
                query.setParameter(1, "twenty");
                query.getResultList();
                flop("missing exception");
            } catch (RuntimeException e) {
            }
        } finally {
            closeEntityManager(em);
        }
    }
    
    @Test
    public void testCachedQueryWithClear() throws SQLException {
        init();
        EntityManager em = getEnvironment().getEntityManager();
        try {
            Query query = em.createNamedQuery("getDepartmentCached");
            query.setParameter(1, "twenty");
            List<Department> result = query.getResultList();
            verify(result.size() == 1, "wrong result size");
            em.clear();
            result = query.getResultList();
            verify(result.size() == 1, "wrong result size");
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testCachedQueryWithoutClear() throws SQLException {
        init();
        EntityManager em = getEnvironment().getEntityManager();
        try {
            Query query = em.createNamedQuery("getDepartmentCached");
            query.setParameter(1, "twenty");
            List<Department> result = query.getResultList();
            verify(result.size() == 1, "wrong result size");
            result = query.getResultList();
            verify(result.size() == 1, "wrong result size");
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testUnCachedQuery() throws SQLException {
        init();
        EntityManager em = getEnvironment().getEntityManager();
        try {
            Query query = em.createNamedQuery("getDepartmentUnCached");
            query.setParameter(1, "twenty");
            List<Department> result = query.getResultList();
            verify(result.size() == 1, "wrong result size");
            result = query.getResultList();
            verify(result.size() == 1, "wrong result size");
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    @ToBeInvestigated
    public void testQueryStringNotValid() throws SQLException {
        // TODO enable test as soon as functionality is implemented
        init();
        EntityManager em = getEnvironment().getEntityManager();
        try {
            boolean caught = false;
            Query query;
            try {
                query = em.createQuery("this is not a valid query");
                try {
                    query.getResultList();
                } catch (PersistenceException ex) {
                    caught = true;
                }
            } catch (IllegalArgumentException e) {
                caught = true;
            }
            verify(caught,
                    "illegal query threw neither IllegalArgumentExceptionon create nor PersistenceException on getResultList");
            caught = false;
            try {
                query = em.createQuery((String) null);
                try {
                    query.getResultList();
                } catch (PersistenceException ex) {
                    caught = true;
                }
            } catch (IllegalArgumentException e) {
                caught = true;
            }
            verify(caught,
                    "null query threw neither IllegalArgumentExceptionon create nor PersistenceException on getResultList");
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testExecuteQueryMultipleTimesWithSameParameter() throws SQLException {
        init();
        EntityManager em = getEnvironment().getEntityManager();
        boolean extended = getEnvironment().usesExtendedPC();
        try {
            Query query = em.createQuery("select d from Department d where d.name = :name");
            query.setParameter("name", "twenty");
            List result = query.getResultList();
            result = query.getResultList();
            Iterator iter = result.iterator();
            verify(iter.hasNext(), "row not found");
            Department entity = (Department) iter.next();
            if (extended) {
                verify(em.contains(entity), "entity manager doesn't contain result read outside transaction");
            } else {
                verify(!em.contains(entity), "entity manager contains result read outside transaction");
            }
            verify(entity.equals(dep20), " got wrong department");
            verify(!iter.hasNext(), "too many rows");
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testExecuteQueryMultipleTimesWithDifferentParameter() throws SQLException {
        init();
        EntityManager em = getEnvironment().getEntityManager();
        boolean extended = getEnvironment().usesExtendedPC();
        try {
            Query query = em.createQuery("select d from Department d where d.name = ?1 and d.id = ?2");
            query.setParameter(1, "twenty");
            query.setParameter(2, Integer.valueOf(20));
            List result = query.getResultList();
            Iterator iter = result.iterator();
            verify(iter.hasNext(), "row not found");
            Department entity = (Department) iter.next();
            if (extended) {
                verify(em.contains(entity), "entity manager doesn't contain result read outside transaction");
            } else {
                verify(!em.contains(entity), "entity manager contains result read outside transaction");
            }
            verify(entity.equals(dep20), " got wrong department");
            verify(!iter.hasNext(), "too many rows");
            query.setParameter(1, "ten");
            query.setParameter(2, Integer.valueOf(10));
            result = query.getResultList();
            iter = result.iterator();
            verify(iter.hasNext(), "row not found");
            entity = (Department) iter.next();
            if (extended) {
                verify(em.contains(entity), "entity manager doesn't contain result read outside transaction");
            } else {
                verify(!em.contains(entity), "entity manager contains result read outside transaction");
            }
            verify(entity.equals(dep10), " got wrong department");
            verify(!iter.hasNext(), "too many rows");
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testSingleResultOk() throws SQLException {
        init();
        EntityManager em = getEnvironment().getEntityManager();
        boolean extended = getEnvironment().usesExtendedPC();
        try {
            Query query = em.createQuery("select d from Department d where d.name = :name");
            query.setParameter("name", "twenty");
            Object entity = query.getSingleResult();
            if (extended) {
                verify(em.contains(entity), "entity manager doesn't contain result read outside transaction");
            } else {
                verify(!em.contains(entity), "entity manager contains result read outside transaction");
            }
            verify(entity.equals(dep20), " got wrong department");
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testNoResult() throws SQLException {
        init();
        EntityManager em = getEnvironment().getEntityManager();
        try {
            Query query = em.createQuery("select d from Department d where d.name = :name");
            query.setParameter("name", "hutzliputz");
            try {
                query.getSingleResult();
                flop("missing NoResultException");
            } catch (NoResultException e) {
            }
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testNonUniqueResult() throws SQLException {
        init();
        EntityManager em = getEnvironment().getEntityManager();
        try {
            Query query = em.createQuery("select d from Department d");
            try {
                query.getSingleResult();
                flop("missing NonUniqueResultException");
            } catch (NonUniqueResultException e) {
            }
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testQueryWithFlush() throws SQLException {
        clearAllTables();
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            env.beginTransaction(em);
            em.persist(dep10);
            env.commitTransactionAndClear(em);
            env.beginTransaction(em);
            Department dep = em.find(Department.class, new Integer(10));
            dep.setName("newName");
            em.flush();
            Query query = em.createQuery("select d from Department d where d.name = :name");
            query.setParameter("name", "newName");
            Department entity = (Department) query.getSingleResult();
            verify(entity.getName().equals("newName"), " wrong department name");
            env.commitTransactionAndClear(em);
        } finally {
            closeEntityManager(em);
        }
    }
    
    private static boolean hasGetmaxRowsMethod() {
        try {
            return Query.class.getMethod("getMaxResults") != null;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }

    private void verifyRowCount(Query query, int maxRows, int startPos, int expected) throws SecurityException, NoSuchMethodException {
        query.setMaxResults(maxRows);
        query.setFirstResult(startPos);

        if (hasGetmaxRowsMethod()) {
            assertEquals(query.getMaxResults(), maxRows);
            assertEquals(query.getFirstResult(), startPos);
        }

        int count = query.getResultList().size();
        verify(count == expected, "wrong row count: " + count);

        if (hasGetmaxRowsMethod()) {
            assertEquals(query.getMaxResults(), maxRows);
            assertEquals(query.getFirstResult(), startPos);
        }
    }

    @Test
    public void testMaxResult() throws SQLException, SecurityException, NoSuchMethodException {
        clearAllTables();
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            env.beginTransaction(em);
            for (int i = 0; i < 10; i++) {
                em.persist(new Project("P" + i));
            }
            env.commitTransaction(em);
            em.clear();
            Query query = em.createQuery("select p from Project p");
            verifyRowCount(query, 5, 0, 5);
            verifyRowCount(query, 10, 0, 10);
            verifyRowCount(query, 15, 0, 10);
            verifyRowCount(query, 5, 5, 5);
            verifyRowCount(query, 10, 5, 5);
            verifyRowCount(query, 15, 5, 5);
            verifyRowCount(query, 5, 7, 3);
            verifyRowCount(query, 10, 7, 3);
            verifyRowCount(query, 15, 7, 3);
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testMaxResultUnlimited() throws SQLException, SecurityException, NoSuchMethodException {
        clearAllTables();
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            env.beginTransaction(em);
            for (int i = 0; i < 10; i++) {
                em.persist(new Project("P" + i));
            }
            env.commitTransaction(em);
            em.clear();
            Query query = em.createQuery("select p from Project p");
            verifyRowCount(query, Integer.MAX_VALUE, 0, 10);
            verifyRowCount(query, Integer.MAX_VALUE, 5, 5);
            verifyRowCount(query, Integer.MAX_VALUE, 7, 3);
        } finally {
            closeEntityManager(em);
        }
    }
    
    @Test
    public void testPagingDefaults() throws SQLException {
        if (!hasGetmaxRowsMethod()) {
            return;
        }
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            Query query = em.createQuery("select p from Project p");
            assertEquals(0, query.getFirstResult());
            assertEquals(Integer.MAX_VALUE, query.getMaxResults());
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testFlushMode() throws SQLException {
        testFlushMode(AUTO, null);
        testFlushMode(AUTO, AUTO);
        testFlushMode(AUTO, COMMIT);
        testFlushMode(COMMIT, null);
        testFlushMode(COMMIT, AUTO);
        testFlushMode(COMMIT, COMMIT);
    }

    private void testFlushMode(FlushModeType flushModeEM, FlushModeType flushModeQuery) throws SQLException {
        init();
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            env.beginTransaction(em);
            Query query = em.createQuery("select d from Department d where d.name = 'updated'");
            if (flushModeEM == COMMIT) {
                em.setFlushMode(COMMIT);
            }
            verify(em.getFlushMode() == flushModeEM, "wrong flushMode");
            if (flushModeQuery != null) {
                query.setFlushMode(flushModeQuery);
            }
            boolean flushExpected = isFlushExpected(flushModeEM, flushModeQuery);
            Department dep = em.find(Department.class, Integer.valueOf(10));
            dep.setName("updated");
            List result = query.getResultList();
            if (flushExpected) {
                verify(result.size() == 1, "wrong number of rows: " + result.size());
            } else {
                verify(result.size() == 0, "wrong number of rows: " + result.size());
            }
            env.commitTransaction(em);
        } finally {
            closeEntityManager(em);
        }
    }

    private boolean isFlushExpected(FlushModeType flushModeEM, FlushModeType flushModeQuery) {
        if (flushModeQuery == null) {
            if (flushModeEM == COMMIT) {
                return false;
            } else {
                return true;
            }
        } else if (flushModeQuery == COMMIT) {
            return false;
        } else if (flushModeQuery == AUTO) {
            return true;
        }
        throw new IllegalArgumentException("Illegal flushMode(s): flushModeEM = " + flushModeEM + ", flushModeQuery = "
                + flushModeQuery);
    }

    @Test
    public void testTransactionBoundaries() throws SQLException {
        init();
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        boolean extended = env.usesExtendedPC();
        boolean failureExpected = false;
        if (!extended) {
            failureExpected = true;
        }
        try {
            // create query outside transaction
            Query query = em.createQuery("select d from Department d where d.name = :name");
            query.setParameter("name", "twenty");
            List result = query.getResultList();
            verify(result.size() == 1, "wrong number of rows: " + result.size());
            verify(result.get(0).equals(dep20), "got wrong department");
            // execute again
            result = query.getResultList();
            verify(result.size() == 1, "wrong number of rows: " + result.size());
            verify(result.get(0).equals(dep20), "got wrong department");
            // execute inside transaction
            env.beginTransaction(em);
            try {
                result = query.getResultList();
                verify(result.size() == 1, "wrong number of rows: " + result.size());
                verify(result.get(0).equals(dep20), "got wrong department");
            } catch (PersistenceException e) {
                if (!failureExpected) {
                    throw e;
                }
            }
            env.rollbackTransaction(em);
            // create query inside transaction
            env.beginTransaction(em);
            query = em.createQuery("select d from Department d where d.name = :name");
            query.setParameter("name", "twenty");
            result = query.getResultList();
            verify(result.size() == 1, "wrong number of rows: " + result.size());
            verify(result.get(0).equals(dep20), "got wrong department");
            env.commitTransaction(em);
            // execute outside transaction
            try {
                result = query.getResultList();
                verify(result.size() == 1, "wrong number of rows: " + result.size());
                verify(result.get(0).equals(dep20), "got wrong department");
            } catch (IllegalStateException e) {
                if (!failureExpected) {
                    throw e;
                }
            }
            // execute inside new transaction
            env.beginTransaction(em);
            try {
                result = query.getResultList();
                verify(result.size() == 1, "wrong number of rows: " + result.size());
                verify(result.get(0).equals(dep20), "got wrong department");
            } catch (IllegalStateException e) {
                if (!failureExpected) {
                    throw e;
                }
            }
            env.rollbackTransaction(em);
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testBooleanParameter() {
        EntityManager em = getEnvironment().getEntityManager();
        JPAEnvironment env = getEnvironment();
        try {
            env.beginTransaction(em);
            BasicTypesFieldAccess fieldAccess = new BasicTypesFieldAccess();
            fieldAccess.setId(1);
            fieldAccess.setPrimitiveBoolean(true);
            em.persist(fieldAccess);
            fieldAccess = new BasicTypesFieldAccess();
            fieldAccess.setId(2);
            fieldAccess.setPrimitiveBoolean(false);
            em.persist(fieldAccess);
            env.commitTransactionAndClear(em);
            Query query = em.createQuery("select b from BasicTypesFieldAccess b where b.primitiveBoolean = ?1");
            query.setParameter(1, Boolean.TRUE);
            List list = query.getResultList();
            Iterator iterator = list.iterator();
            verify(iterator.hasNext(), "no rows");
            BasicTypesFieldAccess value = (BasicTypesFieldAccess) iterator.next();
            verify(value.getId() == 1, "wrong id: " + value.getId());
            verify(!iterator.hasNext(), "too many rows");
        } finally {
            closeEntityManager(em);
        }
    }
}
