You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-commits@db.apache.org by br...@apache.org on 2005/10/12 14:15:35 UTC

svn commit: r314855 - in /incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck: pc/company/CompanyModelReader.java query/QueryElementHolder.java query/QueryTest.java

Author: brazil
Date: Wed Oct 12 05:15:27 2005
New Revision: 314855

URL: http://svn.apache.org/viewcvs?rev=314855&view=rev
Log:
JDO-156: Implement infrastructur to execute JDOQL queries as single queries or API queries.

Added:
    incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck/query/QueryElementHolder.java
Modified:
    incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck/pc/company/CompanyModelReader.java
    incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck/query/QueryTest.java

Modified: incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck/pc/company/CompanyModelReader.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck/pc/company/CompanyModelReader.java?rev=314855&r1=314854&r2=314855&view=diff
==============================================================================
--- incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck/pc/company/CompanyModelReader.java (original)
+++ incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck/pc/company/CompanyModelReader.java Wed Oct 12 05:15:27 2005
@@ -248,14 +248,14 @@
         return (Project)getBean(name, Project.class);
     }
     
-    public Class[] getAllClasses() {
+    public static Class[] getAllClasses() {
         return allClasses;
     }
     
     /**
      * @return Returns the tearDownClasses.
      */
-    public Class[] getTearDownClasses() {
+    public static Class[] getTearDownClasses() {
         return tearDownClasses;
     }
 }

Added: incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck/query/QueryElementHolder.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck/query/QueryElementHolder.java?rev=314855&view=auto
==============================================================================
--- incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck/query/QueryElementHolder.java (added)
+++ incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck/query/QueryElementHolder.java Wed Oct 12 05:15:27 2005
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.jdo.tck.query;
+
+import javax.jdo.Extent;
+import javax.jdo.PersistenceManager;
+import javax.jdo.Query;
+
+/**
+ * This class is an abstraction of a JDOQL query,
+ * which may be represented as a single string 
+ * (e.g. <code>SELECT FROM Person WHERE personid == 1</code>) or
+ * as an API query using methods on class {@link Query}.<p>
+ * 
+ * The class may be used as the factory of a JDO {@link Query} instance
+ * using method {@link QueryElementHolder#getAPIQuery(PersistenceManager)} or
+ * method {@link QueryElementHolder#getSingleStringQuery(PersistenceManager)}.<p>
+ * 
+ * Instances of this class are capable to hold all elements of a JDOQL query,
+ * e.g. the candidate class, the filter, etc. These elements are passed
+ * calling the constructor. It is valid to pass <code>null</code> as a value
+ * for JDOQL querys elements. Such elements are not transfered into a 
+ * JDO {@link javax.jdo.Query} instance. 
+ * Instead, the default of JDO {@link javax.jdo.Query} instance is taken.
+ */
+public class QueryElementHolder {
+
+    // fields holding JDOQL query elements
+    private Boolean unique;
+    private String result;
+    private Class resultClass;
+    private Class candidateClass;
+    private Boolean excludeSubClasses;
+    private String filter;
+    private String variables;
+    private String parameters;
+    private String imports;
+    private String grouping;
+    private String ordering;
+    private String fromString;
+    private String toString;
+    private Long   fromLong;
+    private Long   toLong;
+    
+    /**
+     * Returns an instance of this class holding the given arguments
+     * such as the candidate class, the filter, etc. 
+     * The given arguments represent JDOQL query elements. 
+     * It is valid to pass <code>null</code> as a value
+     * for JDOQL querys elements. Such elements are not transfered into a 
+     * JDO {@link javax.jdo.Query} instance.
+     * Instead, the default of JDO {@link javax.jdo.Query} instance is taken.
+     * @param unique the JDOQL unique query element
+     * @param result the JDOQL result query element
+     * @param resultClass the JDOQL result class query element
+     * @param candidateClass the JDOQL candidate class query element
+     * @param excludeSubClasses the JDOQL exclude subclasses query element
+     * @param filter the JDOQL filter query element
+     * @param variables the JDOQL variables query element
+     * @param parameters the JDOQL parameters query element
+     * @param imports the JDOQL imports query element
+     * @param grouping the JDOQL grouping query element
+     * @param ordering the JDOQL ordering query element
+     * @param from the JDOQL range from query element
+     * @param to the JDOQL range to query element
+     */
+    public QueryElementHolder(Boolean unique, String result, 
+            Class resultClass, Class candidateClass, 
+            Boolean excludeSubClasses, String filter,
+            String variables, String parameters, String imports, 
+            String grouping, String ordering, String from, String to) {
+        if (from != null ^ to == null) {
+            throw new IllegalArgumentException(
+                    "Arguments from and to must both be null, " +
+                    "or must not be null both.");
+        }
+        this.unique = unique;
+        this.result = result;
+        this.resultClass = resultClass;
+        this.candidateClass = candidateClass;
+        this.excludeSubClasses = excludeSubClasses;
+        this.filter = filter;
+        this.variables = variables;
+        this.parameters = parameters;
+        this.imports = imports;
+        this.grouping = grouping;
+        this.ordering = ordering;
+        this.fromString = from;
+        this.toString = to;
+    }
+    
+    /**
+     * Returns an instance of this class holding the given arguments
+     * such as the candidate class, the filter, etc. 
+     * The given arguments represent JDOQL query elements. 
+     * It is valid to pass <code>null</code> as a value
+     * for JDOQL querys elements. Such elements are not transfered into a 
+     * JDO {@link javax.jdo.Query} instance.
+     * Instead, the default of JDO {@link javax.jdo.Query} instance is taken.
+     * @param unique the JDOQL unique query element
+     * @param result the JDOQL result query element
+     * @param resultClass the JDOQL result class query element
+     * @param candidateClass the JDOQL candidate class query element
+     * @param excludeSubClasses the JDOQL exclude subclasses query element
+     * @param filter the JDOQL filter query element
+     * @param variables the JDOQL variables query element
+     * @param parameters the JDOQL parameters query element
+     * @param imports the JDOQL imports query element
+     * @param grouping the JDOQL grouping query element
+     * @param ordering the JDOQL ordering query element
+     * @param from the JDOQL from query element
+     * @param to the JDOQL to query element
+     */
+    public QueryElementHolder(Boolean unique, String result, 
+            Class resultClass, Class candidateClass, 
+            Boolean excludeSubClasses, String filter,
+            String variables, String parameters, String imports, 
+            String grouping, String ordering, long from, long to) {
+        this.unique = unique;
+        this.result = result;
+        this.resultClass = resultClass;
+        this.candidateClass = candidateClass;
+        this.excludeSubClasses = excludeSubClasses;
+        this.filter = filter;
+        this.variables = variables;
+        this.parameters = parameters;
+        this.imports = imports;
+        this.grouping = grouping;
+        this.ordering = ordering;
+        this.fromLong = new Long(from);
+        this.toLong = new Long(to);
+    }
+    
+    /**
+     * Returns the single string JDOQL representation.
+     * @see Object#toString()
+     */
+    public String toString() {
+        return "SELECT " +
+        toString("UNIQUE", this.unique) +
+        toString(this.result) +
+        toString("INTO", this.resultClass) +
+        toString("FROM", this.candidateClass) +
+        toString("EXCLUDE SUBCLASSES", this.excludeSubClasses) +
+        toString("WHERE", this.filter) +
+        toString("VARIABLES", this.variables) +
+        toString("PARAMETERS", this.parameters) +
+        toString("IMPORTS", this.imports) +
+        toString("GROUP BY", this.grouping) +
+        toString("ORDER BY", this.ordering) +
+        rangeToString();
+    }
+    
+    /**
+     * Creates a JDO {@link javax.jdo.Query} instance using the JDOQL query elements 
+     * of this instance. The returned instance is created calling
+     * {@link PersistenceManager#newQuery(String)}.
+     * The passed {@link String} instance is the 
+     * single string representation of this,
+     * e.g. <code>SELECT FROM Person WHERE personid == 1</code>.
+     * @param pm the persistence manager
+     * @return the JDO query instance
+     */
+    public Query getSingleStringQuery(PersistenceManager pm) {
+        return pm.newQuery(toString());
+    }
+
+    /**
+     * Creates a JDO {@link javax.jdo.Query} instance using the JDOQL query elements 
+     * of this instance. The returned instance is created calling
+     * {@link PersistenceManager#newQuery(Extent)}.
+     * Afterwards, all query elements of this are transfered 
+     * into that instance using API methods like 
+     * {@link javax.jdo.Query#setFilter(java.lang.String) etc.
+     * @param pm the persistence manager
+     * @return the JDO query instance
+     */
+    public Query getAPIQuery(PersistenceManager pm) {
+        Extent extent = this.excludeSubClasses != null ? 
+                pm.getExtent(this.candidateClass, 
+                        !this.excludeSubClasses.booleanValue()) :
+                pm.getExtent(this.candidateClass);
+        Query query = pm.newQuery(extent);
+        if (this.unique != null) {
+            query.setUnique(this.unique.booleanValue());
+        }
+        if (this.result != null ) {
+            query.setResult(this.result);
+        }
+        if (this.resultClass != null) {
+            query.setResultClass(this.resultClass);
+        }
+        if (this.filter != null) {
+            query.setFilter(this.filter);
+        }
+        if (this.variables != null) {
+            query.declareVariables(this.variables);
+        }
+        if (this.parameters != null) {
+            query.declareParameters(this.parameters);
+        }
+        if (this.imports != null ) {
+            query.declareImports(this.imports);
+        }
+        if (this.grouping != null) {
+            query.setGrouping(this.grouping);
+        }
+        if (this.ordering != null) {
+            query.setOrdering(this.ordering);
+        }
+        rangeToAPI(query);
+        return query;
+    }
+    
+    /**
+     * Returns the unique JDOQL query element.
+     * @return the unique JDOQL query element.
+     */
+    protected boolean isUnique() {
+        return this.unique != null && this.unique.booleanValue();
+    }
+
+    /**
+     * Returns the unique JDOQL query element.
+     * @return the unique JDOQL query element.
+     */
+    protected boolean hasOrdering() {
+        return this.ordering != null;
+    }
+
+    /**
+     * Delegates to {@link QueryElementHolder#toString(String, String)
+     * if argument <code>clazz</code> does not equal <code>null</code>,
+     * otherwise returns an empty string.
+     * @param prefix the prefix of the returned string.
+     * @param clazz the returned string has the class name as a suffix.
+     * @return the string.
+     */
+    private String toString(String prefix, Class clazz) {
+        return (clazz != null? toString(prefix, clazz.getName()) : "");
+    }
+
+    /**
+     * Returns a string prefixed by argument <code>prefix</code> and 
+     * suffixed by the string representation of argument <code>bool</code>,
+     * if argument <code>bool</code> does not equal <code>null</code>.
+     * Otherwise, an empty string is returned.
+     * @param prefix the prefix of the returned string.
+     * @param bool the returned string has the string representation 
+     * of the value as a suffix.
+     * @return the string.
+     */
+    private String toString(String prefix, Boolean bool) {
+        return bool!=null && bool.booleanValue() ? prefix + ' ' : "";
+    }
+
+    /**
+     * Returns a string prefixed by argument <code>prefix</code> and 
+     * suffixed by argument <code>suffix</code>,
+     * if argument <code>suffix</code> does not equal <code>null</code>.
+     * Otherwise, an empty string is returned.
+     * @param prefix the prefix of the returned string.
+     * @param suffix the suffix of the returned string.
+     * @return the string.
+     */
+    private String toString(String prefix, String suffix) {
+        return (suffix != null ? prefix + ' ' + suffix + ' ' : "");
+    }
+
+    /**
+     * Returns a string prefixed by argument <code>prefix</code>,
+     * if argument <code>prefix</code> does not equal <code>null</code>.
+     * Otherwise, an empty string is returned.
+     * @param prefix the prefix of the returned string.
+     * @return the string.
+     */
+    private String toString(String prefix) {
+        return (prefix != null ? prefix + ' ' : "");
+    }
+
+    /**
+     * Returns the single string representation 
+     * of the JDOQL query element <i>range</i>.
+     * If that element is <code>null</code>, 
+     * then an empty string is returned.
+     * @return the single string representation 
+     * of the JDOQL query element <i>range</i> or <code>null</code>, 
+     */
+    private String rangeToString() {
+        String result = "";
+        if (this.fromString != null && this.toString != null) { 
+            result = "RANGE " + this.fromString + " TO " + this.toString;
+        }
+        else if (this.fromLong != null && this.toLong != null) {
+            result = "RANGE " + this.fromLong + " TO " + this.toLong;
+        }
+        return result;
+    }
+    
+    /**
+     * Calls API method {@link javax.jdo.Query#setRange(String)} or
+     * {@link javax.jdo.Query#setRange(long, long)} depending on
+     * which of the from/to fields are set.
+     * @param query the query instance
+     */
+    private void rangeToAPI(Query query) {
+        /*TODO if (this.fromString != null && this.toString != null) {
+            query.setRange(this.fromString + ',' + this.toString);
+        } 
+        else*/ if (this.fromLong != null && this.toLong != null) {
+            query.setRange(this.fromLong.longValue(), this.toLong.longValue());
+        }
+    }
+}

Modified: incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck/query/QueryTest.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck/query/QueryTest.java?rev=314855&r1=314854&r2=314855&view=diff
==============================================================================
--- incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck/query/QueryTest.java (original)
+++ incubator/jdo/trunk/tck20/test/java/org/apache/jdo/tck/query/QueryTest.java Wed Oct 12 05:15:27 2005
@@ -19,14 +19,15 @@
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 
 import javax.jdo.Extent;
 import javax.jdo.JDOFatalInternalException;
+import javax.jdo.JDOUserException;
 import javax.jdo.PersistenceManager;
 import javax.jdo.Query;
 import javax.jdo.Transaction;
@@ -155,6 +156,21 @@
         }
     }
     
