XProc Test Suite markup
Table of Contents
1. Introduction
The XProc Test Suite consists of a set of test suite documents and assorted ancillary files. The test suite documents are defined by the schema described in this document.
The test suite schema is normatively defined in RELAX NG Compact Syntax, but it isn’t necessary for an implementation to use this schema for validation.
Each individual test is defined by a test
element. Tests can be grouped
together with div
elements and/or collected together in a test-suite
.
A test suite document must begin with one of these elements.
All of the test suite elements are in the test suite namespace, see
Namespaces.
start = test | test-suite | test-div
2. Metadata
All tests, test suites, and divisions begin with a required metadata
element named info
. Metadata consists of a title
, a simple string
with inline markup, a revision-history
that documents changes to the
test, and optional specref
elements.
info = element t:info { title & revision-history & specref* }
2.1. Revision history
A revision history is a collection of one or more revisions.
revision-history = element t:revision-history { revision+ }
Revisions must be listed in reverse chronological order, so the most
recent revision appears first. Each revision consists of a date
, an author
,
and a description
of the revision (see Description).
revision = element t:revision { attribute initials { text }?, date, author?, description }
The date
must be an ISO 8601 date or dateTime. An author
has a name
and an optional email
address and uri
. The description
should describe what has been changed and why.
author = element t:author { attribute initials { text }? & name? & email? & uri? }
2.2. Specref
If a test, or set of tests, relates to a particular aspect of a
particular specification, a link can be provided. The link consists of
a spec
attribute that identifies the specification and a linkend
attribute that must contain the ID value in the specification with
which this test is associated.
specref = element t:specref { attribute spec { "xproc" | "steps" }? & attribute linkend { xsd:NMTOKEN } & empty }
(It’s not clear if this turned out to be as useful in practice as it was in theory.)
3. Description
The description can contain any mixture of text and HTML elements. HTML elements
must be in the HTML namespace:
http://www.w3.org/1999/xhtml
.
4. Test suites and divisions
The test-suite
and div
elements serve to group tests together.
test-suite = element t:test-suite { testattr, (info, description?, property*, test*, test-div*) }
Divisions may be nested.
test-div = element t:div { (info, description?, property*, test*, test-div*) }
5. Common attributes
Each test
(and test-suite
) has attributes to identify the features
it requires and the circumstances under which it should be run.
testattr = attribute features { list { xsd:token+ } } ? & attribute when { text }? & attribute src { text }? & attribute version { text }?
The attributes should be interpreted as follows:
features
is a set of one or more feature tokens. Feature tokens identify features that the implementation must support in order for this test to pass. The test should be skipped if it identifies any unsupported features.The set of feature tokens is a bit ad hoc. Here’s a summary of the feature tokens at the time this document was written:
archive-order
, ???dtd-id-ref-warning
, a RELAX NG validator capable of reporting DTD-based ID/IDREF warnings is required.lazy-eval
, lazy evaluation of variable bindings is required.p-validate-with-relax-ng
, a RELAX NG validator is required.p-validate-with-schematron
, a Schematron validator is required.p-validate-with-xsd
, a W3C XML Schema validator is required.webaccess
, access to the web is required (this test cannot be run offline).xquery_1_0
, an XQuery 1.0 processor is required.xquery_3_0
, an XQuery 3.0 processor is required.xquery_3_1
, an XQuery 3.1 processor is required.xslt-1
, an XSLT 1.0 processor is required.xslt-1-output-base-uri
, ???xslt-2
, an XSLT 2.0 processor is required.xslt-3
, an XSLT 3.0 processor is required.xslt-serialization
, ???
when
specifies an XPath expression that can be evaluated statically by the test processor. If the effective boolean value of the result isfalse()
, the test is ignored.src
specifies a URI where thetest
(ortest-suite
) is located. If this attribute is specified, the element on which it occurs must be empty.version
specifies the version of the XProc processor required for this test.
6. Tests
If a test specifies a particular platform
, it is only run on that platform.
There are two kinds of tests, passing tests and failing tests.
test = passingTest | failingTest
Passing and failing tests are mostly the same. Tests have common
attributes, metadata, and a description. The body of the test in each
case consists of property
, filetest–, ~input
, output
, and pipeline
elements.
A passing test has an expected
attribute (that must have the value be pass
)
and may have schematron
tests to verify the results.
passingTest = element t:test { testattr & attribute expected { "pass" } & attribute platform { ("Linux" | "MacOS" | "Windows") }? & (info, description?, (property* & file-environment? & input* & option* & pipeline? & schematron?)) }
A failing test has an expected
attribute (that must have the value be fail
)
and must specify one or more expected error conditions.
failingTest = element t:test { testattr & attribute expected { "fail" } & attribute code { xsd:NMTOKENS } & attribute platform { ("Linux" | "MacOS" | "Windows") }? & (info, description?, (property* & file-environment? & input* & option* & pipeline?)) }
Broadly speaking, the test harness sets the specified properties and runs the specified pipeline with the specified inputs and options. A passing test must complete without error, or it must be recorded as a failure. If it completes, its output is tested against any Schematron rules provided. No assertions must be raised.
If a failing test raises one of the specified error codes, it is a “pass” from the perspective of the test suite, otherwise it must be recorded as a failure.
Like tests and test-suites, inputs, pipelines, and Schematron rules
can be specified inline or with a src
attribute that points to their
content.
6.1. Properties
A property is a name/value pair. These must be made available to the implementation, but the precise mechanism is necessarily implementation defined.
property = element t:property { attribute name { text } & attribute value { text } }
On the Java platform, these are system properties.
6.2. File environment
The optional file-environment
element defines a test environment in the local
filesystem to run tests for steps from the file steps specification. The
file
element specifies that a file with the the given path (and the
requested properties) should be created. The folder
element specifies the same
for folders. All pathes must be relative. The test harness has to resolve them
agains a folder "testfolder". This folder is located in the parent folder of the
test
element. The test harness is required to create "testfolder" when a
file-environment
element is present and delete it after the test is finished.
file-environment = element t:file-environment{ (file* & folder*) } file = element t:file{ filetest-attr & filetest-content? } filetest-content = text folder = element t:folder{ filetest-attr } filetest-attr = attribute path {xsd:anyURI} & attribute last-modified {xsd:dateTime}? & attribute readable {xsd:boolean}? & attribute writable {xsd:boolean}? & attribute hidden {xsd:boolean}?
6.3. Inputs
Each input
element identifies the input for a source port on the pipeline.
XML and text documents can be placed inline; other media types must be
stored externally and identified by URI.
If several inputs identify the same port
, then the sequence of
documents identified appears on that port, in document order of the input
elements in the test.
input = element t:input { attribute port { text } & attribute src { text }? & any* }
6.4. Options
Each option
element identifies the value for a pipeline option. If a
select
attribute is provided, it must be an XPath expression.
Evaluating that expression gives the value of the option. If the
select
attribute is not provided, the contents of the element is the
value of the option.
If static
is specified, and true
, the option is a static option and
must be provided to the processor at compile time. Options which do
not specify a value for static
, or that specify the value false
, are
dynamic options passed to the processor at runtime with the pipeline.
option = element t:option { attribute name { text } & attribute static { xsd:boolean }? & attribute select { text }? & any* }
6.5. Pipeline
The pipeline
element, which can only occur once, provides the pipeline
to be tested. The pipeline must be written so that it has only a single, primary
output port named result
.
pipeline = element t:pipeline { attribute src { text }? & any* }
6.6. Schematron
The schematron
element contains Schematron rules. Assertions in the
Schematron are tested against the results of the pipeline.
schematron = element t:schematron { attribute src { text }? & any* }
7. Namespaces
The following namespaces are defined in this schema.
namespace rng = "http://relaxng.org/ns/structure/1.0" namespace t = "http://xproc.org/ns/testsuite/3.0" namespace h = "http://www.w3.org/1999/xhtml" default namespace = "http://xproc.org/ns/testsuite/3.0"
8. Relax NG Schema
These fragments are stitched together (with a few other fragments) into a complete schema.
namespace rng = "http://relaxng.org/ns/structure/1.0" namespace t = "http://xproc.org/ns/testsuite/3.0" namespace h = "http://www.w3.org/1999/xhtml" default namespace = "http://xproc.org/ns/testsuite/3.0" start = test | test-suite | test-div testattr = attribute features { list { xsd:token+ } } ? & attribute when { text }? & attribute src { text }? & attribute version { text }? test-suite = element t:test-suite { testattr, (info, description?, property*, test*, test-div*) } passingTest = element t:test { testattr & attribute expected { "pass" } & attribute platform { ("Linux" | "MacOS" | "Windows") }? & (info, description?, (property* & file-environment? & input* & option* & pipeline? & schematron?)) } failingTest = element t:test { testattr & attribute expected { "fail" } & attribute code { xsd:NMTOKENS } & attribute platform { ("Linux" | "MacOS" | "Windows") }? & (info, description?, (property* & file-environment? & input* & option* & pipeline?)) } file-environment = element t:file-environment{ (file* & folder*) } file = element t:file{ filetest-attr & filetest-content? } filetest-content = text folder = element t:folder{ filetest-attr } filetest-attr = attribute path {xsd:anyURI} & attribute last-modified {xsd:dateTime}? & attribute readable {xsd:boolean}? & attribute writable {xsd:boolean}? & attribute hidden {xsd:boolean}? test-div = element t:div { (info, description?, property*, test*, test-div*) } info = element t:info { title & revision-history & specref* } author = element t:author { attribute initials { text }? & name? & email? & uri? } name = element t:name { text } email = element t:email { text } uri = element t:uri { xsd:anyURI } revision-history = element t:revision-history { revision+ } revision = element t:revision { attribute initials { text }?, date, author?, description } title = element t:title { text } date = element t:date { xsd:date|xsd:dateTime } specref = element t:specref { attribute spec { "xproc" | "steps" }? & attribute linkend { xsd:NMTOKEN } & empty } test = passingTest | failingTest pipeline = element t:pipeline { attribute src { text }? & any* } schematron = element t:schematron { attribute src { text }? & any* } input = element t:input { attribute port { text } & attribute src { text }? & any* } option = element t:option { attribute name { text } & attribute static { xsd:boolean }? & attribute select { text }? & any* } any = element * { attribute * { text }* & (text | any)* } anyhtml = element h:* { attribute * { text }* & (text | anyhtml)* } description = element t:description { anyhtml+ } property = element t:property { attribute name { text } & attribute value { text } }