[MOD] Module calls updated.

[MOD] Module calls updated.

(:~
 : Serialization module.
 : @author Leo Woerteler
 : @version 0.1
 :)
module namespace qt3ts-java='http://www.basex.org/modules/qt3ts/java';

declare variable $qt3ts-java:not-supported :=
  QName('http://www.basex.org/modules/qt3ts/java', 'NSUP0001');

declare function qt3ts-java:test-suites(
  $package,
  $test-sets
) as map(*) {
  map:new((
    $test-sets,
    for $path in map:keys($test-sets)
    let $parts   := tokenize($path, '/'),
        $classes := $parts[2]
    group by $suite := $parts[1]
    order by $suite
    return
      let $suite-name := qt3ts-java:class-name($suite || 'Tests')
      return map:entry(
        $suite-name,
        string-join((
  'package ', $package, ';

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

import org.basex.test.qt3ts.', $suite, '.*;

/**
 * Test suite for the "', $suite, '" test group.
 *
 * @author BaseX Team 2005-12, BSD License
 * @author Leo Woerteler
 */
@RunWith(Suite.class)
@SuiteClasses({',
  string-join(
    for $class in $classes
    order by $class
    return '
  ' || $class || '.class',
    ','
  ),
'
})
public class ', $suite-name, ' { }
'
      ))
    )
  ))
};

