Added a second ordering for the Wiki reports.

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

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

import module namespace file =
  "http://expath.org/ns/file";

import module namespace driver =
  "http://www.zorba-xquery.com/fots-driver" at "fots-driver.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";
import module namespace functx =
  "http://www.functx.com/";

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

declare default element namespace
  "http://www.w3.org/2012/08/qt-fots-results";

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

declare namespace op = "http://www.zorba-xquery.com/options/features";
declare namespace f = "http://www.zorba-xquery.com/features";
declare option op:disable "f:trace";

(:~
 : Loops through the test-sets, executes them and reports results.
 : @param $FOTSCatalogFilePath path to the FOTS catalog file.
 : @param $FOTSZorbaManifestPath path to the FOTS Zorba manifest file.
 : @param $exceptedTestCases lists of test cases that are not run( empty
 : sequence means all test cases will be run).
 : @param $exceptedTestSets lists of test sets that are not run(empty sequence
 : means all test sets will be run).
 : @return a report of tests that were executed.
 :)
declare %ann:sequential function reporting:run-and-report(
  $FOTSCatalogFilePath    as xs:string,
  $FOTSZorbaManifestPath  as xs:string,
  $exceptedTestCases      as xs:string*,
  $exceptedTestSets       as xs:string*
) as document-node()
{
  try
  {
    {
      variable $FOTSCatalog := doc(trace(resolve-uri($FOTSCatalogFilePath),
                                  "Path to FOTS catalog.xml set to: "));

      variable $catalogBaseURI := resolve-uri(util:parent-folder($FOTSCatalogFilePath));

      variable $FOTSZorbaManifest := doc(trace(resolve-uri($FOTSZorbaManifestPath),
                                        "Path to FOTSZorbaManifest set to:"));

      variable $results := driver:run-fots($FOTSCatalogFilePath,
                                           $FOTSZorbaManifestPath,
                                           (),
                                           $exceptedTestSets,
                                           (),
                                           $exceptedTestCases,
                                           '',
                                           (),
                                           fn:false(),
                                           '',
                                           'run-test-sets');

      file:write("results.xml",
                 $results,
                 $util:writeXML);

      reporting:W3C-reporting($results,
                              $FOTSZorbaManifestPath)
    }
  }
  catch err:FODC0002
  {
    error($err:code,
          $err:description,
          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 test sets, executes them and reports results.
 : @param $FOTSZorbaManifestPath path to the FOTS Zorba manifest file.
 : @param $resultsFilePath path to the FOTS results file.
 : @return The W3C conformance submission file.
 :)
declare %ann:sequential function reporting:report(
  $FOTSZorbaManifestPath  as xs:string,
  $resultsFilePath        as xs:string
) as document-node()
{
  try
  {
    {
      reporting:W3C-reporting(parse-xml(file:read-text($resultsFilePath))/fots:test-cases,
                              $FOTSZorbaManifestPath)
    }
  }
  catch *
  {
    error($err:code, $err:description)
  }
};

(:~
 : Format the W3C conformance report.
 : @param $results FOTS results file.
 : @param $FOTSZorbaManifestPath  path to the FOTS Zorba manifest file.
 : @return The W3C conformance submission file.
 :)
declare %ann:sequential function reporting:W3C-reporting(
  $results                as element(fots:test-cases)?,
  $FOTSZorbaManifestPath  as xs:string
) as document-node()
{
  try
  {
    {
      if (not(file:is-file(resolve-uri($FOTSZorbaManifestPath))))
      then
      {
        error($fots-err:errNA,
              "The 'FOTSZorbaManifest.xml' was not found.");
      }
      else ();

      variable $FOTSZorbaManifest := parse-xml(file:read-text(resolve-uri($FOTSZorbaManifestPath)));

      variable $CLIBaseURI := resolve-uri(util:parent-folder($FOTSZorbaManifestPath));

      variable $W3CTemplatePath := resolve-uri("W3C_submission_template.xml", $CLIBaseURI);

      if (not(file:is-file($W3CTemplatePath)))
      then
      {
        error($fots-err:errNA,
              "'W3C_submission_template.xml' file was not found.");
      }
      else ();

      variable $W3CTemplate := parse-xml(file:read-text($W3CTemplatePath));

      (: add dependecies:)
     (insert nodes
      for $dependency in $FOTSZorbaManifest/fots:test-suite-result/fots:dependency
      return <dependency type="{$dependency/@type}"
                         value="{$dependency/@value}"
                         satisfied="{$dependency/@satisfied}"/>
      as last into $W3CTemplate/results:test-suite-result/results:product,

      (: add test set results:)
      insert nodes
      for $testSet in $results/fots:test-set
      return
      <test-set name="{$testSet/@name}">
        {
          for $testCase in $testSet/fots:test-case
          return
          if(exists($testCase/@comment))
          then
            <test-case name="{$testCase/@name}"
                       result="{$testCase/@result}"
                       comment="{$testCase/@comment}" />
          else
            <test-case name="{$testCase/@name}"
                       result="{$testCase/@result}" />
        }
      </test-set>
      as last into $W3CTemplate/results:test-suite-result);

      $W3CTemplate
    }
  }
  catch err:FODC0002
  {
    error($err:code,
          $err:description,
          concat("
Please make sure there is a 'W3C_submission_template.xml'",
                 " file in the same folder as cli.xq"))
  }
};

(:~
 : Loops through the test-sets and creates statistics.
 : @param $FOTSCatalogFilePath  Path to the FOTS catalog file.
 : @param $failures Path to the results fo the FOTS.
 : @return a report of tests run.
 :)
declare %ann:nondeterministic function reporting:wiki-report(
  $FOTSCatalogFilePath  as xs:string,
  $resultsFilePath      as xs:string
) as element(fots:report)
{
try
{
  {
    variable $FOTSCatalog := doc(trace(resolve-uri($FOTSCatalogFilePath),
                                "Path to FOTS catalog.xml set to: "));

    variable $catalogBaseURI := resolve-uri(util:parent-folder($FOTSCatalogFilePath));

    variable $results := parse-xml(file:read-text($resultsFilePath));

  <fots:report>
  {
    let $totalNoTests := count($results//fots:test-set//fots:test-case),
        $totalPass := sum(for $testSet in $results//fots:test-set
                          return count($testSet//fots:test-case[@result ='pass'])),
        $totalFail := sum(for $testSet in $results//fots:test-set
                          return count($testSet//fots:test-case[@result ='fail'])),
        $totalNotApplicable := sum(for $testSet in $results//fots:test-set
                                   return count($testSet//fots:test-case[@result ='n/a'])),
        $totalNotRun := sum(for $testSet in $results//fots:test-set
                            return count($testSet//fots:test-case[@result ='notRun']))
    return
    <fots:brief totalTests="{$totalNoTests}"
                totalPass="{$totalPass}"
                totalFail="{$totalFail}"
                totalNotApplicable="{$totalNotApplicable}"
                totalNotRun="{$totalNotRun}"/>
  }
  {
    for $testSetFile in $FOTSCatalog//fots:test-set
    let $testSetURI := resolve-uri($testSetFile/@file,
                                   $catalogBaseURI),
        $testSetDoc := doc($testSetURI),
        $testSetName := data($testSetDoc/fots:test-set/@name),
        $totalNoTestCases := count($testSetDoc//fots:test-case),
        $totalFailures := for $testCase in $results//fots:test-set[@name = $testSetName]//fots:test-case[@result ="fail"]
                          return $testCase,
        $percent := round((1 - (count($totalFailures) div $totalNoTestCases))*100,2),
        $executionTime := sum(for $testCase in $results//fots:test-set[@name = $testSetName]//fots:test-case
                              return xs:dayTimeDuration($testCase/@executionTime))
    where count($totalFailures) gt 0
    order by count($totalFailures) descending, $testSetName
    return
    <fots:test-set  name="{$testSetName}"
                    noFailures="{count($totalFailures)}"
                    noTestCases="{$totalNoTestCases}"
                    percent="{$percent}"
                  failedTestNames="{string-join(for $failure in $totalFailures
                                                order by data($failure/@name)
                                                return data($failure/@name)
                                              ,",")}">
    </fots:test-set>
   }
  </fots:report>

  }
}
catch err:FODC0002
{
  error($err:code,
        $err:description,
        concat("
Please make sure the passed 'fotsPath' points to the ",
               "exact location of the FOTS catalog.xml:
",
               resolve-uri($FOTSCatalogFilePath)))
}
};

(:~
 : Loops through the results and creates ExpectedFailures.xml.
 : @param $pathResults path to the FOTS results.
 : @return ExpectedFailures.xml.
 :)
declare %ann:nondeterministic function reporting:generate-expected-failures(
  $pathResults  as xs:string
)
{
  try
  {
    {
      if (not(file:is-file($pathResults)))
      then
      {
        error($fots-err:errNA,
              "The file results file was not found. Suggestion: use driver:run-fots to generate it.");
      }
      else ();

      variable $results := parse-xml(file:read-text($pathResults));

      {
        for $testSet in $results//fots:test-set
        let $countFailures := count($testSet//fots:test-case[@result ="fail"])
        let $testSetName := xs:string($testSet/@name)
        order by $testSetName
        where $countFailures gt xs:integer(0)
        return
        for $testCase in $testSet//fots:test-case[@result ="fail"]
        return
          concat('EXPECTED_FOTS_FAILURE (',
                $testSetName,
                ' ',
                $testCase/@name,
                ' 0)
')
      }
    }
  }
  catch *
  {
    error($err:code, $err:description)
  }
};

declare function reporting:regressions(
) as xs:string*
{
  let $old_report:=fn:parse-xml(file:read-text('/home/spungi/work/zorba/repo/fots-ctest/build/bin/report_04_Dec.xml'))
  let $new_report:=fn:parse-xml(file:read-text('/home/spungi/work/zorba/repo/fots-ctest/build/bin/report_18_Dec.xml'))

  for $testSetOld in $old_report/*:report/*:test-set
  let $testSetNew := $new_report/*:report/*:test-set[@name = data($testSetOld/@name)]
  let $regression := if (exists($testSetNew))
                     then xs:decimal(data($testSetOld/@noFailures)) - xs:decimal(data($testSetNew/@noFailures))
                     else xs:decimal(0)
  let $testsOld as xs:string* := tokenize(data($testSetOld/@failedTestNames),",")
  let $testsNew as xs:string* := tokenize(data($testSetNew/@failedTestNames),",")
  where $regression < xs:decimal(0)
  order by $regression ascending
  return
    concat(data($testSetOld/@name),
           " ",
           $regression,
           " ",
           string-join((functx:value-except($testsNew, $testsOld)),","),
           "
")
};

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

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

import module namespace file =
  "http://expath.org/ns/file";

import module namespace driver =
  "http://www.zorba-xquery.com/fots-driver" at "fots-driver.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";
import module namespace functx =
  "http://www.functx.com/";

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

declare default element namespace
  "http://www.w3.org/2012/08/qt-fots-results";

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

declare namespace op = "http://www.zorba-xquery.com/options/features";
declare namespace f = "http://www.zorba-xquery.com/features";
declare option op:disable "f:trace";

(:~
 : Loops through the test-sets, executes them and reports results.
 : @param $FOTSCatalogFilePath path to the FOTS catalog file.
 : @param $FOTSZorbaManifestPath path to the FOTS Zorba manifest file.
 : @param $exceptedTestCases lists of test cases that are not run( empty
 : sequence means all test cases will be run).
 : @param $exceptedTestSets lists of test sets that are not run(empty sequence
 : means all test sets will be run).
 : @return a report of tests that were executed.
 :)
declare %ann:sequential function reporting:run-and-report(
  $FOTSCatalogFilePath    as xs:string,
  $FOTSZorbaManifestPath  as xs:string,
  $exceptedTestCases      as xs:string*,
  $exceptedTestSets       as xs:string*
) as document-node()
{
  try
  {
    {
      variable $FOTSCatalog := doc(trace(resolve-uri($FOTSCatalogFilePath),
                                  "Path to FOTS catalog.xml set to: "));

      variable $catalogBaseURI := resolve-uri(util:parent-folder($FOTSCatalogFilePath));

      variable $FOTSZorbaManifest := doc(trace(resolve-uri($FOTSZorbaManifestPath),
                                        "Path to FOTSZorbaManifest set to:"));

      variable $results := driver:run-fots($FOTSCatalogFilePath,
                                           $FOTSZorbaManifestPath,
                                           (),
                                           $exceptedTestSets,
                                           (),
                                           $exceptedTestCases,
                                           '',
                                           (),
                                           fn:false(),
                                           '',
                                           'run-test-sets');

      file:write("results.xml",
                 $results,
                 $util:writeXML);

      reporting:W3C-reporting($results,
                              $FOTSZorbaManifestPath)
    }
  }
  catch err:FODC0002
  {
    error($err:code,
          $err:description,
          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 test sets, executes them and reports results.
 : @param $FOTSZorbaManifestPath path to the FOTS Zorba manifest file.
 : @param $resultsFilePath path to the FOTS results file.
 : @return The W3C conformance submission file.
 :)
declare %ann:sequential function reporting:report(
  $FOTSZorbaManifestPath  as xs:string,
  $resultsFilePath        as xs:string
) as document-node()
{
  try
  {
    {
      reporting:W3C-reporting(parse-xml(file:read-text($resultsFilePath))/fots:test-cases,
                              $FOTSZorbaManifestPath)
    }
  }
  catch *
  {
    error($err:code, $err:description)
  }
};

(:~
 : Format the W3C conformance report.
 : @param $results FOTS results file.
 : @param $FOTSZorbaManifestPath  path to the FOTS Zorba manifest file.
 : @return The W3C conformance submission file.
 :)
declare %ann:sequential function reporting:W3C-reporting(
  $results                as element(fots:test-cases)?,
  $FOTSZorbaManifestPath  as xs:string
) as document-node()
{
  try
  {
    {
      if (not(file:is-file(resolve-uri($FOTSZorbaManifestPath))))
      then
      {
        error($fots-err:errNA,
              "The 'FOTSZorbaManifest.xml' was not found.");
      }
      else ();

      variable $FOTSZorbaManifest := parse-xml(file:read-text(resolve-uri($FOTSZorbaManifestPath)));

      variable $CLIBaseURI := resolve-uri(util:parent-folder($FOTSZorbaManifestPath));

      variable $W3CTemplatePath := resolve-uri("W3C_submission_template.xml", $CLIBaseURI);

      if (not(file:is-file($W3CTemplatePath)))
      then
      {
        error($fots-err:errNA,
              "'W3C_submission_template.xml' file was not found.");
      }
      else ();

      variable $W3CTemplate := parse-xml(file:read-text($W3CTemplatePath));

      (: add dependecies:)
     (insert nodes
      for $dependency in $FOTSZorbaManifest/fots:test-suite-result/fots:dependency
      return <dependency type="{$dependency/@type}"
                         value="{$dependency/@value}"
                         satisfied="{$dependency/@satisfied}"/>
      as last into $W3CTemplate/results:test-suite-result/results:product,

      (: add test set results:)
      insert nodes
      for $testSet in $results/fots:test-set
      return
      <test-set name="{$testSet/@name}">
        {
          for $testCase in $testSet/fots:test-case
          return
          if(exists($testCase/@comment))
          then
            <test-case name="{$testCase/@name}"
                       result="{$testCase/@result}"
                       comment="{$testCase/@comment}" />
          else
            <test-case name="{$testCase/@name}"
                       result="{$testCase/@result}" />
        }
      </test-set>
      as last into $W3CTemplate/results:test-suite-result);

      $W3CTemplate
    }
  }
  catch err:FODC0002
  {
    error($err:code,
          $err:description,
          concat("
Please make sure there is a 'W3C_submission_template.xml'",
                 " file in the same folder as cli.xq"))
  }
};

(:~
 : Loops through the test-sets and creates statistics.
 : @param $FOTSCatalogFilePath  Path to the FOTS catalog file.
 : @param $failures Path to the results fo the FOTS.
 : @return a report of tests run.
 :)
declare %ann:nondeterministic function reporting:wiki-report(
  $FOTSCatalogFilePath  as xs:string,
  $resultsFilePath      as xs:string
) as element(fots:report)
{
try
{
  {
    variable $FOTSCatalog := doc(trace(resolve-uri($FOTSCatalogFilePath),
                                "Path to FOTS catalog.xml set to: "));

    variable $catalogBaseURI := resolve-uri(util:parent-folder($FOTSCatalogFilePath));

    variable $results := parse-xml(file:read-text($resultsFilePath));

  <fots:report>
  {
    let $totalNoTests := count($results//fots:test-set//fots:test-case),
        $totalPass := sum(for $testSet in $results//fots:test-set
                          return count($testSet//fots:test-case[@result ='pass'])),
        $totalFail := sum(for $testSet in $results//fots:test-set
                          return count($testSet//fots:test-case[@result ='fail'])),
        $totalNotApplicable := sum(for $testSet in $results//fots:test-set
                                   return count($testSet//fots:test-case[@result ='n/a'])),
        $totalNotRun := sum(for $testSet in $results//fots:test-set
                            return count($testSet//fots:test-case[@result ='notRun']))
    return
    <fots:brief totalTests="{$totalNoTests}"
                totalPass="{$totalPass}"
                totalFail="{$totalFail}"
                totalNotApplicable="{$totalNotApplicable}"
                totalNotRun="{$totalNotRun}"/>
  }
  {
    for $testSetFile in $FOTSCatalog//fots:test-set
    let $testSetURI := resolve-uri($testSetFile/@file,
                                   $catalogBaseURI),
        $testSetDoc := doc($testSetURI),
        $testSetName := data($testSetDoc/fots:test-set/@name),
        $totalNoTestCases := count($testSetDoc//fots:test-case),
        $totalFailures := for $testCase in $results//fots:test-set[@name = $testSetName]//fots:test-case[@result ="fail"]
                          return $testCase,
        $percent := round((1 - (count($totalFailures) div $totalNoTestCases))*100,2),
        $executionTime := sum(for $testCase in $results//fots:test-set[@name = $testSetName]//fots:test-case
                              return xs:dayTimeDuration($testCase/@executionTime))
    where count($totalFailures) gt 0
    order by count($totalFailures) descending
    return
    <fots:test-set  name="{$testSetName}"
                    noFailures="{count($totalFailures)}"
                    noTestCases="{$totalNoTestCases}"
                    percent="{$percent}"
                  failedTestNames="{string-join(for $failure in $totalFailures
                                                order by data($failure/@name)
                                                return data($failure/@name)
                                              ,",")}">
    </fots:test-set>
   }
  </fots:report>

  }
}
catch err:FODC0002
{
  error($err:code,
        $err:description,
        concat("
Please make sure the passed 'fotsPath' points to the ",
               "exact location of the FOTS catalog.xml:
",
               resolve-uri($FOTSCatalogFilePath)))
}
};

(:~
 : Loops through the results and creates ExpectedFailures.xml.
 : @param $pathResults path to the FOTS results.
 : @return ExpectedFailures.xml.
 :)
declare %ann:nondeterministic function reporting:generate-expected-failures(
  $pathResults  as xs:string
)
{
  try
  {
    {
      if (not(file:is-file($pathResults)))
      then
      {
        error($fots-err:errNA,
              "The file results file was not found. Suggestion: use driver:run-fots to generate it.");
      }
      else ();

      variable $results := parse-xml(file:read-text($pathResults));

      {
        for $testSet in $results//fots:test-set
        let $countFailures := count($testSet//fots:test-case[@result ="fail"])
        let $testSetName := xs:string($testSet/@name)
        order by $testSetName
        where $countFailures gt xs:integer(0)
        return
        for $testCase in $testSet//fots:test-case[@result ="fail"]
        return
          concat('EXPECTED_FOTS_FAILURE (',
                $testSetName,
                ' ',
                $testCase/@name,
                ' 0)
')
      }
    }
  }
  catch *
  {
    error($err:code, $err:description)
  }
};

declare function reporting:regressions(
) as xs:string*
{
  let $old_report:=fn:parse-xml(file:read-text('/home/spungi/work/zorba/repo/fots-ctest/build/bin/report_04_Dec.xml'))
  let $new_report:=fn:parse-xml(file:read-text('/home/spungi/work/zorba/repo/fots-ctest/build/bin/report_18_Dec.xml'))

  for $testSetOld in $old_report/*:report/*:test-set
  let $testSetNew := $new_report/*:report/*:test-set[@name = data($testSetOld/@name)]
  let $regression := if (exists($testSetNew))
                     then xs:decimal(data($testSetOld/@noFailures)) - xs:decimal(data($testSetNew/@noFailures))
                     else xs:decimal(0)
  let $testsOld as xs:string* := tokenize(data($testSetOld/@failedTestNames),",")
  let $testsNew as xs:string* := tokenize(data($testSetNew/@failedTestNames),",")
  where $regression < xs:decimal(0)
  order by $regression ascending
  return
    concat(data($testSetOld/@name),
           " ",
           $regression,
           " ",
           string-join((functx:value-except($testsNew, $testsOld)),","),
           "
")
};


[ignore] added failing test map:remove

[ignore] added failing test map:remove

svn path=/trunk/eXist/; revision=18552

xquery version "1.0";

module namespace mt="http://exist-db.org/xquery/test/maps";

import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";

declare variable $mt:daysOfWeek :=
    map {
        "Su" := "Sunday",
        "Mo" := "Monday",
        "Tu" := "Tuesday",
        "We" := "Wednesday",
        "Th" := "Thursday",
        "Fr" := "Friday",
        "Sa" := "Saturday"
    };

declare %test:assertEquals("Wednesday") function mt:createLiteral1() {
    $mt:daysOfWeek("We")
};

declare %test:assertEquals("Wednesday") function mt:createWithIntKeys() {
    let $map := map {
        1 := "Sunday",
        2 := "Monday",
        3 := "Tuesday",
        4 := "Wednesday",
        5 := "Thursday",
        6 := "Friday",
        7 := "Saturday"
    }
    return
        $map(4)
};

declare %test:assertEquals(20) function mt:createWithFunctionValue() {
    let $fn := function($p) { $p * 2 }
    let $map := map { "callback" := $fn }
    return
        map:get($map, "callback")(10)
};

declare %test:assertEquals("Sunday") function mt:createWithEntry() {
    let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:new(map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days))
    return
        $map("Su")
};

declare %test:assertXPath("count($result) = 8") %test:assertXPath("7 = $result")
function mt:createFromTwoMaps() {
    let $week := map{0:="Sonntag", 1:="Montag", 2:="Dienstag", 3:="Mittwoch", 4:="Donnerstag", 5:="Freitag", 6:="Samstag"}
    let $map := map:new(($week, map { 7 := "Sonntag" }))
    return
        map:keys($map)
};

declare %test:assertEquals("Sunday") function mt:createWithSingleKey() {
    let $map := map:entry("Su", "Sunday")
    return
        $map("Su")
};

declare %test:assertEquals("Samstag", "Sonnabend") function mt:overwriteKeyInNewMap() {
    let $week := map {0:="Sonntag", 1:="Montag", 2:="Dienstag", 3:="Mittwoch", 4:="Donnerstag", 5:="Freitag", 6:="Samstag"}
    let $map := map:new(($week, map { 6 := "Sonnabend" }))
    return
        ($week(6), $map(6))
};

declare %test:assertEmpty function mt:mapEmptyValue() {
    let $map := map {0:= (), 1 := ("One", "Two") }
    return
        $map(0)
};

declare %test:assertEquals("One", "Two") function mt:mapSequenceValue() {
    let $map := map {0:= (), 1 := ("One", "Two") }
    return
        $map(1)
};

declare %test:assertEquals("Heinz", "Roland", "Uschi", "Verona") function mt:keyTypeDate () {
    let $map := map {
        xs:date("1975-03-19") := "Uschi",
        xs:date("1980-01-22") := "Verona",
        xs:date("1960-06-14") := "Heinz",
        xs:date("1963-10-21") := "Roland"
    }
    for $key in map:keys($map)
    let $name := $map($key)
    order by $name ascending
    return
        $name
};

declare %test:assertEquals(0, "One") function mt:mixedKeyTypes() {
    let $map := map{ "Zero" := 0, 1 := "One" }
    return
        ($map("Zero"), $map(1))
};

declare %test:assertTrue function mt:containsOnEmptyValue() {
    let $map := map{0:= () }
    return
        map:contains($map, 0)
};

declare %test:assertEquals("Monday") function mt:createWithCollation() {
    let $map := map:new(map:entry("Mo", "Monday"), "?strength=primary")
    return
        $map("mo")
};

declare %test:assertEquals("Fr", "Mo", "Sa", "Su", "Th", "Tu", "We") function mt:keys() {
    let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:new(map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days))
    for $day in map:keys($map)
    order by $day ascending
    return
        $day
};

declare %test:assertEquals("Su") function mt:keysOnMapWithSingleKey() {
    let $map := map:entry("Su", "Sunday")
    return
        map:keys($map)
};

declare %test:assertEquals("Fr", "Mo", "Sa", "Su", "Th") function mt:remove() {
    let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:new(map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days))
    for $day in map:keys(map:remove(map:remove($map, "We"), "Tu"))
    order by $day
    return
        $day
};

declare %test:assertFalse function mt:remove() {
    let $days := ("Monday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:new(map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days))
    return
        map:contains(map:remove($map, "Tu"), "Tu")
};

declare %test:assertEmpty function mt:removeSingleKey() {
    let $map := map:entry("Su", "Sunday")
    let $empty := map:remove($map, "Su")
    return
        map:keys($empty)
};

declare %test:assertTrue function mt:contains() {
    map:contains($mt:daysOfWeek, "We")
};

declare %test:assertFalse function mt:containsOnMissingKey() {
    map:contains($mt:daysOfWeek, "Al")
};

declare %test:assertTrue function mt:containsSingleKey() {
    let $map := map:entry("Su", "Sunday")
    return
        map:contains($map, "Su")
};

declare %test:assertEquals("Hello world") function mt:computedKeyValue() {
    let $map := map { 2 + 1 := concat("Hello ", "world") }
    return
        $map(3)
};

declare %test:assertEquals("false", "true") function mt:immutability() {
    let $map := map {
        "Su" := "Sunday",
        "Mo" := "Monday",
        "Tu" := "Tuesday",
        "We" := "Wednesday",
        "Th" := "Thursday",
        "Fr" := "Friday"
    }
    let $map2 := map:new(($map, map:entry("Sa", "Saturday")))
    return
        (map:contains($map, "Sa"), map:contains($map2, "Sa"))
};

declare %test:assertTrue function mt:immutability2() {
    let $map := map {
        "Su" := "Sunday",
        "Mo" := "Monday",
        "Tu" := "Tuesday",
        "We" := "Wednesday",
        "Th" := "Thursday",
        "Fr" := "Friday"
    }
    let $map2 := map:remove($map, "Fr")
    return
        map:contains($map, "Fr")
};

declare %test:assertFalse function mt:immutability3() {
    let $map := map {
        "Su" := "Sunday",
        "Mo" := "Monday",
        "Tu" := "Tuesday",
        "We" := "Wednesday",
        "Th" := "Thursday",
        "Fr" := "Friday"
    }
    let $map2 := map:remove($map, "Fr")
    return
        map:contains($map2, "Fr")
};

(:
declare %test:assertTrue function mt:immutability4() {

    let $daysOfWeek :=  map {   "Sunday" := 1,
                                 "Monday" := 2,
                                 "Tuesday" := 3,
                                 "Wednesday" := 4,
                                 "Thursday" := 5,
                                 "Friday" := 6,
                                 "Saturday" := 7
                             }
    let $workDays := map:remove($daysOfWeek, "Sunday")

    return map:contains($workDays,"Monday")
};
:)

declare %test:assertEquals("Sunday") function mt:sequenceType1() {
    let $map := map { 1 := "Sunday" }
    return
        map:get(mt:mapTest($map), 1)
};

declare %private function mt:mapTest($map as map(*)) as map(xs:integer, xs:string) {
    $map
};

declare
    %test:assertError("EXMPDY001")
    %test:name("Throw error if key is not a single atomic value")
function mt:wrongCardinality() {
    let $map := map { (1, 2) := "illegal" }
    return
        $map(1)
};

declare
	%test:assertEquals("two")
function mt:nestedMaps() {
	let $map := map { 1:= map { 1:= "one", 2:= "two" } }
    return
        $map(1)(2)
};

declare
    %test:assertEquals("Monday")
function mt:nestedMaps2() {
	let $map := map { "week" := map { "days" := $mt:daysOfWeek } }
    return
        $map("week")("days")("Mo")
};

declare
    %test:assertEquals(2)
function mt:qnameKeys() {
    let $map := map { xs:QName("mt:one") := 1, xs:QName("mt:two") := 2 }
    return
        $map(xs:QName("mt:two"))
};

declare
    %test:assertEquals(2)
function mt:longKeys() {
    let $map := map { xs:long(1) := 1, xs:long(2) := 2 }
    return
        $map(2)
};

declare
    %test:args(2)
    %test:assertEquals(3)
    %test:args("Three")
    %test:assertEmpty
function mt:doubleKeys($key) {
    let $map := map { xs:double(1.1) := 1, xs:double(2) := 2 }
    return
        map:new(($map, map:entry(xs:double(2), 3)))($key)
};

declare
    %test:assertEquals(2, "value")
function mt:mixedNumeric() {
    let $map := map { 1.1 := 1, 2 := 2, "key" := "value" }
    return
        ($map(2), $map("key"))
};

declare
    %test:assertEquals("<c ns='c'/>", "<c ns='c'/>")
function mt:pathExpr() as element(c)+ {
    let $test :=
        <a>
            <b ns="b">
                <c ns="c"/>
            </b>
        </a>
    let $map :=
        map {
            "a" := $test//c,
            "b" := ($test//c)
        }
    return
        ($map("a"), $map("b"))
};

xquery version "1.0";

module namespace mt="http://exist-db.org/xquery/test/maps";

import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";

declare variable $mt:daysOfWeek :=
    map {
        "Su" := "Sunday",
        "Mo" := "Monday",
        "Tu" := "Tuesday",
        "We" := "Wednesday",
        "Th" := "Thursday",
        "Fr" := "Friday",
        "Sa" := "Saturday"
    };

declare %test:assertEquals("Wednesday") function mt:createLiteral1() {
    $mt:daysOfWeek("We")
};

declare %test:assertEquals("Wednesday") function mt:createWithIntKeys() {
    let $map := map {
        1 := "Sunday",
        2 := "Monday",
        3 := "Tuesday",
        4 := "Wednesday",
        5 := "Thursday",
        6 := "Friday",
        7 := "Saturday"
    }
    return
        $map(4)
};

declare %test:assertEquals(20) function mt:createWithFunctionValue() {
    let $fn := function($p) { $p * 2 }
    let $map := map { "callback" := $fn }
    return
        map:get($map, "callback")(10)
};

declare %test:assertEquals("Sunday") function mt:createWithEntry() {
    let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:new(map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days))
    return
        $map("Su")
};

declare %test:assertXPath("count($result) = 8") %test:assertXPath("7 = $result")
function mt:createFromTwoMaps() {
    let $week := map{0:="Sonntag", 1:="Montag", 2:="Dienstag", 3:="Mittwoch", 4:="Donnerstag", 5:="Freitag", 6:="Samstag"}
    let $map := map:new(($week, map { 7 := "Sonntag" }))
    return
        map:keys($map)
};

declare %test:assertEquals("Sunday") function mt:createWithSingleKey() {
    let $map := map:entry("Su", "Sunday")
    return
        $map("Su")
};

declare %test:assertEquals("Samstag", "Sonnabend") function mt:overwriteKeyInNewMap() {
    let $week := map {0:="Sonntag", 1:="Montag", 2:="Dienstag", 3:="Mittwoch", 4:="Donnerstag", 5:="Freitag", 6:="Samstag"}
    let $map := map:new(($week, map { 6 := "Sonnabend" }))
    return
        ($week(6), $map(6))
};

declare %test:assertEmpty function mt:mapEmptyValue() {
    let $map := map {0:= (), 1 := ("One", "Two") }
    return
        $map(0)
};

declare %test:assertEquals("One", "Two") function mt:mapSequenceValue() {
    let $map := map {0:= (), 1 := ("One", "Two") }
    return
        $map(1)
};

declare %test:assertEquals("Heinz", "Roland", "Uschi", "Verona") function mt:keyTypeDate () {
    let $map := map {
        xs:date("1975-03-19") := "Uschi",
        xs:date("1980-01-22") := "Verona",
        xs:date("1960-06-14") := "Heinz",
        xs:date("1963-10-21") := "Roland"
    }
    for $key in map:keys($map)
    let $name := $map($key)
    order by $name ascending
    return
        $name
};

declare %test:assertEquals(0, "One") function mt:mixedKeyTypes() {
    let $map := map{ "Zero" := 0, 1 := "One" }
    return
        ($map("Zero"), $map(1))
};

declare %test:assertTrue function mt:containsOnEmptyValue() {
    let $map := map{0:= () }
    return
        map:contains($map, 0)
};

declare %test:assertEquals("Monday") function mt:createWithCollation() {
    let $map := map:new(map:entry("Mo", "Monday"), "?strength=primary")
    return
        $map("mo")
};

declare %test:assertEquals("Fr", "Mo", "Sa", "Su", "Th", "Tu", "We") function mt:keys() {
    let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:new(map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days))
    for $day in map:keys($map)
    order by $day ascending
    return
        $day
};

declare %test:assertEquals("Su") function mt:keysOnMapWithSingleKey() {
    let $map := map:entry("Su", "Sunday")
    return
        map:keys($map)
};

declare %test:assertEquals("Fr", "Mo", "Sa", "Su", "Th") function mt:remove() {
    let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:new(map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days))
    for $day in map:keys(map:remove(map:remove($map, "We"), "Tu"))
    order by $day
    return
        $day
};

declare %test:assertFalse function mt:remove() {
    let $days := ("Monday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:new(map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days))
    return
        map:contains(map:remove($map, "Tu"), "Tu")
};

declare %test:assertEmpty function mt:removeSingleKey() {
    let $map := map:entry("Su", "Sunday")
    let $empty := map:remove($map, "Su")
    return
        map:keys($empty)
};

declare %test:assertTrue function mt:contains() {
    map:contains($mt:daysOfWeek, "We")
};

declare %test:assertFalse function mt:containsOnMissingKey() {
    map:contains($mt:daysOfWeek, "Al")
};

declare %test:assertTrue function mt:containsSingleKey() {
    let $map := map:entry("Su", "Sunday")
    return
        map:contains($map, "Su")
};

declare %test:assertEquals("Hello world") function mt:computedKeyValue() {
    let $map := map { 2 + 1 := concat("Hello ", "world") }
    return
        $map(3)
};

declare %test:assertEquals("false", "true") function mt:immutability() {
    let $map := map {
        "Su" := "Sunday",
        "Mo" := "Monday",
        "Tu" := "Tuesday",
        "We" := "Wednesday",
        "Th" := "Thursday",
        "Fr" := "Friday"
    }
    let $map2 := map:new(($map, map:entry("Sa", "Saturday")))
    return
        (map:contains($map, "Sa"), map:contains($map2, "Sa"))
};

declare %test:assertTrue function mt:immutability2() {
    let $map := map {
        "Su" := "Sunday",
        "Mo" := "Monday",
        "Tu" := "Tuesday",
        "We" := "Wednesday",
        "Th" := "Thursday",
        "Fr" := "Friday"
    }
    let $map2 := map:remove($map, "Fr")
    return
        map:contains($map, "Fr")
};

declare %test:assertEquals("Sunday") function mt:sequenceType1() {
    let $map := map { 1 := "Sunday" }
    return
        map:get(mt:mapTest($map), 1)
};

declare %private function mt:mapTest($map as map(*)) as map(xs:integer, xs:string) {
    $map
};

declare
    %test:assertError("EXMPDY001")
    %test:name("Throw error if key is not a single atomic value")
function mt:wrongCardinality() {
    let $map := map { (1, 2) := "illegal" }
    return
        $map(1)
};

declare
	%test:assertEquals("two")
function mt:nestedMaps() {
	let $map := map { 1:= map { 1:= "one", 2:= "two" } }
    return
        $map(1)(2)
};

declare
    %test:assertEquals("Monday")
function mt:nestedMaps2() {
	let $map := map { "week" := map { "days" := $mt:daysOfWeek } }
    return
        $map("week")("days")("Mo")
};

declare
    %test:assertEquals(2)
function mt:qnameKeys() {
    let $map := map { xs:QName("mt:one") := 1, xs:QName("mt:two") := 2 }
    return
        $map(xs:QName("mt:two"))
};

declare
    %test:assertEquals(2)
function mt:longKeys() {
    let $map := map { xs:long(1) := 1, xs:long(2) := 2 }
    return
        $map(2)
};

declare
    %test:args(2)
    %test:assertEquals(3)
    %test:args("Three")
    %test:assertEmpty
function mt:doubleKeys($key) {
    let $map := map { xs:double(1.1) := 1, xs:double(2) := 2 }
    return
        map:new(($map, map:entry(xs:double(2), 3)))($key)
};

declare
    %test:assertEquals(2, "value")
function mt:mixedNumeric() {
    let $map := map { 1.1 := 1, 2 := 2, "key" := "value" }
    return
        ($map(2), $map("key"))
};

declare
    %test:assertEquals("<c ns='c'/>", "<c ns='c'/>")
function mt:pathExpr() as element(c)+ {
    let $test :=
        <a>
            <b ns="b">
                <c ns="c"/>
            </b>
        </a>
    let $map :=
        map {
            "a" := $test//c,
            "b" := ($test//c)
        }
    return
        ($map("a"), $map("b"))
};


[testsuite] Update of annotation-based test runner. %test:assertEquals now takes arbitrary number of arguments to compare with sequences.

svn path=/trunk/eXist/; revision=16531

xquery version "3.0";

(:~
 : XQSuite - a functional test framework based on XQuery 3.0 annotations.
 : Relies on the functions util:list-functions and util:inspect-function
 : to inspect annotations. The rest is pretty much standard XQuery.
 :
 : Usage:
 :
 :

 : import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";
 : import module namespace t="http://exist-db.org/xquery/test/examples" at "examples.xql";
 :
 : test:suite(util:list-functions("http://exist-db.org/xquery/test/examples"))
 :

 :
 : @author Wolfgang Meier
 :)
module namespace test="http://exist-db.org/xquery/xqsuite";

declare variable $test:TEST_NAMESPACE := "http://exist-db.org/xquery/xqsuite";

declare variable $test:UNKNOWN_ASSERTION := QName($test:TEST_NAMESPACE, "no-such-assertion");
declare variable $test:WRONG_ARG_COUNT := QName($test:TEST_NAMESPACE, "wrong-number-of-arguments");

(:~
 : Main entry point into the module. Takes a sequence of function items.
 : Functions with known test annotations will be evaluated and their results
 : checked against the annotations.
 :
 : @param $functions a sequence of function items
 : @return an XML report (in xUnit format)
 :)
declare function test:suite($functions as function(*)+) {
    let $modules := test:distinct-modules($functions)
    return
        <testsuites>
        {
            (: Run tests for each module in turn :)
            for $module in $modules
            let $modFunctions := filter(function($func) {
                    namespace-uri-from-QName(function-name($func)) = $module
                }, $functions)
            let $setup := test:call-func-with-annotation($modFunctions, "setUp")
            let $result :=
                if (empty($setup) or $setup/self::ok) then
                    let $startTime := util:system-time()
                    let $results :=
                        test:function-by-annotation($modFunctions, "assert", test:run-tests#2)
                    let $elapsed :=
                        util:system-time() - $startTime
                    return
                        <testsuite package="{$module}" timestamp="{util:system-dateTime()}"
                            failures="{count($results/failure)}" tests="{count($results)}"
                            time="{$elapsed}">
                            { $results }
                        </testsuite>
                else
                    <testsuite package="{$module}" timestamp="{util:system-dateTime()}"
                        errors="{count($functions)}">
                        {$setup/string()}
                    </testsuite>
            return
                ($result, test:call-func-with-annotation($modFunctions, "tearDown"))[1]
        }
        </testsuites>
};

(:~
 : Find functions having the given annotation and call the callback function.
 :)
declare %private function test:function-by-annotation($functions as function(*)+, $annot as xs:string,
    $callback as function(function(*), element(function)) as item()*) {
    for $function in $functions
    let $meta := util:inspect-function($function)
    where $meta/annotation[@namespace = $test:TEST_NAMESPACE][matches(@name, ":" || $annot)]
    return
        $callback($function, $meta)
};

(:~
 : Return the namespace URI of all distinct modules in the input set.
 :)
declare %private function test:distinct-modules($functions as function(*)+) as xs:string+ {
    distinct-values(
        for $func in $functions
        return
            namespace-uri-from-QName(function-name($func))
    )
};

(:~
 : Find functions having the specified annotation and call them,
 : return <ok/> upon success, an error description otherwise.
 : Used for setUp and tearDown.
 :)
declare %private function test:call-func-with-annotation($functions as function(*)+, $annot as xs:string) as element()? {
    test:function-by-annotation($functions, $annot, function($func, $meta) {
        try {
            (<ok/>, $func())[1]
        } catch * {
            <system-err>{$err:description}</system-err>
        }
    })
};

(:~
 : Calls the test function one or more times, depending on the number of
 : %args() annotations found. Each %arg annotation triggers one test run
 : using the supplied parameters.
 :)
declare %private function test:run-tests($func as function(*), $meta as element(function)) {
    let $argsAnnot := $meta/annotation[matches(@name, ":args")]
    return
        if ($argsAnnot) then
            for $args in $argsAnnot
            return
                test:test($func, $meta, $args)
        else
            test:test($func, $meta, ())
};

(:~
 : The main function for running a single test. Executes the test function
 : and compares the result against each assertXXX annotation.
 :)
declare %private function test:test($func as function(*), $meta as element(function), $args as element(annotation)?) {
    let $assertions := test:get-assertions($meta, $args)
    return
        if (exists($assertions)) then
            try {
                let $result := test:call-test($func, $meta, $args)
                let $assertResult := test:check-assertions($assertions, $result)
                return
                    test:print-result($meta, $result, $assertResult)
            } catch * {
                let $assertError := $meta/annotation[contains(@name, ":assertError")]
                return
                    if ($assertError) then
                        if ($assertError/value and not(contains($err:code, $assertError/value/string())
                            or contains($err:description, $assertError/value/string())))then
                            <report>
                                <failure message="Expected error {$assertError/value/string()}, got: {$err:code}"
                                    type="failure-error-code-1"/>
                            </report>
                        else
                            test:print-result($meta, (), ())
                    else
                        <error code="{$err:code}" message="{$err:description}">
                            <xquery-trace>{$exerr:xquery-stack-trace}</xquery-trace>
                            <java-trace>{$exerr:java-stack-trace}</java-trace>
                        </error>
            }
        else
            ()
};

(:~
 : Get all %assertXXX annotations of the function. If %args is used multiple times,
 : assertions apply to the result of running the function with the parameters given
 : in the preceding %args.
 :)
declare %private function test:get-assertions($meta as element(function), $args as element(annotation)?) {
    if ($args) then
        let $nextArgs := $args/following-sibling::annotation[contains(@name, ":args")]
        return
            $args/following-sibling::annotation[contains(@name, ":assert")]
            except
            $nextArgs/following-sibling::annotation[contains(@name, ":assert")]
    else
        $meta/annotation[contains(@name, ":assert")]
};

(:~
 : Map any arguments from the %args annotation into function parameters and evaluate
 : the resulting function.
 :)
declare %private function test:call-test($func as function(*), $meta as element(function), $args as element(annotation)*) {
    let $argCount := count($meta/argument)
    let $testArgs := $args/value/string()
    return
        if (count($testArgs) != $argCount) then
            error(
                $test:WRONG_ARG_COUNT,
                "The number of arguments specified in test:args must match the arguments of the function to test"
            )
        else
            let $args := test:map-arguments($testArgs, $meta/argument)
            return
                test:apply($func, $args)
};

(:~
 : Transform the annotation to the type required by the function parameter.
 :)
declare %private function test:map-arguments($testArgs as xs:string*, $funcArgs as element(argument)*) {
    if (exists($testArgs)) then
        map-pairs(function($targ, $farg) {
            switch (string($farg/@type))
                case "xs:string" return
                    string($targ)
                case "xs:integer" case "xs:int" return
                    xs:integer($targ)
                case "xs:decimal" return
                    xs:decimal($targ)
                case "xs:float" case "xs:double" return
                    xs:double($targ)
                case "xs:date" return
                    xs:date($targ)
                case "xs:dateTime" return
                    xs:dateTime($targ)
                case "xs:time" return
                    xs:time($targ)
                case "element()" return
                    util:parse($targ)/*
                case "text()" return
                    text { string($targ) }
                default return
                    $targ
        }, $testArgs, $funcArgs)
    else
        ()
};

(:~
 : Call the given function with parameters taken from $args.
 :)
declare %private function test:apply($func as function(*), $args as item()*) {
    switch (count($args))
        case 0 return
            $func()
        case 1 return
            $func($args[1])
        case 2 return
            $func($args[1], $args[2])
        case 3 return
            $func($args[1], $args[2], $args[3])
        case 4 return
            $func($args[1], $args[2], $args[3], $args[4])
        case 5 return
            $func($args[1], $args[2], $args[3], $args[4], $args[5])
        case 6 return
            $func($args[1], $args[2], $args[3], $args[4], $args[5], $args[6])
        case 7 return
            $func($args[1], $args[2], $args[3], $args[4], $args[5], $args[6], $args[7])
        default return
            error($test:WRONG_ARG_COUNT, "Function takes too many arguments")
};

(:~
 : Print out evaluation results for a given test.
 :)
declare %private function test:print-result($meta as element(function), $result as item()*,
    $assertResult as element(report)*) {
    let $nameAnnot := $meta/annotation[matches(@name, ":name")]
    let $name := if ($nameAnnot) then $nameAnnot/value else replace($meta/@name, "^\w+:([^:]+)$", "$1")
    return
        <testcase name="{$name}" class="{$meta/@name}">
        {
            if (exists($assertResult)) then
                ($assertResult[failure] | $assertResult)[1]/*
            else
                ()
        }
        </testcase>
};

(:~
 : Check the function's return value against each assertion.
 :)
declare %private function test:check-assertions($assertions as element(annotation)*, $result as item()*) as element(report)* {
    for $annotation in $assertions
    let $assert := replace($annotation/@name, "^\w+:(.*)$", "$1")
    return
        switch ($assert)
            case "assertEquals" return
                test:assertEquals($annotation/value/string(), $result)
            case "assertEmpty" return
                test:assertEmpty($result)
            case "assertExists" return
                test:assertExists($result)
            case "assertTrue" return
                test:assertTrue($result)
            case "assertFalse" return
                test:assertFalse($result)
            case "assertXPath" return
                test:assertXPath($annotation, $result)
            case "assertError" return
                test:assertError($annotation/value/string(), $result)
            default return
                error($test:UNKNOWN_ASSERTION, $annotation/@name)
};

(:~
 : Check for equality of the function's result with the value in the annotation.
 : This function transforms the result to a string before checking for equality.
 :)
declare %private function test:assertEquals($values as item()*, $result as item()*) as element(report)? {
    if (exists($values)) then
        if (count($values) eq count($result)) then
            let $tests := map-pairs(test:equals#2, $values, $result)
            let $equal := every $test in $tests satisfies $test
            return
                if ($equal) then
                    ()
                else
                   <report>
                        <failure message="assertEquals failed."
                            type="failure-error-code-1">
                        { $values }
                        </failure>
                        <output>{ $result }</output>
                    </report>
        else
            <report>
                <failure message="assertEquals failed: wrong number of items returned by function. Expected: {count($values)}. Got: {count($result)}"
                    type="failure-error-code-1">
                { $values }
                </failure>
                <output>{ $result }</output>
            </report>
    else
        ()
};

declare %private function test:equals($value as item(), $result as item()) as xs:boolean {
    let $normResult :=
        typeswitch ($result)
            case node() return
                test:normalize($result)
            default return
                $result
    let $normValue := test:cast-to-type($value, $result)
    return
        typeswitch ($normResult)
            case node() return
                deep-equal($normValue, $normResult)
            default return
                $normResult eq $normValue
};

declare %private function test:normalize($nodes as node()*) {
    for $node in $nodes return test:normalize-node($node)
};

declare %private function test:normalize-node($node as node()) {
    typeswitch ($node)
        case document-node() return
            test:normalize-node($node/*)
        case element() return
            element { node-name($node) } {
                $node/@*, for $child in $node/node() return test:normalize-node($child)
            }
        case text() return
            let $norm := normalize-space($node)
            return
                if (string-length($norm) eq 0) then () else $node
        default return
            $node
};

(:~
 : Check if the function's result is empty.
 :)
declare %private function test:assertEmpty($result as item()*) as element(report)? {
    if (empty($result)) then
        ()
    else
        <report>
            <failure message="assertEmpty failed."
                type="failure-error-code-1"/>,
            <output>{ $result }</output>
        </report>
};

(:~
 : Check if the function's result is not empty.
 :)
declare %private function test:assertExists($result as item()*) as element(report)? {
    if (exists($result)) then
        ()
    else
        <report>
            <failure message="assertExists failed."
                type="failure-error-code-1"/>,
            <output>{ $result }</output>
        </report>
};

(:~
 : Check if the function's result is true.
 :)
declare %private function test:assertTrue($result as item()*) as element(report)? {
    if ($result) then
        ()
    else
        <report>
            <failure message="assertExists failed."
                type="failure-error-code-1"/>,
            <output>{ $result }</output>
        </report>
};

(:~
 : Check if the function caused an error.
 :)
declare %private function test:assertError($value as xs:string, $result as item()*) as element(report)? {
    if ($result) then
        ()
    else
        <report>
            <failure message="assertError failed. Expected error {$value}"
                type="failure-error-code-1"/>,
            <output>{ $result }</output>
        </report>
};

(:~
 : Check if the function's result is false.
 :)
declare %private function test:assertFalse($result as item()*) as element(report)? {
    if (not($result)) then
        ()
    else
        <report>
            <failure message="assertExists failed."
                type="failure-error-code-1"/>,
            <output>{ $result }</output>
        </report>
};

(:~
 : Evaluate an arbitrary XPath expression against result. The test passes if
 : the XPath returns either true or a non-empty sequence.
 :)
declare %private function test:assertXPath($annotation as element(annotation), $output as item()*) as element(report)? {
    let $expr := $annotation/value[1]/string()
    let $result :=
        if (count($annotation/value) = 2 and boolean($annotation/value[2])) then
            util:expand($output)
        else
            $output
    let $xr :=
        test:checkXPathResult(
            if (matches($expr, "^\s*/")) then
                util:eval(concat("$result", $expr))
            else
                util:eval($expr)
        )
    return
        if ($xr) then
            ()
        else
            <report>
                <failure message="assertXPath failed."
                    type="failure-error-code-1">{ $expr }</failure>,
                <output>{ $result }</output>
            </report>
};

declare %private function test:checkXPathResult($result as item()*) {
    if ($result instance of xs:boolean) then
        $result
    else
        exists($result)
};

declare %private function test:cast-to-type($value as item(), $result as item()) {
    typeswitch ($result)
        case node() return
            util:parse("<r>" || $value || "</r>")/r/node()
        case xs:integer return
            xs:integer($value)
        case xs:int return
            xs:int($value)
        case xs:long return
            xs:long($value)
        case xs:decimal return
            xs:decimal($value)
        case xs:double return
            xs:double($value)
        case xs:float return
            xs:float($value)
        case xs:date return
            xs:date($value)
        case xs:dateTime return
            xs:dateTime($value)
        case xs:time return
            xs:time($value)
        case xs:boolean return
            xs:boolean($value)
        case xs:anyURI return
            xs:anyURI($value)
        default return
            string($value)
};

(: Helper functions to be used by test modules :)

declare function test:mkcol($root as xs:string, $path as xs:string) as empty() {
    test:mkcol-recursive($root, tokenize($path, "/"))
};

declare %private function test:mkcol-recursive($collection, $components) as empty() {
    if (exists($components)) then
        let $newColl := concat($collection, "/", $components[1])
        return (
            xmldb:create-collection($collection, $components[1])[2],
            test:mkcol-recursive($newColl, subsequence($components, 2))
        )
    else
        ()
};

declare function test:to-html($output as element(testsuites)) {

    {
        for $suite in $output/testsuite
        return

{$suite/@package/string()}

                {
                    for $case in $suite/testcase
                    return
                        test:print-testcase($case)
                }

    }

};

declare %private function test:print-testcase($case as element(testcase)) {

        {$case/@name/string()}

        {
            if ($case/failure) then
                ($case/failure/@message/string(), " Expected: ", $case/failure/text())
            else
                "OK"
        }

};

xquery version "3.0";

(:~
 : XQSuite - a functional test framework based on XQuery 3.0 annotations.
 : Relies on the functions util:list-functions and util:inspect-function
 : to inspect annotations. The rest is pretty much standard XQuery.
 :
 : Usage:
 :
 :

 : import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";
 : import module namespace t="http://exist-db.org/xquery/test/examples" at "examples.xql";
 :
 : test:suite(util:list-functions("http://exist-db.org/xquery/test/examples"))
 :

 :
 : @author Wolfgang Meier
 :)
module namespace test="http://exist-db.org/xquery/xqsuite";

declare variable $test:TEST_NAMESPACE := "http://exist-db.org/xquery/xqsuite";

declare variable $test:UNKNOWN_ASSERTION := QName($test:TEST_NAMESPACE, "no-such-assertion");
declare variable $test:WRONG_ARG_COUNT := QName($test:TEST_NAMESPACE, "wrong-number-of-arguments");

(:~
 : Main entry point into the module. Takes a sequence of function items.
 : Functions with known test annotations will be evaluated and their results
 : checked against the annotations.
 :
 : @param $functions a sequence of function items
 : @return an XML report (in xUnit format)
 :)
declare function test:suite($functions as function(*)+) {
    let $modules := test:distinct-modules($functions)
    return
        <testsuites>
        {
            (: Run tests for each module in turn :)
            for $module in $modules
            let $modFunctions := filter(function($func) {
                    namespace-uri-from-QName(function-name($func)) = $module
                }, $functions)
            let $setup := test:call-func-with-annotation($modFunctions, "setUp")
            let $result :=
                if (empty($setup) or $setup/self::ok) then
                    let $startTime := util:system-time()
                    let $results :=
                        test:function-by-annotation($modFunctions, "assert", test:run-tests#2)
                    let $elapsed :=
                        util:system-time() - $startTime
                    return
                        <testsuite package="{$module}" timestamp="{util:system-dateTime()}"
                            failures="{count($results/failure)}" tests="{count($results)}"
                            time="{$elapsed}">
                            { $results }
                        </testsuite>
                else
                    <testsuite package="{$module}" timestamp="{util:system-dateTime()}"
                        errors="{count($functions)}">
                        {$setup/string()}
                    </testsuite>
            return
                ($result, test:call-func-with-annotation($modFunctions, "tearDown"))[1]
        }
        </testsuites>
};

(:~
 : Find functions having the given annotation and call the callback function.
 :)
declare %private function test:function-by-annotation($functions as function(*)+, $annot as xs:string,
    $callback as function(function(*), element(function)) as item()*) {
    for $function in $functions
    let $meta := util:inspect-function($function)
    where $meta/annotation[@namespace = $test:TEST_NAMESPACE][matches(@name, ":" || $annot)]
    return
        $callback($function, $meta)
};

(:~
 : Return the namespace URI of all distinct modules in the input set.
 :)
declare %private function test:distinct-modules($functions as function(*)+) as xs:string+ {
    distinct-values(
        for $func in $functions
        return
            namespace-uri-from-QName(function-name($func))
    )
};

(:~
 : Find functions having the specified annotation and call them,
 : return <ok/> upon success, an error description otherwise.
 : Used for setUp and tearDown.
 :)
declare %private function test:call-func-with-annotation($functions as function(*)+, $annot as xs:string) as element()? {
    test:function-by-annotation($functions, $annot, function($func, $meta) {
        try {
            (<ok/>, $func())[1]
        } catch * {
            <system-err>{$err:description}</system-err>
        }
    })
};

(:~
 : Calls the test function one or more times, depending on the number of
 : %args() annotations found. Each %arg annotation triggers one test run
 : using the supplied parameters.
 :)
declare %private function test:run-tests($func as function(*), $meta as element(function)) {
    let $argsAnnot := $meta/annotation[matches(@name, ":args")]
    return
        if ($argsAnnot) then
            for $args in $argsAnnot
            return
                test:test($func, $meta, $args)
        else
            test:test($func, $meta, ())
};

(:~
 : The main function for running a single test. Executes the test function
 : and compares the result against each assertXXX annotation.
 :)
declare %private function test:test($func as function(*), $meta as element(function), $args as element(annotation)?) {
    let $assertions := test:get-assertions($meta, $args)
    return
        if (exists($assertions)) then
            try {
                let $result := test:call-test($func, $meta, $args)
                let $assertResult := test:check-assertions($assertions, $result)
                return
                    test:print-result($meta, $result, $assertResult)
            } catch * {
                let $assertError := $meta/annotation[contains(@name, ":assertError")]
                return
                    if ($assertError) then
                        if ($assertError/value and not(contains($err:code, $assertError/value/string())
                            or contains($err:description, $assertError/value/string())))then
                            <report>
                                <failure message="Expected error {$assertError/value/string()}, got: {$err:code}"
                                    type="failure-error-code-1"/>
                            </report>
                        else
                            test:print-result($meta, (), ())
                    else
                        <error code="{$err:code}" message="{$err:description}">
                            <xquery-trace>{$exerr:xquery-stack-trace}</xquery-trace>
                            <java-trace>{$exerr:java-stack-trace}</java-trace>
                        </error>
            }
        else
            ()
};

(:~
 : Get all %assertXXX annotations of the function. If %args is used multiple times,
 : assertions apply to the result of running the function with the parameters given
 : in the preceding %args.
 :)
declare %private function test:get-assertions($meta as element(function), $args as element(annotation)?) {
    if ($args) then
        let $nextArgs := $args/following-sibling::annotation[contains(@name, ":args")]
        return
            $args/following-sibling::annotation[contains(@name, ":assert")]
            except
            $nextArgs/following-sibling::annotation[contains(@name, ":assert")]
    else
        $meta/annotation[contains(@name, ":assert")]
};

(:~
 : Map any arguments from the %args annotation into function parameters and evaluate
 : the resulting function.
 :)
declare %private function test:call-test($func as function(*), $meta as element(function), $args as element(annotation)*) {
    let $argCount := count($meta/argument)
    let $testArgs := $args/value/string()
    return
        if (count($testArgs) != $argCount) then
            error(
                $test:WRONG_ARG_COUNT,
                "The number of arguments specified in test:args must match the arguments of the function to test"
            )
        else
            let $args := test:map-arguments($testArgs, $meta/argument)
            return
                test:apply($func, $args)
};
(:~
 : Transform the annotation to the type required by the function parameter.
 :)
declare function test:map-arguments($testArgs as xs:string*, $funcArgs as element(argument)*) {
    if (exists($testArgs)) then
        map-pairs(function($targ, $farg) {
            switch (string($farg/@type))
                case "xs:string" return
                    string($targ)
                case "xs:integer" case "xs:int" return
                    xs:integer($targ)
                case "xs:decimal" return
                    xs:decimal($targ)
                case "xs:float" case "xs:double" return
                    xs:double($targ)
                case "xs:date" return
                    xs:date($targ)
                case "xs:dateTime" return
                    xs:dateTime($targ)
                case "xs:time" return
                    xs:time($targ)
                case "element()" return
                    util:parse($targ)/*
                case "text()" return
                    text { string($targ) }
                default return
                    $targ
        }, $testArgs, $funcArgs)
    else
        ()
};

(:~
 : Call the given function with parameters taken from $args.
 :)
declare %private function test:apply($func as function(*), $args as item()*) {
    switch (count($args))
        case 1 return
            $func($args[1])
        case 2 return
            $func($args[1], $args[2])
        case 3 return
            $func($args[1], $args[2], $args[3])
        case 4 return
            $func($args[1], $args[2], $args[3], $args[4])
        case 5 return
            $func($args[1], $args[2], $args[3], $args[4], $args[5])
        case 6 return
            $func($args[1], $args[2], $args[3], $args[4], $args[5], $args[6])
        case 7 return
            $func($args[1], $args[2], $args[3], $args[4], $args[5], $args[6], $args[7])
        default return
            error($test:WRONG_ARG_COUNT, "Function takes too many arguments")
};

(:~
 : Print out evaluation results for a given test.
 :)
declare %private function test:print-result($meta as element(function), $result as item()*,
    $assertResult as element(report)*) {
    let $nameAnnot := $meta/annotation[matches(@name, ":name")]
    let $name := if ($nameAnnot) then $nameAnnot/value else replace($meta/@name, "^\w+:([^:]+)$", "$1")
    return
        <testcase name="{$name}" class="{$meta/@name}">
        {
            if (exists($assertResult)) then
                ($assertResult[failure] | $assertResult)[1]/*
            else
                ()
        }
        </testcase>
};

(:~
 : Check the function's return value against each assertion.
 :)
declare %private function test:check-assertions($assertions as element(annotation)*, $result as item()*) as element(report)* {
    for $annotation in $assertions
    let $assert := replace($annotation/@name, "^\w+:(.*)$", "$1")
    return
        switch ($assert)
            case "assertEquals" return
                test:assertEquals($annotation/value/string(), $result)
            case "assertEmpty" return
                test:assertEmpty($result)
            case "assertExists" return
                test:assertExists($result)
            case "assertTrue" return
                test:assertTrue($result)
            case "assertFalse" return
                test:assertFalse($result)
            case "assertXPath" return
                test:assertXPath($annotation, $result)
            case "assertError" return
                test:assertError($annotation/value/string(), $result)
            default return
                error($test:UNKNOWN_ASSERTION, $annotation/@name)
};

(:~
 : Check for equality of the function's result with the value in the annotation.
 : This function transforms the result to a string before checking for equality.
 :)
declare %private function test:assertEquals($value as xs:string, $result as item()*) as element(report)? {
    let $normResult :=
        typeswitch ($result)
            case node()* return
                test:normalize($result)
            default return
                string-join($result, " ")
    let $normValue :=
        typeswitch ($result)
            case node()* return
                util:parse("<r>" || $value || "</r>")/r/node()
            default return
                $value
    let $equal :=
        typeswitch ($normResult)
            case node()* return
                deep-equal($normValue, $normResult)
            default return
                $normResult = $normValue
    return
        if ($equal) then
            ()
        else
           <report>
                <failure message="assertEquals failed."
                    type="failure-error-code-1">
                { $normValue }
                </failure>
                <output>{ $result }</output>
            </report>
};

declare %private function test:normalize($nodes as node()*) {
    for $node in $nodes return test:normalize-node($node)
};

declare %private function test:normalize-node($node as node()) {
    typeswitch ($node)
        case document-node() return
            test:normalize-node($node/*)
        case element() return
            element { node-name($node) } {
                $node/@*, for $child in $node/node() return test:normalize-node($child)
            }
        case text() return
            let $norm := normalize-space($node)
            return
                if (string-length($norm) eq 0) then () else $node
        default return
            $node
};

(:~
 : Check if the function's result is empty.
 :)
declare %private function test:assertEmpty($result as item()*) as element(report)? {
    if (empty($result)) then
        ()
    else
        <report>
            <failure message="assertEmpty failed."
                type="failure-error-code-1"/>,
            <output>{ $result }</output>
        </report>
};

(:~
 : Check if the function's result is not empty.
 :)
declare %private function test:assertExists($result as item()*) as element(report)? {
    if (exists($result)) then
        ()
    else
        <report>
            <failure message="assertExists failed."
                type="failure-error-code-1"/>,
            <output>{ $result }</output>
        </report>
};

(:~
 : Check if the function's result is true.
 :)
declare %private function test:assertTrue($result as item()*) as element(report)? {
    if ($result) then
        ()
    else
        <report>
            <failure message="assertExists failed."
                type="failure-error-code-1"/>,
            <output>{ $result }</output>
        </report>
};

(:~
 : Check if the function caused an error.
 :)
declare %private function test:assertError($value as xs:string, $result as item()*) as element(report)? {
    if ($result) then
        ()
    else
        <report>
            <failure message="assertError failed. Expected error {$value}"
                type="failure-error-code-1"/>,
            <output>{ $result }</output>
        </report>
};

(:~
 : Check if the function's result is false.
 :)
declare %private function test:assertFalse($result as item()*) as element(report)? {
    if (not($result)) then
        ()
    else
        <report>
            <failure message="assertExists failed."
                type="failure-error-code-1"/>,
            <output>{ $result }</output>
        </report>
};

(:~
 : Evaluate an arbitrary XPath expression against result. The test passes if
 : the XPath returns either true or a non-empty sequence.
 :)
declare %private function test:assertXPath($annotation as element(annotation), $output as item()*) as element(report)? {
    let $expr := $annotation/value[1]/string()
    let $result :=
        if (count($annotation/value) = 2 and boolean($annotation/value[2])) then
            util:expand($output)
        else
            $output
    let $xr :=
        test:checkXPathResult(
            if (matches($expr, "^\s*/")) then
                util:eval(concat("$result", $expr))
            else
                util:eval($expr)
        )
    return
        if ($xr) then
            ()
        else
            <report>
                <failure message="assertXPath failed."
                    type="failure-error-code-1">{ $expr }</failure>,
                <output>{ $result }</output>
            </report>
};

declare %private function test:checkXPathResult($result as item()*) {
    if ($result instance of xs:boolean) then
        $result
    else
        exists($result)
};

(: Helper functions to be used by test modules :)

declare function test:mkcol($root as xs:string, $path as xs:string) as empty() {
    test:mkcol-recursive($root, tokenize($path, "/"))
};

declare %private function test:mkcol-recursive($collection, $components) as empty() {
    if (exists($components)) then
        let $newColl := concat($collection, "/", $components[1])
        return (
            xmldb:create-collection($collection, $components[1])[2],
            test:mkcol-recursive($newColl, subsequence($components, 2))
        )
    else
        ()
};

declare function test:to-html($output as element(testsuites)) {

    {
        for $suite in $output/testsuite
        return

{$suite/@package/string()}

                {
                    for $case in $suite/testcase
                    return
                        test:print-testcase($case)
                }

    }

};

declare %private function test:print-testcase($case as element(testcase)) {

        {$case/@name/string()}

        {
            if ($case/failure) then
                ($case/failure/@message/string(), " Expected: ", $case/failure/text())
            else
                "OK"
        }

};


creating facility from DHIS2 and HFR

creating facility from DHIS2 and HFR

import module namespace util = "https://github.com/openhie/openinfoman-dhis/util";
declare namespace csd = "urn:ihe:iti:csd:2013";
declare default element  namespace   "urn:ihe:iti:csd:2013";
declare variable $careServicesRequest as item() external;
(:
   The query will be executed against the root element of the CSD document.

   The dynamic context of this query has $careServicesRequest set to contain any of the search
   and limit paramaters as sent by the Service Finder
:)

let $namespace_uuid := "7ee93e32-78da-4913-82f8-49eb0a618cfc"

let $uuid_generate := function($name) {
  concat('urn:uuid:' , util:uuid_generate($name,$namespace_uuid))
}

let $dhisid := $careServicesRequest/organization/@id
let $pid := $careServicesRequest/organization/parent/@id
let $urn := $uuid_generate($dhisid)
let $parent :=
     if ($pid)
     then
       let $parent_urn := $uuid_generate($pid)
       return <csd:parent entityID="{$parent_urn}"/>
     else ()
let $name := $careServicesRequest/organization/name
let $org :=
if (($name) and ($dhisid)  and ($urn) )
     then
       <csd:organization entityID="{$urn}">
	 <csd:otherID assigningAuthorityName='tanzania-hmis' code='{$dhisid}'/>
	 <csd:primaryName>{$name}</csd:primaryName>
	 {$parent}
       </csd:organization>
     else ()  (:no name or id or type :)

let $t0:= trace($org,"Org is ")
let $t0:= trace($dhisid/string(),"ID is ")
let $t0:= trace($parent,"Parent is ")
let $t1:= trace($urn,"URN IS")
let $t1:= trace($name/string(),"Name IS")
let $t1:= trace(/CSD/organizationDirectory,"Dir is ")
let $t1:= trace(/,"Doc is ")
let $t1:= trace($careServicesRequest,"CSR is ")

return insert node $org into /CSD/organizationDirectory

import module namespace util = "https://github.com/openhie/openinfoman-dhis/util";
declare namespace csd = "urn:ihe:iti:csd:2013";
declare default element  namespace   "urn:ihe:iti:csd:2013";
declare variable $careServicesRequest as item() external;
(:
   The query will be executed against the root element of the CSD document.

   The dynamic context of this query has $careServicesRequest set to contain any of the search
   and limit paramaters as sent by the Service Finder
:)

let $namespace_uuid := "7ee93e32-78da-4913-82f8-49eb0a618cfc"

let $uuid_generate := function($name) {
  concat('urn:uuid:' , util:uuid_generate($name,$namespace_uuid))
}

let $id := $careServicesRequest/organization/@id
let $pid := $careServicesRequest/organization/parent/@id
let $urn := $uuid_generate(concat('organization:',$id))
let $parent :=
     if ($pid)
     then
       let $parent_urn := $uuid_generate(concat('organization:',$pid))
       return <csd:parent entityID="{$parent_urn}"/>
     else ()
let $level := count(tokenize($id,"[\s.]"))-1
let $name := $careServicesRequest/organization/name/text()
let $org :=
if (($name) and ($level)  and ($urn) )
     then
       <csd:organization entityID="{$urn}">
	 <csd:otherID assigningAuthorityName='resource_map_tanzania' code="{$id}"/>
	 <csd:codedType code="{$level}" codingScheme='2.25.123494412831734081331965080571820180508'/>
	 <csd:primaryName>{$name}</csd:primaryName>
	 {$parent}
       </csd:organization>
     else ()  (:no name or id or type :)

let $t0:= trace($org,"Org is ")
let $t1:= trace(/CSD/organizationDirectory,"Dir is ")
let $t1:= trace(/,"Doc is ")
let $t1:= trace($careServicesRequest,"CSR is ")

return insert node $org into /CSD/organizationDirectory