+    /**
+     * Returns an array of company mode instances for beans names 
+     * in the given argument.
+     * @param beanNames the bean names of company mode instances.
+     * @return the array of company model instances. 
+     */
+    protected Object[] getCompanyModelInstances(String[] beanNames) {
+        CompanyModelReader reader = new CompanyModelReader(COMPANY_TESTDATA);
+        Object[] result = new Object[beanNames.length];
+        for (int i = 0; i < beanNames.length; i++) {
+            result[i] = reader.getBean(beanNames[i]);
+        }
+        return result;
+    }
+    
     // PrimitiveTypes helper methods (creation and query)
 
     /** */
@@ -351,6 +367,20 @@
         }
     }
 
+    /** */
+    protected void checkUniqueResult(String assertion, 
+                                     Object result, 
+                                     Object expected) {
+        if ((result != null && expected == null) ||
+            (result == null && expected != null) || 
+            (result != null && expected != null && !result.equals(expected))) {
+            String lf = System.getProperty("line.separator");
+            fail(assertion, "Wrong query result: " + lf +
+                    "query returns: " + result + lf +
+                    "expected result: " + expected);
+        }
+    }
+
     // Debugging helper methods
      
     /** */
@@ -380,5 +410,281 @@
             pcp = (PCPoint)iter.next();
             logger.debug("X = " + pcp.getX() + "\tY = " + pcp.getY());
         }
