Skip to content

Instantly share code, notes, and snippets.

@joewiz
Last active June 8, 2018 06:10
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joewiz/fa32be80749a69fcb8da to your computer and use it in GitHub Desktop.
Save joewiz/fa32be80749a69fcb8da to your computer and use it in GitHub Desktop.
Unit testing XQuery with XQSuite in eXist-db: tests for a sample function, how to run tests, and test results
xquery version "3.0";
(: This sample library module contains a single function, iu:analyze-date-string().
: The purpose of the sample is to demonstrate XQSuite tests, a unit test framework that uses
: XQuery 3.0's Annotations facility to embed testing assertions and parameters in XQuery functions.
:
: By writing unit tests and running them after each new change to an application, we can spot new bugs
: right away and prevent regressions.
:
: The XQSuite tests in this example are stored in a separate module, 02-tests-xql.
: For more on XQSuite, see http://exist-db.org/exist/apps/doc/xqsuite.xml and
: http://en.wikibooks.org/wiki/XQuery/XUnit_Annotations :)
module namespace iu = "http://history.state.gov/ns/xquery/import-utilities";
(:~
: Analyzes a date string to make sure that it is in the basic form expected by the date-parser.xqm
: utility. Splits date ranges into start and end dates, since the date-parser utility
: only takes one date at a time.
:
: @param $date-string A space-normalized date string
: @return Either a date element containing the original date, a range element containing the start and end dates, or an error element
:)
declare function iu:analyze-date-string($date-string as xs:string) as element() {
(: regular expressions for each component of a date :)
let $year-pattern := '\d{4}'
let $month-pattern := '((Jan|Feb|Mar|Apr|Jun|Aug|Sep|Sept|Oct|Nov|Dec)\.?|(January|February|March|April|May|June|July|August|September|October|November|December))'
let $day-pattern := '\d{1,2}'
let $range-delimiter-pattern := '-' (: dash; not expecting en dash :)
(: regular expressions to use for matching the different types of expected dates :)
(: "June 30, 2014" :)
let $simple-date-pattern := concat('^', $month-pattern, ' ', $day-pattern, ', ', $year-pattern, '$')
(: "April 3-15, 1943" :)
let $intra-month-range-pattern := concat('^', $month-pattern, ' ', $day-pattern, $range-delimiter-pattern, $day-pattern, ', ', $year-pattern, '$')
(: "September 30-October 1, 1973" :)
let $inter-month-range-pattern := concat('^', $month-pattern, ' ', $day-pattern, $range-delimiter-pattern, $month-pattern, ' ', $day-pattern, ', ', $year-pattern, '$')
(: "December 7, 1941-August 15, 1945" :)
let $inter-year-range-pattern := concat('^', $month-pattern, ' ', $day-pattern, ', ', $year-pattern, $range-delimiter-pattern, $month-pattern, ' ', $day-pattern, ', ', $year-pattern, '$')
return
if (matches($date-string, $simple-date-pattern)) then
<date>{$date-string}</date>
else if (matches($date-string, $intra-month-range-pattern)) then
let $start-date := concat(substring-before($date-string, '-'), ', ', replace($date-string, '\w+ \d+-\d+, (\d{4})', '$1'))
let $end-date := replace($date-string, '(\w+) \d+-(\d+), (\d{4})', '$1 $2, $3')
return
<range type="intra-month">
<date>{$start-date}</date>
<date>{$end-date}</date>
</range>
else if (matches($date-string, $inter-month-range-pattern)) then
let $start-date := concat(substring-before($date-string, '-'), ', ', replace($date-string, '.*?(\d{4})', '$1'))
let $end-date := replace($date-string, '\w+ \d+-(\w+ \d+, \d{4})', '$1')
return
<range type="inter-month">
<date>{$start-date}</date>
<date>{$end-date}</date>
</range>
else if (matches($date-string, $inter-year-range-pattern)) then
let $start-date := replace($date-string, '^([^-]*?)-.*$', '$1')
let $end-date := replace($date-string, '^[^-]*?-(.*)$', '$1')
return
<range type="inter-year">
<date>{$start-date}</date>
<date>{$end-date}</date>
</range>
else
<error>Unable to verify validity of date string: {$date-string}</error>
};
xquery version "3.0";
(: This library module contains XQSuite tests for the iu:analyze-date-string() module storedd in 01-library.xql :)
module namespace iu-test = "http://history.state.gov/ns/xquery/import-utilities/test";
import module namespace iu = "http://history.state.gov/ns/xquery/import-utilities" at "01-library.xql";
declare namespace test="http://exist-db.org/xquery/xqsuite";
declare
%test:args("June 30, 2014")
%test:assertXPath("deep-equal($result, <date>June 30, 2014</date>)")
function iu-test:analyze-date-string-simple-date($string as xs:string) {
iu:analyze-date-string($string)
};
declare
%test:args("Sep. 30, 2014")
%test:assertXPath("deep-equal($result, <date>Sep. 30, 2014</date>)")
function iu-test:analyze-date-string-simple-date-abbreviation($string as xs:string) {
iu:analyze-date-string($string)
};
declare
%test:args("April 3-15, 1943")
%test:assertXPath("deep-equal($result, <range type=""intra-month"">
<date>April 3, 1943</date>
<date>April 15, 1943</date>
</range>)")
function iu-test:analyze-date-string-intra-month-range($string as xs:string) {
iu:analyze-date-string($string)
};
declare
%test:args("September 30-October 1, 1973")
%test:assertXPath("deep-equal($result, <range type=""inter-month"">
<date>September 30, 1973</date>
<date>October 1, 1973</date>
</range>)")
function iu-test:analyze-date-string-inter-month-range($string as xs:string) {
iu:analyze-date-string($string)
};
declare
%test:args("December 7, 1941-August 15, 1945")
%test:assertXPath("deep-equal($result, <range type=""inter-year"">
<date>December 7, 1941</date>
<date>August 15, 1945</date>
</range>)")
function iu-test:analyze-date-string-inter-year-range($string as xs:string) {
iu:analyze-date-string($string)
};
declare
%test:args("May 3, 8, 1963")
%test:assertTrue
function iu-test:analyze-date-string-fail-on-date-sequence($string as xs:string) {
iu:analyze-date-string($string)/self::error
};
xquery version "3.0";
(: This main module fires off the tests stored in 02-tests.xql :)
import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";
import module namespace iu-test="http://history.state.gov/ns/xquery/import-utilities/test" at "02-tests.xql";
test:suite(util:list-functions("http://history.state.gov/ns/xquery/import-utilities/test"))
<testsuites>
<testsuite package="http://history.state.gov/ns/xquery/import-utilities/test" timestamp="2014-06-10T16:10:46.879-04:00" failures="0" tests="6" time="PT0.017S">
<testcase name="iu-test:analyze-date-string-fail-on-date-sequence" class="iu-test:analyze-date-string-fail-on-date-sequence"/>
<testcase name="iu-test:analyze-date-string-inter-month-range" class="iu-test:analyze-date-string-inter-month-range"/>
<testcase name="iu-test:analyze-date-string-inter-year-range" class="iu-test:analyze-date-string-inter-year-range"/>
<testcase name="iu-test:analyze-date-string-intra-month-range" class="iu-test:analyze-date-string-intra-month-range"/>
<testcase name="iu-test:analyze-date-string-simple-date-abbreviation" class="iu-test:analyze-date-string-simple-date-abbreviation"/>
<testcase name="iu-test:analyze-date-string-simple-date" class="iu-test:analyze-date-string-simple-date"/>
</testsuite>
</testsuites>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment