Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added XSLT 3.0 support. #74

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.xpr
346 changes: 4 additions & 342 deletions src/compiler/generate-xspec-tests.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@

<xsl:template match="x:description" mode="x:generate-tests">
<!-- The compiled stylesheet element. -->
<stylesheet version="2.0"
<!-- OXYGEN patch to support XSLT 3.0 -->
<!-- Patch is under MIT : https://www.oxygenxml.com/pipermail/oxygen-user/2016-January/005696.html -->
<stylesheet version="{( @xslt-version, '2.0' )[1]}"
exclude-result-prefixes="pkg impl">
<xsl:apply-templates select="." mode="x:copy-namespaces" />
<import href="{$stylesheet-uri}" />
Expand Down Expand Up @@ -287,8 +289,6 @@

<!--
Generate the following:

TODO: Review if it is still ok, regarding the below new description...

<template name="x:...">
<param name="x:result" required="yes"/> # if not pending
Expand All @@ -297,9 +297,6 @@
</message>
# if not pending
<variable name="impl:expected" ...> # depend on content, @href and @select
# if @context, change the context to the result of evaluating it
# if no @context, the result is the context (if exactly one item)
# if @assert, evaluate it, the result must be boolean
# if @test, evaluate it with result as context node then
# if it is not a boolean, compare it to $impl:expected
# if no @test, compare result to $impl:expected
Expand All @@ -308,100 +305,8 @@
...
</x:test>
</template>

By assertion
@assert
@assert, @context

By comparing nodes
content
content, @context

By comparing atomic values
@select
@select, @context

Old-school (result wrapped into doc node)
@test (= @assert)
@test, @context (= @assert, @context)
content, @test (= content, @context)
-> actually, that's not exctly what has been implemented
now we evaluate @test, and if it results to one boolean,
then that's an assert, if not it is compared to content

Context: if multiple items, loop as current item ($x:result still full result)
- with @assert, assertion eval'd once for each
- with content, compare the whole sequence
- with @select, compare the whole sequence

IF @context
set context (@context)
ELIF @test AND content
set context (@test)
ELSE
set context ($result)

IF @assert
assert (@assert)
ELIF content
compare (content)
ELIF @select
compare (@select)
ELIF @test AND content
compare (content)
ELIF @test
assert (@test)

set context (@context):
variable with-context := true
variable context
if count($result) <= 1
eval @context with $result as context
else
eval @context without any context
-> must be ONE item

set context (@test):
variable with-context := true
variable context
like set context (@context), but if node()+, then wrap in doc node

set context ($result):
variable with-context := true
variable context
no context if count($result) ne 1
like set context (@context) if no @test
like set context (@test) if @test

no context:
variable with-context := false
variable context := ()

assert (@assert):
if $with-context
evaluate assert with $context
else
evaluate assert without context

compare (content):
if $with-context
compare $context to content
else
compare $result to content

compare (@select):
if $with-context
compare $context to content
else
compare $result to content

assert (@test):
if $with-context
evaluate @test with $context
else
evaluate @test without context
-->
<xsl:template name="x:output-expect-FIXME-TOREMOVE">
<xsl:template name="x:output-expect">
<xsl:param name="pending" select="()" tunnel="yes" as="node()?"/>
<xsl:param name="context" required="yes" tunnel="yes" as="element(x:context)?"/>
<xsl:param name="call" required="yes" tunnel="yes" as="element(x:call)?"/>
Expand Down Expand Up @@ -508,249 +413,6 @@
</template>
</xsl:template>

<xsl:template name="x:output-expect">
<xsl:param name="pending" select="()" tunnel="yes" as="node()?"/>
<xsl:param name="context" required="yes" tunnel="yes" as="element(x:context)?"/>
<xsl:param name="call" required="yes" tunnel="yes" as="element(x:call)?"/>
<xsl:param name="params" required="yes" as="element(param)*"/>
<xsl:variable name="pending-p" select="exists($pending) and empty(ancestor::*/@focus)"/>
<template name="x:{generate-id()}">
<xsl:for-each select="$params">
<param name="{ @name }" required="{ @required }"/>
</xsl:for-each>
<message>
<xsl:if test="$pending-p">
<xsl:text>PENDING: </xsl:text>
<xsl:if test="normalize-space($pending) != ''">
<xsl:text>(</xsl:text>
<xsl:value-of select="normalize-space($pending)"/>
<xsl:text>) </xsl:text>
</xsl:if>
</xsl:if>
<xsl:value-of select="normalize-space(x:label(.))"/>
</message>
<xsl:variable name="is-assert" select="empty(node()|@select)"/>
<xsl:if test="not($pending-p)">
<xsl:variable name="version" as="xs:double" select="
( ancestor-or-self::*[@xslt-version]/@xslt-version, 2.0 )[1]"/>

<!--
CONTEXT

IF @context
set context (@context)
ELIF @test AND content
set context (@test)
ELIF count($result) = 1
set context ($result)
ELSE
no context
-->
<xsl:choose>
<xsl:when test="exists(@context)">
<variable name="impl:with-context" select="true()"/>
<variable name="impl:context" as="item()?">
<choose>
<!-- aka "count($x:result) le 1" (so if empty, context is empty too) -->
<when test="empty($x:result[2])">
<for-each select="$x:result">
<sequence select="{ @context }"/>
</for-each>
</when>
<!-- when count($x:result) ge 2 -->
<otherwise>
<!-- no context node set here -->
<sequence select="{ @context }"/>
</otherwise>
</choose>
</variable>
</xsl:when>
<xsl:when test="exists(@test) and exists(node())">
<variable name="impl:with-context" select="true()"/>
<variable name="impl:context-tmp" as="item()*">
<choose>
<!-- aka "count($x:result) le 1" (so if empty, context is empty too) -->
<when test="empty($x:result[2])">
<for-each select="$x:result">
<sequence select="{ @test }"/>
</for-each>
</when>
<!-- when count($x:result) ge 2 -->
<otherwise>
<!-- no context node set here -->
<sequence select="{ @test }"/>
</otherwise>
</choose>
</variable>
<variable name="impl:context" as="item()?">
<choose>
<when test="$impl:context-tmp instance of node()+">
<document>
<sequence select="$impl:context-tmp"/>
</document>
</when>
<otherwise>
<sequence select="$impl:context-tmp"/>
</otherwise>
</choose>
</variable>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="exists(@test)">
<variable name="impl:just-nodes" select="
$x:result instance of node()+"/>
<!-- aka "count($x:result) eq 1 or ..." -->
<variable name="impl:with-context" select="
exists($x:result) and empty($x:result[2]) or $impl:just-nodes"/>
<variable name="impl:context" as="item()?">
<choose>
<when test="$impl:just-nodes">
<document>
<sequence select="$x:result"/>
</document>
</when>
<when test="$impl:with-context">
<sequence select="$x:result"/>
</when>
<otherwise/>
</choose>
</variable>
</xsl:when>
<xsl:otherwise>
<!-- aka "count($x:result) eq 1" -->
<variable name="impl:with-context" select="
exists($x:result) and empty($x:result[2])"/>
<variable name="impl:context" as="item()?">
<choose>
<when test="$impl:with-context">
<sequence select="$x:result"/>
</when>
<otherwise/>
</choose>
</variable>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>

<!--
ASSERT & COMPARE

IF content|@select
compare (content|@select)
ELIF @assert|@test
assert (@assert|@test)
ELSE
compilation error