+    }
+    
+    // compile query methods
+
+    /**
+     * Compiles the given query element holder instance as a JDO API query.
+     * Argument <code>positive</code> determines if the compilation is supposed
+     * to succeed or to fail. If <code>true</code> and the compilation fails,
+     * then the test case fails prompting argument <code>assertion</code>.
+     * If <code>false</code> and the compilation succeeds,
+     * then the test case fails prompting argument <code>assertion</code>.
+     * Otherwise the test case succeeds. 
+     * @param assertion the assertion to prompt if the test case fails.
+     * @param queryElementHolder the query to execute.
+     * @param positive determines if the compilation is supposed
+     * to succeed or to fail.
+     */
+    protected void compileAPIQuery(String assertion,
+            QueryElementHolder queryElementHolder, boolean positive) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("Compiling API query: " + queryElementHolder);
+        }
+        compile(assertion, queryElementHolder, false, null, positive);
+    }
+
+    /**
+     * Compiles the given query element holder instance 
+     * as a JDO single string query.
+     * Argument <code>positive</code> determines if the compilation is supposed
+     * to succeed or to fail. If <code>true</code> and the compilation fails,
+     * then the test case fails prompting argument <code>assertion</code>.
+     * If <code>false</code> and the compilation succeeds,
+     * then the test case fails prompting argument <code>assertion</code>.
+     * Otherwise the test case succeeds. 
+     * @param assertion the assertion to prompt if the test case fails.
+     * @param queryElementHolder the query to execute.
+     * @param positive determines if the compilation is supposed
+     * to succeed or to fail.
+     */
+    protected void compileSingleStringQuery(String assertion,
+            QueryElementHolder queryElementHolder, boolean positive) {
+        if (logger.isDebugEnabled())
+            logger.debug("Compiling single string query: " + 
+                    queryElementHolder);
+        compile(assertion, queryElementHolder, true, null, positive);
+    }
+    
+    /**
+     * Compiles the given single string query.
+     * Argument <code>positive</code> determines if the compilation is supposed
+     * to succeed or to fail. If <code>true</code> and the compilation fails,
+     * then the test case fails prompting argument <code>assertion</code>.
+     * If <code>false</code> and the compilation succeeds,
+     * then the test case fails prompting argument <code>assertion</code>.
+     * Otherwise the test case succeeds. 
+     * @param assertion the assertion to prompt if the test case fails.
+     * @param singleStringQuery the single string query
+     * @param positive determines if the compilation is supposed
+     * to succeed or to fail.
+     */
+    protected void compileSingleStringQuery(String assertion, 
+            String singleStringQuery, boolean positive) {
+        if (logger.isDebugEnabled())
+            logger.debug("Compiling single string query: " + 
+                    singleStringQuery);
+        compile(assertion, null, true, singleStringQuery, positive);
+    }
+
+    /**
+     * Compiles the given query element holder instance 
+     * as a JDO API query or single string query, 
+     * depending on argument <code>asSingleString</code>.
+     * Argument <code>singleStringQuery</code> exists to support queries
+     * which cannot be expressed as query element holder instances.
+     * That argument is ignored if argument <code>queryElementHolder</code> 
+     * is set.
+     * Argument <code>positive</code> determines if the compilation is supposed
+     * to succeed or to fail. If <code>true</code> and the compilation fails,
+     * then the test case fails prompting argument <code>assertion</code>.
+     * If <code>false</code> and the compilation succeeds,
+     * then the test case fails prompting argument <code>assertion</code>.
+     * Otherwise the test case succeeds. 
+     * @param assertion the assertion to prompt if the test case fails.
+     * @param queryElementHolder the query to compile.
+     * @param asSingleString determines if the query specified by 
+     * <code>queryElementHolder</code> is compiled as single string query 
+     * or as API query. 
+     * @param singleStringQuery the query to compile 
+     * as a JDO single string query if there is no query element holder.
+     * @param positive determines if the compilation is supposed
+     * to succeed or to fail.
+     */
+    private void compile(String assertion, 
+            QueryElementHolder queryElementHolder, boolean asSingleString,  
+            String singleStringQuery, boolean positive) {
+        PersistenceManager pm = getPM();
+        Transaction tx = pm.currentTransaction();
+        tx.begin();
+        try {
+            Query query;
+            if (queryElementHolder != null) {
+                if (asSingleString) {
+                    query = queryElementHolder.getSingleStringQuery(pm);
+                } else {
+                    query = queryElementHolder.getAPIQuery(pm);
+                }
+            } else {
+                query = getPM().newQuery(singleStringQuery);
+            }
+            query.compile();
+            if (!positive) {
+                String queryText = queryElementHolder != null ? 
+                        queryElementHolder.toString() :
+                        singleStringQuery;
+                fail(assertion + 
+                        "Query compilation must throw JDOUserException: " + 
+                        queryText);
+            }
+        } catch (JDOUserException e) {
+            if (positive) {
+                String queryText = queryElementHolder != null ? 
+                        queryElementHolder.toString() :
+                        singleStringQuery;
+                fail(assertion + "Query '" + queryText +
+                        "' must be compilable. The exception message is: " + 
+                        e.getMessage());
+            }
+        } finally {
+            if (tx.isActive()) {
+                tx.rollback();
+            }
+        }
+    }
+    
+    // execute query methods
+    
+    /**
+     * Executes the given query element holder instance as a JDO API query.
+     * The result of that query is compared against the given argument 
+     * <code>expectedResult</code>. The array elements of that argument
+     * must match the content of the result collection 
+     * returned by {@link Query#execute()}.
+     * If the expected result does not match the returned query result,
+     * then the test case fails prompting argument <code>assertion</code>.
+     * @param assertion the assertion to prompt if the test case fails.
+     * @param queryElementHolder the query to execute.
+     * @param expectedResult the expected query result.
+     */
+    protected void executeAPIQuery(String assertion,
+            QueryElementHolder queryElementHolder, Object[] expectedResult) {
+        executeAPIQuery(assertion, queryElementHolder, null, expectedResult);
+    }
+
+    /**
+     * Executes the given query element holder instance as a JDO API query.
+     * The result of that query is compared against the given argument 
+     * <code>expectedResult</code>. The array elements of that argument
+     * must match the content of the result collection 
+     * returned by {@link Query#executeWithArray(java.lang.Object[])}.
+     * Argument <code>parameters</code> is passed as the parameter 
+     * to that method.
+     * If the expected result does not match the returned query result,
+     * then the test case fails prompting argument <code>assertion</code>.
+     * @param assertion the assertion to prompt if the test case fails.
+     * @param queryElementHolder the query to execute.
+     * @param parameters the parmaters of the query.
+     * @param expectedResult the expected query result.
+     */
+    protected void executeAPIQuery(String assertion,
+            QueryElementHolder queryElementHolder, 
+            Object[] parameters, Object[] expectedResult) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("Executing API query: " + queryElementHolder);
+        }
+        execute(assertion, queryElementHolder, false, 
+                parameters, expectedResult);
+    }
+    
+    /**
+     * Executes the given query element holder instance 
+     * as a JDO single string query.
+     * The result of that query is compared against the given argument 
+     * <code>expectedResult</code>. The array elements of that argument
+     * must match the content of the result collection 
+     * returned by {@link Query#execute()}.
+     * If the expected result does not match the returned query result,
+     * then the test case fails prompting argument <code>assertion</code>.
+     * @param assertion the assertion to prompt if the test case fails.
+     * @param queryElementHolder the query to execute.
+     * @param expectedResult the expected query result.
+     */
+    protected void executeSingleStringQuery(String assertion,
+            QueryElementHolder queryElementHolder, Object[] expectedResult) {
+        executeSingleStringQuery(assertion, queryElementHolder, 
+                null, expectedResult);
+    }
+    
+    /**
+     * Executes the given query element holder instance 
+     * as a JDO single string query.
+     * The result of that query is compared against the given argument 
+     * <code>expectedResult</code>. The array elements of that argument
+     * must match the content of the result collection 
+     * returned by {@link Query#executeWithArray(java.lang.Object[])}.
+     * Argument <code>parameters</code> is passed as the parameter 
+     * to that method.
+     * If the expected result does not match the returned query result,
+     * then the test case fails prompting argument <code>assertion</code>.
+     * @param assertion the assertion to prompt if the test case fails.
+     * @param queryElementHolder the query to execute.
+     * @param parameters the parmaters of the query.
+     * @param expectedResult the expected query result.
+     */
+    protected void executeSingleStringQuery(String assertion,
+            QueryElementHolder queryElementHolder, 
+            Object[] parameters, Object[] expectedResult) {
+        if (logger.isDebugEnabled())
+            logger.debug("Executing single string query: " + 
+                    queryElementHolder);
+        execute(assertion, queryElementHolder, true, 
+                parameters, expectedResult);
+    }
+    
+    /**
+     * Executes the given query element holder instance 
+     * as a JDO API query of a single string query,
+     * depending on argument <code>asSingleString</code>.
+     * The result of that query is compared against the given argument 
+     * <code>expectedResult</code>. The array elements of that argument
+     * must match the content of the result collection 
+     * returned by {@link Query#executeWithArray(java.lang.Object[])}.
+     * Argument <code>parameters</code> is passed as the parameter 
+     * to that method.
+     * If the expected result does not match the returned query result,
+     * then the test case fails prompting argument <code>assertion</code>.
+     * @param assertion the assertion to prompt if the test case fails.
+     * @param queryElementHolder the query to execute.
+     * @param asSingleString determines if the query is executed as
+     * single string query or as API query.
+     * @param parameters the parmaters of the query.
+     * @param expectedResult the expected query result.
+     * @return
+     */
+    private Object execute(String assertion, 
+            QueryElementHolder queryElementHolder, boolean asSingleString,
+            Object[] parameters, Object[] expectedResult) {
+        Object result;
+        PersistenceManager pm = getPM();
+        Transaction tx = pm.currentTransaction();
+        tx.begin();
+        try {
+            Query query = asSingleString ?
+                    queryElementHolder.getSingleStringQuery(pm) :
+                        queryElementHolder.getAPIQuery(pm);
+            result = parameters != null ? 
+                    query.executeWithArray(parameters) : query.execute();
+
+            if (queryElementHolder.isUnique()) {
+                checkUniqueResult(assertion, result, expectedResult[0]);
+            } else if (queryElementHolder.hasOrdering()) {
+                List expectedResultList = 
+                    Arrays.asList(expectedResult);
+                checkQueryResultWithOrder(assertion, result, 
+                        expectedResultList);
+            } else {
+                Collection expectedResultCollection = 
+                    Arrays.asList(expectedResult);
+                checkQueryResultWithoutOrder(assertion, result, 
+                        expectedResultCollection);
+            }
+        } finally {
+            if (tx.isActive()) {
+                tx.rollback();
+            }
+        }
+        return result;
     }
 }