471 lines
16 KiB
XML
471 lines
16 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!--
|
|
Tests dynamic function application boilerplate generation
|
|
|
|
Copyright (C) 2014 LoVullo Associates, Inc.
|
|
|
|
This file is part of hoxsl.
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
-->
|
|
|
|
<description xmlns="http://www.jenitennison.com/xslt/xspec"
|
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
|
xmlns:f="http://mikegerwitz.com/hoxsl/apply"
|
|
xmlns:foo="http://mikegerwitz.com/_junk"
|
|
stylesheet="apply-gen-test.xsl">
|
|
|
|
<variable name="args">
|
|
<foo:args>
|
|
<foo:arg1 />
|
|
<foo:arg2 />
|
|
<foo:arg3 />
|
|
<foo:arg4 />
|
|
<foo:arg5 />
|
|
<foo:arg6 />
|
|
<foo:arg7 />
|
|
<foo:arg8 />
|
|
</foo:args>
|
|
</variable>
|
|
|
|
|
|
<!-- source namespaces must be copied -->
|
|
<scenario label="source namespaces">
|
|
<context>
|
|
<xsl:stylesheet xmlns:foobar="baz">
|
|
<xsl:function name="foobar:baz">
|
|
<xsl:param name="foo" />
|
|
</xsl:function>
|
|
</xsl:stylesheet>
|
|
</context>
|
|
|
|
<expect label="are copied to destination"
|
|
test="exists( xsl:stylesheet/namespace::foobar )" />
|
|
</scenario>
|
|
|
|
|
|
<!-- basic case -->
|
|
<scenario label="given a unary function">
|
|
<context>
|
|
<xsl:stylesheet>
|
|
<xsl:function name="foo:bar">
|
|
<xsl:param name="foo" />
|
|
</xsl:function>
|
|
</xsl:stylesheet>
|
|
</context>
|
|
|
|
<expect label="generates a function of the same name"
|
|
test="xsl:stylesheet/xsl:function/@name = 'foo:bar'" />
|
|
|
|
<expect label="generates function of type `element()'"
|
|
test="xsl:stylesheet/xsl:function/@as = 'element()'" />
|
|
|
|
<!-- this function is used to generate an element for later
|
|
application -->
|
|
<expect label="generated function is nullary"
|
|
test="count( xsl:stylesheet/xsl:function/xsl:param ) = 0" />
|
|
|
|
<!-- the generated node is simply the same name and namespace as
|
|
the function -->
|
|
<expect label="generated function produces function reference
|
|
node"
|
|
test="exists( xsl:stylesheet/xsl:function/f:ref/foo:bar )" />
|
|
|
|
|
|
<!-- more detailed tests below -->
|
|
<expect label="generates application template"
|
|
test="xsl:stylesheet/xsl:template/@match
|
|
= 'f:ref[ foo:bar ]'" />
|
|
|
|
<expect label="generated template has mode f:apply"
|
|
test="xsl:stylesheet/xsl:template/@mode = 'f:apply'" />
|
|
</scenario>
|
|
|
|
|
|
<!-- we'll test the application directly; we won't parse the output,
|
|
since that is error-prone, fragile, and misses the poin -->
|
|
<scenario label="application templates">
|
|
<scenario label="of N-ary functions">
|
|
<context>
|
|
<xsl:stylesheet>
|
|
<xsl:function name="foo:bar">
|
|
<xsl:param name="a" />
|
|
<xsl:param name="b" as="xs:decimal" />
|
|
<xsl:param name="c" />
|
|
</xsl:function>
|
|
</xsl:stylesheet>
|
|
</context>
|
|
|
|
<expect label="yields N template parameters"
|
|
test="count( xsl:stylesheet/xsl:template/xsl:param )
|
|
= 3" />
|
|
|
|
<!-- important for application! -->
|
|
<expect label="template parameter names are sequential"
|
|
test="xsl:stylesheet/xsl:template/xsl:param
|
|
/@name = concat( 'arg', position() )" />
|
|
|
|
<expect label="mirrors params without @as"
|
|
test="not( xsl:stylesheet/xsl:template
|
|
/xsl:param[ 1 ]/@as )" />
|
|
|
|
<expect label="mirrors params with @as"
|
|
test="xsl:stylesheet/xsl:template
|
|
/xsl:param[ 2 ]/@as = 'xs:decimal'" />
|
|
</scenario>
|
|
</scenario>
|
|
|
|
|
|
<!-- if a function is nullary, then it is either a thunk or used for
|
|
its side-effects; we expect the user to take appropriate
|
|
caution -->
|
|
<scenario label="given a nullary function">
|
|
<context>
|
|
<xsl:stylesheet>
|
|
<xsl:function name="foo:bar">
|
|
<foo:thunk />
|
|
</xsl:function>
|
|
</xsl:stylesheet>
|
|
</context>
|
|
|
|
<!-- generating one would conflict, of couse -->
|
|
<expect label="does not generate a function"
|
|
test="not( xsl:stylesheet/xsl:function )" />
|
|
</scenario>
|
|
|
|
|
|
<!-- see SUT for rationale -->
|
|
<scenario label="given an arity-overloaded function">
|
|
<context>
|
|
<xsl:stylesheet>
|
|
<xsl:function name="foo:overloaded">
|
|
<xsl:param name="a" />
|
|
</xsl:function>
|
|
|
|
<xsl:function name="foo:overloaded">
|
|
<xsl:param name="a" />
|
|
<xsl:param name="b" />
|
|
</xsl:function>
|
|
</xsl:stylesheet>
|
|
</context>
|
|
|
|
<expect label="yields no functions of that name"
|
|
test="not( xsl:stylesheet/xsl:function[
|
|
@name='foo:overloaded' ] )" />
|
|
</scenario>
|
|
|
|
|
|
<scenario label="given a stylesheet">
|
|
<scenario label="with no function elements">
|
|
<context>
|
|
<xsl:stylesheet>
|
|
<xsl:template name="foo" />
|
|
<xsl:template name="bar" />
|
|
</xsl:stylesheet>
|
|
</context>
|
|
|
|
<expect label="produces an empty stylesheet"
|
|
context="xsl:stylesheet">
|
|
<xsl:stylesheet version="2.0" />
|
|
</expect>
|
|
</scenario>
|
|
</scenario>
|
|
|
|
|
|
<!-- xsl:transform is an alternative to xsl:stylesheet -->
|
|
<scenario label="given a xsl:template root note">
|
|
<context>
|
|
<xsl:transform />
|
|
</context>
|
|
|
|
<expect label="properly outputs stylesheet"
|
|
context="xsl:stylesheet">
|
|
<xsl:stylesheet version="2.0" />
|
|
</expect>
|
|
</scenario>
|
|
|
|
|
|
<!-- This actually tests the generated stylesheet to ensure proper
|
|
execution. We test by invoking the application template with
|
|
the result of the generated nullary. We expect that the
|
|
application template will apply the arguments to the proper
|
|
function and return the result of the expected type.
|
|
|
|
You can't see it here (check the imported stylesheet), but
|
|
`foo:apply-add-two' defines a return type, so we also ensure
|
|
that such type data are retained.
|
|
|
|
Exciting! -->
|
|
<scenario label="given a generated document">
|
|
<scenario label="with a processed function">
|
|
<!-- calling the generated nullary -->
|
|
<call function="foo:apply-add-two">
|
|
<param name="x" select="2" />
|
|
<param name="y" select="3" />
|
|
</call>
|
|
|
|
<expect label="applying template to nullary yields proper result"
|
|
test="$x:result = 5" />
|
|
</scenario>
|
|
|
|
|
|
<!-- ensure that multiple functions are processed -->
|
|
<scenario label="with multiple functions">
|
|
<call function="foo:apply-sub-two">
|
|
<param name="x" select="2" />
|
|
<param name="y" select="3" />
|
|
</call>
|
|
|
|
<expect label="applying template to nullary yields proper result"
|
|
test="$x:result = -1" />
|
|
</scenario>
|
|
|
|
|
|
<!-- note that this _does not_ test f:arity itself: it is intended
|
|
to test that the arity datum is properly generated -->
|
|
<scenario label="constructed dynamic function reference">
|
|
<variable name="two-result"
|
|
select="foo:sub-two()" />
|
|
|
|
<scenario label="is recognized as">
|
|
<call function="f:is-ref">
|
|
<param name="fnref" select="$two-result" />
|
|
</call>
|
|
|
|
<expect label="a dynamic function reference"
|
|
select="true()" />
|
|
</scenario>
|
|
|
|
|
|
<scenario label="target QName">
|
|
<call function="f:QName">
|
|
<param name="fnref" select="$two-result" />
|
|
</call>
|
|
|
|
<expect label="is the QName of the target function"
|
|
select="QName( 'http://mikegerwitz.com/_junk',
|
|
'sub-two' )" />
|
|
</scenario>
|
|
|
|
|
|
<scenario label="arity">
|
|
<call function="f:arity">
|
|
<param name="fnref" select="$two-result" />
|
|
</call>
|
|
|
|
<expect label="is the arity of target function"
|
|
select="2" />
|
|
</scenario>
|
|
</scenario>
|
|
|
|
|
|
<!-- more duplication...we support up to eight arguments, so we'll
|
|
have to test the generation of 1..7 (nullary is already
|
|
tested and 8 results in a full application) -->
|
|
<scenario label="with partial functions of 8-ary target, given">
|
|
<variable name="qname"
|
|
select="QName( 'http://mikegerwitz.com/_junk',
|
|
'foo:eight' )" />
|
|
|
|
<scenario label="one argument">
|
|
<call function="foo:eight">
|
|
<param name="arg1" select="$args/foo:arg1" />
|
|
</call>
|
|
|
|
<expect label="returns partially applied function"
|
|
test="f:is-partial( $x:result )" />
|
|
|
|
<expect label="references the target function"
|
|
test="f:QName( $x:result ) = $qname" />
|
|
|
|
<expect label="partially applies one argument"
|
|
test="f:arity( $x:result ) = 7" />
|
|
|
|
<variable name="result-args" as="item()+"
|
|
select="f:args( $x:result )" />
|
|
<expect label="argument is partially applied by reference"
|
|
test="$result-args[ 1 ] is $args/foo:arg1" />
|
|
</scenario>
|
|
|
|
|
|
<scenario label="two arguments">
|
|
<call function="foo:eight">
|
|
<param name="arg1" select="$args/foo:arg1" />
|
|
<param name="arg2" select="$args/foo:arg2" />
|
|
</call>
|
|
|
|
<expect label="returns partially applied function"
|
|
test="f:is-partial( $x:result )" />
|
|
|
|
<expect label="references the target function"
|
|
test="f:QName( $x:result ) = $qname" />
|
|
|
|
<expect label="partially applies one argument"
|
|
test="f:arity( $x:result ) = 6" />
|
|
|
|
<variable name="result-args" as="item()+"
|
|
select="f:args( $x:result )" />
|
|
<expect label="argument is partially applied by reference"
|
|
test="$result-args[ 1 ] is $args/foo:arg1
|
|
and $result-args[ 2 ] is $args/foo:arg2" />
|
|
</scenario>
|
|
|
|
|
|
<scenario label="three arguments">
|
|
<call function="foo:eight">
|
|
<param name="arg1" select="$args/foo:arg1" />
|
|
<param name="arg2" select="$args/foo:arg2" />
|
|
<param name="arg3" select="$args/foo:arg3" />
|
|
</call>
|
|
|
|
<expect label="returns partially applied function"
|
|
test="f:is-partial( $x:result )" />
|
|
|
|
<expect label="references the target function"
|
|
test="f:QName( $x:result ) = $qname" />
|
|
|
|
<expect label="partially applies one argument"
|
|
test="f:arity( $x:result ) = 5" />
|
|
|
|
<variable name="result-args" as="item()+"
|
|
select="f:args( $x:result )" />
|
|
<expect label="argument is partially applied by reference"
|
|
test="$result-args[ 1 ] is $args/foo:arg1
|
|
and $result-args[ 2 ] is $args/foo:arg2
|
|
and $result-args[ 3 ] is $args/foo:arg3" />
|
|
</scenario>
|
|
|
|
|
|
<scenario label="four arguments">
|
|
<call function="foo:eight">
|
|
<param name="arg1" select="$args/foo:arg1" />
|
|
<param name="arg2" select="$args/foo:arg2" />
|
|
<param name="arg3" select="$args/foo:arg3" />
|
|
<param name="arg4" select="$args/foo:arg4" />
|
|
</call>
|
|
|
|
<expect label="returns partially applied function"
|
|
test="f:is-partial( $x:result )" />
|
|
|
|
<expect label="references the target function"
|
|
test="f:QName( $x:result ) = $qname" />
|
|
|
|
<expect label="partially applies one argument"
|
|
test="f:arity( $x:result ) = 4" />
|
|
|
|
<variable name="result-args" as="item()+"
|
|
select="f:args( $x:result )" />
|
|
<expect label="argument is partially applied by reference"
|
|
test="$result-args[ 1 ] is $args/foo:arg1
|
|
and $result-args[ 2 ] is $args/foo:arg2
|
|
and $result-args[ 3 ] is $args/foo:arg3
|
|
and $result-args[ 4 ] is $args/foo:arg4" />
|
|
</scenario>
|
|
|
|
|
|
<scenario label="five arguments">
|
|
<call function="foo:eight">
|
|
<param name="arg1" select="$args/foo:arg1" />
|
|
<param name="arg2" select="$args/foo:arg2" />
|
|
<param name="arg3" select="$args/foo:arg3" />
|
|
<param name="arg4" select="$args/foo:arg4" />
|
|
<param name="arg5" select="$args/foo:arg5" />
|
|
</call>
|
|
|
|
<expect label="returns partially applied function"
|
|
test="f:is-partial( $x:result )" />
|
|
|
|
<expect label="references the target function"
|
|
test="f:QName( $x:result ) = $qname" />
|
|
|
|
<expect label="partially applies one argument"
|
|
test="f:arity( $x:result ) = 3" />
|
|
|
|
<variable name="result-args" as="item()+"
|
|
select="f:args( $x:result )" />
|
|
<expect label="argument is partially applied by reference"
|
|
test="$result-args[ 1 ] is $args/foo:arg1
|
|
and $result-args[ 2 ] is $args/foo:arg2
|
|
and $result-args[ 3 ] is $args/foo:arg3
|
|
and $result-args[ 4 ] is $args/foo:arg4
|
|
and $result-args[ 5 ] is $args/foo:arg5" />
|
|
</scenario>
|
|
|
|
|
|
<scenario label="six arguments">
|
|
<call function="foo:eight">
|
|
<param name="arg1" select="$args/foo:arg1" />
|
|
<param name="arg2" select="$args/foo:arg2" />
|
|
<param name="arg3" select="$args/foo:arg3" />
|
|
<param name="arg4" select="$args/foo:arg4" />
|
|
<param name="arg5" select="$args/foo:arg5" />
|
|
<param name="arg6" select="$args/foo:arg6" />
|
|
</call>
|
|
|
|
<expect label="returns partially applied function"
|
|
test="f:is-partial( $x:result )" />
|
|
|
|
<expect label="references the target function"
|
|
test="f:QName( $x:result ) = $qname" />
|
|
|
|
<expect label="partially applies one argument"
|
|
test="f:arity( $x:result ) = 2" />
|
|
|
|
<variable name="result-args" as="item()+"
|
|
select="f:args( $x:result )" />
|
|
<expect label="argument is partially applied by reference"
|
|
test="$result-args[ 1 ] is $args/foo:arg1
|
|
and $result-args[ 2 ] is $args/foo:arg2
|
|
and $result-args[ 3 ] is $args/foo:arg3
|
|
and $result-args[ 4 ] is $args/foo:arg4
|
|
and $result-args[ 5 ] is $args/foo:arg5
|
|
and $result-args[ 6 ] is $args/foo:arg6" />
|
|
</scenario>
|
|
|
|
|
|
<scenario label="seven arguments">
|
|
<call function="foo:eight">
|
|
<param name="arg1" select="$args/foo:arg1" />
|
|
<param name="arg2" select="$args/foo:arg2" />
|
|
<param name="arg3" select="$args/foo:arg3" />
|
|
<param name="arg4" select="$args/foo:arg4" />
|
|
<param name="arg5" select="$args/foo:arg5" />
|
|
<param name="arg6" select="$args/foo:arg6" />
|
|
<param name="arg7" select="$args/foo:arg7" />
|
|
</call>
|
|
|
|
<expect label="returns partially applied function"
|
|
test="f:is-partial( $x:result )" />
|
|
|
|
<expect label="references the target function"
|
|
test="f:QName( $x:result ) = $qname" />
|
|
|
|
<expect label="partially applies one argument"
|
|
test="f:arity( $x:result ) = 1" />
|
|
|
|
<variable name="result-args" as="item()+"
|
|
select="f:args( $x:result )" />
|
|
<expect label="argument is partially applied by reference"
|
|
test="$result-args[ 1 ] is $args/foo:arg1
|
|
and $result-args[ 2 ] is $args/foo:arg2
|
|
and $result-args[ 3 ] is $args/foo:arg3
|
|
and $result-args[ 4 ] is $args/foo:arg4
|
|
and $result-args[ 5 ] is $args/foo:arg5
|
|
and $result-args[ 6 ] is $args/foo:arg6
|
|
and $result-args[ 7 ] is $args/foo:arg7" />
|
|
</scenario>
|
|
</scenario>
|
|
</scenario>
|
|
</description>
|