blob: e5072e3d1dca670a972923591b07c8587f93f8d8 [file] [log] [blame]
<?xml version="1.0" encoding="ASCII"?>
<?xml-stylesheet type="text/xsl" href="DFDLTutorialStylesheet.xsl"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<tdml:testSuite suiteName="A TDML Tutorial" description="Illustration of how to test DFDL schemas, and also how to report a bug using TDML."
xmlns:tdml="http://www.ibm.com/xmlns/dfdl/testData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xml="http://www.w3.org/XML/1998/namespace"
xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ex="http://example.com"
xmlns:gpf="http://www.ibm.com/dfdl/GeneralPurposeFormat" xmlns:daf="urn:ogf:dfdl:2013:imp:daffodil.apache.org:2018:ext" xmlns="http://www.w3.org/1999/xhtml"
defaultRoundTrip="true">
<tdml:tutorial xml:space="preserve"><p>
This file is an example of a self-contained test described in a TDML file.
<br />
These are easily run using the Daffodil command line interface (CLI).
<br />
A TDML file is actually a test suite of tests, and we include two here. One
is a parser test case, the other an unparser test case.
<br />
The file root element is tdml:testSuite which contains namespace prefix
definitions (several are generally needed), and other important attributes:
</p>
<dl>
<dt>defaultRoundTrip</dt>
<dd>by default a parse test will be run "round trip"
meaning both a parse and unparse will be done. If false or omitted
a parse test will only parse, an unparse test will only unparse, though
this may be controlled on a test-by-test basis with the roundTrip
attribute of parserTestCase and unparserTestCase elements.</dd>
<dt>defaultConfig</dt>
<dd>gives the name of a defined configuration, which can bind
external variables, or set tunable parameters. This can also be controlled
on a test-by-test basis with the config attribute of the parserTestCase
and unparserTestCase elements.</dd>
</dl>
<p>
We begin below by defining a DFDL schema directly in our TDML file.
<br />
Use defineSchema to include a DFDL schema directly inside the TDML file.
You can alternatively put the DFDL schema in a separate file if you prefer.
<br />
The target namespace of these named defineSchemas will be http://example.com which is
bound to the prefix "ex" above.
<br />
Each defineSchema has a name, so that one TDML file can contain tests which reference
different DFDL schemas.
<br />
To embed a schema inside the TDML you don't include the xs:schema element from
the schema file, nor do you need to wrap the top-level DFDL annotation objects with
xs:annotation and xs:appinfo.
<br />
In other words, inside a defineSchema you can directly put:
dfdl:defineFormat, dfdl:defineEscapeSchema,
dfdl:format (for the default format), xs:element, xs:simpleType, xs:complexType, xs:group,
xs:import, or xs:include.
<br />
It is common for a TDML file to contain an embedded schema which includes or
imports other DFDL schemas that are in files.
<br />
Our embedded DFDL schema begins with a named format definition - notice no
surrounding xs:annotation nor xs:appinfo
<br />
We reference a useful starting point format definition provided to the DFDL
community by IBM. (It is built into the Daffodil software.)
</p></tdml:tutorial>
<tdml:defineSchema name="s1" elementFormDefault="unqualified">
<xs:include schemaLocation="/org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
<dfdl:defineFormat name="myDefaults">
<dfdl:format lengthKind="implicit" representation="text" encoding="ASCII" initiator="" terminator="" separator=""
ref="gpf:GeneralPurposeFormat" />
</dfdl:defineFormat>
<!--
The dfdl:format annotation puts the above format definition into use
for tests that use this defined schema.
-->
<dfdl:format ref="ex:myDefaults" />
<!--
Include the format we reference from myDefaults. IBM provided this
nice one as a good starting point.
-->
<xs:import namespace="http://www.ibm.com/dfdl/GeneralPurposeFormat" schemaLocation="/IBMdefined/GeneralPurposeFormat.xsd" />
<!--
Now imagine we are reporting a bug with date/time functionality, and
this element exercises the feature of concern.
-->
<xs:element name="myTestRoot" type="xs:dateTime" dfdl:calendarPattern="MM.dd.yyyy 'at' HH:mm:ssZZZZZ" dfdl:calendarPatternKind="explicit"
dfdl:lengthKind="delimited" dfdl:terminator="%NL;" />
</tdml:defineSchema>
<tdml:tutorial xml:space="preserve">
<h1>Parser Test Cases</h1><p>
Here is a test case that exercises the above schema.
<br />
A single TDML file can contain many test cases like the one below.
<br />
You must give the name of the model (aka the schema), that can be the name of a
schema defined immediately in this file like above, or a file name.
<br />
You must also give the name of the root element that the test will use.
<br />
Because the tdml:testSuite element has defaultRoundTrip="true" this "parser"
test case will actually test parsing and unparsing, but as it is a parser
test case, it begins with parsing the data to an infoset, then unparses it
and checks that it gets back the original data.
<br />
Except, that it won't get back the exact original data. The Time Zone notation won't
be reproduced exactly. What is unparsed is equivalent to the original, but not identical.
So this pass requires that we do a second parse pass, and
verify that we get the infoset back that we expected. That is, what was unparsed
can be reparsed back to the same infoset. So this test specifies the roundTrip="twoPass"
attribute which overrides the default behavior of the suite.
</p></tdml:tutorial>
<tdml:parserTestCase name="dateTimeTest" root="myTestRoot" model="s1"
description="Test of date/time. Runs round trip (parse and unparse) because that is the default for this test suite."
roundTrip="twoPass">
<tdml:tutorial xml:space="preserve"><p>
The data for your test is given by the tdml:document element, which optionally
contains tdml:documentPart elements. A tdml:documentPart can be of type "text",
"bytes" or "bits".
<br />
Notice specifically the use of the CDATA bracketing of the data in the TDML
file. This insures that no unintended whitespace gets inserted around your data.
<br />
DFDL Character Entities can be used in textual data. (See the %LF; in there), if the
attribute 'replaceDFDLEntities', a boolean, is true.
<br />
There are ways to do binary data in hexadecimal, and even bit by bit, and
even mixtures of text and binary data.
<br />
For this example we'll just look at a simple textual data document.
</p></tdml:tutorial>
<tdml:document>
<tdml:documentPart type="text" replaceDFDLEntities="true"><![CDATA[04.02.2013 at 14:00:56 GMT-05:00%LF;]]></tdml:documentPart>
</tdml:document>
<tdml:tutorial xml:space="preserve"><p>
The infoset element gives the expected infoset, expressed as an XML fragment.
</p></tdml:tutorial>
<tdml:infoset>
<tdml:dfdlInfoset><!--Always need this extra tdml:dfdlInfoset element as well -->
<!--
Here is our actual expected result, where the date and time
is now in XML's cannonical representation for these.
-->
<ex:myTestRoot>2013-04-02T14:00:56-05:00</ex:myTestRoot>
</tdml:dfdlInfoset>
</tdml:infoset>
<!-- end of the test case -->
</tdml:parserTestCase>
<tdml:tutorial xml:space="preserve">
<h1>Unparser Test Cases</h1><p>
This is how unparser tests work.
<br />
Note the use of the roundTrip="false" attribute to override the
defaultRoundTrip="true" that was set on the tdml:testSuite element.
<br />
So this test will unparse only, and not attempt to use the same schema to
parse the data.
</p></tdml:tutorial>
<tdml:unparserTestCase name="unparseDateTimeTest" root="myTestRoot" model="s1" description="date time issue, unparser"
roundTrip="false">
<tdml:tutorial xml:space="preserve"><p>
For an unparser test, the incoming data is the infoset element.
<br />
The data for your test is what is expected as output of the unparse.
<br />
The infoset element gives the expected infoset, expressed as an XML fragment.
In an unparser test, it is normally written first, with the data document
second. The order doesn't actually matter.
</p></tdml:tutorial>
<tdml:infoset>
<tdml:dfdlInfoset>
<ex:myTestRoot>2013-04-02T14:00:56-05:00</ex:myTestRoot>
</tdml:dfdlInfoset>
</tdml:infoset>
<tdml:document>
<tdml:documentPart type="text" replaceDFDLEntities="true"><![CDATA[04.02.2013 at 14:00:56-05:00%CR;%LF;]]></tdml:documentPart>
</tdml:document>
<!-- end of the test case -->
</tdml:unparserTestCase>
<!-- end of the whole TDML file -->
</tdml:testSuite>