db-jdo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Apache Wiki <wikidi...@apache.org>
Subject [Jdo Wiki] Update of "QueryTests" by MichaelWatzek
Date Fri, 16 Sep 2005 15:55:52 GMT
Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Jdo Wiki" for change notification.

The following page has been changed by MichaelWatzek:
http://wiki.apache.org/jdo/QueryTests

------------------------------------------------------------------------------
- = Query API =
+ = TCK20: JDO2 Query Test Cases =
  
- JDO 2.0 adds a couple of new methods to teh query API. The spreadsheet lists the following
assertions for JDK TCK 2.0 that make sure a JDO 2.0 implementation supports the new Query
API methods:
+ [#JDOQL20 JDOQL 2.0]
  
- ||Assertion No.||Comment||
- ||A14.6-16||Query.setResult||
- ||A14.6-17||Query.setGrouping||
- ||A14.6-18||Query.setUnique||
- ||A14.6-19||Query.setResultClass||
- ||A14.6-20||Query.setRange||
- ||A14.6-18||Query.setUnique||
+ [#NewQueryTests New TCK Query Tests][[BR]]
+  [#LanguageExtensions Language Extensions][[BR]]
+   [#Keywords Keywords][[BR]]
+   [#NewOperators New Operators][[BR]]
+   [#NewSupportedMethods New Supported Methods][[BR]]
+   [#Parameters Parameters][[BR]]
+   [#Variables Variables][[BR]]
+   [#OtherLanguageChanges Other Language Changes][[BR]]
+  [#QueryAPIExtensions Query API Extensions][[BR]]
+  [#ResultHandling Result Handling][[BR]]
+  [#SQLQueries SQL Queries][[BR]]
+  [#DeletionByQuery Deletetion by Query][[BR]]
+  [#TestcasePattern Testcase Pattern][[BR]]
+   [#PositiveTest Positive Test][[BR]]
+   [#NegativeTest Negative Test][[BR]]
  
+ [[Anchor(JDOQL20)]]
- JDO adds the following methods to the Query API, but there are no assertions for these methods
yet:
-  * void setUnmodifiable()
-  * boolean isUnmodifiable()
-  * void setExtensions(Map extensions)
-  * void addExtension(String key, Object value)
  
  = JDOQL 2.0 =
+ 
+ JDO 2.0 adds the following methods to the Query API:
+ 
+  * setResult
+  * setGrouping
+  * setUnique
+  * setResultClass
+  * setRange
+  * setUnique
+  * setUnmodifiable
+  * isUnmodifiable
+  * setExtensions
+  * addExtension
  
  JDO 2.0 extensions of the JDO query language JDOQL:
  
@@ -44, +61 @@

   * Support for implicit variables
   * Deletion by query
  
+ [[Anchor(NewQueryTests)]]
  
+ = NewQueryTests New TCK Query Tests =
  
+ Package names of all query test classes start with `org.apache.jdo.query.`.[[BR]]
+ Package names of all queries start with `org.apache.jdo.tck.pc.`.
+ 
+ [[Anchor(LanguageExtensions)]]
+ 
+ == Language Extensions ==
+ 
+ [[Anchor(Keywords)]]
+ === Keywords ===
+ 
+ || '''Assertion''' || '''JDOQL''' || '''Testclass''' || '''Comment''' ||
+ ||<|4> '''A14.4-6:''' Keywords must not be used as package names, class names, parameter
names, or variable names in queries. || `SELECT FROM this.Employee` ||<|4> `jdoql.keywords.`[[BR]]`InvalidUseOfKeywords`
||<|4> Negative test. ||
+ || `SELECT FROM this` ||
+ || `SELECT FROM company.Employee PARAMETERS int this` ||
+ || `SELECT FROM company.Employee VARIABLES long this` ||
+ ||<|2> '''A14.4-7''': Keywords are permitted as field names only if they are on the
right side of the "." in field access expressions || '''`valid:`'''[[BR]] `SELECT this.select
FROM ...` ||<|2> `jdoql.keywords.`[[BR]]`KeywordsAsFieldNames` ||<|2> Positive
and negative test. ||
+ || '''`invalid:`'''[[BR]] `SELECT select FROM ...` ||
+ ||'''A14.6.13-1:''' The String version of Query represents all query elements using a single
string. The string contains the following structure: || `SELECT firstname INTO ...FullName
AS first,` `lastname INTO FullName AS last` `FROM company.FullTimeEmployee` `WHERE salary
> 1000` `& projects.contains(project)` `& project.budget > limit` `VARIABLES
Project project` `PARAMETERS BigDecimal limit` `ORDER BY salary` `GROUP BY firstname, lastname`
`HAVING lastname.startsWith('R')` `RANGE 1 TO 10` || `jdoql.keywords.`[[BR]]`SingleString`
|| Positive test. ||
+ ||<|3> '''A14.6.13-2:''' Keywords, identified above in '''bold''', are either all
upper-case or all lower-case. Keywords cannot be mixed case. || '''`valid:`'''[[BR]] `SELECT
FROM company.Person` ||<|3> `jdoql.keywords.`[[BR]]`UppercaseLowercase` ||<|3>
Positive and negative test. ||
+ || '''`valid:`'''[[BR]] `select from company.Person` ||
+ || '''`invalid:`'''[[BR]] `SELECT from company.Person` ||
+ 
+ [[Anchor(NewOperators)]]
+ === New Operators ===
+ 
+ || '''Assertion''' || '''JDOQL''' || '''Testclass''' || '''Comment''' ||
+ || '''A14.6.2-40:''' modulo operator || `SELECT FROM company.Person` `WHERE personid % 2
== 0` || `jdoql.operators.`[[BR]]`Modulo` || Positive test. ||
+ || '''A14.6.2-41:''' instanceof operator || `SELECT FROM company.Employee` `WHERE mentor
instanceof` `company.PartTimeEmployee` || `jdoql.operators.`[[BR]]`Instanceof` || Positive
test. ||
+ 
+ [[Anchor(NewSupportedMethods)]]
+ === New Supported Methods ===
+ 
+ || '''Assertion''' || '''JDOQL''' || '''Testclass''' || '''Comment''' ||
+ || '''A14.6.2-46:''' Supported Map methods:[[BR]] - `get(Object)`[[BR]] - `containsKey(Object)`[[BR]]
- `containsValue(Object)` || `...` || `jdoql.methods.`[[BR]]`SupportedMapMethods` || Positive
Test. ||
+ ||<|9> '''A14.6.2-47''': New supported String methods:[[BR]] - `toLowerCase()`[[BR]]
- `toUpperCase()`[[BR]] - `indexOf(String)`[[BR]] - `indexOf(String, int)`[[BR]] - `matches(String)`[[BR]]
- `substring(int)`[[BR]] - `substring(int, int)`[[BR]] - `startsWith()`[[BR]] - `endsWith()`[[BR]]
|| '''`toLowerCase:`'''[[BR]]`SELECT FROM company.Person` `WHERE firstname.toLowerCase() ==
'john'` ||<|9> `jdoql.methods.`[[BR]]`SupportedStringMethods` ||<|9> Positive
test. ||
+ || '''`toUpperCase:`'''[[BR]]`SELECT FROM company.Person` `WHERE firstname.toUpperCase()
== 'JOHN'`||
+ || '''`indexOf:`'''[[BR]]`SELECT FROM company.Person` `WHERE firstname.indexOf('hn') ==
2` ||
+ || '''`indexOf:`'''[[BR]]`SELECT FROM company.Person` `WHERE firstname.indexOf('hn', 2)
== 2` ||
+ || '''`matches:`'''[[BR]]`SELECT FROM company.Person` `WHERE firstname.matches('*hn')` ||
+ || '''`substring:`'''[[BR]]`SELECT FROM company.Person` `WHERE firstname.substring(2) ==
'hn'` ||
+ || '''`substring:`'''[[BR]]`SELECT FROM company.Person` `WHERE firstname.substring(2,4)
== 'hn'` ||
+ || '''`startsWith:`'''[[BR]]`SELECT FROM company.Person` `WHERE firstname.startsWith('Jo')`
||
+ || '''`endsWith:`'''[[BR]]`SELECT FROM company.Person` `WHERE firstname.endsWith('hn')`
||
+ ||<|2> '''A14.6.2-48:''' Supported Math methods: [[BR]] - `Math.abs(numeric)`[[BR]]
- `Math.sqrt(numeric)` || `SELECT FROM company.FullTimeEmployee` `WHERE Math.abs(salary) >
10000` ||<|2> `jdoql.methods.`[[BR]]`SupportedMathMethods` ||<|2> Positive test.
||
+ || `SELECT FROM company.FullTimeEmployee` `WHERE Math.sqrt(salary) > 100` ||
+ || '''A14.6.2-49:''' Supported JDOHelper methods:[[BR]] - `JDOHelper.getObjectId(Object)`
|| `...` || `jdoql.methods.`[[BR]]`SupportedJDOHelperMethods` || Positive test.||
+ 
+ [[Anchor(Parameters)]]
+ === Parameters ===
+ 
+ || '''Assertion''' || '''JDOQL''' || '''Testclass''' || '''Comment''' ||
+ ||<|3> '''A14.6.3-2''': Parameters must all be declared explicitly via `declareParameters`
or all be declared implicitly in the filter. || '''`valid:`'''[[BR]] `SELECT FROM company.Person`
`WHERE firstname = param` `PARAMETERS String param` ||<|3> `jdoql.parameters.`[[BR]]`MixedParameters`
||<|3> Positive and negative test. ||
+ || '''`valid:`'''[[BR]] `SELECT FROM company.Person` `WHERE firstname = :param` ||
+ || '''`invalid:`'''[[BR]] `SELECT FROM company.Person` `WHERE firstname = param` ||
+ ||<|5> '''A14.6.3-3:''' Parameters implicitly declared (in the result, filter, grouping,
ordering, or range) are identified by prepending a ":" to the parameter everywhere it appears.
All parameter types can be determined by one of the following techniques: || '''`result:`'''[[BR]]
`SELECT avg(employee.salary),` `:limit FROM company.FullTimeEmployee` `WHERE employee.salary
> :limit` ||<|5> `jdoql.parameters.`[[BR]]`ImplicitParameters` ||<|5> Positive
test. ||
+ || '''`filter:`'''[[BR]] `SELECT FROM company.Person` `WHERE firstname = :param` ||
+ || '''`grouping:`'''[[BR]] `...` ||
+ || '''`ordering:`'''[[BR]] `...` ||
+ || '''`range:`'''[[BR]] `SELECT FROM company.FullTimeEmployee` `RANGE :one TO :ten` ||
+ || '''A14.6.13-3:''' If implicit parameters are used, their order of appearance in the query
determines their order for binding to positional parameters for execution. || `SELECT FROM
company.Person` `WHERE firstname == :param1` `& lastname == :param2` || `jdoql.parameters.`[[BR]]`OrderOfParameters`
|| Positive test. ||
+ 
+ [[Anchor(Variables)]]
+ === Variables ===
+ 
+ || '''Assertion''' || '''JDOQL''' || '''Testclass''' || '''Comment''' ||
+ || '''A14.6.5-1:''' ?? A variable that is not constrained with an explicit contains clause
is constrained by the extent of the persistence capable class (including subclasses). || `SELECT
department FROM company.Person` `WHERE firstname.endsWith('hn')` `VARIABLES Department department`
|| `jdoql.variables.`[[BR]]`UnconstrainedVariable` || Posistive test. ||
+ || '''A14.6.5-2''': ?? If the class does not manage an `Extent`, then no results will satisfy
the query. || `...` || `jdoql.variables.`[[BR]]`VariablesWithoutExtent` || Positive test.
||
+ ||<|3> '''A14.6.5-3:''' All variables must be explicitly declared, or all variables
must be implicitly declared. || '''`explicit:`'''[[BR]] `SELECT FROM company.Employee` `WHERE
team.contains(employee)` `& employee.firstname == 'John'` `& projects.contains(project)`
`& project.name == 'orange'` `VARIABLES Employee employee; Project project` ||<|3>
`jdoql.variables.`[[BR]]`MixedVariables` ||<|3> Positive and negative test. ||
+ || '''`implicit:`'''[[BR]] `SELECT FROM company.Employee` `WHERE team.contains(employee)`
`& employee.firstname == 'John'` `& projects.contains(project)` `& project.name
== 'orange'` ||
+ || '''`invalid:`'''[[BR]] `SELECT FROM company.Company` `WHERE departments.contains(department)`
`& department.name == 'Development'` `VARIABLES Employee employee` ||
+ ||<|3> '''A14.6.5-4:''' Names are treated as variable names if they are explicitly
declared via `declareVariables`. Otherwise, names are treated as field names if they are members
of the candidate class. Finally, names are treated as implicitly defined variable names. ||
'''`explicit:`'''[[BR]] `SELECT FROM company.Employee` `WHERE team.contains(employee)` `&
employee.firstname == 'John'` `VARIABLES Employee employee` ||<|3> `jdoql.variables.`[[BR]]`VariablesAndFields`
||<|3> Positive test. ||
+ || '''`implicit:`'''[[BR]] `SELECT FROM company.Employee` `WHERE team.contains(employee)`
`& employee.firstname == 'John'` ||
+ || '''`field name:`'''[[BR]] `SELECT FROM company.Person` `WHERE firstname == 'John'` ||
+ 
+ [[Anchor(OtherLanguageChanges)]]
+ === Other Language Changes ===
+ 
+ || '''Assertion''' || '''JDOQL''' || '''Testclass''' || '''Comment''' ||
+ ||<|2> '''A14.6.2-42:''' There is no distinction made between character literals and
`String` literals. Single character `String` literals can be used wherever character literals
are permitted. `String` literals are allowed to be delimited by single quote marks or double
quote marks. This allows `String` literal filters to use single quote marks instead of escaped
double quote marks. || '''`valid:`'''[[BR]] `SELECT FROM company.Person ` `WHERE firstname
== 'John' OR ... == 'F'` ||<|2> `jdoql.`[[BR]]`CharacterAndStringLiterals` ||<|2>
Positive and negative test. ||
+ || '''`invalid:`'''[[BR]] `SELECT FROM company.Person` `WHERE firstname == 'John' OR ...
== 'F.'` ||
+ ||<|2> '''A14.6.2-43:''' Identifiers that are persistent field names or `public final
static` field names are required to be supported by JDO implementations. || '''`field names:`'''[[BR]]
`SELECT FROM company.Person` `VARIABLES String firstname PARAMETERS long personid` ||<|2>
`jdoql.`[[BR]]`IdentifiersEqualFieldNames` ||<|2> Positive test. ||
+ || '''`static field names:`'''[[BR]] `...` ||
+ || '''A14.6.8-1:''' `setRange(long fromIncl, long toExcl)` || `SELECT lastname FROM company.Person
RANGE 1 TO 10` || `jdoql.`[[BR]]`PositiveRange` || Positive test. ||
+ || '''A14.6.8-2:''' If `((toExcl - fromIncl) <= 0)` evaluates to `true`, if the result
of the query execution is a List, the returned List contains no instances, and an Iterator
obtained from the List returns `false` to `hasNext()`. If the result of the query execution
is a single instance `(setUnique(true))`, it will have a value of `null`. || `SELECT lastname
FROM company.Person RANGE 10 TO 1` || `jdoql.`[[BR]]`NegativeRange` || Positive test. ||
+ || '''A14.6.8-3:''' `setRange(String range);` || `SELECT lastname FROM company.Person RANGE
1 TO 10` || `jdoql.`[[BR]]`RangeAsString` || Positive test. ||
+ 
+ [[Anchor(QueryAPIExtensions)]]
+ == Query API Extensions ==
+ 
+ || '''Assertion''' || '''JDOQL''' || '''Testclass''' || '''Comment''' ||
+ || '''A14.5-11:''' Construct a new query instance using the specified `String` as the single-string
representation of the query. || `SELECT FROM company.Person` || `api.`[[BR]]`NewQuerySingleString`
|| Positive test. ||
+ || '''A14.5-12:''' Construct a new query instance with the given candidate class from a
named query. || `SELECT FROM company.Person` || `api.`[[BR]]`NewNamedQuery` || Positive test.
||
+ || '''A14.5-13:''' If the named query is not found in already-loaded metadata, the query
is searched for using an algorithm. Files containing metadata are examined in turn until the
query is found. The order is based on the metadata search order for class metadata, but includes
files named based on the query name. || `SELECT FROM company.Person` || `api.`[[BR]]`MetadataSearchOrder`
|| Positive test. ||
+ || '''A14.5-14:''' If the metadata is not found in the above, a `JDOUserException` is thrown.
|| || `api.`[[BR]]`NamedQueryNotFound` || Negative test. ||
+ || '''A14.5-15:''' The `Query` instance returned from this method can be modified by the
application, just like any other `Query` instance. || `SELECT FROM company.Person WHERE firstname
== 'John'` || `api.`[[BR]]`ChangeQuery` || Positive test. ||
+ || '''A14.5-16:''' Named queries must be compilable. Attempts to get a named query that
cannot be compiled result in `JDOUserException`. || `SELECT from company.Person` || `api.`[[BR]]`InvalidNamedQuery`
|| Negative test. ||
+ || '''A14.6-21:''' This method retrieves the fetch plan associated with the `Query`. It
always returns the identical instance for the same `Query` instance. Any change made to the
fetch plan affects subsequent query execution. || `SELECT FROM company.Person` || `api.`[[BR]]`FetchPan`
|| Positive test. ||
+ ||<|2> '''A14.6-16:''' `void setResult (String result);` Specify the results of the
query if not instances of the candidate class. || '''`valid:`'''[[BR]]`SELECT lastname FROM
company.Person` ||<|2> `api.`[[BR]]`NewNamedQuery` ||<|2> Positive test and negative
test. ||
+ ||'''`invalid:`'''[[BR]]`SELECT middlename FROM company.Person` ||
+ || '''A14.6-17:''' `void setGrouping (String grouping);` Specify the grouping of results
for aggregates. || `SELECT lastname FROM company.Person GROUP BY lastname` || `api.`[[BR]]`SetGrouping`
|| Positive test. ||
+ || '''A14.6-18:''' `void setUnique (boolean unique);` Specify that there is a single result
of the query. || `SELECT UNIQUE firstname` `FROM company.Person` `WHERE lastname == Russel'`
|| `api.`[[BR]]`SetUnique` || Positive test. ||
+ || '''A14.6-19:''' `void setResultClass (Class resultClass);` Specify the class to be used
to return result instances. || `SELECT firstname, lastname INTO ...FullName` `FROM company.Person`
|| `api.`[[BR]]`SetResultClass` || Positive test. ||
+ || '''A14.6-20:''' `setRange(int fromIncl, int toExcl);` Specify the number of instances
to skip over and the maximum number of result in­stances to return. || `SELECT FROM company.Person
RANGE 1 TO 10` || `api.`[[BR]]`SetRange` || Positive test. ||
+ || '''A14.6-22:''' The `Unmodifiable` option, when set to `true`, disallows further modification
of the query, except for specifying the range and result class and `ignoreCache` option. ||
`SELECT FROM company.Person` || `api.`[[BR]]`UnmodifiableQuery` || Negative test. ||
+ || '''A14.6-23:''' The single string query is first parsed to yield the result, result class,
filter, variable list, parameter list, import list, grouping, ordering, and range. Then, the
values specified in APIs `setResult`, `setResultClass`, `setFilter`, `declareVariables`, `declareParamters`,
`declareImports`, `setGrouping`, `setOrdering`, and `setRange` override the corresponding
settings from the single string query. || `...` || `api.`[[BR]]`SingleStringQuery` || Positive
test. ||
+ || '''A14.9-1:''' Some JDO vendors provide extensions to the query, and these extensions
must be set in the query instance prior to execution. || `SELECT FROM company.Person` || `api.`[[BR]]`QueryExtentions`
|| Positive test. ||
+ 
+ [[Anchor(ResultHandling)]]
+ == Result Handling ==
+ 
+ || '''Assertion''' || '''JDOQL''' || '''Testclass''' || '''Comment''' ||
+ || '''A14.6.9-1:''' If `distinct` is specified, the query result does not include any duplicates.
If the result parameter specifies more than one result expression, duplicates are those with
matching values for each result expression. || `SELECT DISTINCT FROM company.Person` || `result.`[[BR]]`DistinctQuery`
|| Positive test. ||
+ || '''A14.6.9-2:''' Queries against an extent always consider only distinct candidate instances,
regardless of whether `distinct` is specified. Queries against a collection might contain
duplicate candidate instances; the `distinct` keyword removes duplicates from the candidate
collection in this case. || ''`(javax.jdo.option.UnconstrainedQueryVariables`)'' `SELECT FROM
company.Person` `VARIABLES Project project` || `jdoql.`[[BR]]`DistintCandidateInstances` ||
Positive test. ||
+ ||<|2> '''A14.6.9-3:''' If a variable or a field of a variable is included in the
result, either directly or via navigation through the variable, then the semantics of the
contains clause that include the variable change. In this case, all values of the variable
that satisfy the filter are included in the result. || '''`variable:`'''[[BR]]`SELECT project
FROM company.Employee` `WHERE projects.contains(project)` `& project.name == 'orange'`
`VARIABLES Project project` ||<|2> `result.`[[BR]]`VariableInResult` ||<|2> Positive
test. ||
+ || '''`field of variable:`'''[[BR]]`SELECT project.name FROM company.Employee` `WHERE projects.contains(project)`
`& project.name == 'orange'` `VARIABLES Project project` ||
+ ||<|2> '''A14.6.9-4:''' If any result is a navigational expression, and a non-terminal
field or variable has a `null` value for a particular set of conditions (the result calculation
would throw `NullPointerException`), then the result is null for that result expression. ||
'''`field:`'''[[BR]]`SELECT FROM company.Employee` `WHERE projects.contains(project)` ||<|2>
`result.`[[BR]]`NPEInResultExpr` ||<|2> Positive test. ||
+ || '''`variable:`'''[[BR]]`SELECT FROM company.Employee` `WHERE firstname == variable.firstname`
`VARIABLES Employee variable;` ||
+ || '''A14.6.9-5:''' The result expressions include: ... The result expression can be explicitly
cast using the (cast) operator. || `SELECT DISTINCT (FullTimeEmployee)manager` `FROM company.Employee`
|| `result.`[[BR]]`CastResult` || Positive test. ||
+ ||<|7> '''A14.6.9-6:''' `Count` returns `Long`. `Sum` returns `Long` for integral
types and the field's type for other `Number` types (`BigDecimal`, `BigInteger`, `Float`,
and `Double`). `Sum` is invalid if applied to non-`Number` types. `Avg`, `min`, and `max`
return the type of the expression. || '''`Count:`'''[[BR]]`SELECT COUNT(salary) from company.FullTimeEmployee`
||<|7> `result.`[[BR]]`AggregateResult` ||<|7> Positive and negative test. ||
+ || '''`Sum:`'''[[BR]]`SELECT SUM(salary) from company.FullTimeEmployee` ''`(TBD for all
integral types)`'' ||
+ || '''`invalid Sum:`'''[[BR]]`SELECT SUM(hiredate) from FullTimeEmployee` ''`(TBD for all
non-Number types)`'' ||
+ || '''`Avg:`'''[[BR]]`SELECT AVG(salary) from company.FullTimeEmployee` ''`(TBD for all
integral types)`'' ||
+ || '''`invalid Avg:`'''[[BR]]`SELECT AVG(hiredate) from FullTimeEmployee` ''`(TBD for all
non-Number types)`'' ||
+ || '''`Min:`'''[[BR]]`SELECT MIN(salary) from company.FullTimeEmployee` ''`(TBD for all
integral types)`'' ||
+ || '''`Max:`'''[[BR]]`SELECT MAX(salary) from company.FullTimeEmployee` ''`(TBD for all
integral types)`'' ||
+ || '''A14.6.9-7:''' If the returned value from a query specifying a result is `null`, this
indicates that the expression specified as the result was `null`. || '''`valid:`'''[[BR]]`SELECT
lastname FROM company.PERSON` || `result.`[[BR]]`NullResults` || Positive test. ||
+ || '''A14.6.9-8:''' If not specified, the result defaults to `distinct this as C` || `SELECT
FROM company.Department` || `result.`[[BR]]`DefaultResult` || Positive test. ||
+ ||<|2> '''A14.6.10-1:''' When grouping is specified, each result expression must be
one of: an expression contained in the grouping expression; or, an aggregate expression evaluated
once per group. The query groups all elements where all expressions specified in `setGrouping`
have the same values. The query result consists of one element per group. || '''`valid:`'''[[BR]]`SELECT
department, SUM(salary)` `FROM company.FullTimeEmployee GROUP BY department` ||<|2>
`result.`[[BR]]`Grouping` ||<|2> Positive and negative test. ||
+ || '''`invalid:`'''[[BR]]`SELECT department, salary` `FROM company.FullTimeEmployee GROUP
BY department` ||
+ ||<|2> '''A14.6.10-2:''' When `having` is specified, the `having` expression consists
of arithmetic and boolean expressions containing aggregate expressions. || '''`valid:`'''[[BR]]`SELECT
department, SUM(salary)` `FROM company.FullTimeEmployee GROUP BY department` `HAVING COUNT(department.employees)
> 0` ||<|2> `result.`[[BR]]`Having` ||<|2> Positive and negative test. ||
+ || '''`invalid:`'''[[BR]]`SELECT department, SUM(salary)` `FROM company.FullTimeEmployee
GROUP BY department` `HAVING firstname == 'John'` ||
+ ||<|3> '''A14.6.11-1:''' When the value of the `Unique` flag is `true`, then the result
of a query is a single value, with `null` used to indicate that none of the instances in the
candidates satisfied the filter. If more than one instance satisfies the filter, and the range
is not limited to one result, then `execute` throws a `JDOUserException.` || '''`valid, result
is non-null:`'''[[BR]]`SELECT UNIQUE FROM company.Company` `WHERE companyid == 1` ||<|3>
`result.`[[BR]]`Unique` ||<|3> Positive and negative test. ||
+ || '''`valid, result is null:`'''[[BR]]`SELECT UNIQUE FROM company.Company` WHERE name ==
'non-existent' ||
+ || '''`invalid:`'''[[BR]]`SELECT UNIQUE FROM company.Person` ||
+ ||<|3> '''A14.6.11-2:''' The default Unique setting is `true` for aggregate results
without a grouping expression, and `false` otherwise. || '''`true:`'''[[BR]]`SELECT COUNT(THIS)
FROM company.Person` ||<|3> `result.`[[BR]]`DefaultUnique` ||<|3> Positive test.
||
+ || '''`false grouping:`'''[[BR]]`SELECT FROM company.Person` `GROUP BY lastname` ||
+ || '''`false:`'''[[BR]]`SELECT FROM company.Person` ||
+ || '''A14.6.12-1:''' The result class may be one of ... ... Portable result classes do not
invoke any persistence behavior during their no-args constructor or set methods. || `SELECT
firstname, lastname INTO ...FullName FROM company.Person` || `result.`[[BR]]`ResultClassRequirements`
|| Positive test. ||
+ || '''A14.6.12-2:''' Table 6: Shape of Result (C is the candidate class) || `...` || `result.`[[BR]]`ShapeOfResult`
|| Positive test. ||
+ 
+ [[Anchor(SQLQueries)]]
+ == SQL Queries ==
+ 
+ || '''Assertion''' || '''JDOQL''' || '''Testclass''' || '''Comment''' ||
+ ||'''A14.7-1:''' In this case, the factory method that takes the language string and Object
is used: `newQuery (String language, Object query)`. The language parameter is `javax.jdo.query.SQL`
and the query parameter is the SQL query string. || `SELECT * FROM company.Person` || `sql.`[[BR]]`NewQuery`
|| Positive test.  ||
+ ||<|4> '''A14.7-2:''' The only methods that can be used are `setClass` to establish
the candidate class, `setUnique` to declare that there is only one result row, and `setResultClass`
to establish the result class. || '''`setClass:`'''[[BR]]`SELECT * FROM company.Person` ||<|4>
`sql.`[[BR]]`AllowedAPIMethods` ||<|4> Positive and negative test. ||
+ || '''`setUnique:`'''[[BR]]`SELECT * FROM company.Company` ||
+ || '''`setResultClass:`'''[[BR]]`SELECT firstname, lastname FROM company.Person` ||
+ || '''`invalid:`'''[[BR]]''`for all other query api methods`'' ||
+ ||<|2> '''A14.7-3:''' SQL queries can be defined without a candidate class. These
queries can be found by name using the factory method `newNamedQuery`, specifying the class
as `null`, or can be constructed without a candidate class. || '''`named query:`'''[[BR]]`Select
* from company.Person` ||<|2> `sql.`[[BR]]`CandidateClass` ||<|2> Positive test.
||
+ || '''`non-named query:`'''[[BR]]`Select * from company.Person` ||
+ || '''A14.7-4:''' Table 7: Shape of Result of SQL Query || `...` || `sql.`[[BR]]`ShapeOfResult`
|| Positive test. ||
+ 
+ [[Anchor(DeletionByQuery)]]
+ == Deletion by Query ==
+ 
+ || '''Assertion''' || '''JDOQL''' || '''Testclass''' || '''Comment''' ||
+ || '''A14.8-1:''' These methods delete the instances of affected classes that pass the filter,
and all dependent instances. Affected classes are the candidate class and its persistence-capable
subclasses. || `SELECT * FROM company.Person` || `api.`[[BR]]`DeletePersistentAll` || Positive
test. ||
+ || '''A14.8-2:''' The number of instances of affected classes that were deleted is returned.
Embedded instances and dependent instances are not counted in the return value. || `SELECT
* FROM company.Person` || `api.`[[BR]]`NoOfDeletedInstances` || Positive test. ||
+ ||<|6> '''A14.8-3:''' Query elements `filter`, `parameters`, `imports`, `variables`,
and `unique` are valid in queries used for delete. Elements `result`, `result class`, `range`,
`grouping`, and `ordering` are invalid. If any of these elements is set to its non-default
value when one of the `deletePersistentAll` methods is called, a `JDOUserException` is thrown
and no instances are deleted. || '''`valid:`'''[[BR]]`SELECT UNIQUE FROM company.FullTimeEmployee`
`WHERE salary > 1000` `& projects.contains(project)` `& project.budget > limit`
`VARIABLES Project project` `PARAMETERS BigDecimal limit` ||<|6> `api.`[[BR]]`DeleteQueryElements`
||<|6> Positive and negative test. ||
+ || '''`invalid result:`'''[[BR]]`SELECT firstname INTO ...FullName AS first` `FROM company.FullTimeEmployee`
||
+ || '''`invalid order by:`'''[[BR]]`SELECT FROM company.FullTimeEmployee` `ORDER BY salary`
||
+ || '''`invalid group by:`'''[[BR]]`SELECT FROM company.FullTimeEmployee` `GROUP BY lastname`
||
+ || '''`invalid having:`'''[[BR]]`SELECT FROM company.FullTimeEmployee` `GROUP BY lastname`
`HAVING lastname.startsWith('R')` ||
+ || '''`invalid range:`'''[[BR]]`SELECT FROM company.FullTimeEmployee` `RANGE 1 TO 10` ||
+ || '''A14.8-4:''' Dirty instances of affected classes are first flushed to the datastore.
Instances already in the cache when deleted via these methods or brought into the cache as
a result of these methods undergo the life cycle transitions as if `deletePersistent` had
been called on them. That is, if an affected class implements the `DeleteCallback` interface,
the instances to be deleted are instantiated in memory and the `jdoPreDelete` method is called
prior to deleting the instance in the datastore. If any `LifecycleListener` instances are
registered with affected classes, these listeners are called for each deleted instance. Before
returning control to the application, instances of affected classes in the cache are refreshed
by the implementation so their status in the cache reflects whether they were deleted from
the datastore. || `SELECT * FROM company.Person` || `api.`[[BR]]`DeleteCallback` || Positive
test. ||
+ 
+ [[Anchor(TestcasePattern)]]
+ == Testcase Pattern ==
+ 
+ [[Anchor(PositiveTest)]]
+ === Positive test ===
+ 
+ A positive test expects that the query compiles and executes w/o exception and returns the
expected result:
+ 
+ {{{
+     Query query = pm.newQuery();
+     ... 
+     // define query
+     Object results = query.execute(...);
+ 
+     // check query result
+     List expected = new ArrayList();
+     expected.add(...);
+     checkQueryResultWithoutOrder(assertion, results, expected);
+ }}}     
+ 
+ [[Anchor(NegativeTest)]]
+ === Negative test ===
+ 
+ A negative test case uses an invalid JDOQL query and expects an exception to be thrown by
compile or execute:
+ 
+ {{{
+     try {
+         Query query = pm.newQuery();
+         ... 
+         // define query
+         Object results = query.execute();
+         fail(ASSERTION_FAILED, text);
+     } catch (JDOException e) {
+         if (debug) logger.debug("Caught expected " + e);
+     }
+ }}}
+ 

Mime
View raw message