diff --git a/exist-core/src/main/resources/org/exist/xquery/lib/xqsuite/xqsuite.xql b/exist-core/src/main/resources/org/exist/xquery/lib/xqsuite/xqsuite.xql index 2f677ad4f86..966295f195b 100755 --- a/exist-core/src/main/resources/org/exist/xquery/lib/xqsuite/xqsuite.xql +++ b/exist-core/src/main/resources/org/exist/xquery/lib/xqsuite/xqsuite.xql @@ -57,6 +57,7 @@ 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"); declare variable $test:TYPE_ERROR := QName($test:TEST_NAMESPACE, "type-error"); +declare variable $test:CUSTOM_ASSERTION_FAILURE_TYPE := "custom-assertion-failure"; (:~ : Main entry point into the module. Takes a sequence of function items. @@ -138,20 +139,34 @@ declare function test:suite( }; -declare function test:fail ($expected as item()*, $actual as item()*, $message as xs:string) as empty-sequence() { - test:fail($expected, $actual, $message, "custom-assertion-failure") +declare function test:fail () as empty-sequence() { + test:fail( + $test:CUSTOM_ASSERTION_FAILURE_TYPE, "A custom assertion failed", true(), false()) +}; + +declare function test:fail ($type as xs:string) as empty-sequence() { + test:fail( + $type, "The custom assertion of type """ || $type || """ failed", true(), false()) +}; + +declare function test:fail ($type as xs:string, $message as xs:string) as empty-sequence() { + test:fail($type, $message, true(), false()) +}; + +declare function test:fail ($message as xs:string, $expected as item()*, $actual as item()*) as empty-sequence() { + test:fail($test:CUSTOM_ASSERTION_FAILURE_TYPE, $message, $expected, $actual) }; declare function test:fail ( - $expected as item()*, - $actual as item()*, + $type as xs:string, $message as xs:string, - $type as xs:string + $expected as item()*, + $actual as item()* ) as empty-sequence() { error(xs:QName("test:failure"), $message, map { + "type": $type, "expected": $expected, - "actual": $actual, - "type": $type + "actual": $actual }) }; diff --git a/exist-core/src/test/xquery/xqsuite/custom-assertion.xqm b/exist-core/src/test/xquery/xqsuite/custom-assertion.xqm index 65cebea79d0..1e357844ed1 100644 --- a/exist-core/src/test/xquery/xqsuite/custom-assertion.xqm +++ b/exist-core/src/test/xquery/xqsuite/custom-assertion.xqm @@ -32,79 +32,137 @@ import module namespace test="http://exist-db.org/xquery/xqsuite" declare variable $ca:var := map {"a": 1, "b": 2}; declare - %test:assertEquals("expected", "actual", "Custom message", "custom-assertion-failure") -function ca:test-fail-3() as item()* { + %test:assertEquals("A custom assertion failed", "custom-assertion-failure", "true", "false") +function ca:test-fail-0() as item()* { try { - test:fail("expected", "actual", "Custom message") + test:fail() } catch test:failure { - $err:value?expected, $err:value?actual, $err:description, $err:value?type + $err:description, $err:value?type, $err:value?expected, $err:value?actual } }; declare - %test:assertEquals("expected", "actual", "Custom message", "custom-type") + %test:assertEquals("The custom assertion of type ""custom-type"" failed", "custom-type", "true", "false") +function ca:test-fail-1() as item()* { + try { + test:fail("custom-type") + } + catch test:failure { + $err:description, $err:value?type, $err:value?expected, $err:value?actual + } +}; + +declare + %test:assertEquals("Custom message", "custom-type", "true", "false") +function ca:test-fail-2() as item()* { + try { + test:fail("custom-type", "Custom message") + } + catch test:failure { + $err:description, $err:value?type, $err:value?expected, $err:value?actual + } +}; + +declare + %test:assertEquals("Custom message", "custom-type", "expected", "actual") function ca:test-fail-4() as item()* { try { - test:fail("expected", "actual", "Custom message", "custom-type") + test:fail("custom-type", "Custom message", "expected", "actual") } catch test:failure { - $err:value?expected, $err:value?actual, $err:description, $err:value?type + $err:description, $err:value?type, $err:value?expected, $err:value?actual } }; declare %test:assertTrue -function ca:pass() as item()* { +function ca:map-assertion-pass() as item()* { ca:map-assertion($ca:var, map {"b": 2, "a": 1}) }; declare - %test:assertEquals("Key 'b' is missing", "map-assertion-failure") -function ca:missing-key-default-type() as item()* { + %test:assertEquals("Key 'b' is missing", "map-assertion-failure", "{""a"":1}") +function ca:map-assertion-missing-key() as item()* { try { - ca:map-assertion($ca:var, map {"a": 1, "c": 3}) + ca:map-assertion($ca:var, map {"a": 1}) } catch test:failure { - $err:description, $err:value?type + $err:description, $err:value?type, + fn:serialize($err:value?actual, map{"method":"json"}) } }; declare - %test:assertEquals("Value mismatch for key 'b'", "custom-assertion-failure") -function ca:wrong-value-custom-type() as item()* { + %test:assertEquals("Value mismatch for key 'b'", "map-assertion-failure", "{""a"":1,""b"":3}") +function ca:map-assertion-wrong-value() as item()* { try { ca:map-assertion($ca:var, map {"a": 1, "b": 3}) } catch test:failure { - $err:description, $err:value?type + $err:description, $err:value?type, + fn:serialize($err:value?actual, map{"method":"json"}) } }; declare - %test:assertEquals("Type mismatch", "type-mismatch") -function ca:type-mismatch-custom-type() as item()* { + %test:assertEquals("Additional keys found: (23, o)", "map-assertion-failure", "{""a"":1,""23"":3,""o"":""o""}") +function ca:map-assertion-additional-key() as item()* { + try { + ca:map-assertion($ca:var, map {"a": 1, 23: 3, "o": "o"}) + } + catch test:failure { + $err:description, $err:value?type, + fn:serialize($err:value?actual, map{"method":"json"}) + } +}; + +declare + %test:assertEquals("Type mismatch", "type-mismatch", "[1,2]") +function ca:map-assertion-type-mismatch() as item()* { try { ca:map-assertion($ca:var, [1,2]) } catch test:failure { - $err:description, $err:value?type + $err:description, $err:value?type, + fn:serialize($err:value?actual, map{"method":"json"}) } }; +(: + : custom assertion, which could also be imported from a library module + :) + +declare %private variable $ca:MAP_ASSERTION_TYPE := "map-assertion-failure"; + declare %private function ca:map-assertion ($expected as map(*), $actual as item()*) as item()* { - if (exists($actual) and count($actual) eq 1 and $actual instance of map(*)) - then ( - for-each(map:keys($expected), function ($key as xs:anyAtomicType) { - if (not(map:contains($actual, $key))) - then test:fail($expected, $actual, "Key '" || $key || "' is missing", "map-assertion-failure") - else if ($expected($key) ne $actual($key)) - then test:fail($expected, $actual, "Value mismatch for key '" || $key || "'") - else () - }) - , + if (not(exists($actual))) + then test:fail("type-mismatch", "Actual is empty") + else if (count($actual) gt 1) + then test:fail("type-mismatch", "Actual is a sequence with more than one item", $expected, $actual) + else if (not($actual instance of map(*))) + then test:fail("type-mismatch", "Type mismatch", $expected, $actual) + else if (not(empty( + map:keys(map:remove($actual, map:keys($expected)))))) + then test:fail( + $ca:MAP_ASSERTION_TYPE, + "Additional keys found: (" || string-join( + map:keys(map:remove($actual, map:keys($expected))), ', ') || ")", + $expected, + $actual + ) + else ( + for-each(map:keys($expected), ca:map-assert-key(?, $expected, $actual)), true() ) - else test:fail($expected, $actual, "Type mismatch", "type-mismatch") +}; + +declare %private +function ca:map-assert-key ($key as xs:anyAtomicType, $expected as map(*), $actual as map(*)) as item()* { + if (not(map:contains($actual, $key))) + then test:fail($ca:MAP_ASSERTION_TYPE, "Key '" || $key || "' is missing", $expected, $actual) + else if ($expected($key) ne $actual($key)) + then test:fail($ca:MAP_ASSERTION_TYPE, "Value mismatch for key '" || $key || "'", $expected, $actual) + else () };