more xqdoc documentation

more xqdoc documentation

(:
 : Copyright 2006-2009 The FLWOR 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.
:)

(:~
 : This module provides functions to fetch the contents or the type
 : of the content for a resource identified by a URI.
 : For example, it fetches content for file or http resources if Zorba
 : allows file or http access, respectively.
 :
 : @author Matthias Brantner
 : @project external
 :)
module namespace fetch = "http://www.zorba-xquery.com/modules/fetch";

declare namespace ann = "http://www.zorba-xquery.com/annotations";

declare variable $fetch:ErrRetrievingResource as xs:QName :=
  fn:QName("http://www.zorba-xquery.com/modules/fetch",
           "fetch:ErrRetrievingResource");

declare variable $fetch:ResourceDoesNotExist as xs:QName :=
  fn:QName("http://www.zorba-xquery.com/modules/fetch",
           "fetch:ResourceDoesNotExist");

(:~
 : Tries to fetch the resource refered to by the given URI.
 :
 : @param $uri the resource to fetch to
 : @error fetch:ErrRetrievingResource if an error occured
 :        retrieving the resource.
 : @error fetch:ResourceDoesNotExist if no resource could be found at
 :        the given location.
 :)
declare %ann:streamable function fetch:content($uri as xs:string) as xs:string external;

(:~
 : Tries to figure out the media type of the resource refered to by the
 : given URI (see [RFC 2376], [RFC 3023] and/or its successors).
 :
 : @param $uri the resource
 : @error fetch:ErrRetrievingResource if an error occured
 :        retrieving the resource.
 : @error fetch:ResourceDoesNotExist if no resource could be found at
 :        the given location.
 :)
declare function fetch:content-type($uri as xs:string) as xs:string external;

(:
 : Copyright 2006-2009 The FLWOR 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.
:)

(:~
 :)
module namespace fetch = "http://www.zorba-xquery.com/modules/fetch";

declare namespace ann = "http://www.zorba-xquery.com/annotations";

declare variable $fetch:ErrRetrievingResource as xs:QName :=
  fn:QName("http://www.zorba-xquery.com/modules/fetch",
           "fetch:ErrRetrievingResource");

declare variable $fetch:ResourceDoesNotExist as xs:QName :=
  fn:QName("http://www.zorba-xquery.com/modules/fetch",
           "fetch:ResourceDoesNotExist");

(:~
 : Tries to fetch the resource refered to by the given URI.
 :
 : @param $uri the resource to fetch to
 : @error fetch:ErrRetrievingResource if an error occured
 :        retrieving the resource.
 : @error fetch:ResourceDoesNotExist if no resource could be found at
 :        the given location.
 :)
declare %ann:streamable function fetch:content($uri as xs:string) as xs:string external;

(:~
 : Tries to figure out the media type of the resource refered to by the
 : given URI (see [RFC 2376], [RFC 3023] and/or its successors).
 :
 : @param $uri the resource
 : @error fetch:ErrRetrievingResource if an error occured
 :        retrieving the resource.
 : @error fetch:ResourceDoesNotExist if no resource could be found at
 :        the given location.
 :)
declare function fetch:content-type($uri as xs:string) as xs:string external;


[MOD] DBA, Navigation. Closes #1647

[MOD] DBA, Navigation. Closes #1647

(:~
 : Provides HTML components.
 :
 : @author Christian Grün, BaseX Team, 2014-18
 :)
module namespace html = 'dba/html';

import module namespace options = 'dba/options' at 'options.xqm';
import module namespace session = 'dba/session' at 'session.xqm';
import module namespace util = 'dba/util' at 'util.xqm';

(: Number formats. :)
declare variable $html:NUMBER := ('decimal', 'number', 'bytes');

(:~
 : Extends the specified table rows with the page template.
 : @param  $rows  tr elements
 : @return HTML page
 :)
declare function html:wrap(
  $rows  as element(tr)+
) as element(html) {
  html:wrap(map { }, $rows)
};

(:~
 : Extends the specified table rows with the page template.
 : The following options can be specified:
 :

 :
header: page headers

 :
error: error string

 :
css: CSS files

 :
scripts: JavaScript files

 :

 : @param  $options  options
 : @param  $rows     tr elements
 : @return page
 :)
declare function html:wrap(
  $options  as map(*),
  $rows     as element(tr)+
) as element(html) {
  let $header := head($options?header) ! util:capitalize(.)
  let $user := $session:VALUE
  return

      <meta charset="utf-8"/>
      <title>DBA{ ($header, tail($options?header)) ! (' » ' || .) }</title>
      <meta name="description" content="Database Administration"/>
      <meta name="author" content="BaseX Team, 2014-18"/>
      <link rel="stylesheet" type="text/css" href="static/style.css"/>
      { $options?css ! <link rel="stylesheet" type="text/css" href="static/{ . }"/> }

};


- remove unnecessary call to env:check-dependencies inside driver:test function.

(:
 : Copyright 2006-2011 The FLWOR 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.
 :)

(:~
 : Zorba FOTS driver
 : @author Sorin Nasoi
 :)

module namespace driver =
  "http://www.zorba-xquery.com/fots-driver";

import module namespace functx =
  "http://www.functx.com/";

import module namespace xqxq =
  "http://www.zorba-xquery.com/modules/xqxq";
import module namespace datetime  =
  "http://www.zorba-xquery.com/modules/datetime";

import module namespace eval =
  "http://www.zorba-xquery.com/fots-driver/evaluate" at "evaluate.xq";
import module namespace env =
  "http://www.zorba-xquery.com/fots-driver/environment" at "environment.xq";
import module namespace util =
  "http://www.zorba-xquery.com/fots-driver/util" at "util.xq";
import module namespace fots-err =
  "http://www.zorba-xquery.com/fots-driver/errors" at "errors.xq";

declare default element namespace "http://www.w3.org/2010/09/qt-fots-catalog";

declare namespace err =
  "http://www.w3.org/2005/xqt-errors";
declare namespace fots =
  "http://www.w3.org/2010/09/qt-fots-catalog";

declare namespace ann =
  "http://www.zorba-xquery.com/annotations";

(:~
 : Loops through the FOTS catalog and returns all available test set names.
 : @param $fotsPath path to the FOTS catalog file.
 : @param $testSetPrefixes name/criteria for the test sets
 : (empty string means all).
 : @return available FOTS test sets.
 :)
declare %ann:nondeterministic function driver:list-test-sets(
  $fotsPath         as xs:string,
  $testSetPrefixes  as xs:string*
) as xs:string* {
  let $doc := doc(resolve-uri($fotsPath))
  return
    if(string-join($testSetPrefixes,'') = '')
    then
      for $testSet in $doc/fots:catalog/fots:test-set
      return data($testSet/@name)
    else
      for $prefix in $testSetPrefixes
        for $testSet in $doc/fots:catalog/fots:test-set[starts-with(@name, $prefix)]
        return data($testSet/@name)
};

(:~
 : Loops through the given test sets and returns the corresponding test cases.
 : @param $fotsPath path to the FOTS catalog file.
 : @param $testSetPrefixes name/criteria for the test sets
 : (empty string means all).
 : @return available FOTS test cases.
 :)
declare %ann:nondeterministic function driver:list-test-cases(
  $fotsPath         as xs:string,
  $testSetPrefixes  as xs:string*
) as xs:string* {
  let $doc := doc(resolve-uri($fotsPath)),
      $baseUri:= resolve-uri(util:parent-folder($fotsPath))
  return
    if(string-join($testSetPrefixes,'') = '')
    then
      for $testSet in $doc/fots:catalog/fots:test-set
      let $testSetDoc := doc(resolve-uri($testSet/@file, $baseUri))
      return data($testSetDoc//fots:test-case/@name)
    else
      for $prefix in $testSetPrefixes
        for $testSet in $doc/fots:catalog/fots:test-set[starts-with(@name, $prefix)]
        let $testSetDoc := doc(resolve-uri($testSet/@file, $baseUri))
        return data($testSetDoc//fots:test-case/@name)
};

(:~
 : Loops through all the test cases and returns those that have a 'test' node
 : that matches given pattern using given flags.
 : @param $fotsPath 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 driver:list-matching-test-cases(
  $fotsPath as xs:string,
  $pattern  as xs:string,
  $flags    as xs:string?
) as xs:string* {
  let $doc := doc(resolve-uri($fotsPath)),
      $baseUri:= resolve-uri(util:parent-folder($fotsPath))
  return
    for $testSet in $doc/fots:catalog/fots:test-set
    let $uri := resolve-uri($testSet/@file, $baseUri),
        $testSetDoc := doc($uri)
      for $testCase in $testSetDoc//test-case
      where matches(util:get-value($testCase,
                                  util:parent-folder($uri),
                                  "test"),
                   $pattern,
                   $flags)
      return
        concat(resolve-uri($testSet/@file, $baseUri),
              ", test name:",
              data($testCase/@name))
};

declare %private function driver:list-assertions(
  $case as element(fots:test-case)
) as xs:string* {
  distinct-values(for $assert in $case/result/descendant-or-self::*
                  return local-name-from-QName(node-name($assert)))
};

(:~
 : Loops through the FOTS catalog and evaluates all test cases that have
 : a certain assert-type.
 : This is useful for testing the implementation of a certain assert type.
 : @param $FOTSCatalogFilePath path to the FOTS catalog file.
 : @param $FOTSZorbaManifestPath the path to the file that describes optional
 : features and implementation defined items in Zorba.
 : @param $testSetPrefixes name/criteria for the test sets (empty string
 : means all).
 : @param $testCasePrefixes name/criteria for the test cases (empty string
 : means all).
 : @param $exceptedTestCases lists of test cases that should not be run(empty
 : string means all tests will be run).
 : @param $exceptedTestSets lists of test sets that should not be run(empty
 : string means all tests will be run).
 : @param $assert lists of tests that contain a certain assert-type(empty
 : string means all tests will be run).
 : @param $verbose if set to TRUE it will also output the actual failures.
 : @param $showResult if set to TRUE it will also show the actual result of the
 : Query run.
 : @return an element containing all failed tests
 :)
declare %ann:sequential function driver:run-fots(
  $FOTSCatalogFilePath    as xs:string,
  $FOTSZorbaManifestPath  as xs:string,
  $testSetPrefixes        as xs:string*,
  $testCasePrefixes       as xs:string*,
  $exceptedTestCases      as xs:string*,
  $exceptedTestSets       as xs:string*,
  $assert                 as xs:string*,
  $verbose                as xs:boolean,
  $showResult             as xs:boolean
) as element(fots:test-cases) {
  try {
  let $FOTSCatalog := doc(trace(resolve-uri($FOTSCatalogFilePath),
                              "The path to FOTS catalog.xml was set to: ")),
      $FOTSZorbaManifest := doc(trace(resolve-uri($FOTSZorbaManifestPath),
                                    "The path to FOTSZorbaManifest was set to:"))
  return driver:run($FOTSCatalog,
                    resolve-uri(util:parent-folder($FOTSCatalogFilePath)),
                    $FOTSZorbaManifest,
                    $testSetPrefixes,
                    $testCasePrefixes,
                    $exceptedTestCases,
                    $exceptedTestSets,
                    trace($assert,          "The filter for 'assert name' was set to: "),
                    trace($verbose,         "'Verbose' parameter was set to: "),
                    $showResult)
  }
  catch * {
    error($err:code,
          concat("
Please make sure the passed 'fotsPath' points to the",
                 "exact location of the FOTS catalog.xml:
",
                 resolve-uri($FOTSCatalogFilePath),
                 "
and that the passed 'fotsZorbaManifestPath' points to",
                 "a file in the same folder as cli.xq:
",
                 resolve-uri($FOTSZorbaManifestPath)))
  }
};

(:~
 : Loops through the FOTS catalog and evaluates all test cases
 :
 : @param $FOTSCatalog the FOTS catalog.xml file.
 : @param $FOTSZorbaManifest the file that describes optional features and
 : implementation defined items in Zorba.
 : @param $testSetPrefixes name/criteria for the test sets (empty string means
 : all).
 : @param $testCasePrefixes name/criteria for the test cases (empty string
 : means all).
 : @param $exceptedTestCases lists of test cases that should not be run(empty
 : string means all tests will be run).
 : @param $exceptedTestSets lists of test sets that should not be run(empty
 : string means all tests will be run).
 : @param $assert lists of tests that contain a certain assert-type(empty
 : string means all tests will be run).
 : @param $verbose if set to TRUE it will also output the actual failures.
 : @param $showResult if set to TRUE it will also show the actual result of the
 : Query run.
 : @return an element containing all failed tests
 :)
declare %ann:sequential function driver:run(
  $FOTSCatalog        as document-node(),
  $catalogBaseURI     as xs:anyURI,
  $FOTSZorbaManifest  as document-node(),
  $testSetPrefixes    as xs:string*,
  $testCasePrefixes   as xs:string*,
  $exceptedTestCases  as xs:string*,
  $exceptedTestSets   as xs:string*,
  $assert             as xs:string*,
  $verbose            as xs:boolean,
  $showResult         as xs:boolean
) as element(fots:test-cases) {
    <test-cases>{
      let $catalogTestSetNames := $FOTSCatalog//fots:test-set/@name,
          $testSetNames :=  if ($testSetPrefixes = '')
                            then functx:value-except($catalogTestSetNames,
                                                     $exceptedTestSets)
                            else functx:value-except(
                                  functx:value-intersect($testSetPrefixes,
                                                         $catalogTestSetNames),
                                  $exceptedTestSets)
      for $testSetName in $testSetNames
      let $testSet := $FOTSCatalog//fots:test-set[@name=$testSetName],
          $testSetURI := resolve-uri($testSet/@file,
                                     $catalogBaseURI),
          $testSetDoc := doc($testSetURI),
          $depMet as xs:string*:= env:check-dependencies($testSetDoc/fots:test-set/fots:dependency,
                                                         $FOTSZorbaManifest)
      return
      if(exists($depMet))
      then <test-set name="{$testSetName}">
      {
        for $testCase in $testSetDoc/fots:test-set/fots:test-case
        let $envName := data($testCase/fots:environment/@ref),
            $envTestSet := $testSetDoc/fots:test-set/fots:environment[@name = $envName],
            $envCatalog := $FOTSCatalog/fots:catalog/fots:environment[@name = $envName],
            $shouldRun  := if ($testCasePrefixes = '')
                           then functx:value-except(xs:string(data($testCase/@name)),
                                                    $exceptedTestCases)
                           else functx:value-except(
                                  functx:value-intersect(data($testCase/@name),
                                                         $testCasePrefixes),
                                  $exceptedTestCases),
            (:true if the tests-case has an assertion type that is requested :)
            $hasReqAssert := (($assert = '') or
                              exists(functx:value-intersect(
                                      driver:list-assertions($testCase),
                                                             $assert)))
          where $shouldRun and $hasReqAssert
          return
            driver:not-applicable($testCase,
                                  $envTestSet,
                                  string-join($depMet,''),
                                  $verbose)
        }</test-set>
        else <test-set name="{$testSetName}">
        {
          for $testCase in $testSetDoc/fots:test-set/fots:test-case
          let $envName := data($testCase/fots:environment/@ref),
              $envTestSet := $testSetDoc/fots:test-set/fots:environment[@name = $envName],
              $envCatalog := $FOTSCatalog/fots:catalog/fots:environment[@name = $envName],
              $shouldRun  := if ($testCasePrefixes = '')
                             then functx:value-except(xs:string(data($testCase/@name)),
                                                      $exceptedTestCases)
                              else functx:value-except(
                                     functx:value-intersect(data($testCase/@name),
                                                            $testCasePrefixes),
                                     $exceptedTestCases),
            (:true if the tests-case has an assertion type that is requested :)
              $hasReqAssert := (($assert = '') or
                              exists(functx:value-intersect(driver:list-assertions($testCase),
                                                            $assert)))
          where $shouldRun and $hasReqAssert
          return
            if(exists(env:check-dependencies($testCase/fots:dependency,
                                             $FOTSZorbaManifest)))
            then driver:not-applicable( $testCase,
                                        $envTestSet,
                                        string-join(distinct-values(env:check-dependencies($testCase/fots:dependency,
                                                                                $FOTSZorbaManifest)),
                                                   ''),
                                        $verbose)
            else if(empty($envTestSet))
            then driver:test( $FOTSZorbaManifest,
                              $testCase,
                              $envCatalog,
                              $catalogBaseURI,
                              ($testCase/fots:dependency,
                               $testSetDoc/fots:test-set/fots:dependency),
                              $testSetName,
                              $testSetURI,
                              $verbose,
                              $showResult)
            else driver:test( $FOTSZorbaManifest,
                              $testCase,
                              $envTestSet,
                              $testSetURI,
                              ($testCase/fots:dependency,
                               $testSetDoc/fots:test-set/fots:dependency),
                              $testSetName,
                              $testSetURI,
                              $verbose,
                              $showResult)
        }</test-set>
    }</test-cases>
};

(:~
 : Creates the complete query that will be evaluated by adding the necessary
 : XQXQ URL resolvers.
 : @param $queryText the test-case/test after all the additional prolog
 : statements were added.
 : @param $case the test case.
 : @param $env the environment.
 : @param $envBaseURI URI of the environment.
 : @param $testSetBaseURI URI of the test set that defines the test case.
 : @return the query that will be evaluated.
 :)
declare %private function driver:create-XQXQ-query(
  $queryText      as xs:string,
  $case           as element(fots:test-case),
  $env            as element(fots:environment)?,
  $envBaseURI     as xs:anyURI?,
  $testSetBaseURI as xs:anyURI
) as xs:string {
  let $resolver as xs:string? := env:resolver($case,
                                              $env,
                                              $envBaseURI,
                                              $testSetBaseURI)
  return string-join(
  ("import module namespace xqxq = 'http://www.zorba-xquery.com/modules/xqxq';",
  if (exists($resolver))
  then $resolver
  else (),
  (concat("variable $queryID := xqxq:prepare-main-module('",
          "
",
          replace($queryText,"'","''"),
          "'",
          "
",
          if (exists($resolver))
          then ", resolver:url-resolver#2, ());"
          else ");")),
          env:set-context-item($env, $envBaseURI),
          env:set-context-item($case/fots:environment,
                               $testSetBaseURI),
          env:set-variables($env,
                            $envBaseURI),
          env:set-variables($case/environment,
                            $testSetBaseURI),
          "xqxq:evaluate($queryID)"
   ),
  "
")
};

(:~
 : XQXQ invoke.
 : @param $xqxqQueryText the query that will be run.
 : @param $case the test case.
 : @return the result of running the query with XQXQ.
 :)
declare %private %ann:sequential function driver:xqxq-invoke(
  $xqxqQueryText  as xs:string,
  $case           as element(fots:test-case),
  $showResult     as xs:boolean?,
  $testSetBaseURI as xs:anyURI
) {
  try {
    {
      variable $queryKey := xqxq:prepare-main-module($xqxqQueryText);
      variable $queryResult := xqxq:evaluate-sequential($queryKey);
      (:TODO check if this works:)
      (:variable $expResult := util:get-value($case, $testSetBaseURI, "result");:)
      eval:result($queryResult,
                  $case/fots:result/*,
                  $showResult)
    }
  } catch * {
    eval:error((),
               $case/fots:result/*,
               $err:code,
               $err:description,
               $showResult)
  }
};

(:~
 : Runs a single test case.
 :
 : @param $FOTSZorbaManifest the file that describes optional features and
 : implementation defined items in Zorba.
 : @param $case test case.
 : @param $env the environment.
 : @param $envBaseURI the relative URI used to calculate the full URI for the
 : different children of the environment that have a "file" attribute.
 : @param $deps the dependencies that should be checked for given test case.
 : @param $testSetName the name of the test set.
 : @param $testSetBaseURI the URI of the test set.
 : @param $verbose xs:boolean indicating if a result should be returned in case
 : of success or not.
 : @return the result of running the test case depending on $verbose.
 :)
declare %ann:sequential function driver:test(
  $FOTSZorbaManifest  as document-node(),
  $case               as element(fots:test-case),
  $env                as element(fots:environment)?,
  $envBaseURI         as xs:anyURI?,
  $deps               as element(fots:dependency)*,
  $testSetName        as xs:string?,
  $testSetBaseURI     as xs:anyURI,
  $verbose            as xs:boolean,
  $showResult         as xs:boolean?
) as element(fots:test-case)? {
(:TODO Cover the "(:%VARDECL%:)"when there are tests in FOTS that use it:)
try {
{
  variable $queryName := trace(data($case/@name),
                              "processing test case :");

  variable $test := util:get-value($case,
                                   $testSetBaseURI,
                                   "test");
  variable $enableHOF := env:enable-HOF-feature(($deps, $case//fots:dependency),
                                                $test);
  variable $query := string-join((env:add-xquery-30(($deps, $case//fots:dependency),
                                                   $test),
                                  env:decl-def-elem-namespace($env,
                                                              $case/fots:environment),
                                  env:decl-base-uri($env,
                                                    $case/fots:environment),
                                  env:decl-namespaces($env,
                                                      $case,
                                                      $testSetBaseURI),
                                  $enableHOF,
                                  env:decl-decimal-formats(($env/fots:decimal-format,
                                                           $case/fots:environment/fots:decimal-format)),
                                  env:add-var-decl($env,
                                                   $case),
                                  $test
                                  ),"
"),
           $xqxqQuery := driver:create-XQXQ-query($query,
                                                  $case,
                                                  $env,
                                                  $envBaseURI,
                                                  $testSetBaseURI),
           $startDateTime := datetime:current-dateTime (),
           $result := driver:xqxq-invoke($xqxqQuery,
                                         $case,
                                         $showResult,
                                         $testSetBaseURI),
           $duration := (datetime:current-dateTime () - $startDateTime);

           if(empty($result))
           then driver:pass($case,
                            $result,
                            $xqxqQuery,
                            $env,
                            (),
                            $duration,
                            $verbose)

(: if the exact error code was not found, report the test as 'Pass'
   with an attribute correctError=false :)
           else if(exists($result) and
                   contains(string-join($result,''), "Expected error:") and
                   contains(string-join($result,''), "Found error:"))
           then driver:pass($case,
                            $result,
                            $xqxqQuery,
                            $env,
                            $result,
                            $duration,
                            $verbose)
           else
             driver:fail($case,
                         $result,
                         $xqxqQuery,
                         $testSetName,
                         $env,
                         $duration,
                         $verbose)
}
} catch * {
  driver:fail($case,
              <result>{$err:description}</result>,
              "",
              $testSetName,
              $env,
              xs:dayTimeDuration("PT0S"),
              $verbose)
}
};

(:~
 : Gives feedback on a test case that is not run when dependencies are not met.
 :
 : @param $case test case.
 : @param $dependencyError test error returned by the dependency checking.
 : @return the test case.
 :)
declare  %private %ann:sequential function driver:not-applicable(
  $case             as element(fots:test-case),
  $env              as element(fots:environment)?,
  $dependencyError  as xs:string,
  $verbose          as xs:boolean
) as element(fots:test-case)? {
  trace(data($case/@name), "processing test case :");
  trace($dependencyError, "Dependency error :");
  if($verbose)
  then
  {
    let $tmp := $case
    return {
      insert node
      attribute result{'not applicable'}
      as last into $tmp;

      insert node
      attribute comment{$dependencyError}
      as last into $tmp;

      insert node
        <info>
          { $env }
        </info>
      as last into $tmp;

      delete node $tmp/description;
      delete node $tmp/created;

      $tmp
      }
  }
  else
    <test-case  name="{data($case/@name)}"
                result="not applicable"
                comment="{$dependencyError}" />
};

(:~
 : Gives feedback on a test case run with success.
 :
 : @param $case test case.
 : @return the test case after certain information was added.
 :)
declare  %private %ann:sequential function driver:pass(
  $case         as element(fots:test-case),
  $result       as item()*,
  $zorbaQuery   as xs:string,
  $env          as element(fots:environment)?,
  $comment      as xs:string?,
  $duration     as xs:dayTimeDuration,
  $verbose      as xs:boolean
) as element(fots:test-case)? {
  if($verbose)
  then
  {
    let $tmp := $case
    return {
      insert node
      attribute result{'pass'}
      as last into $tmp;

      if(exists($comment)) then
        insert node
        attribute correctError{'false'}
        as last into $tmp;
      else ();

      if(exists($comment)) then
        insert node
        attribute comment{$comment}
        as last into $tmp;
      else ();

      insert node
      attribute executionTime{$duration}
      as last into $tmp;

      insert node
        <info>
          { $env }
          <query>{ $zorbaQuery }</query>
          {$result}
        </info>
      as last into $tmp;

      delete node $tmp/description;
      delete node $tmp/created;

      $tmp
    }
  }
  else if(empty($comment))
  then <test-case name="{data($case/@name)}"
                  result="pass"
                  executionTime="{$duration}" />
  else <test-case name="{data($case/@name)}"
                  result="pass"
                  correctError="{empty($comment)}"
                  executionTime="{$duration}" />
};

(:~
 : Gives feedback on a test case run without success.
 :
 : @param $case test case.
 : @return the test case after certain information was added.
 :)
declare %private %ann:sequential function driver:fail(
  $case         as element(fots:test-case),
  $result       as item()*,
  $zorbaQuery   as xs:string,
  $testSetName  as xs:string?,
  $env          as element(fots:environment)?,
  $duration     as xs:dayTimeDuration,
  $verbose      as xs:boolean
) as element(fots:test-case)? {
  trace($testSetName, "test set name");
  trace("above test case failed", "result");

  if($verbose)
  then
  {
    let $tmp := $case
    return {
      insert node
      attribute result{'fail'}
      as last into $tmp;

      insert node
      attribute executionTime{$duration}
      as last into $tmp;

      insert node
        <info>
          { $env }
          <query>{ $zorbaQuery }</query>
          {$result}
        </info>
      as last into $tmp;

      delete node $tmp/description;
      delete node $tmp/created;

      $tmp
    }
  }
  else <test-case name="{data($case/@name)}"
                  result="fail"
                  executionTime="{$duration}"/>
};

(:
 : Copyright 2006-2011 The FLWOR 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.
 :)

(:~
 : Zorba FOTS driver
 : @author Sorin Nasoi
 :)

module namespace driver =
  "http://www.zorba-xquery.com/fots-driver";

import module namespace functx =
  "http://www.functx.com/";

import module namespace xqxq =
  "http://www.zorba-xquery.com/modules/xqxq";
import module namespace datetime  =
  "http://www.zorba-xquery.com/modules/datetime";

import module namespace eval =
  "http://www.zorba-xquery.com/fots-driver/evaluate" at "evaluate.xq";
import module namespace env =
  "http://www.zorba-xquery.com/fots-driver/environment" at "environment.xq";
import module namespace util =
  "http://www.zorba-xquery.com/fots-driver/util" at "util.xq";
import module namespace fots-err =
  "http://www.zorba-xquery.com/fots-driver/errors" at "errors.xq";

declare default element namespace "http://www.w3.org/2010/09/qt-fots-catalog";

declare namespace err =
  "http://www.w3.org/2005/xqt-errors";
declare namespace fots =
  "http://www.w3.org/2010/09/qt-fots-catalog";

declare namespace ann =
  "http://www.zorba-xquery.com/annotations";

(:~
 : Loops through the FOTS catalog and returns all available test set names.
 : @param $fotsPath path to the FOTS catalog file.
 : @param $testSetPrefixes name/criteria for the test sets
 : (empty string means all).
 : @return available FOTS test sets.
 :)
declare %ann:nondeterministic function driver:list-test-sets(
  $fotsPath         as xs:string,
  $testSetPrefixes  as xs:string*
) as xs:string* {
  let $doc := doc(resolve-uri($fotsPath))
  return
    if(string-join($testSetPrefixes,'') = '')
    then
      for $testSet in $doc/fots:catalog/fots:test-set
      return data($testSet/@name)
    else
      for $prefix in $testSetPrefixes
        for $testSet in $doc/fots:catalog/fots:test-set[starts-with(@name, $prefix)]
        return data($testSet/@name)
};

(:~
 : Loops through the given test sets and returns the corresponding test cases.
 : @param $fotsPath path to the FOTS catalog file.
 : @param $testSetPrefixes name/criteria for the test sets
 : (empty string means all).
 : @return available FOTS test cases.
 :)
declare %ann:nondeterministic function driver:list-test-cases(
  $fotsPath         as xs:string,
  $testSetPrefixes  as xs:string*
) as xs:string* {
  let $doc := doc(resolve-uri($fotsPath)),
      $baseUri:= resolve-uri(util:parent-folder($fotsPath))
  return
    if(string-join($testSetPrefixes,'') = '')
    then
      for $testSet in $doc/fots:catalog/fots:test-set
      let $testSetDoc := doc(resolve-uri($testSet/@file, $baseUri))
      return data($testSetDoc//fots:test-case/@name)
    else
      for $prefix in $testSetPrefixes
        for $testSet in $doc/fots:catalog/fots:test-set[starts-with(@name, $prefix)]
        let $testSetDoc := doc(resolve-uri($testSet/@file, $baseUri))
        return data($testSetDoc//fots:test-case/@name)
};

(:~
 : Loops through all the test cases and returns those that have a 'test' node
 : that matches given pattern using given flags.
 : @param $fotsPath 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 driver:list-matching-test-cases(
  $fotsPath as xs:string,
  $pattern  as xs:string,
  $flags    as xs:string?
) as xs:string* {
  let $doc := doc(resolve-uri($fotsPath)),
      $baseUri:= resolve-uri(util:parent-folder($fotsPath))
  return
    for $testSet in $doc/fots:catalog/fots:test-set
    let $uri := resolve-uri($testSet/@file, $baseUri),
        $testSetDoc := doc($uri)
      for $testCase in $testSetDoc//test-case
      where matches(util:get-value($testCase,
                                  util:parent-folder($uri),
                                  "test"),
                   $pattern,
                   $flags)
      return
        concat(resolve-uri($testSet/@file, $baseUri),
              ", test name:",
              data($testCase/@name))
};

declare %private function driver:list-assertions(
  $case as element(fots:test-case)
) as xs:string* {
  distinct-values(for $assert in $case/result/descendant-or-self::*
                  return local-name-from-QName(node-name($assert)))
};

(:~
 : Loops through the FOTS catalog and evaluates all test cases that have
 : a certain assert-type.
 : This is useful for testing the implementation of a certain assert type.
 : @param $FOTSCatalogFilePath path to the FOTS catalog file.
 : @param $FOTSZorbaManifestPath the path to the file that describes optional
 : features and implementation defined items in Zorba.
 : @param $testSetPrefixes name/criteria for the test sets (empty string
 : means all).
 : @param $testCasePrefixes name/criteria for the test cases (empty string
 : means all).
 : @param $exceptedTestCases lists of test cases that should not be run(empty
 : string means all tests will be run).
 : @param $exceptedTestSets lists of test sets that should not be run(empty
 : string means all tests will be run).
 : @param $assert lists of tests that contain a certain assert-type(empty
 : string means all tests will be run).
 : @param $verbose if set to TRUE it will also output the actual failures.
 : @param $showResult if set to TRUE it will also show the actual result of the
 : Query run.
 : @return an element containing all failed tests
 :)
declare %ann:sequential function driver:run-fots(
  $FOTSCatalogFilePath    as xs:string,
  $FOTSZorbaManifestPath  as xs:string,
  $testSetPrefixes        as xs:string*,
  $testCasePrefixes       as xs:string*,
  $exceptedTestCases      as xs:string*,
  $exceptedTestSets       as xs:string*,
  $assert                 as xs:string*,
  $verbose                as xs:boolean,
  $showResult             as xs:boolean
) as element(fots:test-cases) {
  try {
  let $FOTSCatalog := doc(trace(resolve-uri($FOTSCatalogFilePath),
                              "The path to FOTS catalog.xml was set to: ")),
      $FOTSZorbaManifest := doc(trace(resolve-uri($FOTSZorbaManifestPath),
                                    "The path to FOTSZorbaManifest was set to:"))
  return driver:run($FOTSCatalog,
                    resolve-uri(util:parent-folder($FOTSCatalogFilePath)),
                    $FOTSZorbaManifest,
                    $testSetPrefixes,
                    $testCasePrefixes,
                    $exceptedTestCases,
                    $exceptedTestSets,
                    trace($assert,          "The filter for 'assert name' was set to: "),
                    trace($verbose,         "'Verbose' parameter was set to: "),
                    $showResult)
  }
  catch * {
    error($err:code,
          concat("
Please make sure the passed 'fotsPath' points to the",
                 "exact location of the FOTS catalog.xml:
",
                 resolve-uri($FOTSCatalogFilePath),
                 "
and that the passed 'fotsZorbaManifestPath' points to",
                 "a file in the same folder as cli.xq:
",
                 resolve-uri($FOTSZorbaManifestPath)))
  }
};

(:~
 : Loops through the FOTS catalog and evaluates all test cases
 :
 : @param $FOTSCatalog the FOTS catalog.xml file.
 : @param $FOTSZorbaManifest the file that describes optional features and
 : implementation defined items in Zorba.
 : @param $testSetPrefixes name/criteria for the test sets (empty string means
 : all).
 : @param $testCasePrefixes name/criteria for the test cases (empty string
 : means all).
 : @param $exceptedTestCases lists of test cases that should not be run(empty
 : string means all tests will be run).
 : @param $exceptedTestSets lists of test sets that should not be run(empty
 : string means all tests will be run).
 : @param $assert lists of tests that contain a certain assert-type(empty
 : string means all tests will be run).
 : @param $verbose if set to TRUE it will also output the actual failures.
 : @param $showResult if set to TRUE it will also show the actual result of the
 : Query run.
 : @return an element containing all failed tests
 :)
declare %ann:sequential function driver:run(
  $FOTSCatalog        as document-node(),
  $catalogBaseURI     as xs:anyURI,
  $FOTSZorbaManifest  as document-node(),
  $testSetPrefixes    as xs:string*,
  $testCasePrefixes   as xs:string*,
  $exceptedTestCases  as xs:string*,
  $exceptedTestSets   as xs:string*,
  $assert             as xs:string*,
  $verbose            as xs:boolean,
  $showResult         as xs:boolean
) as element(fots:test-cases) {
    <test-cases>{
      let $catalogTestSetNames := $FOTSCatalog//fots:test-set/@name,
          $testSetNames :=  if ($testSetPrefixes = '')
                            then functx:value-except($catalogTestSetNames,
                                                     $exceptedTestSets)
                            else functx:value-except(
                                  functx:value-intersect($testSetPrefixes,
                                                         $catalogTestSetNames),
                                  $exceptedTestSets)
      for $testSetName in $testSetNames
      let $testSet := $FOTSCatalog//fots:test-set[@name=$testSetName],
          $testSetURI := resolve-uri($testSet/@file,
                                     $catalogBaseURI),
          $testSetDoc := doc($testSetURI),
          $depMet as xs:string*:= env:check-dependencies($testSetDoc/fots:test-set/fots:dependency,
                                                         $FOTSZorbaManifest)
      return
      if(exists($depMet))
      then <test-set name="{$testSetName}">
      {
        for $testCase in $testSetDoc/fots:test-set/fots:test-case
        let $envName := data($testCase/fots:environment/@ref),
            $envTestSet := $testSetDoc/fots:test-set/fots:environment[@name = $envName],
            $envCatalog := $FOTSCatalog/fots:catalog/fots:environment[@name = $envName],
            $shouldRun  := if ($testCasePrefixes = '')
                           then functx:value-except(xs:string(data($testCase/@name)),
                                                    $exceptedTestCases)
                           else functx:value-except(
                                  functx:value-intersect(data($testCase/@name),
                                                         $testCasePrefixes),
                                  $exceptedTestCases),
            (:true if the tests-case has an assertion type that is requested :)
            $hasReqAssert := (($assert = '') or
                              exists(functx:value-intersect(
                                      driver:list-assertions($testCase),
                                                             $assert)))
          where $shouldRun and $hasReqAssert
          return
            driver:not-applicable($testCase,
                                  $envTestSet,
                                  string-join($depMet,''),
                                  $verbose)
        }</test-set>
        else <test-set name="{$testSetName}">
        {
          for $testCase in $testSetDoc/fots:test-set/fots:test-case
          let $envName := data($testCase/fots:environment/@ref),
              $envTestSet := $testSetDoc/fots:test-set/fots:environment[@name = $envName],
              $envCatalog := $FOTSCatalog/fots:catalog/fots:environment[@name = $envName],
              $shouldRun  := if ($testCasePrefixes = '')
                             then functx:value-except(xs:string(data($testCase/@name)),
                                                      $exceptedTestCases)
                              else functx:value-except(
                                     functx:value-intersect(data($testCase/@name),
                                                            $testCasePrefixes),
                                     $exceptedTestCases),
            (:true if the tests-case has an assertion type that is requested :)
              $hasReqAssert := (($assert = '') or
                              exists(functx:value-intersect(driver:list-assertions($testCase),
                                                            $assert)))
          where $shouldRun and $hasReqAssert
          return
            if(exists(env:check-dependencies($testCase/fots:dependency,
                                             $FOTSZorbaManifest)))
            then driver:not-applicable( $testCase,
                                        $envTestSet,
                                        string-join(distinct-values(env:check-dependencies($testCase/fots:dependency,
                                                                                $FOTSZorbaManifest)),
                                                   ''),
                                        $verbose)
            else if(empty($envTestSet))
            then driver:test( $FOTSZorbaManifest,
                              $testCase,
                              $envCatalog,
                              $catalogBaseURI,
                              ($testCase/fots:dependency,
                               $testSetDoc/fots:test-set/fots:dependency),
                              $testSetName,
                              $testSetURI,
                              $verbose,
                              $showResult)
            else driver:test( $FOTSZorbaManifest,
                              $testCase,
                              $envTestSet,
                              $testSetURI,
                              ($testCase/fots:dependency,
                               $testSetDoc/fots:test-set/fots:dependency),
                              $testSetName,
                              $testSetURI,
                              $verbose,
                              $showResult)
        }</test-set>
    }</test-cases>
};

(:~
 : Creates the complete query that will be evaluated by adding the necessary
 : XQXQ URL resolvers.
 : @param $queryText the test-case/test after all the additional prolog
 : statements were added.
 : @param $case the test case.
 : @param $env the environment.
 : @param $envBaseURI URI of the environment.
 : @param $testSetBaseURI URI of the test set that defines the test case.
 : @return the query that will be evaluated.
 :)
declare %private function driver:create-XQXQ-query(
  $queryText      as xs:string,
  $case           as element(fots:test-case),
  $env            as element(fots:environment)?,
  $envBaseURI     as xs:anyURI?,
  $testSetBaseURI as xs:anyURI
) as xs:string {
  let $resolver as xs:string? := env:resolver($case,
                                              $env,
                                              $envBaseURI,
                                              $testSetBaseURI)
  return string-join(
  ("import module namespace xqxq = 'http://www.zorba-xquery.com/modules/xqxq';",
  if (exists($resolver))
  then $resolver
  else (),
  (concat("variable $queryID := xqxq:prepare-main-module('",
          "
",
          replace($queryText,"'","''"),
          "'",
          "
",
          if (exists($resolver))
          then ", resolver:url-resolver#2, ());"
          else ");")),
          env:set-context-item($env, $envBaseURI),
          env:set-context-item($case/fots:environment,
                               $testSetBaseURI),
          env:set-variables($env,
                            $envBaseURI),
          env:set-variables($case/environment,
                            $testSetBaseURI),
          "xqxq:evaluate($queryID)"
   ),
  "
")
};

(:~
 : XQXQ invoke.
 : @param $xqxqQueryText the query that will be run.
 : @param $case the test case.
 : @return the result of running the query with XQXQ.
 :)
declare %private %ann:sequential function driver:xqxq-invoke(
  $xqxqQueryText  as xs:string,
  $case           as element(fots:test-case),
  $showResult     as xs:boolean?,
  $testSetBaseURI as xs:anyURI
) {
  try {
    {
      variable $queryKey := xqxq:prepare-main-module($xqxqQueryText);
      variable $queryResult := xqxq:evaluate-sequential($queryKey);
      (:TODO check if this works:)
      (:variable $expResult := util:get-value($case, $testSetBaseURI, "result");:)
      eval:result($queryResult,
                  $case/fots:result/*,
                  $showResult)
    }
  } catch * {
    eval:error((),
               $case/fots:result/*,
               $err:code,
               $err:description,
               $showResult)
  }
};

(:~
 : Runs a single test case.
 :
 : @param $FOTSZorbaManifest the file that describes optional features and
 : implementation defined items in Zorba.
 : @param $case test case.
 : @param $env the environment.
 : @param $envBaseURI the relative URI used to calculate the full URI for the
 : different children of the environment that have a "file" attribute.
 : @param $deps the dependencies that should be checked for given test case.
 : @param $testSetName the name of the test set.
 : @param $testSetBaseURI the URI of the test set.
 : @param $verbose xs:boolean indicating if a result should be returned in case
 : of success or not.
 : @return the result of running the test case depending on $verbose.
 :)
declare %ann:sequential function driver:test(
  $FOTSZorbaManifest  as document-node(),
  $case               as element(fots:test-case),
  $env                as element(fots:environment)?,
  $envBaseURI         as xs:anyURI?,
  $deps               as element(fots:dependency)*,
  $testSetName        as xs:string?,
  $testSetBaseURI     as xs:anyURI,
  $verbose            as xs:boolean,
  $showResult         as xs:boolean?
) as element(fots:test-case)? {
(:TODO Cover the "(:%VARDECL%:)"when there are tests in FOTS that use it:)
try {
{
  variable $queryName := trace(data($case/@name),
                              "processing test case :"),
           $depMet := env:check-dependencies($deps,
                                             $FOTSZorbaManifest);

  if(exists($depMet))
  then driver:not-applicable($case,
                             $env,
                             string-join($depMet,''),
                             $verbose)
  else
  {
   variable $test := util:get-value($case,
                                    $testSetBaseURI,
                                    "test");
   variable $enableHOF := env:enable-HOF-feature(($deps, $case//fots:dependency),
                                                 $test);
   variable $query := string-join((env:add-xquery-30(($deps, $case//fots:dependency),
                                                    $test),
                                   env:decl-def-elem-namespace($env,
                                                               $case/fots:environment),
                                   env:decl-base-uri($env,
                                                     $case/fots:environment),
                                   env:decl-namespaces($env,
                                                       $case,
                                                       $testSetBaseURI),
                                   $enableHOF,
                                   env:decl-decimal-formats(($env/fots:decimal-format,
                                                            $case/fots:environment/fots:decimal-format)),
                                   env:add-var-decl($env,
                                                    $case),
                                   $test
                                   ),"
"),
            $xqxqQuery := driver:create-XQXQ-query($query,
                                                   $case,
                                                   $env,
                                                   $envBaseURI,
                                                   $testSetBaseURI),
            $startDateTime := datetime:current-dateTime (),
            $result := driver:xqxq-invoke($xqxqQuery,
                                          $case,
                                          $showResult,
                                          $testSetBaseURI),
            $duration := (datetime:current-dateTime () - $startDateTime);

            if(empty($result))
            then driver:pass($case,
                             $result,
                             $xqxqQuery,
                             $env,
                             (),
                             $duration,
                             $verbose)

(: if the exact error code was not found, report the test as 'Pass'
   with an attribute correctError=false :)
            else if(exists($result) and
                    contains(string-join($result,''), "Expected error:") and
                    contains(string-join($result,''), "Found error:"))
            then driver:pass($case,
                             $result,
                             $xqxqQuery,
                             $env,
                             $result,
                             $duration,
                             $verbose)
            else
              driver:fail($case,
                          $result,
                          $xqxqQuery,
                          $testSetName,
                          $env,
                          $duration,
                          $verbose)
  }
}
} catch * {
  driver:fail($case,
              <result>{$err:description}</result>,
              "",
              $testSetName,
              $env,
              xs:dayTimeDuration("PT0S"),
              $verbose)
}
};

(:~
 : Gives feedback on a test case that is not run when dependencies are not met.
 :
 : @param $case test case.
 : @param $dependencyError test error returned by the dependency checking.
 : @return the test case.
 :)
declare  %private %ann:sequential function driver:not-applicable(
  $case             as element(fots:test-case),
  $env              as element(fots:environment)?,
  $dependencyError  as xs:string,
  $verbose          as xs:boolean
) as element(fots:test-case)? {
  trace(data($case/@name), "processing test case :");
  trace($dependencyError, "Dependency error :");
  if($verbose)
  then
  {
    let $tmp := $case
    return {
      insert node
      attribute result{'not applicable'}
      as last into $tmp;

      insert node
      attribute comment{$dependencyError}
      as last into $tmp;

      insert node
        <info>
          { $env }
        </info>
      as last into $tmp;

      delete node $tmp/description;
      delete node $tmp/created;

      $tmp
      }
  }
  else
    <test-case  name="{data($case/@name)}"
                result="not applicable"
                comment="{$dependencyError}" />
};

(:~
 : Gives feedback on a test case run with success.
 :
 : @param $case test case.
 : @return the test case after certain information was added.
 :)
declare  %private %ann:sequential function driver:pass(
  $case         as element(fots:test-case),
  $result       as item()*,
  $zorbaQuery   as xs:string,
  $env          as element(fots:environment)?,
  $comment      as xs:string?,
  $duration     as xs:dayTimeDuration,
  $verbose      as xs:boolean
) as element(fots:test-case)? {
  if($verbose)
  then
  {
    let $tmp := $case
    return {
      insert node
      attribute result{'pass'}
      as last into $tmp;

      if(exists($comment)) then
        insert node
        attribute correctError{'false'}
        as last into $tmp;
      else ();

      if(exists($comment)) then
        insert node
        attribute comment{$comment}
        as last into $tmp;
      else ();

      insert node
      attribute executionTime{$duration}
      as last into $tmp;

      insert node
        <info>
          { $env }
          <query>{ $zorbaQuery }</query>
          {$result}
        </info>
      as last into $tmp;

      delete node $tmp/description;
      delete node $tmp/created;

      $tmp
    }
  }
  else if(empty($comment))
  then <test-case name="{data($case/@name)}"
                  result="pass"
                  executionTime="{$duration}" />
  else <test-case name="{data($case/@name)}"
                  result="pass"
                  correctError="{empty($comment)}"
                  executionTime="{$duration}" />
};

(:~
 : Gives feedback on a test case run without success.
 :
 : @param $case test case.
 : @return the test case after certain information was added.
 :)
declare %private %ann:sequential function driver:fail(
  $case         as element(fots:test-case),
  $result       as item()*,
  $zorbaQuery   as xs:string,
  $testSetName  as xs:string?,
  $env          as element(fots:environment)?,
  $duration     as xs:dayTimeDuration,
  $verbose      as xs:boolean
) as element(fots:test-case)? {
  trace($testSetName, "test set name");
  trace("above test case failed", "result");

  if($verbose)
  then
  {
    let $tmp := $case
    return {
      insert node
      attribute result{'fail'}
      as last into $tmp;

      insert node
      attribute executionTime{$duration}
      as last into $tmp;

      insert node
        <info>
          { $env }
          <query>{ $zorbaQuery }</query>
          {$result}
        </info>
      as last into $tmp;

      delete node $tmp/description;
      delete node $tmp/created;

      $tmp
    }
  }
  else <test-case name="{data($case/@name)}"
                  result="fail"
                  executionTime="{$duration}"/>
};


Clean up some tests

Clean up some tests

xquery version "3.1";

(:~
 : Tests for namespace functions.
 :)
module namespace test = 'http://xokomola.com/xquery/origami/tests';

import module namespace o = 'http://xokomola.com/xquery/origami'
    at '../origami.xqm';

declare %unit:test function test:ns-map()
{
    let $ns := o:ns-map()
    return
        unit:assert-equals($ns?html,'http://www.w3.org/1999/xhtml',
            "XHTML namespace is in default namespace map"
        ),

    let $ns := o:ns-map()
    return
        unit:assert-equals($ns?x,(),
            "X namespace is not in default namespace map"
        ),

    let $ns := o:ns-map(map { 'x': 'foobar' })
    return
        unit:assert-equals($ns?x,'foobar',
            "X namespace is in the namespace map"
        ),

    let $ns := o:ns-map(map { 'html': 'foobar' })
    return
        unit:assert-equals($ns?html,'foobar',
            "XHTML is mapped to foobar"
        )
};

(:~
 : A document is _normal_ (or _in namespace-normal form_) if all
 : namespace declarations appear on the root element and it is
 : not psychotic.  (A borderline document with all namespace
 : declarations in the same place is automatically psychotic;
 : a neurotic document with this property would be illegal according
 : to the Namespaces REC.)
 :)
declare variable $test:normal :=
    <foo xmlns="foo" xmlns:x="bar"><x:bar foo="bar"/></foo>;

(:~
 : It's not always possible to produce normal documents -- the producer
 : might not know all of the relevant namespaces at the time it emits
 : the root element start-tag -- so a weaker definition is useful:
 : A document is _sane_ if it is neither neurotic nor borderline.
 :)
declare variable $test:sane :=
    <foo xmlns="foo"><x:bar xmlns:x="bar" foo="bar"/></foo>;

(:~
 : Let's say that an XML document is _neurotic_ if it maps the same
 : namespace prefix to two different namespace URIs at different
 : points.  Neurosis makes it necessary for XML processors to
 : work with {URI+localname} pairs instead of GIs, and to keep
 : track of the namespace environment at each point in the tree
 : if there are QNames-in-content.  If it weren't for neurosis,
 : applications could use a single namespace map that applied to
 : the entire document.
 :)
declare variable $test:neurotic :=
    <x:foo xmlns:x="foo">
        <x:bar xmlns:x="bar"/>
    </x:foo>;

(:~
 : Conversely, a document is _borderline_ if it maps two different
 : namespace prefixes to the same namespace URI.  Borderline documents
 : complicate reserialization: the choice of which prefix to
 : use for a particular {URI+localname} pair depends on its
 : position in the tree.
 :)
declare variable $test:borderline :=
    <x:foo xmlns:x="foo">
        <y:bar xmlns:y="foo"/>
    </x:foo>;

(:~
 : A document is _psychotic_ if it maps two different namespace prefixes
 : to the same URI _in the same scope_.  Psychosis presents an even
 : bigger difficulty for reserialization: now applications must keep
 : track of the original prefix as well as the {URI+localname} pair.
 :)
declare variable $test:psychotic :=
    <x:foo xmlns:x="foo" xmlns:y="foo" y:bar="bar"/>;

(:~
 : This document suffers from multiple disorders.
 :)
declare variable $test:psychotic-borderline-neurotic :=
    <x:foo xmlns:x="foo" xmlns:y="foo" y:bar="bar">
        <x:foo xmlns:y="bar" xmlns:z="foo" z:foo="bar"/>
    </x:foo>;

(:~
 : This document redefines default namespace on child nodes.
 : A sane approach probably only returns the namespace from
 : the highest node.
 :)
declare variable $test:remap-default-ns :=
  <foo xmlns="foo">
    <bar xmlns="bar"/>
  </foo>;

declare %unit:test function test:remap-default-ns()
{
    unit:assert-equals(
        o:ns-map($test:remap-default-ns),
        map { '': 'foo' },
        "A weird XML document."
    )
};

declare %unit:test function test:normal-xml()
{
    unit:assert-equals(
        o:ns-map($test:sane),
        map { '': 'foo', 'x': 'bar' },
        "A sane XML document."
    )
};

declare %unit:test function test:sane-xml()
{
    unit:assert-equals(
        o:ns-map($test:sane),
        map { '': 'foo', 'x': 'bar' },
        "A sane XML document."
    )
};

declare %unit:test function test:insane-xml()
{
    unit:assert-equals(
        o:ns-map($test:neurotic),
        map { 'x': 'foo' },
        "A neurotic XML maps the same namespace prefix to two different
         namespace URIs at different points."
    ),

    unit:assert-equals(
        o:ns-map($test:borderline),
        map { 'x': 'foo', 'y': 'foo' },
        "A borderline XML maps two different namespace prefixes to the same
         namespace URI."
    ),

    unit:assert-equals(
        o:ns-map($test:psychotic),
        map { 'x': 'foo', 'y': 'foo' },
        "A psychotic XML maps two different URIs to the same prefix."
    ),

    unit:assert-equals(
        o:ns-map($test:psychotic-borderline-neurotic),
        map { 'x': 'foo', 'y': 'foo', 'z': 'foo' },
        "A mixture of insanity."
    )
};

declare %unit:test function test:ns-builder()
{
    let $xf := o:ns-builder(o:ns-map())
    return
        unit:assert-equals(
            $xf?ns?html,
            'http://www.w3.org/1999/xhtml',
            "Transformer has XHTML namespace URI"
        ),

    let $xf := o:ns-builder($test:sane)
    return
        unit:assert-equals(
            $xf?ns,
            map { '': 'foo', 'x': 'bar' },
            "Transformer has sane XML namespace map"
        ),

    let $xf := o:ns-builder(o:ns-builder(), map:merge((o:ns-map(), o:ns-map($test:sane))))
    return (
        unit:assert-equals(
            $xf?ns?html,
            'http://www.w3.org/1999/xhtml',
            "Transformer is composed of default namespaces and XML namespaces"
        ),
        unit:assert-equals(
            $xf?ns?x,
            'bar',
            "Transformer has bar namespace"
        ),
        unit:assert-equals(
            $xf?ns(''),
            'foo',
            "Transformer has foo namespace"
        )
    )
};

declare %unit:test function test:default-ns()
{
    unit:assert-equals(
        o:default-ns(map {}, 'foo')(''),
        'foo',
        "Default namespace foo"
    ),

    unit:assert-equals(
        o:default-ns(o:ns-map(), 'bar')(''),
        'bar',
        "Default namespace foo"
    )
};

declare %unit:test function test:default-namespace()
{
    let $xml := o:xml(['p'])
    return
        unit:assert-equals(namespace-uri($xml), '')
    ,
    let $xml := o:xml(['h:p'], o:ns-builder(o:ns-map('h')))
    return
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/1999/xhtml')
    ,
    let $xml := o:xml(['p'], o:ns-builder(o:default-ns('http://foobar')))
    return
        unit:assert-equals(namespace-uri($xml), 'http://foobar')
    ,
    let $xml := o:xml(['h:x',['p']], o:ns-builder(o:default-ns(o:ns-map(), 'http://foobar')))
    return (
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/1999/xhtml'),
        (: default is set to a uri so we cannot just use $xml/p to get at the child element :)
        unit:assert-equals(namespace-uri($xml/*[1]), 'http://foobar')
    )
    ,
    let $xml := o:xml(['h:x',['p']], o:ns-builder(o:default-ns(o:ns-map(), '')))
    return (
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/1999/xhtml'),
        unit:assert-equals(namespace-uri($xml/p), '')
    )
};

(: TODO: default ns prefixes are present in the result :)
declare %unit:test function test:no-extra-namespaces-in-result()
{
      unit:assert-equals(
        in-scope-prefixes(o:xml(['x'])),
        ('xml')
      )
};

declare %unit:test function test:prefixes()
{
    let $xml := o:xml(['p'])
    return
        unit:assert-equals(prefix-from-QName(node-name($xml)), ())
    ,
    let $xml := o:xml(['p'], o:ns-builder(o:default-ns('http://www.w3.org/1999/xhtml')))
    return (
        unit:assert-equals(prefix-from-QName(node-name($xml)), ()),
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/1999/xhtml')
    ),
    let $xml := o:xml(['h:p'], o:ns-builder(o:default-ns(o:ns-map(), 'http://www.w3.org/1999/xhtml')))
    return
        unit:assert-equals(prefix-from-QName(node-name($xml)), ())
    ,
    let $xml := o:xml(['x:p'],o:ns-builder(map { 'x': 'http://foobar' } => o:default-ns('http://foobar')))
    return
        unit:assert-equals(prefix-from-QName(node-name($xml)), ())
    ,
    let $xml := o:xml(['x:p'], o:ns-builder(map { 'x': 'http://foobar' }))
    return
        unit:assert-equals(prefix-from-QName(node-name($xml)), 'x')
};

declare %unit:test function test:mixed-namespaces()
{
    let $xml := o:xml(
        ['app:foo', ['atom:bar'], ['atom:bar'], ['category']],
        o:ns-builder(o:ns-map()))
    return (
        unit:assert-equals(prefix-from-QName(node-name($xml)), 'app'),
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/2007/app'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[1])), 'atom'),
        unit:assert-equals(namespace-uri($xml/*[1]), 'http://www.w3.org/2005/Atom'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[3])), ()),
        unit:assert-equals(namespace-uri($xml/*[3]), '')
    ),
    let $xml := o:xml(
        ['app:foo', ['atom:bar'], ['atom:bar'], ['category']],
        o:ns-builder(o:ns-map()
        => o:default-ns('http://www.w3.org/2007/app')))
    return (
        unit:assert-equals(prefix-from-QName(node-name($xml)), ()),
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/2007/app'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[1])), 'atom'),
        unit:assert-equals(namespace-uri($xml/*[1]), 'http://www.w3.org/2005/Atom'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[3])), ()),
        unit:assert-equals(namespace-uri($xml/*[3]), 'http://www.w3.org/2007/app')
    ),
    let $xml := o:xml(
        ['app:foo', ['atom:bar'], ['atom:bar'], ['category']],
        o:ns-builder(o:ns-map()
        => o:default-ns('http://www.w3.org/2005/Atom')))
    return (
        unit:assert-equals(prefix-from-QName(node-name($xml)), 'app'),
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/2007/app'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[1])), ()),
        unit:assert-equals(namespace-uri($xml/*[1]), 'http://www.w3.org/2005/Atom'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[3])), ()),
        unit:assert-equals(namespace-uri($xml/*[3]), 'http://www.w3.org/2005/Atom')
    ),
    let $xml := o:xml(
        ['app:foo', ['x:bar'], ['atom:bar'], ['category']],
        o:ns-builder(map {
            'x': 'http://www.w3.org/2005/Atom',
            'atom': 'http://www.w3.org/2005/Atom',
            'app': 'http://www.w3.org/2007/app' }
        => o:default-ns('http://www.w3.org/2005/Atom')))
    return (
        unit:assert-equals(prefix-from-QName(node-name($xml)), 'app'),
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/2007/app'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[1])), ()),
        unit:assert-equals(namespace-uri($xml/*[1]), 'http://www.w3.org/2005/Atom'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[2])), ()),
        unit:assert-equals(namespace-uri($xml/*[1]), 'http://www.w3.org/2005/Atom'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[3])), ()),
        unit:assert-equals(namespace-uri($xml/*[3]), 'http://www.w3.org/2005/Atom')
    )
};

xquery version "3.1";

(:~
 : Tests for namespace functions.
 :)
module namespace test = 'http://xokomola.com/xquery/origami/tests';

import module namespace o = 'http://xokomola.com/xquery/origami'
    at '../origami.xqm';

declare %unit:test function test:ns-map()
{
    let $ns := o:ns-map()
    return
        unit:assert-equals($ns?html,'http://www.w3.org/1999/xhtml',
            "XHTML namespace is in default namespace map"
        ),

    let $ns := o:ns-map()
    return
        unit:assert-equals($ns?x,(),
            "X namespace is not in default namespace map"
        ),

    let $ns := o:ns-map(map { 'x': 'foobar' })
    return
        unit:assert-equals($ns?x,'foobar',
            "X namespace is in the namespace map"
        ),

    let $ns := o:ns-map(map { 'html': 'foobar' })
    return
        unit:assert-equals($ns?html,'foobar',
            "XHTML is mapped to foobar"
        )
};

(:~
 : A document is _normal_ (or _in namespace-normal form_) if all
 : namespace declarations appear on the root element and it is
 : not psychotic.  (A borderline document with all namespace
 : declarations in the same place is automatically psychotic;
 : a neurotic document with this property would be illegal according
 : to the Namespaces REC.)
 :)
declare variable $test:normal :=
    <foo xmlns="foo" xmlns:x="bar"><x:bar foo="bar"/></foo>;

(:~
 : It's not always possible to produce normal documents -- the producer
 : might not know all of the relevant namespaces at the time it emits
 : the root element start-tag -- so a weaker definition is useful:
 : A document is _sane_ if it is neither neurotic nor borderline.
 :)
declare variable $test:sane :=
    <foo xmlns="foo"><x:bar xmlns:x="bar" foo="bar"/></foo>;

(:~
 : Let's say that an XML document is _neurotic_ if it maps the same
 : namespace prefix to two different namespace URIs at different
 : points.  Neurosis makes it necessary for XML processors to
 : work with {URI+localname} pairs instead of GIs, and to keep
 : track of the namespace environment at each point in the tree
 : if there are QNames-in-content.  If it weren't for neurosis,
 : applications could use a single namespace map that applied to
 : the entire document.
 :)
declare variable $test:neurotic :=
    <x:foo xmlns:x="foo">
        <x:bar xmlns:x="bar"/>
    </x:foo>;

(:~
 : Conversely, a document is _borderline_ if it maps two different
 : namespace prefixes to the same namespace URI.  Borderline documents
 : complicate reserialization: the choice of which prefix to
 : use for a particular {URI+localname} pair depends on its
 : position in the tree.
 :)
declare variable $test:borderline :=
    <x:foo xmlns:x="foo">
        <y:bar xmlns:y="foo"/>
    </x:foo>;

(:~
 : A document is _psychotic_ if it maps two different namespace prefixes
 : to the same URI _in the same scope_.  Psychosis presents an even
 : bigger difficulty for reserialization: now applications must keep
 : track of the original prefix as well as the {URI+localname} pair.
 :)
declare variable $test:psychotic :=
    <x:foo xmlns:x="foo" xmlns:y="foo" y:bar="bar"/>;

(:~
 : This document suffers from multiple disorders.
 :)
declare variable $test:psychotic-borderline-neurotic :=
    <x:foo xmlns:x="foo" xmlns:y="foo" y:bar="bar">
        <x:foo xmlns:y="bar" xmlns:z="foo" z:foo="bar"/>
    </x:foo>;

(:~
 : This document redefines default namespace on child nodes.
 : A sane approach probably only returns the namespace from
 : the highest node.
 :)
declare variable $test:remap-default-ns :=
  <foo xmlns="foo">
    <bar xmlns="bar"/>
  </foo>;

declare %unit:test function test:remap-default-ns()
{
    unit:assert-equals(
        o:ns-map($test:remap-default-ns),
        map { '': 'foo' },
        'A weird XML document.'
    )
};

declare %unit:test function test:normal-xml()
{
    unit:assert-equals(
        o:ns-map($test:sane),
        map { '': 'foo', 'x': 'bar' },
        'A sane XML document.'
    )
};

declare %unit:test function test:sane-xml()
{
    unit:assert-equals(
        o:ns-map($test:sane),
        map { '': 'foo', 'x': 'bar' },
        'A sane XML document.'
    )
};

declare %unit:test function test:insane-xml()
{
    unit:assert-equals(
        o:ns-map($test:neurotic),
        map { 'x': 'foo' },
        'A neurotic XML maps the same namespace prefix to two different
         namespace URIs at different points.'
    ),

    unit:assert-equals(
        o:ns-map($test:borderline),
        map { 'x': 'foo', 'y': 'foo' },
        'A borderline XML maps two different namespace prefixes to the same
        namespace URI.'
    ),

    unit:assert-equals(
        o:ns-map($test:psychotic),
        map { 'x': 'foo', 'y': 'foo' },
        'A psychotic XML maps two different URIs to the same prefix.'
    ),

    unit:assert-equals(
        o:ns-map($test:psychotic-borderline-neurotic),
        map { 'x': 'foo', 'y': 'foo', 'z': 'foo' },
        'A mixture of insanity.'
    )
};

declare %unit:test function test:ns-builder()
{
    let $xf := o:ns-builder(o:ns-map())
    return
        unit:assert-equals(
            $xf?ns?html,
            'http://www.w3.org/1999/xhtml',
            'Transformer has XHTML namespace URI'
        ),

    let $xf := o:ns-builder($test:sane)
    return
        unit:assert-equals(
            $xf?ns,
            map { '': 'foo', 'x': 'bar' },
            'Transformer has sane XML namespace map'
        ),

    let $xf := o:ns-builder(o:ns-builder(), map:merge((o:ns-map(), o:ns-map($test:sane))))
    return (
        unit:assert-equals(
            $xf?ns?html,
            'http://www.w3.org/1999/xhtml',
            'Transformer is composed of default namespaces and XML namespaces'
        ),
        unit:assert-equals(
            $xf?ns?x,
            'bar',
            'Transformer has bar namespace'
        ),
        unit:assert-equals(
            $xf?ns(''),
            'foo',
            'Transformer has foo namespace'
        )
    )
};

declare %unit:test function test:default-ns()
{
    unit:assert-equals(
        o:default-ns(map {}, 'foo')(''),
        'foo',
        'Default namespace foo'
    ),

    unit:assert-equals(
        o:default-ns(o:ns-map(), 'bar')(''),
        'bar',
        'Default namespace foo'
    )
};

declare %unit:test function test:default-namespace()
{
    let $xml := o:xml(['p'])
    return
        unit:assert-equals(namespace-uri($xml), '')
    ,
    let $xml := o:xml(['h:p'], o:ns-builder(o:ns-map('h')))
    return
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/1999/xhtml')
    ,
    let $xml := o:xml(['p'], o:ns-builder(o:default-ns('http://foobar')))
    return
        unit:assert-equals(namespace-uri($xml), 'http://foobar')
    ,
    let $xml := o:xml(['h:x',['p']], o:ns-builder(o:default-ns(o:ns-map(), 'http://foobar')))
    return (
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/1999/xhtml'),
        (: default is set to a uri so we cannot just use $xml/p to get at the child element :)
        unit:assert-equals(namespace-uri($xml/*[1]), 'http://foobar')
    )
    ,
    let $xml := o:xml(['h:x',['p']], o:ns-builder(o:default-ns(o:ns-map(), '')))
    return (
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/1999/xhtml'),
        unit:assert-equals(namespace-uri($xml/p), '')
    )
};

(: TODO: default ns prefixes are present in the result :)
declare %unit:test function test:no-extra-namespaces-in-result()
{
      unit:assert-equals(
        in-scope-prefixes(o:xml(['x'])),
        ('xml')
      )
};

declare %unit:test function test:prefixes()
{
    let $xml := o:xml(['p'])
    return
        unit:assert-equals(prefix-from-QName(node-name($xml)), ())
    ,
    let $xml := o:xml(['p'], o:ns-builder(o:default-ns('http://www.w3.org/1999/xhtml')))
    return (
        unit:assert-equals(prefix-from-QName(node-name($xml)), ()),
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/1999/xhtml')
    ),
    let $xml := o:xml(['h:p'], o:ns-builder(o:default-ns(o:ns-map(), 'http://www.w3.org/1999/xhtml')))
    return
        unit:assert-equals(prefix-from-QName(node-name($xml)), ())
    ,
    let $xml := o:xml(['x:p'],o:ns-builder(map { 'x': 'http://foobar' } => o:default-ns('http://foobar')))
    return
        unit:assert-equals(prefix-from-QName(node-name($xml)), ())
    ,
    let $xml := o:xml(['x:p'], o:ns-builder(map { 'x': 'http://foobar' }))
    return
        unit:assert-equals(prefix-from-QName(node-name($xml)), 'x')
};

declare %unit:test function test:mixed-namespaces()
{
    let $xml := o:xml(
        ['app:foo', ['atom:bar'], ['atom:bar'], ['category']],
        o:ns-builder(o:ns-map()))
    return (
        unit:assert-equals(prefix-from-QName(node-name($xml)), 'app'),
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/2007/app'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[1])), 'atom'),
        unit:assert-equals(namespace-uri($xml/*[1]), 'http://www.w3.org/2005/Atom'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[3])), ()),
        unit:assert-equals(namespace-uri($xml/*[3]), '')
    ),
    let $xml := o:xml(
        ['app:foo', ['atom:bar'], ['atom:bar'], ['category']],
        o:ns-builder(o:ns-map()
        => o:default-ns('http://www.w3.org/2007/app')))
    return (
        unit:assert-equals(prefix-from-QName(node-name($xml)), ()),
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/2007/app'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[1])), 'atom'),
        unit:assert-equals(namespace-uri($xml/*[1]), 'http://www.w3.org/2005/Atom'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[3])), ()),
        unit:assert-equals(namespace-uri($xml/*[3]), 'http://www.w3.org/2007/app')
    ),
    let $xml := o:xml(
        ['app:foo', ['atom:bar'], ['atom:bar'], ['category']],
        o:ns-builder(o:ns-map()
        => o:default-ns('http://www.w3.org/2005/Atom')))
    return (
        unit:assert-equals(prefix-from-QName(node-name($xml)), 'app'),
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/2007/app'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[1])), ()),
        unit:assert-equals(namespace-uri($xml/*[1]), 'http://www.w3.org/2005/Atom'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[3])), ()),
        unit:assert-equals(namespace-uri($xml/*[3]), 'http://www.w3.org/2005/Atom')
    ),
    let $xml := o:xml(
        ['app:foo', ['x:bar'], ['atom:bar'], ['category']],
        o:ns-builder(map {
            'x': 'http://www.w3.org/2005/Atom',
            'atom': 'http://www.w3.org/2005/Atom',
            'app': 'http://www.w3.org/2007/app' }
        => o:default-ns('http://www.w3.org/2005/Atom')))
    return (
        unit:assert-equals(prefix-from-QName(node-name($xml)), 'app'),
        unit:assert-equals(namespace-uri($xml), 'http://www.w3.org/2007/app'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[1])), ()),
        unit:assert-equals(namespace-uri($xml/*[1]), 'http://www.w3.org/2005/Atom'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[2])), ()),
        unit:assert-equals(namespace-uri($xml/*[1]), 'http://www.w3.org/2005/Atom'),
        unit:assert-equals(prefix-from-QName(node-name($xml/*[3])), ()),
        unit:assert-equals(namespace-uri($xml/*[3]), 'http://www.w3.org/2005/Atom')
    )
};