every branch of this xsl:choose generates the variable $impl:successful,
which is a boolean with the outcome of the test case (either passed or
failed), and which is used later on in the generated code
-->
<xsl:choose>
<xsl:when test="not($is-assert)">
<!-- check there is exactly one of node()|@select -->
<xsl:if test="exists(node()) and exists(@select)">
<xsl:message terminate="yes">
<xsl:text>ERROR in scenario "</xsl:text>
<xsl:value-of select="x:label(.)"/>
<xsl:text>": can't have both @select and context at the same time</xsl:text>
</xsl:message>
</xsl:if>
<xsl:apply-templates select="." mode="test:generate-variable-declarations">
<xsl:with-param name="var" select="'impl:expected'"/>
</xsl:apply-templates>
<variable name="impl:successful" as="xs:boolean" select="
test:deep-equal(
$impl:expected,
if ( $impl:with-context ) then $impl:context else $x:result,
{ $version })"/>
</xsl:when>
<xsl:when test="exists(@assert|@test)">
<!-- check there is exactly one of @assert|@test -->
<xsl:if test="exists(@assert) and exists(@test)">
<xsl:message terminate="yes">
<xsl:text>ERROR in scenario "</xsl:text>
<xsl:value-of select="x:label(.)"/>
<xsl:text>": can't have both @context and @test at the same time</xsl:text>
</xsl:message>
</xsl:if>
<variable name="impl:assert" as="item()*">
<choose>
<when test="$impl:with-context">
<for-each select="$impl:context">
<sequence select="{ @assert|@test }"/>
</for-each>
</when>
<otherwise>
<sequence select="{ @assert|@test }"/>
</otherwise>
</choose>
</variable>
<if test="not($impl:assert instance of xs:boolean)">
<!-- TODO: For now, generate an error, make the test fails instead? -->
<message terminate="yes">
<xsl:text>ERROR in scenario "</xsl:text>
<xsl:value-of select="x:label(.)"/>
<!-- TODO: Generate the SequenceType of $impl:assert. -->
<xsl:text>": @assert|@test did not return a boolean</xsl:text>
</message>
</if>
<variable name="impl:successful" as="xs:boolean" select="$impl:assert"/>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">
<xsl:text>ERROR in scenario "</xsl:text>
<xsl:value-of select="x:label(.)"/>
<xsl:text>": unknown expect combination</xsl:text>
<xsl:text>&#10; content : </xsl:text>
<xsl:value-of select="exists(node())"/>
<xsl:text>&#10; @context: </xsl:text>
<xsl:value-of select="exists(@context)"/>
<xsl:text>&#10; @assert : </xsl:text>
<xsl:value-of select="exists(@assert)"/>
<xsl:text>&#10; @select : </xsl:text>
<xsl:value-of select="exists(@select)"/>
<xsl:text>&#10; @test : </xsl:text>
<xsl:value-of select="exists(@test)"/>
</xsl:message>
</xsl:otherwise>
</xsl:choose>
<if test="not($impl:successful)">
<message>
<xsl:text> FAILED</xsl:text>
</message>
</if>
</xsl:if>
<x:test>
<xsl:choose>
<xsl:when test="$pending-p">
<xsl:attribute name="pending" select="$pending"/>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="successful" select="'{ $impl:successful }'"/>
</xsl:otherwise>
</xsl:choose>
<xsl:sequence select="x:label(.)"/>
<xsl:if test="not($pending-p)">
<call-template name="test:report-value">
<with-param name="value" select="$x:result"/>
<with-param name="wrapper-name" select="'x:result'"/>
<with-param name="wrapper-ns" select="'{ $xspec-ns }'"/>
</call-template>
<xsl:if test="not($is-assert)">
<call-template name="test:report-value">
<with-param name="value" select="$impl:expected"/>
<with-param name="wrapper-name" select="'x:expect'"/>
<with-param name="wrapper-ns" select="'{ $xspec-ns }'"/>
</call-template>
</xsl:if>
</xsl:if>
</x:test>
</template>
</xsl:template>

<!-- *** x:generate-declarations *** -->
<!-- Code to generate parameter declarations -->
<xsl:template match="x:param" mode="x:generate-declarations">
Expand Down