declare function qt3ts-java:test-set(
  $package as xs:string,
  $dir as xs:string,
  $name as xs:string,
  $comment as xs:string,
  $test-cases as map(*)
) as xs:string+ {
  let $class-name := qt3ts-java:class-name($name)
  return (
    $class-name,
    string-join((
'package ', $package, '.', $dir, ';

import org.basex.tests.bxapi.XQuery;
import ', $package, '.QT3TestSet;

/**
',
  string-join(
    for $line in tokenize($comment, '\r?\n|\r')
    return concat(' * ', replace($line, '\*/', '* /')),
    '
'
  ),
  '.
 *
 * @author BaseX Team 2005-12, BSD License
 * @author Leo Woerteler
 */
@SuppressWarnings("all")
public class ',  $class-name, ' extends QT3TestSet {
',
  for $name in map:keys($test-cases)
  let $test-case := $test-cases($name)
  order by $name
  return try {'
  /**
',
  string-join(
    for $line in tokenize($test-case('description'), '\r?\n|\r')
    return concat('   * ', replace($line, '\*/', '* /')),
    '
'
  ),
  '.
   */
  @org.junit.Test
  public void ', qt3ts-java:method-name($name), '() {
    final XQuery query = new XQuery(
',  qt3ts-java:string-literal($test-case('test'), '      '), ',
      ctx);
',
  for $line in qt3ts-java:environment($test-case('environment'))
  return concat('    ', $line, '
'),

  let $mods := $test-case('modules')
  for $mod in map:keys($mods)
  return concat('    query.addModule("', qt3ts-java:escape-string($mod),
    '", file("', qt3ts-java:escape-string($mods($mod)), '"));
'),
  '
    final QT3Result res = result(query);
    result = res;
    test(
',
  for $line in qt3ts-java:result($test-case('result'), '')
  return concat('      ', $line, '
'),
'    );
  }
'
  } catch qt3ts-java:NSUP0001 {
    trace('', 'Skipped test because of environment')[2]
  },
'}
'), '')
  )
};

declare function qt3ts-java:environment(
  $envs as map(*)*
) as xs:string* {
  for $env in $envs
  for $name in map:keys($env)
  let $vals := $env($name)
  return switch($name)
    case 'source'
      return if(exists($vals('validation'))) then error($qt3ts-java:not-supported)
        else if($vals('role') = '.')
          then 'query.context(node(file("' || qt3ts-java:escape-string($vals('file')) || '")));'
        else if(exists($vals('role')))
          then 'query.bind("' || qt3ts-java:escape-string($vals('role')) || '", ' ||
          'node(file("' || qt3ts-java:escape-string($vals('file')) || '")));'
        else 'query.addDocument("' || qt3ts-java:escape-string(($vals('uri'), $vals('file'))[1]) ||
          '", ' || 'file("' || qt3ts-java:escape-string($vals('file')) || '"));'

    case 'namespace'
      return 'query.namespace("' || qt3ts-java:escape-string($vals('prefix')) ||
        '", "' || qt3ts-java:escape-string($vals('uri')) || '");'
    case 'collation'
      return if($vals('uri') != 'http://www.w3.org/2005/xpath-functions/collation/codepoint')
        then error($qt3ts-java:not-supported)
        else ()
    case 'collection'
      return 'query.addCollection("' || qt3ts-java:escape-string($vals('uri')) || '", ' ||
        'new String[] { "' || string-join(
          for $doc in map:keys($vals('docs'))
          return qt3ts-java:escape-string($vals('docs')($doc)('file'))
        , '", "') || '" });'
    case 'decimal-format'
      return '// decimal format'
    case 'resource'
      return '// resource: ' || $vals('uri')
    case 'schema'
      return error($qt3ts-java:not-supported)
    case 'static-base-uri'
      return 'query.baseURI("' || qt3ts-java:escape-string($vals) || '");'
    case 'param'
      return 'query.bind("' || qt3ts-java:escape-string($vals('name')) || '", ' ||
        'new XQuery("' || qt3ts-java:escape-string($vals('select')) || '", ctx).value());'
      (: map:entry($name, map{
        'name' := $env/@name/string(),
        'select' := $env/@select/string(),
        'as' := $env/@as/string(),
        'declared' := $env/@declared != 'false'
      }) :)
    default
      return trace('', 'Unknown Java-serialization for: ')[2]
};

declare function qt3ts-java:result(
  $result as map(*),
  $indent as xs:string
) as xs:string* {
  let $name := map:keys($result),
      $vals := $result($name)
  return
    switch($name)
      case 'assert-true' return $indent || 'assertBoolean(true)'
      case 'assert-false' return $indent || 'assertBoolean(false)'
      case 'assert-empty' return $indent || 'assertEmpty()'
      case 'assert'
        return $indent || 'assertQuery("' || qt3ts-java:escape-string($vals) || '")'
      case 'assert-eq'
        return $indent || 'assertEq("' || qt3ts-java:escape-string($vals) || '")'
      case 'assert-string-value'
        return $indent || 'assertStringValue(' || $vals('normalize-space') || ', "' ||
          qt3ts-java:escape-string($vals('result')) || '")'
      case 'assert-permutation'
        return $indent || 'assertPermutation("' || qt3ts-java:escape-string($vals) || '")'
      case 'assert-type'
        return $indent || 'assertType("' || qt3ts-java:escape-string($vals) || '")'
      case 'assert-deep-eq'
        return $indent || 'assertDeepEq("' || qt3ts-java:escape-string($vals) || '")'
      case 'assert-count' return $indent || 'assertCount(' || $vals || ')'
      case 'error'
        return $indent || 'error("' || qt3ts-java:escape-string($vals) || '")'
      case 'assert-serialization-error'
        return $indent || 'assertSerialError("' || qt3ts-java:escape-string($vals) || '")'
      case 'assert-serialization'
        return $indent || 'assertSerialization("' ||
          qt3ts-java:escape-string($vals('result')) || '", ' || $vals('ignore-prefixes') || ')'
      case 'all-of' return (
          $indent || '(',
          tail(
            for $sub in $vals
            return (
              $indent || '&&',
              qt3ts-java:result($sub, '  ' || $indent)
            )
          ),
          $indent || ')'
        )
      case 'any-of' return (
          $indent || '(',
          tail(
            for $sub in $vals
            return (
              $indent || '||',
              qt3ts-java:result($sub, '  ' || $indent)
            )
          ),
          $indent || ')'
        )
      default return 'true'
};

declare function qt3ts-java:string-literal(
  $str as xs:string,
  $indent as xs:string
) as xs:string {
  if(empty($str) or string-length($str) eq 0)
  then $indent || '""'
  else concat(
    string-join(
      for $line in qt3ts-java:lines($str)
      return concat($indent, '"', qt3ts-java:escape-string($line)),
      '\n" +
'
    ),
    '"'
  )
};

declare function qt3ts-java:method-name(
  $name as xs:string
) as xs:string {
  let $camel :=  qt3ts-java:class-name($name)
  return concat(lower-case(substring($camel, 1, 1)), substring($camel, 2))
};

declare function qt3ts-java:class-name(
  $name as xs:string
) as xs:string {
  string-join(
    for $part in tokenize($name, '\W')
    where string-length($part) gt 0
    return concat(upper-case(substring($part, 1, 1)), substring($part, 2))
  )
};

declare function qt3ts-java:escape-string(
  $str as xs:string
) as xs:string {
  string-join((
    for $cp in string-to-codepoints($str)
    return switch($cp)
      case  9 return '\t'
      case 10 return '\n'
      case 11 return '\v'
      case 13 return '\r'
      case 34 return '\"'
      case 92 return '\\'
      default return
        if($cp ge 0 and $cp le 31 or $cp ge 127 and $cp le 159)
        then out:format('\u%04x', $cp)
        else
          let $ch := codepoints-to-string($cp) return
          if($cp le 255 or matches($ch, '\w')) then $ch
          else if($cp lt 65536) then out:format('\u%04x', $cp)
          else
            let $offset := $cp - 65536,
                $high   := xs:int(($offset idiv 1024) + 55296),
                $low    := xs:int(($offset mod 1024) + 56320)
            return out:format('\u%04x\u%04x', $high, $low)
  ))
};

declare function qt3ts-java:lines(
  $str as xs:string
) as xs:string* {
  tokenize($str, '
')
};

(:~
 : Serialization module.
 : @author Leo Woerteler
 : @version 0.1
 :)
module namespace qt3ts-java='http://www.basex.org/modules/qt3ts/java';

declare variable $qt3ts-java:not-supported :=
  QName('http://www.basex.org/modules/qt3ts/java', 'NSUP0001');

declare function qt3ts-java:test-suites(
  $package,
  $test-sets
) as map(*) {
  map:new((
    $test-sets,
    for $path in map:keys($test-sets)
    let $parts   := tokenize($path, '/'),
        $classes := $parts[2]
    group by $suite := $parts[1]
    order by $suite
    return
      let $suite-name := qt3ts-java:class-name($suite || 'Tests')
      return map:entry(
        $suite-name,
        string-join((
  'package ', $package, ';

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

import org.basex.test.qt3ts.', $suite, '.*;

/**
 * Test suite for the "', $suite, '" test group.
 *
 * @author BaseX Team 2005-12, BSD License
 * @author Leo Woerteler
 */
@RunWith(Suite.class)
@SuiteClasses({',
  string-join(
    for $class in $classes
    order by $class
    return '
  ' || $class || '.class',
    ','
  ),
'
})
public class ', $suite-name, ' { }
'
      ))
    )
  ))
};

declare function qt3ts-java:test-set(
  $package as xs:string,
  $dir as xs:string,
  $name as xs:string,
  $comment as xs:string,
  $test-cases as map(*)
) as xs:string+ {
  let $class-name := qt3ts-java:class-name($name)
  return (
    $class-name,
    string-join((
'package ', $package, '.', $dir, ';

import org.basex.tests.bxapi.XQuery;
import ', $package, '.QT3TestSet;

/**
',
  string-join(
    for $line in tokenize($comment, '\r?\n|\r')
    return concat(' * ', replace($line, '\*/', '* /')),
    '
'
  ),
  '.
 *
 * @author BaseX Team 2005-12, BSD License
 * @author Leo Woerteler
 */
@SuppressWarnings("all")
public class ',  $class-name, ' extends QT3TestSet {
',
  for $name in map:keys($test-cases)
  let $test-case := $test-cases($name)
  order by $name
  return try {'
  /**
',
  string-join(
    for $line in tokenize($test-case('description'), '\r?\n|\r')
    return concat('   * ', replace($line, '\*/', '* /')),
    '
'
  ),
  '.
   */
  @org.junit.Test
  public void ', qt3ts-java:method-name($name), '() {
    final XQuery query = new XQuery(
',  qt3ts-java:string-literal($test-case('test'), '      '), ',
      ctx);
',
  for $line in qt3ts-java:environment($test-case('environment'))
  return concat('    ', $line, '
'),

  let $mods := $test-case('modules')
  for $mod in map:keys($mods)
  return concat('    query.addModule("', qt3ts-java:escape-string($mod),
    '", file("', qt3ts-java:escape-string($mods($mod)), '"));
'),
  '
    final QT3Result res = result(query);
    result = res;
    test(
',
  for $line in qt3ts-java:result($test-case('result'), '')
  return concat('      ', $line, '
'),
'    );
  }
'
  } catch qt3ts-java:NSUP0001 {
    trace('', 'Skipped test because of environment')[2]
  },
'}
'), '')
  )
};

declare function qt3ts-java:environment(
  $envs as map(*)*
) as xs:string* {
  for $env in $envs
  for $name in map:keys($env)
  let $vals := $env($name)
  return switch($name)
    case 'source'
      return if(exists($vals('validation'))) then error($qt3ts-java:not-supported)
        else if($vals('role') = '.')
          then 'query.context(node(file("' || qt3ts-java:escape-string($vals('file')) || '")));'
        else if(exists($vals('role')))
          then 'query.bind("' || qt3ts-java:escape-string($vals('role')) || '", ' ||
          'node(file("' || qt3ts-java:escape-string($vals('file')) || '")));'
        else 'query.addDocument("' || qt3ts-java:escape-string(($vals('uri'), $vals('file'))[1]) ||
          '", ' || 'file("' || qt3ts-java:escape-string($vals('file')) || '"));'

    case 'namespace'
      return 'query.namespace("' || qt3ts-java:escape-string($vals('prefix')) ||
        '", "' || qt3ts-java:escape-string($vals('uri')) || '");'
    case 'collation'
      return if($vals('uri') != 'http://www.w3.org/2005/xpath-functions/collation/codepoint')
        then error($qt3ts-java:not-supported)
        else ()
    case 'collection'
      return 'query.addCollection("' || qt3ts-java:escape-string($vals('uri')) || '", ' ||
        'new String[] { "' || string-join(
          for $doc in map:keys($vals('docs'))
          return qt3ts-java:escape-string($vals('docs')($doc)('file'))
        , '", "') || '" });'
    case 'decimal-format'
      return '// decimal format'
    case 'resource'
      return '// resource: ' || $vals('uri')
    case 'schema'
      return error($qt3ts-java:not-supported)
    case 'static-base-uri'
      return 'query.baseURI("' || qt3ts-java:escape-string($vals) || '");'
    case 'param'
      return 'query.bind("' || qt3ts-java:escape-string($vals('name')) || '", ' ||
        'new XQuery("' || qt3ts-java:escape-string($vals('select')) || '", ctx).value());'
      (: map:entry($name, map{
        'name' := $env/@name/string(),
        'select' := $env/@select/string(),
        'as' := $env/@as/string(),
        'declared' := $env/@declared != 'false'
      }) :)
    default
      return trace('', 'Unknown Java-serialization for: ')[2]
};

declare function qt3ts-java:result(
  $result as map(*),
  $indent as xs:string
) as xs:string* {
  let $name := map:keys($result),
      $vals := $result($name)
  return
    switch($name)
      case 'assert-true' return $indent || 'assertBoolean(true)'
      case 'assert-false' return $indent || 'assertBoolean(false)'
      case 'assert-empty' return $indent || 'assertEmpty()'
      case 'assert'
        return $indent || 'assertQuery("' || qt3ts-java:escape-string($vals) || '")'
      case 'assert-eq'
        return $indent || 'assertEq("' || qt3ts-java:escape-string($vals) || '")'
      case 'assert-string-value'
        return $indent || 'assertStringValue(' || $vals('normalize-space') || ', "' ||
          qt3ts-java:escape-string($vals('result')) || '")'
      case 'assert-permutation'
        return $indent || 'assertPermutation("' || qt3ts-java:escape-string($vals) || '")'
      case 'assert-type'
        return $indent || 'assertType("' || qt3ts-java:escape-string($vals) || '")'
      case 'assert-deep-eq'
        return $indent || 'assertDeepEq("' || qt3ts-java:escape-string($vals) || '")'
      case 'assert-count' return $indent || 'assertCount(' || $vals || ')'
      case 'error'
        return $indent || 'error("' || qt3ts-java:escape-string($vals) || '")'
      case 'assert-serialization-error'
        return $indent || 'assertSerialError("' || qt3ts-java:escape-string($vals) || '")'
      case 'assert-serialization'
        return $indent || 'assertSerialization("' ||
          qt3ts-java:escape-string($vals('result')) || '", ' || $vals('ignore-prefixes') || ')'
      case 'all-of' return (
          $indent || '(',
          tail(
            for $sub in $vals
            return (
              $indent || '&&',
              qt3ts-java:result($sub, '  ' || $indent)
            )
          ),
          $indent || ')'
        )
      case 'any-of' return (
          $indent || '(',
          tail(
            for $sub in $vals
            return (
              $indent || '||',
              qt3ts-java:result($sub, '  ' || $indent)
            )
          ),
          $indent || ')'
        )
      default return 'true'
};

declare function qt3ts-java:string-literal(
  $str as xs:string,
  $indent as xs:string
) as xs:string {
  if(empty($str) or string-length($str) eq 0)
  then $indent || '""'
  else concat(
    string-join(
      for $line in qt3ts-java:lines($str)
      return concat($indent, '"', qt3ts-java:escape-string($line)),
      '\n" +
'
    ),
    '"'
  )
};

declare function qt3ts-java:method-name(
  $name as xs:string
) as xs:string {
  let $camel :=  qt3ts-java:class-name($name)
  return concat(lower-case(substring($camel, 1, 1)), substring($camel, 2))
};

declare function qt3ts-java:class-name(
  $name as xs:string
) as xs:string {
  string-join(
    for $part in tokenize($name, '\W')
    where string-length($part) gt 0
    return concat(upper-case(substring($part, 1, 1)), substring($part, 2))
  )
};

declare function qt3ts-java:escape-string(
  $str as xs:string
) as xs:string {
  string-join((
    for $cp in string-to-codepoints($str)
    return switch($cp)
      case  9 return '\t'
      case 10 return '\n'
      case 11 return '\v'
      case 13 return '\r'
      case 34 return '\"'
      case 92 return '\\'
      default return
        if($cp ge 0 and $cp le 31 or $cp ge 127 and $cp le 159)
        then util:format('\u%04x', $cp)
        else
          let $ch := codepoints-to-string($cp) return
          if($cp le 255 or matches($ch, '\w')) then $ch
          else if($cp lt 65536) then util:format('\u%04x', $cp)
          else
            let $offset := $cp - 65536,
                $high   := xs:int(($offset idiv 1024) + 55296),
                $low    := xs:int(($offset mod 1024) + 56320)
            return util:format('\u%04x\u%04x', $high, $low)
  ))
};

declare function qt3ts-java:lines(
  $str as xs:string
) as xs:string* {
  tokenize($str, '
')
};


Test key update that I missed previously

xquery version '1.0-ml';

(:
 This module was generated by MarkLogic Entity Services.
 The source model was et-required-0.0.1

 For usage and extension points, see the Entity Services Developer's Guide

 https://docs.marklogic.com/guide/entity-services

 After modifying this file, put it in your project for deployment to the modules
 database of your application, and check it into your source control system.

 Generated at timestamp: 2017-08-10T17:49:34.347263Z
 :)

module namespace et-required
    = 'http://baloo#et-required-0.0.1';

import module namespace es = 'http://marklogic.com/entity-services'
    at '/MarkLogic/entity-services/entity-services.xqy';

declare option xdmp:mapping 'false';

(:~
 : Extracts instance data, as a map:map, from some source document.
 : @param $source-node  A document or node that contains
 :   data for populating a ETOne
 : @return A map:map instance with extracted data and
 :   metadata about the instance.
 :)
declare function et-required:extract-instance-ETOne(
    $source as item()?
) as map:map
{
    let $source-node := es:init-source($source, 'ETOne')
    (: begin customizations here :)
    let $a  :=             $source-node/a ! xs:integer(.)
    let $b  :=             $source-node/b ! xs:string(.)
    let $c  :=             $source-node/c ! xs:date(.)
    (: end customizations :)

    let $instance := es:init-instance($source-node, 'ETOne')
    (: Comment or remove the following line to suppress attachments :)
        =>es:add-attachments($source)

    return
    if (empty($source-node/*))
    then $instance
    else $instance
        =>   map:with('a', $a)
        =>   map:with('b', $b)
        =>es:optional('c', $c)
};

(:~
 : Turns an entity instance into a JSON structure.
 : This out-of-the box implementation traverses a map structure
 : and turns it deterministically into a JSON tree.
 : Using this function as-is should be sufficient for most use
 : cases, and will play well with other generated artifacts.
 : @param $entity-instance A map:map instance returned from one of the extract-instance
 :    functions.
 : @return An XML element that encodes the instance.
 :)
declare function et-required:instance-to-canonical-json(

    $entity-instance as map:map
) as object-node()
{
    xdmp:to-json( et-required:canonicalize($entity-instance) )/node()
};

declare function et-required:canonicalize(
    $entity-instance as map:map
) as map:map
{
    json:object()
    =>map:with( map:get($entity-instance,'$type'),
                if ( map:contains($entity-instance, '$ref') )
                then fn:head( (map:get($entity-instance, '$ref'), json:object()) )
                else
                let $m := json:object()
                let $_ :=
                    for $key in map:keys($entity-instance)
                    let $instance-property := map:get($entity-instance, $key)
                    where ($key castable as xs:NCName)
                    return
                        typeswitch ($instance-property)
                        (: This branch handles embedded objects.  You can choose to prune
                           an entity's representation of extend it with lookups here. :)
                        case json:object
                            return
                                if (empty(map:keys($instance-property)))
                                then map:put($m, $key, json:object())
                                else
                                    for $prop in $instance-property
                                    return map:put($m, $key, et-required:canonicalize($prop))
                        (: An array can also treated as multiple elements :)
                        case json:array
                            return
                                (
                                for $val at $i in json:array-values($instance-property)
                                return
                                    if ($val instance of json:object)
                                    then json:set-item-at($instance-property, $i, et-required:canonicalize($val))
                                    else (),
                                map:put($m, $key, $instance-property)
                                )

                        (: A sequence of values should be simply treated as multiple elements :)
                        (: TODO is this lossy? :)
                        case item()+
                            return
                                for $val in $instance-property
                                return map:put($m, $key, $val)
                        default return map:put($m, $key, $instance-property)
                return $m)
};

(:~
 : Turns an entity instance into an XML structure.
 : This out-of-the box implementation traverses a map structure
 : and turns it deterministically into an XML tree.
 : Using this function as-is should be sufficient for most use
 : cases, and will play well with other generated artifacts.
 : @param $entity-instance A map:map instance returned from one of the extract-instance
 :    functions.
 : @return An XML element that encodes the instance.
 :)
declare function et-required:instance-to-canonical-xml(
    $entity-instance as map:map
) as element()
{
    (: Construct an element that is named the same as the Entity Type :)
    let $namespace := map:get($entity-instance, "$namespace")
    let $namespace-prefix := map:get($entity-instance, "$namespacePrefix")
    let $nsdecl :=
        if ($namespace) then
        namespace { $namespace-prefix } { $namespace }
        else ()
    let $type-name := map:get($entity-instance, '$type')
    let $type-qname :=
        if ($namespace)
        then fn:QName( $namespace, $namespace-prefix || ":" || $type-name)
        else $type-name
    return
        element { $type-qname }  {
            $nsdecl,
            if ( map:contains($entity-instance, '$ref') )
            then map:get($entity-instance, '$ref')
            else
                for $key in map:keys($entity-instance)
                let $instance-property := map:get($entity-instance, $key)
                let $ns-key :=
                    if ($namespace and $key castable as xs:NCName)
                    then fn:QName( $namespace, $namespace-prefix || ":" || $key)
                    else $key
                where ($key castable as xs:NCName)
                return
                    typeswitch ($instance-property)
                    (: This branch handles embedded objects.  You can choose to prune
                       an entity's representation of extend it with lookups here. :)
                    case json:object+
                        return
                            for $prop in $instance-property
                            return element { $ns-key } { et-required:instance-to-canonical-xml($prop) }
                    (: An array can also treated as multiple elements :)
                    case json:array
                        return
                            for $val in json:array-values($instance-property)
                            return
                                if ($val instance of json:object)
                                then element { $ns-key } {
                                    attribute datatype { 'array' },
                                    et-required:instance-to-canonical-xml($val)
                                }
                                else element { $ns-key } {
                                    attribute datatype { 'array' },
                                    $val }
                    (: A sequence of values should be simply treated as multiple elements :)
                    case item()+
                        return
                            for $val in $instance-property
                            return element { $ns-key } { $val }
                    default return element { $ns-key } { $instance-property }
        }
};

(:
 : Wraps a canonical instance (returned by instance-to-canonical-xml())
 : within an envelope patterned document, along with the source
 : document, which is stored in an attachments section.
 : @param $entity-instance an instance, as returned by an extract-instance
 : function
 : @return A document which wraps both the canonical instance and source docs.
 :)
declare function et-required:instance-to-xml-envelope(
    $entity-instance as map:map
) as document-node()
{
    document {
        element es:envelope {
            element es:instance {
                element es:info {
                    element es:title { map:get($entity-instance,'$type') },
                    element es:version { '0.0.1' }
                },
                et-required:instance-to-canonical-xml($entity-instance)
            },
            es:serialize-attachments($entity-instance, "xml")
        }
    }
};

(:
 : @param $entity-instance an instance, as returned by an extract-instance
 : function
 : @return A document which wraps both the canonical instance and source docs.
 :)
declare function et-required:instance-to-envelope(
    $entity-instance as map:map
) as document-node()
{
    et-required:instance-to-xml-envelope($entity-instance)
};

(:
 : Wraps a canonical instance (returned by instance-to-canonical-json())
 : within an envelope patterned document, along with the source
 : document, which is stored in an attachments section.
 : @param $entity-instance an instance, as returned by an extract-instance
 : function
 : @return A document which wraps both the canonical instance and source docs.
 :)
declare function et-required:instance-to-json-envelope(
    $entity-instance as map:map
) as document-node()
{
    document {
        object-node { 'envelope' :
            object-node { 'instance' :
                object-node { 'info' :
                    object-node {
                        'title' : map:get($entity-instance,'$type'),
                        'version' : '0.0.1'
                    }
                }
                +
                et-required:instance-to-canonical-json($entity-instance)
            }
            +
            es:serialize-attachments($entity-instance, "json")
        }
    }
};

xquery version '1.0-ml';

(:
 This module was generated by MarkLogic Entity Services.
 The source model was et-required-0.0.1

 For usage and extension points, see the Entity Services Developer's Guide

 https://docs.marklogic.com/guide/entity-services

 After modifying this file, put it in your project for deployment to the modules
 database of your application, and check it into your source control system.

 Generated at timestamp: 2017-08-09T23:38:41.383426Z
 :)

module namespace et-required
    = 'http://baloo#et-required-0.0.1';

import module namespace es = 'http://marklogic.com/entity-services'
    at '/MarkLogic/entity-services/entity-services.xqy';

declare option xdmp:mapping 'false';

(:~
 : Extracts instance data, as a map:map, from some source document.
 : @param $source-node  A document or node that contains
 :   data for populating a ETOne
 : @return A map:map instance with extracted data and
 :   metadata about the instance.
 :)
declare function et-required:extract-instance-ETOne(
    $source as item()?
) as map:map
{
    let $source-node := es:init-source($source, 'ETOne')
    (: begin customizations here :)
    let $a  :=             $source-node/a ! xs:integer(.)
    let $b  :=             $source-node/b ! xs:string(.)
    let $c  :=             $source-node/c ! xs:date(.)
    (: end customizations :)

    let $instance := es:init-instance($source-node, 'ETOne')
    (: Comment or remove the following line to suppress attachments :)
        =>es:add-attachments($source)

    return
    if (empty($source-node/*))
    then $instance
    else $instance
        =>   map:with('a', $a)
        =>   map:with('b', $b)
        =>es:optional('c', $c)
};

(:~
 : Turns an entity instance into a JSON structure.
 : This out-of-the box implementation traverses a map structure
 : and turns it deterministically into a JSON tree.
 : Using this function as-is should be sufficient for most use
 : cases, and will play well with other generated artifacts.
 : @param $entity-instance A map:map instance returned from one of the extract-instance
 :    functions.
 : @return An XML element that encodes the instance.
 :)
declare function et-required:instance-to-canonical-json(

    $entity-instance as map:map
) as object-node()
{
    xdmp:to-json( et-required:canonicalize($entity-instance) )/node()
};

declare function et-required:canonicalize(
    $entity-instance as map:map
) as map:map
{
    json:object()
    =>map:with( map:get($entity-instance,'$type'),
        if ( map:contains($entity-instance, '$ref') )
        then fn:head( (map:get($entity-instance, '$ref'), object-node()) )
        else
        let $m := json:object()
        let $_ :=
            for $key in map:keys($entity-instance)
            let $instance-property := map:get($entity-instance, $key)
            return
                if ($key castable as xs:NCName)
                then
                    typeswitch ($instance-property)
                    (: This branch handles embedded objects.  You can choose to prune
                       an entity's representation of extend it with lookups here. :)
                    case json:object
                        return
                            if (empty(map:keys($instance-property)))
                            then map:put($m, $key, json:object())
                            else
                                for $prop in $instance-property
                                return map:put($m, $key, et-required:canonicalize($prop))
                    (: An array can also treated as multiple elements :)
                    case json:array
                        return
                            (
                            for $val at $i in json:array-values($instance-property)
                            return
                                if ($val instance of object-node())
                                then json:set-item-at($instance-property, $i, et-required:canonicalize($val))
                                else (),
                            map:put($m, $key, $instance-property)
                            )

                    (: A sequence of values should be simply treated as multiple elements :)
                    (: TODO is this lossy? :)
                    case item()+
                        return
                            for $val in $instance-property
                            return map:put($m, $key, $val)
                    default return map:put($m, $key, $instance-property)
                else map:delete($entity-instance, $key)
        return $m)

};

(:~
 : Turns an entity instance into an XML structure.
 : This out-of-the box implementation traverses a map structure
 : and turns it deterministically into an XML tree.
 : Using this function as-is should be sufficient for most use
 : cases, and will play well with other generated artifacts.
 : @param $entity-instance A map:map instance returned from one of the extract-instance
 :    functions.
 : @return An XML element that encodes the instance.
 :)
declare function et-required:instance-to-canonical-xml(
    $entity-instance as map:map
) as element()
{
    (: Construct an element that is named the same as the Entity Type :)
    let $namespace := map:get($entity-instance, "$namespace")
    let $namespace-prefix := map:get($entity-instance, "$namespacePrefix")
    let $nsdecl :=
        if ($namespace) then
        namespace { $namespace-prefix } { $namespace }
        else ()
    let $type-name := map:get($entity-instance, '$type')
    let $type-qname :=
        if ($namespace)
        then fn:QName( $namespace, $namespace-prefix || ":" || $type-name)
        else $type-name
    return
        element { $type-qname }  {
            $nsdecl,
            if ( map:contains($entity-instance, '$ref') )
            then map:get($entity-instance, '$ref')
            else
                for $key in map:keys($entity-instance)
                let $instance-property := map:get($entity-instance, $key)
                let $ns-key :=
                    if ($namespace and $key castable as xs:NCName)
                    then fn:QName( $namespace, $namespace-prefix || ":" || $key)
                    else $key
                where ($key castable as xs:NCName)
                return
                    typeswitch ($instance-property)
                    (: This branch handles embedded objects.  You can choose to prune
                       an entity's representation of extend it with lookups here. :)
                    case json:object+
                        return
                            for $prop in $instance-property
                            return element { $ns-key } { et-required:instance-to-canonical-xml($prop) }
                    (: An array can also treated as multiple elements :)
                    case json:array
                        return
                            for $val in json:array-values($instance-property)
                            return
                                if ($val instance of json:object)
                                then element { $ns-key } {
                                    attribute datatype { 'array' },
                                    et-required:instance-to-canonical-xml($val)
                                }
                                else element { $ns-key } {
                                    attribute datatype { 'array' },
                                    $val }
                    (: A sequence of values should be simply treated as multiple elements :)
                    case item()+
                        return
                            for $val in $instance-property
                            return element { $ns-key } { $val }
                    default return element { $ns-key } { $instance-property }
        }
};

(:
 : Wraps a canonical instance (returned by instance-to-canonical-xml())
 : within an envelope patterned document, along with the source
 : document, which is stored in an attachments section.
 : @param $entity-instance an instance, as returned by an extract-instance
 : function
 : @return A document which wraps both the canonical instance and source docs.
 :)
declare function et-required:instance-to-xml-envelope(
    $entity-instance as map:map
) as document-node()
{
    document {
        element es:envelope {
            element es:instance {
                element es:info {
                    element es:title { map:get($entity-instance,'$type') },
                    element es:version { '0.0.1' }
                },
                et-required:instance-to-canonical-xml($entity-instance)
            },
            es:serialize-attachments($entity-instance, "xml")
        }
    }
};

(:
 : @param $entity-instance an instance, as returned by an extract-instance
 : function
 : @return A document which wraps both the canonical instance and source docs.
 :)
declare function et-required:instance-to-envelope(
    $entity-instance as map:map
) as document-node()
{
    et-required:instance-to-xml-envelope($entity-instance)
};

(:
 : Wraps a canonical instance (returned by instance-to-canonical-json())
 : within an envelope patterned document, along with the source
 : document, which is stored in an attachments section.
 : @param $entity-instance an instance, as returned by an extract-instance
 : function
 : @return A document which wraps both the canonical instance and source docs.
 :)
declare function et-required:instance-to-json-envelope(
    $entity-instance as map:map
) as document-node()
{
    document {
        object-node { 'envelope' :
            object-node { 'instance' :
                object-node { 'info' :
                    object-node {
                        'title' : map:get($entity-instance,'$type'),
                        'version' : '0.0.1'
                    }
                }
                +
                et-required:instance-to-canonical-json($entity-instance)
            }
            +
            es:serialize-attachments($entity-instance, "json")
        }
    }
};


Fixed svnRevs in mkdir.

Fixed svnRevs in mkdir.

(: XQuery main module :)

import module namespace file="http://expath.org/ns/file";
import module namespace proc="http://www.zorba-xquery.com/modules/process";
import module namespace tims="http://www.example.com/timings" at "timings.xq";
import module namespace sys ="http://www.zorba-xquery.com/modules/system";
import module namespace http="http://expath.org/ns/http-client";

declare namespace pdash = "http://www.28msec.com/pdash";

(:
(
    sys:property($sys:os-name),
    sys:property($sys:os-node-name),
    sys:property($sys:os-version),
    sys:property($sys:os-version-build),
    sys:property($sys:os-version-major),
    sys:property($sys:os-version-minor),
    sys:property($sys:os-version-release),
    sys:property($sys:os-version-version),
    sys:property($sys:linux-distributor),
    sys:property($sys:linux-distributor-version),
    sys:property($sys:user-name),
    sys:property($sys:os-arch),
    sys:property($sys:zorba-module-path),
    sys:property($sys:zorba-version),
    sys:property($sys:zorba-version-major),
    sys:property($sys:zorba-version-minor),
    sys:property($sys:zorba-version-patch)
)
:)

declare %sequential function local:getPlatform()
{
    <pdash:platform site-osname="Ubuntu" os-version="11.04" os-platform="Linux"
        hostname="28msec.dyndns.org" is-64bits="true" vendor-id="Cezar" vendor-label="i7"
        number-of-logical-cpu="{xs:int(12)}" number-of-physical-cpu="1"
        total-virtual-memory="6117504000" total-physical-memory="0"
        number-of-logical-cpu-per-physical-cpu="12"/>
};

declare %sequential function local:makeDir($svnDir as xs:string)
{
    if( fn:not( file:exists($svnDir) ) )
    then
    {
        file:create-directory($svnDir);
        fn:trace("", fn:concat("--- Using new ", $svnDir, " directory."));
    }
    else
        if ( fn:not( file:is-directory($svnDir) ) )
        then
        {
            fn:trace("", fn:concat("Error: ", $svnDir, " is not a dir."));
            fn:error(xs:QName("local:ZPERF0001"), fn:concat("Error: ", $svnDir, " is not a dir."));
        }
        else fn:trace("", fn:concat("--- Found ", $svnDir, " directory."));
};

declare %sequential function local:svnCo($svnCmd as xs:string,
    $svnDir as xs:string, $svnRev as xs:integer)
{
    variable $svnCo := fn:concat($svnCmd, " co -r ", $svnRev,
        " http://zorba.svn.sourceforge.net/svnroot/zorba/trunk/zorba ", $svnDir);
    fn:trace($svnCo, "cmd");

    variable $svnCoResult := proc:exec($svnCmd,
        ("co", "-r", xs:string($svnRev),
         "http://zorba.svn.sourceforge.net/svnroot/zorba/trunk/zorba", $svnDir));

    if( $svnCoResult/exit-code eq "0")
    then
        fn:trace( fn:data($svnCoResult/stdout), "--- svn co: ");
    else
    {
        fn:trace( fn:data($svnCoResult/stderr), "ERROR: ");
        fn:error(xs:QName("local:ZPERF0003"), fn:concat("Error svn co: ", fn:data($svnCoResult/stderr)));
    }

    fn:data($svnCoResult/exit-code)
};

declare %sequential function local:makeSvnDir($svnCmd as xs:string,
    $svnDir as xs:string, $svnRev as xs:integer)
{
    if ( file:exists(fn:concat($svnDir, file:directory-separator(), "AUTHORS.txt")) and
         file:exists(fn:concat($svnDir, file:directory-separator(), "src"))  )
    then
        fn:trace("", fn:concat("--- Assuming ", $svnDir, " is the Zorba svn checkout dir."));
    else
        if ( fn:empty(file:list($svnDir)) )
        then
            local:svnCo($svnCmd, $svnDir, $svnRev);
        else
        {
            variable $msg := fn:concat("Error: ", $svnDir, " is not empty and it doesn't contain Zorba.");
            fn:error(xs:QName("local:ZPERF0002"), $msg);
        }
};

declare %sequential function local:update($svnCmd as xs:string,
    $svnDir as xs:string, $svnRev as xs:integer)
{
    fn:trace("", fn:concat("--- Svn update @rev", $svnRev));

    variable $svnUp := fn:concat($svnCmd, " up -r ", $svnRev, " ", $svnDir);
    fn:trace($svnUp, "  - svn up");

    variable $svnUpResult := proc:exec($svnCmd,
        ("up", "-r", xs:string($svnRev), $svnDir));

    if( $svnUpResult/exit-code eq "0")
    then
        fn:trace( fn:data($svnUpResult/stdout), "svn up: ");
    else
    {
        fn:trace( fn:data($svnUpResult/stderr), "ERROR: ");
        fn:trace( $svnUpResult, "svn up: ");
        fn:error(xs:QName("local:ZPERF0004"), fn:concat("Error svn up: ", fn:data($svnUpResult/stderr)));
    }

    fn:trace("", "  - svn info");

    variable $svnInfoResult := proc:exec($svnCmd,
        ("info", "--xml", $svnDir));

    if( $svnInfoResult/exit-code eq "0")
    then
    {
        fn:trace( fn:data($svnInfoResult/stdout), "svn info: ");

        (: need to find the revision date :)
        variable $strOut := fn:data($svnInfoResult/stdout);
        variable $doc := fn:parse-xml($strOut);

        xs:dateTime(fn:data($doc/info/entry/commit/date))
    }
    else
    {
        fn:trace( fn:data($svnInfoResult/stderr), "ERROR: ");
        fn:trace( $svnInfoResult, "svn info: ");
        fn:error(xs:QName("local:ZPERF0004"), fn:concat("Error svn info: ", fn:data($svnInfoResult/stderr)));
    }
};

declare %sequential function local:build( $buildDir as xs:string,
    $clean as xs:boolean, $cmakeCmd as xs:string,
    $makeCmd as xs:string, $makeThreads as xs:int)
{
    fn:trace("", fn:concat("--- Start build clean:", $clean));

    if ($clean)
    then
    {
        variable $res := proc:exec("rm", ("-fR", $buildDir));
        if( $res/exit-code eq "0" )
        then
            fn:trace("", fn:concat("  - rm -fR ", $buildDir) );
        else
        {
            fn:trace($res, fn:concat("ERROR: rm -fR ", $buildDir));
            fn:error(xs:QName("local:ZPERF0005"), fn:concat("Error rm -fR: ", fn:data($res/stderr)));
        }

    }
    else {}

    if ( fn:not(file:exists($buildDir)) )
    then
    {
        variable $res := proc:exec("mkdir", ($buildDir));
        if( $res/exit-code eq "0" )
        then
            fn:trace(fn:data($res/stdout), fn:concat("  - mkdir ", $buildDir) );
        else
        {
            fn:trace($res, fn:concat("ERROR: mkdir", $buildDir));
            fn:error(xs:QName("local:ZPERF0006"), fn:concat("Error mkdir: ", fn:data($res/stderr)));
        }
    }
    else {}

    if ( fn:empty(file:list($buildDir)) )
    then
    {
        fn:trace("---", "--- Starting cmake ... ");
        variable $res := proc:exec("cd", ($buildDir, "&&", $cmakeCmd, ".."));
        if( $res/exit-code eq "0" )
        then
            fn:trace(fn:data($res/stdout), fn:concat("  - cd ", $buildDir, " && cmake ..") );
        else
        {
            fn:trace($res, fn:concat("ERROR: cd ", $buildDir, " && cmake .."));
            fn:error(xs:QName("local:ZPERF0007"), fn:concat("Error cd ", $buildDir, " && cmake ..: ", fn:data($res/stderr)));
        }
    }
    else {}

    fn:trace("---", "--- Starting make ... ");
    variable $res := proc:exec("cd", ($buildDir, "&&", $makeCmd, "-j", fn:string($makeThreads)));
    if( $res/exit-code eq "0" )
    then
        fn:trace(fn:data($res/stdout), fn:concat("  - cd ", $buildDir, " && make") );
    else
    {
        fn:trace($res, fn:concat("ERROR: cd ", $buildDir, " && make"));
        fn:error(xs:QName("local:ZPERF0008"), fn:concat("Error cd ", $buildDir, " && make : ", fn:data($res/stderr)));
    }

    fn:trace("---", " - ls");
    $res := proc:exec("ls", ($buildDir));
    if( $res/exit-code eq "0" )
    then
        fn:trace(fn:data($res/stdout), fn:concat("ls ", $buildDir) );
    else
    {
        fn:trace($res, fn:concat("ERROR: ls ", $buildDir));
        fn:error(xs:QName("local:ZPERF0009"), fn:concat("Error ls: ", fn:data($res/stderr)));
    }
};

declare %sequential function local:runAllTests($zorbaCmd as xs:string, $xmarkDir as xs:string,
    $initialNoOfRuns as xs:int, $revision as xs:integer, $revDate as xs:dateTime, $inputCtx as xs:string)
{
    <rez rev="{$revision}" revDate="{$revDate}">
        <pdash:suite id="{fn:concat("xmark-", $inputCtx, "-", $initialNoOfRuns, "x")}">
        {
            local:runTests($zorbaCmd, $xmarkDir, $initialNoOfRuns, $inputCtx)
        }
        </pdash:suite>
    </rez>
};

declare %sequential function local:runTests($zorbaCmd as xs:string, $xmarkDir as xs:string,
    $initialNoOfRuns as xs:int, $inputCtx as xs:string)
{
    fn:trace("---", "--- Running xmark tests ... ");

    for $i in 1 to 20
    return
    {
        variable $testFile := fn:concat($xmarkDir, file:directory-separator(), "q", $i, ".xq");
        fn:trace($testFile, "test file");

        variable $res := proc:exec($zorbaCmd, ("-m", xs:string($initialNoOfRuns), "-e", $inputCtx,
            "-t", "-f", "-q", $testFile));

        if( $res/exit-code eq "0" )
        then
        {
            fn:trace(fn:data($res/stdout), fn:concat("zorba ", $testFile));

            variable $t;
            try
            {
                $t := tims:parseTimings(fn:data($res/stdout));
            }
            catch * ($ecode, $desc)
            {
                fn:trace("", fn:concat("  - Test q", $i, " failed, skip submiting it: ", $ecode, "  ", $desc ));
                exit returning ();
            }

            fn:trace($t, fn:concat("--- Results for q", $i));

            <pdash:test id="{fn:concat("q", $i)}" iterations="{$initialNoOfRuns}">
            {
                $t,
                <extra>{$inputCtx}</extra>
            }
            </pdash:test>
        }
        else
        {
            fn:trace($res, fn:concat("ERROR: zorba ", $testFile));
            fn:error(xs:QName("local:ZPERF0010"), fn:concat("Error zorba ", $testFile, " : ", fn:data($res/stderr)));
        }
    }
};

declare %sequential function local:publishResults($allResults, $platform, $buildName as xs:string)
{
    fn:trace(fn:count($allResults), "--- Publish results ...");

    for $rez in $allResults
    return
    {
        variable $msg := local:makeMessage($rez/pdash:suite, $platform, fn:data($rez/@rev),
            fn:data($rez/@revDate), $buildName);

        local:submitMessage($msg);
    }
};

declare %sequential function local:makeMessage($suite, $platform, $revision as xs:string,
    $revDate as xs:string, $buildName as xs:string)
{
    fn:trace("", "  - makeMessage");

    <pdash:submission build-id="{$buildName}" revision-number="{$revision}"
                      date="{$revDate}" id="zorba-xmark-test1">
    {
        (
            $platform,
            $suite
        )
    }
    </pdash:submission>
};

declare %sequential function local:submitMessage($msg)
{
    fn:trace(fn:serialize($msg), "  - submitMessage");

    variable $url:="http://pdash-zorba.my28msec.com/api/submissions";

    fn:trace(fn:serialize(
        http:send-request(
          <http:request method="post" href="{$url}">
            <http:body media-type="application/xml">
              {$msg}
            </http:body>
          </http:request>)),
          "  - submitResponse")
};

let $svnDir := "svndir"
let $buildDir := fn:concat($svnDir, file:directory-separator(),"build")
let $xmarkDir := fn:concat($svnDir, file:directory-separator(),
                    "test", file:directory-separator(),
                    "rbkt", file:directory-separator(),
                    "Queries", file:directory-separator(),
                    "zorba", file:directory-separator(),
                    "xmark"
                 )
let $svnCmd := "/usr/bin/svn"
let $cmakeCmd := "/usr/bin/cmake"
let $zorbaCmd := fn:concat($buildDir, file:directory-separator(),"bin", file:directory-separator(),"zorba")
let $makeCmd := xs:string("/usr/bin/make")
let $svnRevs := (8625, 8709, 8852, 9023, 9252, 9496, 9745, 9938, 10069, 10237,
                10431, 10742, 10766)
let $buildName := "ztest"
let $initialNoOfRuns := xs:int(100)
let $inputCtx := "input-context:=auction.xml"
let $platform := local:getPlatform()
return
{
    fn:trace(fn:current-dateTime(), "----- Starting time");

    local:makeDir($svnDir);
    local:makeSvnDir($svnCmd, $svnDir, $svnRevs[1]);

    for $i in ($svnRevs)
    return
    {
        variable $revDate as xs:dateTime := local:update($svnCmd, $svnDir, $i);
        local:build($buildDir, fn:false(), $cmakeCmd, $makeCmd, $platform/@number-of-logical-cpu);

        variable $res := local:runAllTests($zorbaCmd, $xmarkDir, $initialNoOfRuns, $i, $revDate, $inputCtx);
        local:publishResults($res, $platform, $buildName);
    }

    fn:trace(fn:current-dateTime(), "----- Ending time");

    "Done."
}

(: XQuery main module :)

import module namespace file="http://expath.org/ns/file";
import module namespace proc="http://www.zorba-xquery.com/modules/process";
import module namespace tims="http://www.example.com/timings" at "timings.xq";
import module namespace sys ="http://www.zorba-xquery.com/modules/system";
import module namespace http="http://expath.org/ns/http-client";

declare namespace pdash = "http://www.28msec.com/pdash";

(:
(
    sys:property($sys:os-name),
    sys:property($sys:os-node-name),
    sys:property($sys:os-version),
    sys:property($sys:os-version-build),
    sys:property($sys:os-version-major),
    sys:property($sys:os-version-minor),
    sys:property($sys:os-version-release),
    sys:property($sys:os-version-version),
    sys:property($sys:linux-distributor),
    sys:property($sys:linux-distributor-version),
    sys:property($sys:user-name),
    sys:property($sys:os-arch),
    sys:property($sys:zorba-module-path),
    sys:property($sys:zorba-version),
    sys:property($sys:zorba-version-major),
    sys:property($sys:zorba-version-minor),
    sys:property($sys:zorba-version-patch)
)
:)

declare %sequential function local:getPlatform()
{
    <pdash:platform site-osname="Ubuntu" os-version="11.04" os-platform="Linux"
        hostname="28msec.dyndns.org" is-64bits="true" vendor-id="Cezar" vendor-label="i7"
        number-of-logical-cpu="{xs:int(12)}" number-of-physical-cpu="1"
        total-virtual-memory="6117504000" total-physical-memory="0"
        number-of-logical-cpu-per-physical-cpu="12"/>
};

declare %sequential function local:makeDir($svnDir as xs:string)
{
    if( fn:not( file:exists($svnDir) ) )
    then
    {
        file:create-directory($svnDir);
        fn:trace("", fn:concat("--- Using new ", $svnDir, " directory."));
    }
    else
        if ( fn:not( file:is-directory($svnDir) ) )
        then
        {
            fn:trace("", fn:concat("Error: ", $svnDir, " is not a dir."));
            fn:error(xs:QName("local:ZPERF0001"), fn:concat("Error: ", $svnDir, " is not a dir."));
        }
        else fn:trace("", fn:concat("--- Found ", $svnDir, " directory."));
};

declare %sequential function local:svnCo($svnCmd as xs:string,
    $svnDir as xs:string, $svnRev as xs:integer)
{
    variable $svnCo := fn:concat($svnCmd, " co -r ", $svnRev,
        " http://zorba.svn.sourceforge.net/svnroot/zorba/trunk/zorba ", $svnDir);
    fn:trace($svnCo, "cmd");

    variable $svnCoResult := proc:exec($svnCmd,
        ("co", "-r", xs:string($svnRev),
         "http://zorba.svn.sourceforge.net/svnroot/zorba/trunk/zorba", $svnDir));

    if( $svnCoResult/exit-code eq "0")
    then
        fn:trace( fn:data($svnCoResult/stdout), "--- svn co: ");
    else
    {
        fn:trace( fn:data($svnCoResult/stderr), "ERROR: ");
        fn:error(xs:QName("local:ZPERF0003"), fn:concat("Error svn co: ", fn:data($svnCoResult/stderr)));
    }

    fn:data($svnCoResult/exit-code)
};

declare %sequential function local:makeSvnDir($svnCmd as xs:string,
    $svnDir as xs:string, $svnRevs as xs:integer+)
{
    if ( file:exists(fn:concat($svnDir, file:directory-separator(), "AUTHORS.txt")) and
         file:exists(fn:concat($svnDir, file:directory-separator(), "src"))  )
    then
        fn:trace("", fn:concat("--- Assuming ", $svnDir, " is the Zorba svn checkout dir."));
    else
        if ( fn:empty(file:list($svnDir)) )
        then
            local:svnCo($svnCmd, $svnDir, $svnRevs);
        else
        {
            variable $msg := fn:concat("Error: ", $svnDir, " is not empty and it doesn't contain Zorba.");
            fn:error(xs:QName("local:ZPERF0002"), $msg);
        }
};

declare %sequential function local:update($svnCmd as xs:string,
    $svnDir as xs:string, $svnRev as xs:integer)
{
    fn:trace("", fn:concat("--- Svn update @rev", $svnRev));

    variable $svnUp := fn:concat($svnCmd, " up -r ", $svnRev, " ", $svnDir);
    fn:trace($svnUp, "  - svn up");

    variable $svnUpResult := proc:exec($svnCmd,
        ("up", "-r", xs:string($svnRev), $svnDir));

    if( $svnUpResult/exit-code eq "0")
    then
        fn:trace( fn:data($svnUpResult/stdout), "svn up: ");
    else
    {
        fn:trace( fn:data($svnUpResult/stderr), "ERROR: ");
        fn:trace( $svnUpResult, "svn up: ");
        fn:error(xs:QName("local:ZPERF0004"), fn:concat("Error svn up: ", fn:data($svnUpResult/stderr)));
    }

    fn:trace("", "  - svn info");

    variable $svnInfoResult := proc:exec($svnCmd,
        ("info", "--xml", $svnDir));

    if( $svnInfoResult/exit-code eq "0")
    then
    {
        fn:trace( fn:data($svnInfoResult/stdout), "svn info: ");

        (: need to find the revision date :)
        variable $strOut := fn:data($svnInfoResult/stdout);
        variable $doc := fn:parse-xml($strOut);

        xs:dateTime(fn:data($doc/info/entry/commit/date))
    }
    else
    {
        fn:trace( fn:data($svnInfoResult/stderr), "ERROR: ");
        fn:trace( $svnInfoResult, "svn info: ");
        fn:error(xs:QName("local:ZPERF0004"), fn:concat("Error svn info: ", fn:data($svnInfoResult/stderr)));
    }
};

declare %sequential function local:build( $buildDir as xs:string,
    $clean as xs:boolean, $cmakeCmd as xs:string,
    $makeCmd as xs:string, $makeThreads as xs:int)
{
    fn:trace("", fn:concat("--- Start build clean:", $clean));

    if ($clean)
    then
    {
        variable $res := proc:exec("rm", ("-fR", $buildDir));
        if( $res/exit-code eq "0" )
        then
            fn:trace("", fn:concat("  - rm -fR ", $buildDir) );
        else
        {
            fn:trace($res, fn:concat("ERROR: rm -fR ", $buildDir));
            fn:error(xs:QName("local:ZPERF0005"), fn:concat("Error rm -fR: ", fn:data($res/stderr)));
        }

    }
    else {}

    if ( fn:not(file:exists($buildDir)) )
    then
    {
        variable $res := proc:exec("mkdir", ($buildDir));
        if( $res/exit-code eq "0" )
        then
            fn:trace(fn:data($res/stdout), fn:concat("  - mkdir ", $buildDir) );
        else
        {
            fn:trace($res, fn:concat("ERROR: mkdir", $buildDir));
            fn:error(xs:QName("local:ZPERF0006"), fn:concat("Error mkdir: ", fn:data($res/stderr)));
        }
    }
    else {}

    if ( fn:empty(file:list($buildDir)) )
    then
    {
        fn:trace("---", "--- Starting cmake ... ");
        variable $res := proc:exec("cd", ($buildDir, "&&", $cmakeCmd, ".."));
        if( $res/exit-code eq "0" )
        then
            fn:trace(fn:data($res/stdout), fn:concat("  - cd ", $buildDir, " && cmake ..") );
        else
        {
            fn:trace($res, fn:concat("ERROR: cd ", $buildDir, " && cmake .."));
            fn:error(xs:QName("local:ZPERF0007"), fn:concat("Error cd ", $buildDir, " && cmake ..: ", fn:data($res/stderr)));
        }
    }
    else {}

    fn:trace("---", "--- Starting make ... ");
    variable $res := proc:exec("cd", ($buildDir, "&&", $makeCmd, "-j", fn:string($makeThreads)));
    if( $res/exit-code eq "0" )
    then
        fn:trace(fn:data($res/stdout), fn:concat("  - cd ", $buildDir, " && make") );
    else
    {
        fn:trace($res, fn:concat("ERROR: cd ", $buildDir, " && make"));
        fn:error(xs:QName("local:ZPERF0008"), fn:concat("Error cd ", $buildDir, " && make : ", fn:data($res/stderr)));
    }

    fn:trace("---", " - ls");
    $res := proc:exec("ls", ($buildDir));
    if( $res/exit-code eq "0" )
    then
        fn:trace(fn:data($res/stdout), fn:concat("ls ", $buildDir) );
    else
    {
        fn:trace($res, fn:concat("ERROR: ls ", $buildDir));
        fn:error(xs:QName("local:ZPERF0009"), fn:concat("Error ls: ", fn:data($res/stderr)));
    }
};

declare %sequential function local:runAllTests($zorbaCmd as xs:string, $xmarkDir as xs:string,
    $initialNoOfRuns as xs:int, $revision as xs:integer, $revDate as xs:dateTime, $inputCtx as xs:string)
{
    <rez rev="{$revision}" revDate="{$revDate}">
        <pdash:suite id="{fn:concat("xmark-", $inputCtx, "-", $initialNoOfRuns, "x")}">
        {
            local:runTests($zorbaCmd, $xmarkDir, $initialNoOfRuns, $inputCtx)
        }
        </pdash:suite>
    </rez>
};

declare %sequential function local:runTests($zorbaCmd as xs:string, $xmarkDir as xs:string,
    $initialNoOfRuns as xs:int, $inputCtx as xs:string)
{
    fn:trace("---", "--- Running xmark tests ... ");

    for $i in 1 to 20
    return
    {
        variable $testFile := fn:concat($xmarkDir, file:directory-separator(), "q", $i, ".xq");
        fn:trace($testFile, "test file");

        variable $res := proc:exec($zorbaCmd, ("-m", xs:string($initialNoOfRuns), "-e", $inputCtx,
            "-t", "-f", "-q", $testFile));

        if( $res/exit-code eq "0" )
        then
        {
            fn:trace(fn:data($res/stdout), fn:concat("zorba ", $testFile));

            variable $t;
            try
            {
                $t := tims:parseTimings(fn:data($res/stdout));
            }
            catch * ($ecode, $desc)
            {
                fn:trace("", fn:concat("  - Test q", $i, " failed, skip submiting it: ", $ecode, "  ", $desc ));
                exit returning ();
            }

            fn:trace($t, fn:concat("--- Results for q", $i));

            <pdash:test id="{fn:concat("q", $i)}" iterations="{$initialNoOfRuns}">
            {
                $t,
                <extra>{$inputCtx}</extra>
            }
            </pdash:test>
        }
        else
        {
            fn:trace($res, fn:concat("ERROR: zorba ", $testFile));
            fn:error(xs:QName("local:ZPERF0010"), fn:concat("Error zorba ", $testFile, " : ", fn:data($res/stderr)));
        }
    }
};

declare %sequential function local:publishResults($allResults, $platform, $buildName as xs:string)
{
    fn:trace(fn:count($allResults), "--- Publish results ...");

    for $rez in $allResults
    return
    {
        variable $msg := local:makeMessage($rez/pdash:suite, $platform, fn:data($rez/@rev),
            fn:data($rez/@revDate), $buildName);

        local:submitMessage($msg);
    }
};

declare %sequential function local:makeMessage($suite, $platform, $revision as xs:string,
    $revDate as xs:string, $buildName as xs:string)
{
    fn:trace("", "  - makeMessage");

    <pdash:submission build-id="{$buildName}" revision-number="{$revision}"
                      date="{$revDate}" id="zorba-xmark-test1">
    {
        (
            $platform,
            $suite
        )
    }
    </pdash:submission>
};

declare %sequential function local:submitMessage($msg)
{
    fn:trace(fn:serialize($msg), "  - submitMessage");

    variable $url:="http://pdash-zorba.my28msec.com/api/submissions";

    fn:trace(fn:serialize(
        http:send-request(
          <http:request method="post" href="{$url}">
            <http:body media-type="application/xml">
              {$msg}
            </http:body>
          </http:request>)),
          "  - submitResponse")
};

let $svnDir := "svndir"
let $buildDir := fn:concat($svnDir, file:directory-separator(),"build")
let $xmarkDir := fn:concat($svnDir, file:directory-separator(),
                    "test", file:directory-separator(),
                    "rbkt", file:directory-separator(),
                    "Queries", file:directory-separator(),
                    "zorba", file:directory-separator(),
                    "xmark"
                 )
let $svnCmd := "/usr/bin/svn"
let $cmakeCmd := "/usr/bin/cmake"
let $zorbaCmd := fn:concat($buildDir, file:directory-separator(),"bin", file:directory-separator(),"zorba")
let $makeCmd := xs:string("/usr/bin/make")
let $svnRevs := (8625, 8709, 8852, 9023, 9252, 9496, 9745, 9938, 10069, 10237,
                10431, 10742, 10766)
let $buildName := "zorba3"
let $initialNoOfRuns := xs:int(100)
let $inputCtx := "input-context:=auction.xml"
let $platform := local:getPlatform()
return
{
    fn:trace(fn:current-dateTime(), "----- Starting time");

    local:makeDir($svnDir);
    local:makeSvnDir($svnCmd, $svnDir, $svnRevs);

    for $i in ($svnRevs)
    return
    {
        variable $revDate as xs:dateTime := local:update($svnCmd, $svnDir, $i);
        local:build($buildDir, fn:false(), $cmakeCmd, $makeCmd, $platform/@number-of-logical-cpu);

        variable $res := local:runAllTests($zorbaCmd, $xmarkDir, $initialNoOfRuns, $i, $revDate, $inputCtx);
        local:publishResults($res, $platform, $buildName);
    }

    fn:trace(fn:current-dateTime(), "----- Ending time");

    "Done."
}


descendant::* returns all descendants and in this case only the children are needed.

(:
 : 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 feedback
 : @author Sorin Nasoi
 :)

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

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

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

declare namespace err =
  "http://www.w3.org/2005/xqt-errors";

declare function feedback:check-pass(
  $result           as item()*,
  $testCaseName     as xs:string?,
  $testSetName      as xs:string?,
  $expectedFailure  as element(Test)?
) as xs:boolean
{
(: if the exact error code was not found, report the test as 'Pass'
   with an attribute correctError=false :)
  let $resultTestRun as xs:boolean :=
    (empty($result) or
     (exists($result) and
      contains(string-join($result/fots:errors,''), "Expected error:") and
      contains(string-join($result/fots:errors,''), "Found error:")))

  let $expectedFailure as xs:boolean :=
    if (exists($expectedFailure))
    then fn:true()
    else fn:false()

(:if test PASSED and was expected to FAIL OR test FAILED and wasn't expected to
  FAIL => report as FAIL, a.k.a. regression;
  otherwise report as PASS:)
  return ($resultTestRun eq not($expectedFailure))
};

declare %ann:sequential function feedback:pass(
  $case             as element(fots:test-case),
  $result           as item()*,
  $zorbaQuery       as xs:string,
  $env              as element(fots:environment)?,
  $duration         as xs:dayTimeDuration,
  $verbose          as xs:boolean,
  $expectedFailure  as xs:boolean
) as element(fots:test-case)?
{
  if ($expectedFailure)
  then feedback:pass-expected-FOTS-failure( $case,
                                            $result,
                                            $zorbaQuery,
                                            $env,
                                            $verbose)
  else feedback:pass( $case,
                      $result,
                      $zorbaQuery,
                      $env,
                      $duration,
                      $verbose)
};

(:~
 : Feedback on a test case that failed but is marked as EXPECTED_FOTS_FAILURE.
 :
 : @param $case test case.
 : @return the test case after certain information was added.
 :)
declare  %private %ann:sequential function feedback:pass-expected-FOTS-failure(
  $case             as element(fots:test-case),
  $result           as item()*,
  $zorbaQuery       as xs:string,
  $env              as element(fots:environment)?,
  $verbose          as xs:boolean
) as element(fots:test-case)?
{
  variable $info := 'Test case failed but it is marked with EXPECTED_FOTS_FAILURE in test/fots/CMakeLists.txt';
  variable $status := 'pass';

  if ($verbose)
  then
  {
    {
      (insert node attribute result{$status} as last into $case,
       insert node attribute comment{$info} as last into $case,
       insert node
         <fots:info>
           {$env}
           <fots:query>{$zorbaQuery}</fots:query>
           {$result/fots:expected-result,
            $result/fots:result,
            $result/fots:errors}
         </fots:info>
      as last into $case,
      delete node $case/fots:description,
      delete node $case/fots:created,
      delete node $case/fots:result);

      $case
    }
  }
  else <fots:test-case  name="{data($case/@name)}"
                        result="{$status}"
                        comment="{$info}" />
};

(:~
 : 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 feedback:pass(
  $case             as element(fots:test-case),
  $result           as item()*,
  $zorbaQuery       as xs:string,
  $env              as element(fots:environment)?,
  $duration         as xs:dayTimeDuration,
  $verbose          as xs:boolean
) as element(fots:test-case)?
{
  let $status := if(exists($result/fots:errors))
                 then 'wrongError'
                 else 'pass'
  return
  if ($verbose)
  then
  {
    {
      (insert node attribute result{$status} as last into $case,
       if (exists($result/fots:errors))
       then
         insert node
         attribute comment{$result/fots:errors}
         as last into $case
       else (),
       insert node attribute executionTime{$duration} as last into $case,
       insert node
        <fots:info>
          {$env}
          <fots:query>{$zorbaQuery}</fots:query>
          {$result/fots:expected-result,
            $result/fots:result,
            $result/fots:errors}
        </fots:info>
      as last into $case,
      delete node $case/fots:description,
      delete node $case/fots:created,
      delete node $case/fots:result);

      $case
    }
  }
  else <fots:test-case  name="{data($case/@name)}"
                        result="{$status}"
                        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 %ann:sequential function feedback: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,
  $expectedFailure  as xs:boolean
) as element(fots:test-case)?
{
  trace($testSetName, "test set name");
  trace("above test case failed", "result");

  variable $info := 'Test case passed but it is marked with EXPECTED_FOTS_FAILURE in test/fots/CMakeLists.txt';
  variable $status := 'fail';

  if ($verbose)
  then
  {
    {
      (insert node attribute result{$status} as last into $case,
       if ($expectedFailure)
       then insert node attribute comment{$info} as last into $case
       else (),
       insert node
         <fots:info>
           {$env}
           <fots:query>{$zorbaQuery}</fots:query>
           {$result/fots:expected-result,
            $result/fots:result,
            $result/fots:errors}
         </fots:info>
       as last into $case,
       delete node $case/fots:description,
       delete node $case/fots:created,
       delete node $case/fots:result);

       $case
    }
  }
  else if ($expectedFailure)
  then <fots:test-case name="{data($case/@name)}"
                       result="{$status}"
                       comment="{$info}"
                       executionTime="{$duration}"/>

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

(:~
 : Gives feedback on a test case that is not run (because its name is listed
 : in the $exceptedTestCases global var).
 :
 : @param $case test case.
 : @return the test case.
 :)
declare %ann:sequential function feedback:not-run(
  $case     as element(fots:test-case),
  $verbose  as xs:boolean
) as element(fots:test-case)?
{
  trace(data($case/@name), "processing test case :");
  trace("Above test case was not run.","");

  let $status := 'notRun'
  return
  if ($verbose)
  then
  {
    {
      (insert node attribute result {$status} as last into $case,
       delete node $case/fots:description,
       delete node $case/fots:created);

      $case
    }
  }
  else
  {
    <fots:test-case name="{$case/@name}"
                    result="{$status}" />
  }
};

(:~
 : 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 %ann:sequential function feedback: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 :");

  let $status := 'n/a'
  return
  if ($verbose)
  then
  {
   {
    (insert node attribute result{$status} as last into $case,
     insert node attribute comment{$dependencyError} as last into $case,
     insert node
       <fots:info>{$env}</fots:info>
     as last into $case,
     delete node $case/fots:description,
     delete node $case/fots:created);

    $case
   }
  }
  else
    <fots:test-case name="{data($case/@name)}"
                    result="{$status}"
                    comment="{$dependencyError}" />
};

(:
 : 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 feedback
 : @author Sorin Nasoi
 :)

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

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

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

declare namespace err =
  "http://www.w3.org/2005/xqt-errors";

declare function feedback:check-pass(
  $result           as item()*,
  $testCaseName     as xs:string?,
  $testSetName      as xs:string?,
  $expectedFailure  as element(Test)?
) as xs:boolean
{
(: if the exact error code was not found, report the test as 'Pass'
   with an attribute correctError=false :)
  let $resultTestRun as xs:boolean :=
    (empty($result) or
     (exists($result) and
      contains(string-join($result/fots:errors,''), "Expected error:") and
      contains(string-join($result/fots:errors,''), "Found error:")))

  let $expectedFailure as xs:boolean :=
    if (exists($expectedFailure))
    then fn:true()
    else fn:false()

(:if test PASSED and was expected to FAIL OR test FAILED and wasn't expected to
  FAIL => report as FAIL, a.k.a. regression;
  otherwise report as PASS:)
  return ($resultTestRun eq not($expectedFailure))
};

declare %ann:sequential function feedback:pass(
  $case             as element(fots:test-case),
  $result           as item()*,
  $zorbaQuery       as xs:string,
  $env              as element(fots:environment)?,
  $duration         as xs:dayTimeDuration,
  $verbose          as xs:boolean,
  $expectedFailure  as xs:boolean
) as element(fots:test-case)?
{
  if ($expectedFailure)
  then feedback:pass-expected-FOTS-failure( $case,
                                            $result,
                                            $zorbaQuery,
                                            $env,
                                            $verbose)
  else feedback:pass( $case,
                      $result,
                      $zorbaQuery,
                      $env,
                      $duration,
                      $verbose)
};

(:~
 : Feedback on a test case that failed but is marked as EXPECTED_FOTS_FAILURE.
 :
 : @param $case test case.
 : @return the test case after certain information was added.
 :)
declare  %private %ann:sequential function feedback:pass-expected-FOTS-failure(
  $case             as element(fots:test-case),
  $result           as item()*,
  $zorbaQuery       as xs:string,
  $env              as element(fots:environment)?,
  $verbose          as xs:boolean
) as element(fots:test-case)?
{
  variable $info := 'Test case failed but it is marked with EXPECTED_FOTS_FAILURE in test/fots/CMakeLists.txt';
  variable $status := 'pass';

  if ($verbose)
  then
  {
    {
      (insert node attribute result{$status} as last into $case,
       insert node attribute comment{$info} as last into $case,
       insert node
         <fots:info>
           {$env}
           <fots:query>{$zorbaQuery}</fots:query>
           {$result/descendant::*}
         </fots:info>
      as last into $case,
      delete node $case/fots:description,
      delete node $case/fots:created,
      delete node $case/fots:result);

      $case
    }
  }
  else <fots:test-case  name="{data($case/@name)}"
                        result="{$status}"
                        comment="{$info}" />
};

(:~
 : 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 feedback:pass(
  $case             as element(fots:test-case),
  $result           as item()*,
  $zorbaQuery       as xs:string,
  $env              as element(fots:environment)?,
  $duration         as xs:dayTimeDuration,
  $verbose          as xs:boolean
) as element(fots:test-case)?
{
  let $status := if(exists($result/fots:errors))
                 then 'wrongError'
                 else 'pass'
  return
  if ($verbose)
  then
  {
    {
      (insert node attribute result{$status} as last into $case,
       if (exists($result/fots:errors))
       then
         insert node
         attribute comment{$result/fots:errors}
         as last into $case
       else (),
       insert node attribute executionTime{$duration} as last into $case,
       insert node
        <fots:info>
          {$env}
          <fots:query>{$zorbaQuery}</fots:query>
          {$result/descendant::*}
        </fots:info>
      as last into $case,
      delete node $case/fots:description,
      delete node $case/fots:created,
      delete node $case/fots:result);

      $case
    }
  }
  else <fots:test-case  name="{data($case/@name)}"
                        result="{$status}"
                        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 %ann:sequential function feedback: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,
  $expectedFailure  as xs:boolean
) as element(fots:test-case)?
{
  trace($testSetName, "test set name");
  trace("above test case failed", "result");

  variable $info := 'Test case passed but it is marked with EXPECTED_FOTS_FAILURE in test/fots/CMakeLists.txt';
  variable $status := 'fail';

  if ($verbose)
  then
  {
    {
      (insert node attribute result{$status} as last into $case,
       if ($expectedFailure)
       then insert node attribute comment{$info} as last into $case
       else (),
       insert node
         <fots:info>
           {$env}
           <fots:query>{$zorbaQuery}</fots:query>
           {$result/descendant::*}
         </fots:info>
       as last into $case,
       delete node $case/fots:description,
       delete node $case/fots:created,
       delete node $case/fots:result);

       $case
    }
  }
  else if ($expectedFailure)
  then <fots:test-case name="{data($case/@name)}"
                       result="{$status}"
                       comment="{$info}"
                       executionTime="{$duration}"/>

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

(:~
 : Gives feedback on a test case that is not run (because its name is listed
 : in the $exceptedTestCases global var).
 :
 : @param $case test case.
 : @return the test case.
 :)
declare %ann:sequential function feedback:not-run(
  $case     as element(fots:test-case),
  $verbose  as xs:boolean
) as element(fots:test-case)?
{
  trace(data($case/@name), "processing test case :");
  trace("Above test case was not run.","");

  let $status := 'notRun'
  return
  if ($verbose)
  then
  {
    {
      (insert node attribute result {$status} as last into $case,
       delete node $case/fots:description,
       delete node $case/fots:created);

      $case
    }
  }
  else
  {
    <fots:test-case name="{$case/@name}"
                    result="{$status}" />
  }
};

(:~
 : 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 %ann:sequential function feedback: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 :");

  let $status := 'n/a'
  return
  if ($verbose)
  then
  {
   {
    (insert node attribute result{$status} as last into $case,
     insert node attribute comment{$dependencyError} as last into $case,
     insert node
       <fots:info>{$env}</fots:info>
     as last into $case,
     delete node $case/fots:description,
     delete node $case/fots:created);

    $case
   }
  }
  else
    <fots:test-case name="{data($case/@name)}"
                    result="{$status}"
                    comment="{$dependencyError}" />
};