Sorin Marian Nasoi has proposed merging lp:~zorba-coders/zorba/feature_fots into lp:zorba.
Requested reviews: Zorba Coders (zorba-coders) For more details, see: https://code.launchpad.net/~zorba-coders/zorba/feature_fots/+merge/117579 Added Zorba FOTS driver. -- https://code.launchpad.net/~zorba-coders/zorba/feature_fots/+merge/117579 Your team Zorba Coders is requested to review the proposed merge of lp:~zorba-coders/zorba/feature_fots into lp:zorba.
=== added directory 'test/fots_driver' === added file 'test/fots_driver/README.TXT' --- test/fots_driver/README.TXT 1970-01-01 00:00:00 +0000 +++ test/fots_driver/README.TXT 2012-08-01 08:12:20 +0000 @@ -0,0 +1,29 @@ +Information about the W3C XQuery/XPath/XSLT 3.* Test Suite can be found here: http://dev.w3.org/2011/QT3-test-suite . + +In order to use the Zorba FOTS driver (written in XQuery) one has to follow these steps: + +0) Compile Zorba with the XQXQ external module. + +1) Download the FOTS testsuite from W3C + Since currently there is no official release, a simple "cvs get" will do: + + $ export CVSROOT=":pserver:anonym...@dev.w3.org:/sources/public" + $ cvs login + (Logging in to anonym...@dev.w3.org) + CVS password: anonymous + $ cvs get 2011/QT3-test-suite + +2) Check out the examples in the ZORBA_FOLDER/test/fots_driver/fots.xq for: + - listing the available test sets in the FOTS (see function fots:list-test-sets) + - running all test cases in the test sets (see fots:run-fots functions) + - running a single test set if you are a module developer (see fots:run-test-set function) + - running a single test case (see fots:test function) + - running and reporting statistics (see reporting:run-and-report function) + - loading a failures file and reporting statistics (see reporting:run-and-report function) + +3) run + ./zorba -f + -q ../../test/fots_driver/fots.xq + -e fotsPath:="/home/spungi/work/zorba/w3c_repo/2011/QT3-test-suite" + -o failures.xml + --indent === added file 'test/fots_driver/fots-check.xqy' --- test/fots_driver/fots-check.xqy 1970-01-01 00:00:00 +0000 +++ test/fots_driver/fots-check.xqy 2012-08-01 08:12:20 +0000 @@ -0,0 +1,337 @@ +xquery version "3.0"; + +module namespace check = "http://www.w3.org/2010/09/qt-fots-catalog/check"; + +declare namespace err = "http://www.w3.org/2005/xqt-errors"; +import schema namespace output = "http://www.w3.org/2010/xslt-xquery-serialization"; + +import module namespace ser = "http://www.w3.org/2010/09/qt-fots-catalog/serialize" at "serialize.xqy"; + +declare namespace ann = "http://www.zorba-xquery.com/annotations"; +import module namespace xqxq = "http://www.zorba-xquery.com/modules/xqxq"; +import module namespace schema = "http://www.zorba-xquery.com/modules/schema"; +declare namespace features = "http://www.zorba-xquery.com/options/features"; +declare option features:enable "hof"; + +(:~ + : Errors namespace URI. +:) +declare variable $check:errNS as xs:string := "http://www.w3.org/2010/09/qt-fots-catalog/check"; + +(:~ + : xs:QName with namespace URI="http://www.w3.org/2010/09/qt-fots-catalog/check" and local name "check:errNA" +:) +declare variable $check:errNA as xs:QName := fn:QName($check:errNS, "check:errNA"); + +declare %private function check:is-value-in-sequence + ( $value as xs:anyAtomicType?, + $seq as xs:anyAtomicType*) as xs:boolean { + $value = $seq + } ; + +(:~ + : The serialization parameters for XML serialization. + :) +declare %private variable $check:serParamXml := + <output:serialization-parameters> + <output:method value="xml" /> + <output:indent value="no" /> + <output:omit-xml-declaration value="yes" /> + </output:serialization-parameters>; + +declare %private %ann:sequential function check:res( + $result as item()*, + $expResult as element() +) as xs:string* { + let $test := local-name($expResult) + return switch($test) + case 'all-of' + return + for $tmp in $expResult/* + return check:res($result, $tmp) + case 'any-of' + return + let $results := for $tmp in $expResult/* + return empty(check:res($result, $tmp)) + return + if (check:is-value-in-sequence(fn:true(), (for $result in $results return $result))) + then () + else concat("'any-of' assertion returned: ", + string-join(for $result in $results return fn:string($result),', ')) + case 'assert' + return check:assert($result, $expResult) + case 'assert-count' + return + let $count := count($result), + $exp := xs:integer($expResult) + return if($count eq $exp) then () + else concat('Expected ', $exp, ' items, found ', $count, '.') + case 'assert-deep-eq' + return check:assert-deep-eq($result, $expResult) + case 'assert-empty' + return if(empty($result)) then () else 'Result is not empty.' + case 'assert-eq' + return check:assert-eq($result, $expResult) + case 'assert-false' + return check:assert-bool($result, $expResult, fn:false()) + case 'assert-permutation' + return check:assert-permutation($result, $expResult) + case 'assert-xml' + return check:assert-xml($result, $expResult) + case 'assert-serialization-error' + return check:assert-serialization-error($result, $expResult) + case 'assert-string-value' + return check:assert-string-value($result, $expResult) + case 'assert-true' + return check:assert-bool($result, $expResult, fn:true()) + case 'assert-type' + return check:assert-type($result, $expResult) + case 'error' + return concat('Expected Error [', $result/@code, ']') + default return error( + fn:QName('http://www.w3.org/2005/xqt-errors', 'FOTS9999'), + concat('Unknown assertion: "', $test, '"')) +}; + +(: http://dev.w3.org/2011/QT3-test-suite/catalog-schema.html#elem_any-of :) +declare function check:any-of( + $res as item()*, + $result as element() +) as xs:string* { + fn:error($check:errNA, "Assertion type 'any-of' not implemented") +}; + +(: http://dev.w3.org/2011/QT3-test-suite/catalog-schema.html#elem_assert :) +declare %ann:sequential function check:assert( + $result as item()*, + $expResult as element() +) as xs:string* { + try { + let $queryText := concat( + "xquery version '3.0';", + "declare namespace o = 'http://www.zorba-xquery.com/options/features';", + "declare option o:enable 'hof';", + "declare variable $result external; ", + xs:string($expResult)), + $queryKey := xqxq:prepare-main-module($queryText), + $queryKeyResult := xqxq:bind-variable($queryKey, xs:QName('result'), $result), + $queryResult := xqxq:evaluate($queryKey) + return if($queryResult) then () + else concat('Assertion ''', $expResult, ''' failed.') + } catch * { + concat('Assertion ''', + $expResult, + ''' failed with: [', + $err:code, + '] ', + $err:description) + } +}; + +(: http://dev.w3.org/2011/QT3-test-suite/catalog-schema.html#elem_assert-deep-eq :) +declare %ann:sequential function check:assert-deep-eq( + $result as item()*, + $expResult as element() +) as xs:string* { + try { + let $queryText := concat( + "xquery version '3.0';", + "declare namespace o = 'http://www.zorba-xquery.com/options/features';", + "declare option o:enable 'hof';", + "declare variable $x external;", + "let $y := (",fn:string(fn:data($expResult)),") return ", + "every $i in 1 to max((count($x),count($y))) satisfies deep-equal($x[$i],$y[$i])"), + $queryKey := xqxq:prepare-main-module($queryText), + $queryKeyResult := xqxq:bind-variable($queryKey, xs:QName('x'), $result), + $queryResult := xqxq:evaluate($queryKey) + return if($queryResult) then () + else concat('Result is not deep-equal to ''', $expResult, '''.') + } catch * { + concat('Deep comparison to ''', $expResult, ''' failed with: [', + $err:code, '] ', $err:description) + } +}; + +(: http://dev.w3.org/2011/QT3-test-suite/catalog-schema.html#elem_assert-eq :) +declare %ann:sequential function check:assert-eq( + $result as item()*, + $expResult as element() +) as xs:string* { + try { + let $queryText := concat( + "xquery version '3.0';", + "declare namespace o = 'http://www.zorba-xquery.com/options/features';", + "declare option o:enable 'hof';", + "declare variable $x external;", + "declare function local:f($y) as xs:boolean {xs:string($x) eq xs:string(fn:data($y))};", + "let $f := local:f#1 return $f(", $expResult, ")"), + $queryKey := xqxq:prepare-main-module($queryText), + $queryKeyResult := xqxq:bind-variable($queryKey, xs:QName('x'), $result), + $queryResult := xqxq:evaluate($queryKey) + return + if($queryResult) then () + else concat('Result doesn''t match expected item ''', xs:string($expResult), '''.') + } catch * { + concat('Comparison to ''', $expResult/text(), ''' failed with: [', + $err:code, '] ', $err:description) + } +}; + +(: + http://dev.w3.org/2011/QT3-test-suite/catalog-schema.html#elem_assert-true + http://dev.w3.org/2011/QT3-test-suite/catalog-schema.html#elem_assert-false +:) +declare function check:assert-bool( + $res as item()*, + $result as element(), + $exp as xs:boolean +) { + if($res instance of xs:boolean and $res eq $exp) then () + else fn:concat('Query doesn''t evaluate to ''', $exp, '''') +}; + +(: http://dev.w3.org/2011/QT3-test-suite/catalog-schema.html#elem_assert-permutation :) +declare %ann:sequential function check:assert-permutation( + $result as item()*, + $expResult as element() +) { + try { + let $queryText := concat( + "xquery version '3.0';", + "declare namespace o = 'http://www.zorba-xquery.com/options/features';", + "declare option o:enable 'hof';", + "declare variable $x external;", + "let $y := (",fn:string(fn:data($expResult)),") return ", + (: if count(intersection(M1,M2)) = count(union(M1,M2)) = count(M1) then the sequences are identical :) + "(count(distinct-values($x[ . = $y])) = count(fn:distinct-values(($x, $y)))) = count(fn:distinct-values($x))"), + $queryKey := xqxq:prepare-main-module($queryText), + $queryKeyResult := xqxq:bind-variable($queryKey, xs:QName('x'), $result), + $queryResult := xqxq:evaluate($queryKey) + return if($queryResult) then () + else concat('Result isn''t a permutation of ''', $expResult, '''.') + } catch * { + concat('Unordered comparison to ''', $expResult, ''' failed with: [', + $err:code, '] ', $err:description) + } +}; + +(: http://dev.w3.org/2011/QT3-test-suite/catalog-schema.html#elem_assert-xml :) +declare function check:assert-xml( + $result as item()*, + $expResult as element() +) { + try { + let $cmpRes as xs:string := if($result instance of node()) + then fn:string-join(fn:serialize($result, + $check:serParamXml) + , ' ') + else fn:string($result) + return + if($cmpRes eq string($expResult)) + then () + else fn:concat('Serialized result ''', $cmpRes, ''' not equal to ''', $expResult, '''.') + } catch * { + concat('Serialized comparison to ''', $expResult, ''' failed with: [', + $err:code, '] ', $err:description) + } +}; + +(: http://dev.w3.org/2011/QT3-test-suite/catalog-schema.html#elem_assert-serialization-error :) +declare function check:assert-serialization-error( + $result as item()*, + $expResult as element() +) { + try { + let $cmpRes as xs:string := if($result instance of node()) + then fn:string-join(fn:serialize($result, + $check:serParamXml) + , ' ') + else fn:string($result) + return + fn:concat('Expected serialization error but got result ''', $cmpRes, '''.') + } catch * { + check:error($err:code, + $err:description, + $expResult) + } +}; + +(: http://dev.w3.org/2011/QT3-test-suite/catalog-schema.html#elem_assert-string-value :) +declare function check:assert-string-value( + $res as item()*, + $result as element() +) as xs:string* { + try { + let $str := fn:string-join(for $r in $res return xs:string($r), " "), + $exp := xs:string($result) + return if($str eq $exp) then () + else fn:concat('Expected ''', $exp, ''', found ''', $str, '''.') + } catch * { + fn:concat('String eq comparison to ', $result, ' failed with: [', + $err:code, '] ', $err:description) + } +}; + +(: http://dev.w3.org/2011/QT3-test-suite/catalog-schema.html#elem_assert-type :) +declare function check:assert-type( + $result as item()*, + $expResult as element() +) as xs:string* { + try { + let $typeResult := xs:string(schema:schema-type($result[1])), + $type := xs:string($expResult) + return if($type eq $typeResult) then () + else concat('Result doesn''t have type ''', $type, '''.') + } catch * { + concat('Type check for ''', $result, + ''' failed with: [', $err:code, '] ', $err:description) + } +}; + +declare %ann:sequential function check:result( + $result as item()*, + $expResult as element() +) as element()? { + let $err := check:res($result, $expResult) + return if(empty($err)) then () else + <out> + <result>{ser:serialize($result)} + </result> + <errors>{ser:serialize($err)} + </errors> + </out> +}; + +declare function check:error( + $code as xs:QName, + $error as xs:string, + $result as element() +) as element()? { + let $err := check:err($code, $error, $result) + return if(empty($err)) then () else + <out> + <result>Error: {concat('[', $code, '] ', $error)}</result> + <errors>{$err}</errors> + </out> +}; + +declare %private function check:err( + $code as xs:QName, + $err as xs:string, + $result as element() +) as xs:string* { + let $errors := $result/descendant-or-self::*:error + return + if(exists($errors[@code = "*"])) + then () + else + if(fn:namespace-uri-from-QName($code) = 'http://www.w3.org/2005/xqt-errors' and + exists($errors[@code = fn:local-name-from-QName($code)])) + then () + else if(exists($errors)) then ( + concat('Wrong error code [', $code, '] (', $err, '), expected: [', + string-join($errors//@code, '], ['), ']') + ) else ( + concat('Expected result, found error: [', $code, '] ', $err) + ) +}; \ No newline at end of file === added file 'test/fots_driver/fots-environment.xqy' --- test/fots_driver/fots-environment.xqy 1970-01-01 00:00:00 +0000 +++ test/fots_driver/fots-environment.xqy 2012-08-01 08:12:20 +0000 @@ -0,0 +1,133 @@ +xquery version "3.0"; + +module namespace env = "http://www.w3.org/2010/09/qt-fots-catalog/environment"; + +declare namespace ann = "http://www.zorba-xquery.com/annotations"; +import module namespace xqxq = "http://www.zorba-xquery.com/modules/xqxq"; + +import module namespace file = "http://expath.org/ns/file"; + +import module namespace util = "http://www.w3.org/2010/09/qt-fots-catalog/util" + at "fots-util.xqy"; + +declare function env:var-decl-with-value( + $env, + $envCase +) as xs:string? { + fn:string-join( + for $param in ($env/*:param, $envCase/*:param) + where fn:exists(fn:data($param/@select)) + return concat("declare variable $", + fn:data($param/@name), + " := ", + fn:data($param/@select),";") + ," ") +}; + +declare function env:var-decl-without-value( + $env, + $envCase, + $path as xs:string? +) as xs:string? { + fn:string-join( + (for $param in ($env/*:param, $envCase/*:param) + where fn:empty(fn:data($param/@select)) + return concat("declare variable $", + fn:data($param/@name), + " external;"), + for $source in ($env/*:source, $envCase/*:source) + where fn:starts-with(fn:data($source/@role),"$") + return concat("declare variable ", + fn:data($source/@role), + " external;")) + ," ") +}; + +(:~ + : binds the variables that were added with attribute declared="true". + : + : @param $queryKey the query key. + : @param $env the environment of the catalog or the test-set (given with 'ref'). + : @param $envCase the environment of the test-case. + : @return the queryKey after the variables were bound. + :) +declare %ann:sequential function env:set-variables( + $queryKey as xs:anyURI, + $env, + $envCase, + $relativePath as xs:string? +) { + variable $select := for $param in ($env/*:param, $envCase/*:param) + where fn:not(fn:exists($param[@declared="false"])) + return fn:translate(fn:data($param/@select), "'", ""), + $name := for $param in ($env/*:param, $envCase/*:param) + where fn:not(fn:exists($param[@declared="false"])) + return fn:data($param/@name), + $suffix := for $source in ($env/*:source, $envCase/*:source) + where $source[@file = $select] + return data($source/@uri), + + $doc := concat($relativePath, + file:directory-separator(), + $suffix); + if(fn:exists($name)) then + xqxq:bind-variable( $queryKey, + fn:QName("", $name), + $doc); + else (); + + + variable $varNames := for $source in ($env/*:source, $envCase/*:source) + where fn:starts-with(fn:data($source/@role),"$") + return substring-after(fn:data($source/@role),"$"); + if(fn:exists($varNames)) then + for $varName in $varNames + let $xml := util:doc($relativePath, + for $source in ($env/*:source, $envCase/*:source) + where $source[@role = concat("$",$varName)] + return data($source/@file)) + return + xqxq:bind-variable( $queryKey, + fn:QName("", $varName), + $xml); + else (); +}; + +(:~ + : Adds the necessary declare namespace statements. + : + : @param $env the environment of the catalog or the test-set (given with 'ref'). + : @param $envCase the environment of the test-case. + : @return the declare namespace statements. + :) +declare function env:decl-namespaces( + $env, + $envCase +) as xs:string? { + string-join(for $ns in ($env/*:namespace, $envCase/*:namespace) + where fn:not($ns[@prefix=""]) + return concat('declare namespace ', + fn:data($ns/@prefix), + ' = "', + fn:data($ns/@uri), + '";') + ," ") +}; + +(:~ + : Sets the declared default element namespace. + : + : @param $env the environment of the catalog or the test-set (given with 'ref'). + : @param $envCase the environment of the test-case. + : @return the declare default element namespace. + :) +declare function env:decl-def-elem-namespace( + $env, + $envCase +) as xs:string? { + for $ns in ($env/*:namespace, $envCase/*:namespace) + where $ns[@prefix=""] + return concat('declare default element namespace "', + fn:data($ns/@uri), + '";') +}; \ No newline at end of file === added file 'test/fots_driver/fots-reporting.xqy' --- test/fots_driver/fots-reporting.xqy 1970-01-01 00:00:00 +0000 +++ test/fots_driver/fots-reporting.xqy 2012-08-01 08:12:20 +0000 @@ -0,0 +1,107 @@ +xquery version "3.0"; + +module namespace reporting = "http://www.w3.org/2010/09/qt-fots-catalog/reporting"; + +import module namespace file = "http://expath.org/ns/file"; +import module namespace fots = "http://www.w3.org/2010/09/qt-fots-catalog" + at 'fots.xqy'; +import module namespace util = "http://www.w3.org/2010/09/qt-fots-catalog/util" + at "fots-util.xqy"; + +declare namespace err ="http://www.w3.org/2005/xqt-errors"; +declare namespace ann = "http://www.zorba-xquery.com/annotations"; + +declare default element namespace "http://www.w3.org/2010/09/qt-fots-catalog"; + +(:~ + : Loops through the test-sets, runs then and creates statistics. + : @param $pathFOTSCatalog path to the FOTS catalog file. + : @param $except lists of tests that should not be run(empty string means all tests will be run). + : @param $verbose is set to TRUE it will also output the actual failures. + : @return a report of tests run. + :) +declare %ann:sequential function reporting:run-and-report( + $pathFOTSCatalog as xs:string, + $except as xs:string*, + $verbose as xs:boolean +) { + variable $failures := fots:run-fots($pathFOTSCatalog, + fots:list-test-sets($pathFOTSCatalog, ""), + "", + $except); + + reporting:do-reporting($pathFOTSCatalog, $failures, $except, $verbose) +}; + +(:~ + : Loops through the test-sets, reads the report of the failures and creates statistics. + : @param $pathFOTSCatalog path to the FOTS catalog file. + : @param $pathFailures path to the FOTS failures. + : @param $except lists of tests that should not be run(empty string means all tests will be run). + : @param $verbose is set to TRUE it will also output the actual failures. + : @return a report of tests run. + :) +declare %ann:nondeterministic function reporting:report( + $pathFOTSCatalog as xs:string, + $pathFailures as xs:string, + $except as xs:string*, + $verbose as xs:boolean +) { + if(not(file:is-file($pathFailures))) then + { + fn:error("The file failures file was not found. Suggestion: use fots:run-fots to generate it or use reporting:run-and-report function.") + } + else + try + { + let $failures := fn:parse-xml(file:read-text($pathFailures)) + return + reporting:do-reporting($pathFOTSCatalog, $failures, $except, $verbose) + } + catch * + { + fn:error(fn:concat( "The file <", + $pathFailures, + "> does not have the correct structure.")) + } +}; + + +(:~ + : Loops through the test-sets and creates statistics. + : @param $pathFOTSCatalog path to the FOTS catalog file. + : @param $failures the test reported by Zorba as failed. + : @param $except lists of tests that are not run. + : @param $verbose is set to TRUE it will also output the actual failures. + : @return a report of tests run. + :) +declare %ann:nondeterministic %private function reporting:do-reporting( + $pathFOTSCatalog as xs:string, + $failures, + $except, + $verbose as xs:boolean +) { + <report>{ + let $catalog := util:doc($pathFOTSCatalog, 'catalog.xml') + return + for $testSetFile in $catalog//test-set + let $file := fn:data($testSetFile/@file), + $testSet := util:doc($pathFOTSCatalog, $file), + $testSetName := fn:data($testSet/test-set/@name), + $totalNoTestCases := fn:count($testSet//test-case), + $totalFailures := for $testCase in $failures//test-case + where $testCase/test-set[@name = $testSetName] + return $testCase + return + <test-set name="{$testSetName}" + file="{$file}" + noFailures="{fn:count($totalFailures)}" + noTestsCases="{$totalNoTestCases}" + percent="{fn:round((1 - (fn:count($totalFailures) div $totalNoTestCases))*100,2)}" + failedTestNames="{fn:string-join(for $failure in $totalFailures return fn:data($failure/@name),",")}"> + {if ($verbose) then $totalFailures else ()} + </test-set> + } + <except>{$except}</except> + </report> +}; \ No newline at end of file === added file 'test/fots_driver/fots-util.xqy' --- test/fots_driver/fots-util.xqy 1970-01-01 00:00:00 +0000 +++ test/fots_driver/fots-util.xqy 2012-08-01 08:12:20 +0000 @@ -0,0 +1,25 @@ +xquery version "3.0"; + +module namespace util = "http://www.w3.org/2010/09/qt-fots-catalog/util"; + +declare namespace ann = "http://www.zorba-xquery.com/annotations"; + +import module namespace file = "http://expath.org/ns/file"; + +(: retrieves a document using a path and a suffix supplied as xs:strings + and returns the correponding document node :) +declare %ann:nondeterministic function util:doc( + $path as xs:string, + $suffix as xs:string +) as document-node()? { + fn:parse-xml( + file:read-text( + file:resolve-path( + concat( $path, + file:directory-separator(), + $suffix + ) + ) + ) + ) +}; \ No newline at end of file === added file 'test/fots_driver/fots.xq' --- test/fots_driver/fots.xq 1970-01-01 00:00:00 +0000 +++ test/fots_driver/fots.xq 2012-08-01 08:12:20 +0000 @@ -0,0 +1,94 @@ +xquery version "3.0"; + +import module namespace fots = "http://www.w3.org/2010/09/qt-fots-catalog" + at 'fots.xqy'; +import module namespace reporting = "http://www.w3.org/2010/09/qt-fots-catalog/reporting" + at 'fots-reporting.xqy'; + +declare default element namespace "http://www.w3.org/2010/09/qt-fots-catalog"; +declare variable $fotsPath as xs:string external; + +(:~ The test in this list have bugs assigned already and should not be run :) +variable $tests := ( +"context-item-1" (:see bug #867199 :) +,"xqhof7", "xqhof13", "xqhof14" (:see bug #947051 :) +,"FunctionCall-020" (:see bug #947064 :) +,"group-013" (: already asked Matthias to fix the test :) +,"generate-id-901", "generate-id-902" (:see bug #947130:) +,"try-catch-function-call-3", "try-catch-function-call-4" (:see bug #:) +); + +(: example for running a single test case :) +(: +fots:test( + <test-case name="fn-absint1args-1"> + <description>Test: absint1args-1 The "abs" function with the arguments set as follows: $arg = xs:int(lower bound) </description> + <created by="Carmelo Montanez" on="2004-12-13"/> + <environment ref="empty"/> + <test>fn:abs(xs:int("-2147483648"))</test> + <result> + <all-of> + <assert-eq>2147483648</assert-eq> + <assert-type>xs:integer</assert-type> + </all-of> + </result> + </test-case> + ) +:) + +(: example for list-matching-test-cases function :) +(: +fots:list-matching-test-cases("/home/spungi/work/zorba/w3c_repo/2011/QT3-test-suite", + "!", + "") +:) + +(: List all available test-sets in the FOTS + app, fn, map, math, misc, op, prod, xs :) +(: + fots:list-test-sets( + $fotsPath, + "" + ) +:) + +(: example for running a single test set from the FOTS:) +(: + fots:run-fots($fotsPath, + 'fn-abs', (: the test-sets :) + 'K2-ABSFunc-35', (: the test-cases :) + ()) +:) + +(: example for running a test set for an external module :) +(: +fots:run-test-set('/home/spungi/Downloads/has-children.xml', + 'fn-has-children-001' + ) +:) + +(: example for running the FOTS testsuite :) +(: + fots:run-fots($fotsPath, + fots:list-test-sets($fotsPath, ""), + '', + $tests + ) +:) + +(: example for running the FOTS testsuite and reporting statistics :) + + reporting:run-and-report( $fotsPath, + $tests, + fn:false() + ) + + +(: example for loading a failures file and reporting statistics :) +(: + reporting:report( $fotsPath, + "/home/spungi/work/zorba/repo/feature_fots/build_release/bin/failures.xml", + $tests, + fn:false() + ) +:) \ No newline at end of file === added file 'test/fots_driver/fots.xqy' --- test/fots_driver/fots.xqy 1970-01-01 00:00:00 +0000 +++ test/fots_driver/fots.xqy 2012-08-01 08:12:20 +0000 @@ -0,0 +1,379 @@ +xquery version "3.0"; + +(: global namespace of the test suite. :) +module namespace fots = "http://www.w3.org/2010/09/qt-fots-catalog"; + +declare default element namespace "http://www.w3.org/2010/09/qt-fots-catalog"; + +declare namespace ann = "http://www.zorba-xquery.com/annotations"; +import module namespace xqxq = "http://www.zorba-xquery.com/modules/xqxq"; + +declare namespace err = "http://www.w3.org/2005/xqt-errors"; + +import module namespace file = "http://expath.org/ns/file"; +import module namespace functx = "http://www.functx.com/"; + +import module namespace check = "http://www.w3.org/2010/09/qt-fots-catalog/check" + at "fots-check.xqy"; + +import module namespace env = "http://www.w3.org/2010/09/qt-fots-catalog/environment" + at "fots-environment.xqy"; + +import module namespace util = "http://www.w3.org/2010/09/qt-fots-catalog/util" + at "fots-util.xqy"; + +(:~ + : Loops through the FOTS catalog and returns all available test set names. + : @param $path path to the FOTS catalog file. + : @return available fots test-cases element names. + :) +declare %ann:nondeterministic function fots:list-test-sets( + $path as xs:string, + $catalogs as xs:string* +) as xs:string* { + let $doc := util:doc($path, 'catalog.xml'), + $env := $doc//environment + return + for $catalog in $catalogs + for $testSet in $doc//test-set[starts-with(@name, $catalog)] + return + fn:data($testSet/@name) +}; + +(:~ + : Loops through the FOTS catalog and returns all test cases that match given pattern using given flags. + : @param $path path to the FOTS catalog file. + : @param $pattern pattern. + : @param $flags flags. + : @return available fots test-cases matching given pattern and flags. + :) +declare %ann:nondeterministic function fots:list-matching-test-cases( + $path as xs:string, + $pattern as xs:string, + $flags as xs:string? +) as xs:string* { + let $catalog := util:doc($path, 'catalog.xml') + return + for $testSet in $catalog//test-set + let $file := fn:data($testSet/@file), + $testSet := util:doc($path, $file) + for $testCase in $testSet//test-case + where fn:matches(fn:data($testCase/*:test), $pattern, $flags) + return + fn:concat("File: ", $path, file:directory-separator(), $file, + ", test name:", fn:data($testCase/@name)," +") +}; + +(:~ + : Loops throgh the test set and evaluates all test cases. + : @param $path path to the FOTS catalog file. + : @return an element containing all failed tests + :) +declare %ann:sequential function fots:run-fots( + $path as xs:string +) as element(fots:failures) { + fots:run-fots($path, '', '','') +}; + +(:~ + : Loops throgh the test set and evaluates all test cases. + : @param $fotsPath path to the FOTS catalog file. + : @param $except lists of tests that should not be run(empty string means all tests will be run). + : @return an element containing all failed tests + :) +declare %ann:sequential function fots:run-fots( + $fotsPath as xs:string, + $except as xs:string* +) as element(fots:failures) { + fots:run-fots($fotsPath, + fots:list-test-sets($fotsPath, ""), + '', + $except) +}; + +(:~ + : Loops through the test sets and evaluates all test cases. + : @param $path path to the FOTS catalog file. + : @param $category name the catalog to use (empty string means all). + : @param $prefix prefix of test-cases to use (empty string means all). + : @param $except lists of tests that should not be run(empty string means all tests will be run). + : @return an element containing all failed tests + :) +declare %ann:sequential function fots:run-fots( + $path as xs:string, + $categories as xs:string*, + $prefixes as xs:string*, + $except as xs:string* +) as element(fots:failures) { + <failures>{ + let $catalog := util:doc($path, 'catalog.xml') + for $category in $categories + for $testSet in $catalog//test-set + let $file := fn:data($testSet/@file), + $testSetDoc := util:doc($path, $file), + $testSetName := fn:data($testSet/@name) + where $testSetName = $category + for $testCase in $testSetDoc//test-case + let $envName := fn:data($testCase/environment/@ref), + $envTestSet := $testSetDoc/test-set//environment[@name = $envName], + $pathTestSet := fots:path($path, $file), + $envCatalog := $catalog/catalog//environment[@name = $envName], + $pathCatalog := $path, + $dep := ($testSetDoc/test-set/dependency, $testCase/dependency), + $runQuery := fots:check-should-run-test($dep), + $shouldRun := (($prefixes eq xs:string('')) or fn:exists(functx:value-intersect($prefixes,xs:string(fn:data($testCase/@name))))), + $isExcepted := fn:exists(functx:value-intersect($except, xs:string(fn:data($testCase/@name)))) + where $shouldRun and fn:not($isExcepted) + (:TO DO fix this:) + and not($testSetName = "fn-matches.re") + and not($testSetName = "misc-HigherOrderFunctions") + and not($testSetName = "prod-NamedFunctionRef") + order by fn:data($testCase/@name) + return + if(fn:empty($envTestSet) + and $runQuery + and fn:not($isExcepted)) + then fots:test( $testCase, + $envCatalog, + $path, + $dep, + $testSetName) + else if (fn:exists($envTestSet) + and $runQuery + and fn:not($isExcepted)) + then fots:test( $testCase, + $envTestSet, + $pathTestSet, + $dep, + $testSetName) + else () + + }</failures> +}; + +(:~ + : Loops through the test set and evaluates all test cases. + : @param $path path to the test set file. + : @param $prefix prefix of test-cases to use (empty string means all). + : @return an element containing all failed tests + :) +declare %ann:sequential function fots:run-test-set( + $path as xs:string, + $prefixes as xs:string* +) as element(fots:failures) { + <failures>{ + let $testSet := util:doc($path, '')/test-set + for $prefix in $prefixes + for $testCase in $testSet//test-case[starts-with(@name, $prefix)] + let $envName := fn:data($testCase/environment/@ref), + $env := if(empty($envName)) then () + else fots:get-environment((), $testSet, $envName), + $testSetDep := $testSet/dependency, + $testSetName := fn:data($testSet/@name) + return fots:test( $testCase, + $env, + "", + $testSetDep, + $testSetName) + }</failures> +}; + + +(:~ + : Helper function: Runs a single test. + : + : @param $case test-case element + : @return empty sequence on success, the failed + : test-case element with additional information otherwise + :) +declare %ann:sequential function fots:test( + $case as element(fots:test-case) +) as element(fots:test-case)? { + fots:test($case, (), (), (), ()) +}; + +declare %private %ann:sequential function fots:xqxq-invoke( + $queryText as xs:string, + $case as element(fots:test-case), + $env as element(fots:environment)?, + $path as xs:string?) +{ + try { + let $queryKey := xqxq:prepare-main-module($queryText), + $queryKeyResult := fots:set-context-item($queryKey, $env, $path), + $queryKeyResult1 := env:set-variables($queryKey, $env, $case/environment, $path), + $queryResult := xqxq:evaluate($queryKey) + return check:result($queryResult, $case/*:result/*) + } catch * { + check:error($err:code, + $err:description, + $case/*:result/*) + } +}; + +(:~ + : Runs a single test. + : + : @param $case test-case element + : @param $env the environment + : @param $path the relative path used to calculate the full path for the + : different children of the environment that have a "file" attribute + : @param $testSetName the name of the test-set + : @return empty sequence on success, the failed + : test-case element with additional information otherwise + :) +declare %ann:sequential function fots:test( + $case as element(fots:test-case), + $env as element(fots:environment)?, + $path as xs:string?, + $deps as element(fots:dependency)*, + $testSetName as xs:string? +) as element(fots:test-case)? { + let $queryName := fn:data($case/@name), + $queryText as xs:string := fn:string-join( + (fots:add-xquery-30(($deps, $case//dependency)), + env:decl-def-elem-namespace($env, $case/environment), + env:decl-namespaces($env, $case/environment), + fots:enable-HOF-feature(($deps, $case//dependency)), + fots:add-var-decl($env, $case, $path), + xs:string(fn:data($case/*:test)) + )," "), + (:Tests that need XML 1.1 are marked as failing:) + $result := if (fn:data($case/*:dependency[@type="xml-version"]/@value) = "1.1") then + "XML version 1.1 not supported." + else + fots:xqxq-invoke($queryText, $case, $env, $path) + return if(fn:empty($result)) then () + else fots:wrong($case, $result, $queryText, $testSetName) +}; + +(: gives feedback on an erroneous query :) +declare %private %ann:sequential function fots:wrong( + $test as element(fots:test-case), + $result as item()*, + $zorbaQuery as xs:string, + $testSetName as xs:string? +) as element(fots:test-case)? { + let $tmp := $test, + $testName := trace(fn:data($test/@name),"failing test-case-name:") + return { + insert node + <wrong> + <query> + { $zorbaQuery } + </query> + {$result} + </wrong> + as last into $tmp; + + insert node + <test-set name="{trace($testSetName," test-set-name :")}" /> + as first into $tmp; + + delete node $tmp/description; + + delete nodes $tmp/descendant::comment(); + + $tmp + } +}; + +(: retrieves the path given 2 different components + example: fots:path('/home','user/file.ext') returns '/home/user' :) +declare %private function fots:path( + $path as xs:string, + $suffix as xs:string +) as xs:string { + concat($path, + file:directory-separator(), + fn:substring-before($suffix, + concat(file:directory-separator(),file:base-name($suffix))) + ) +}; + +(: retrieves the environment node from a test-set or catalog given a environment name :) +declare %private function fots:get-environment ( + $catalog, + $set, + $envName as xs:string +) as element(fots:environment)? { + let $envTestSet := $set/test-set//environment[@name = $envName] + return + if (fn:empty($envTestSet)) + then $catalog/catalog//environment[@name = $envName] + else $envTestSet +}; + +(: if defined, applies the context item to the $query-key :) +declare %private %ann:sequential function fots:set-context-item( + $queryKey as xs:anyURI, + $env as element(fots:environment)?, + $relativePath as xs:string? +) { + try { + if(data($env/@name) = 'empty') + then $queryKey + else + { + (: Set context item if this exists :) + if (fn:exists($env/*:source[@role = "."])) then + { + variable $xml := util:doc($relativePath, fn:data($env/*:source/@file)); + xqxq:bind-context-item($queryKey, $xml); + } + else (); + } + } + catch * { + fn:error("fots:set-context-item") + } +}; + +declare %private function fots:check-should-run-test( + $deps as element(fots:dependency)* +) as xs:boolean { + let $values := for $dep in $deps return fn:exists($dep[@satisfied="false"]) + return + switch(fn:count(fn:distinct-values($values))) + case xs:integer(2) return fn:false() + case xs:integer(1) return fn:boolean(fn:not(fn:distinct-values($values))) + default return fn:true() +}; + +declare %private function fots:add-xquery-30( + $deps as element(fots:dependency)* +) as xs:string? { + let $val := for $dep in $deps + where $dep[@type="spec"] and fn:contains(fn:data($dep/@value), "30") + return fn:true() + return + if($val[1]) + then "xquery version '3.0';" + else () +}; + +declare %private function fots:enable-HOF-feature( + $deps as element(fots:dependency)* +) as xs:string? { + let $val := for $dep in $deps + where $dep[@type="spec"] and fn:contains(fn:data($dep/@value), "30") + return fn:true() + return + if($val[1]) + then concat("declare namespace o = 'http://www.zorba-xquery.com/options/features';", + "declare option o:enable 'hof';") + else () +}; + +(:TODO If the test expression includes the string "(:%VARDECL%:)" + then the variable declaration should be added to replace this string; + if it does not include this string, the variable declaration can be added at the start. :) +declare %private %ann:nondeterministic function fots:add-var-decl( + $env as element(fots:environment)?, + $case as element(fots:test-case), + $path as xs:string? +) as xs:string? { + fn:concat(env:var-decl-with-value($env, $case/environment), + env:var-decl-without-value($env, $case/environment, $path)) +}; === added file 'test/fots_driver/serialize.xqy' --- test/fots_driver/serialize.xqy 1970-01-01 00:00:00 +0000 +++ test/fots_driver/serialize.xqy 2012-08-01 08:12:20 +0000 @@ -0,0 +1,39 @@ +xquery version "3.0"; + +module namespace ser = "http://www.w3.org/2010/09/qt-fots-catalog/serialize"; + +declare function ser:serialize( + $seq as item()* +) as xs:string { + fn:concat('(', fn:string-join( + (for $it in $seq + return ser:item($it)) + , ', '), ')') +}; + +declare %private function ser:item( + $it as item() +) as xs:string { + typeswitch($it) + case attribute() + return fn:concat(fn:name($it), '="', $it, '"') + case node() + return fn:serialize($it) + case function(*) + return ser:func($it) + case xs:untypedAtomic + return fn:concat('"', fn:replace($it, '"', '""'), '"') + case xs:string + return fn:concat('"', fn:replace($it, '"', '""'), '"') + default + return xs:string($it) +}; + +declare %private function ser:func( + $func as function(*) +) as xs:string { + let $arity := fn:function-arity($func), + $name := if(fn:exists(fn:function-name($func))) + then fn:function-name($func) else '*function*' + return fn:concat($name, '#', $arity) +}; \ No newline at end of file
-- Mailing list: https://launchpad.net/~zorba-coders Post to : zorba-coders@lists.launchpad.net Unsubscribe : https://launchpad.net/~zorba-coders More help : https://help.launchpad.net/ListHelp