blob: 689eb77389cdba1f89d685c6311f309064504967 [file] [log] [blame]
/*
* 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.
*/
package org.apache.daffodil.dsom
import org.apache.daffodil.xml.XMLUtils
import org.junit.Assert._
import org.apache.daffodil.util._
import org.apache.daffodil.dpath.NodeInfo._
import org.junit.Test
import org.apache.daffodil.infoset.DISimple
import org.apache.daffodil.infoset.DIDocument
import org.apache.daffodil.processors.parsers.PState
class TestSimpleTypeUnions {
val xsd = XMLUtils.XSD_NAMESPACE
val dfdl = XMLUtils.DFDL_NAMESPACE
val xsi = XMLUtils.XSI_NAMESPACE
val example = XMLUtils.EXAMPLE_NAMESPACE
val testSchema1 = SchemaUtils.dfdlTestSchema(
<xs:include schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>,
<dfdl:format ref="GeneralFormat"/>,
<xs:simpleType name="int1Type">
<xs:restriction base="xs:int">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="1"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="int2Type">
<xs:restriction base="xs:int">
<xs:minInclusive value="2"/>
<xs:maxInclusive value="2"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="oneOrTwo">
<xs:union memberTypes="ex:int1Type ex:int2Type"/>
</xs:simpleType>
<xs:element name="e1" dfdl:lengthKind="delimited" type="ex:oneOrTwo">
<xs:annotation>
<xs:appinfo source="http://www.ogf.org/dfdl/">
<!--
this assert always passes, but uses e1 in an expression to prevent
the InfosetWalker from freeing it, which allows the tests to
inspect runtime internals
-->
<dfdl:assert test="{ fn:true() or /ex:e1 eq 0 }" />
</xs:appinfo>
</xs:annotation>
</xs:element>)
@Test def testUnion01: Unit = {
val sset = SchemaSet(testSchema1)
val Seq(sch) = sset.schemas
val Seq(sd, _) = sch.schemaDocuments
// Explore global element decl
val Seq(e1) = sd.globalElementDecls
val e1t = e1.simpleType
val u = e1t.optUnion.get
val e1tPrimType = u.primType
assertEquals(PrimType.Int, e1tPrimType)
assertTrue(e1t.optRestriction.isEmpty)
val Seq(st1, st2) = u.unionMemberTypes
st1.asInstanceOf[GlobalSimpleTypeDef].globalQName.toQNameString
val st1n = st1.diagnosticDebugName
assertEquals("int1Type", st1n)
val st2n = st2.diagnosticDebugName
assertEquals("int2Type", st2n)
val st1rd = st1.simpleTypeRuntimeData
val st2rd = st2.simpleTypeRuntimeData
val st1mini = st1rd.minInclusive
assertEquals(1, st1mini.get.intValue())
assertTrue(st1rd.unionMemberTypes.isEmpty)
assertTrue(st2rd.unionMemberTypes.isEmpty)
val st2mini = st2rd.minInclusive
assertEquals(2, st2mini.get.intValue())
assertEquals("int1Type", st1rd.diagnosticDebugName)
assertEquals("int2Type", st2rd.diagnosticDebugName)
}
@Test def testUnionFirstUnionMemberOk: Unit = {
val (result, actual) = TestUtils.testString(testSchema1, "1")
val i = result.resultState.asInstanceOf[PState].infoset.asInstanceOf[DIDocument].contents(0).asInstanceOf[DISimple]
val umstrd = i.unionMemberRuntimeData.get
assertEquals("int1Type", umstrd.diagnosticDebugName)
assertTrue(i.valid.get)
val expected = <e1>1</e1>
TestUtils.assertEqualsXMLElements(expected, actual)
}
@Test def testUnionSecondUnionMemberOk: Unit = {
val (result, actual) = TestUtils.testString(testSchema1, "2")
val i = result.resultState.asInstanceOf[PState].infoset.asInstanceOf[DIDocument].contents(0).asInstanceOf[DISimple]
val umstrd = i.unionMemberRuntimeData.get
assertEquals("int2Type", umstrd.diagnosticDebugName)
assertTrue(i.valid.get)
val expected = <e1>2</e1>
TestUtils.assertEqualsXMLElements(expected, actual)
}
@Test def testUnionNoUnionMemberOK: Unit = {
val (result, _) = TestUtils.testString(testSchema1, "3")
val i = result.resultState.asInstanceOf[PState].infoset.asInstanceOf[DIDocument].contents(0).asInstanceOf[DISimple]
val Some(dv: java.lang.Integer) = Some(i.dataValue.getInt)
assertEquals(3, dv.intValue())
assertTrue(i.unionMemberRuntimeData.isEmpty)
assertFalse(i.valid.get)
val ds = result.getDiagnostics
assertTrue(ds.length == 1)
val d = ds.head
assertTrue(d.isInstanceOf[ValidationError])
val msg = d.getMessage()
def die = { println(msg); fail() }
if (!msg.contains("e1"))
die
if (!msg.contains("union members"))
die
if (!msg.contains("int1Type"))
die
if (!msg.contains("int2Type"))
die
if (!msg.contains("failed facet checks"))
die
}
val testSchema2 = SchemaUtils.dfdlTestSchema(
<xs:include schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>,
<dfdl:format ref="GeneralFormat"/>,
<xs:simpleType name="int19Type">
<xs:restriction base="xs:int">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="9"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="int12Type">
<xs:restriction base="ex:int19Type">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="2"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="int49Type">
<xs:restriction base="ex:int19Type">
<xs:minInclusive value="4"/>
<xs:maxInclusive value="9"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="int12or47Type">
<xs:union memberTypes="ex:int12Type">
<xs:simpleType>
<xs:restriction base="ex:int49Type">
<xs:maxInclusive value="7"/>
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
<xs:simpleType name="negIntType">
<xs:restriction base="xs:int">
<xs:maxInclusive value="-1"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="eType">
<xs:union>
<xs:simpleType>
<xs:restriction base="ex:int12or47Type">
</xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction base="ex:negIntType">
<xs:minInclusive value="-8"/>
<xs:maxInclusive value="-1"/>
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
<xs:element name="e1" dfdl:lengthKind="delimited" type="ex:eType">
<xs:annotation>
<xs:appinfo source="http://www.ogf.org/dfdl/">
<!--
this assert always passes, but uses e1 in an expression to prevent
the InfosetWalker from freeing it, which allows the tests to
inspect runtime internals
-->
<dfdl:assert test="{ fn:true() or /ex:e1 eq 0 }" />
</xs:appinfo>
</xs:annotation>
</xs:element>)
@Test def testUnionNot3: Unit = {
val (result, _) = TestUtils.testString(testSchema2, "3")
val i = result.resultState.asInstanceOf[PState].infoset.asInstanceOf[DIDocument].contents(0).asInstanceOf[DISimple]
val Some(dv: java.lang.Integer) = Some(i.dataValue.getInt)
assertEquals(3, dv.intValue())
assertTrue(i.unionMemberRuntimeData.isEmpty)
assertFalse(i.valid.get)
val ds = result.getDiagnostics
assertTrue(ds.length == 1)
val d = ds.head
assertTrue(d.isInstanceOf[ValidationError])
val msg = d.getMessage()
def die = { println(msg); fail() }
if (!msg.contains("e1"))
die
if (!msg.contains("union members"))
die
if (!msg.contains("int12or47Type"))
die
if (!msg.contains("negIntType"))
die
if (!msg.contains("failed facet checks"))
die
}
@Test def testUnionNot3_01: Unit = {
val (result, actual) = TestUtils.testString(testSchema2, "1")
val i = result.resultState.asInstanceOf[PState].infoset.asInstanceOf[DIDocument].contents(0).asInstanceOf[DISimple]
val umstrd = i.unionMemberRuntimeData.get
assertEquals("int12Type", umstrd.diagnosticDebugName)
assertTrue(i.valid.get)
val expected = <e1>1</e1>
TestUtils.assertEqualsXMLElements(expected, actual)
}
@Test def testUnionNot3_02: Unit = {
val (result, actual) = TestUtils.testString(testSchema2, "2")
val i = result.resultState.asInstanceOf[PState].infoset.asInstanceOf[DIDocument].contents(0).asInstanceOf[DISimple]
val umstrd = i.unionMemberRuntimeData.get
assertEquals("int12Type", umstrd.diagnosticDebugName)
assertTrue(i.valid.get)
val expected = <e1>2</e1>
TestUtils.assertEqualsXMLElements(expected, actual)
}
@Test def testUnionNot3_03: Unit = {
val (result, actual) = TestUtils.testString(testSchema2, "-1")
val i = result.resultState.asInstanceOf[PState].infoset.asInstanceOf[DIDocument].contents(0).asInstanceOf[DISimple]
val umstrd = i.unionMemberRuntimeData.get
assertEquals("ex:negIntType", umstrd.diagnosticDebugName) // anonymous simple type gets this name from base.
assertTrue(i.valid.get)
val expected = <e1>-1</e1>
TestUtils.assertEqualsXMLElements(expected, actual)
}
val testSchema3 = SchemaUtils.dfdlTestSchema(
<xs:include schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>,
<dfdl:format ref="GeneralFormat"/>,
<xs:simpleType name="fooXbar">
<xs:restriction base="xs:string">
<xs:pattern value="foo\w*bar"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="foo1or2bar">
<xs:restriction base="ex:fooXbar">
<xs:enumeration value="foo1bar"/>
<xs:enumeration value="foo2bar"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="foo3or4bar">
<xs:restriction base="ex:fooXbar">
<xs:pattern value="foo[34]bar"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="foo1or2or3bar">
<xs:union memberTypes="ex:foo1or2bar">
<xs:simpleType>
<xs:restriction base="ex:foo3or4bar">
<xs:pattern value="foo[356]bar"/>
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
<xs:simpleType name="foo3bar">
<xs:restriction base="ex:foo1or2or3bar">
<xs:pattern value="foo[1234]bar"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="e1" dfdl:lengthKind="delimited" type="ex:foo3bar">
<xs:annotation>
<xs:appinfo source="http://www.ogf.org/dfdl/">
<!--
this assert always passes, but uses e1 in an expression to prevent
the InfosetWalker from freeing it, which allows the tests to
inspect runtime internals
-->
<dfdl:assert test="{ fn:true() or /ex:e1 eq '' }" />
</xs:appinfo>
</xs:annotation>
</xs:element>)
@Test def testRestrictionOnUnion_01: Unit = {
val (result, actual) = TestUtils.testString(testSchema3, "foo3bar")
val i = result.resultState.asInstanceOf[PState].infoset.asInstanceOf[DIDocument].contents(0).asInstanceOf[DISimple]
val umstrd = i.unionMemberRuntimeData.get
assertEquals("ex:foo3or4bar", umstrd.diagnosticDebugName)
assertTrue(i.valid.get)
val expected = <e1>foo3bar</e1>
TestUtils.assertEqualsXMLElements(expected, actual)
}
@Test def testRestrictionOnUnion_02: Unit = {
val (result, actual) = TestUtils.testString(testSchema3, "foo1bar")
val i = result.resultState.asInstanceOf[PState].infoset.asInstanceOf[DIDocument].contents(0).asInstanceOf[DISimple]
val umstrd = i.unionMemberRuntimeData.get
assertEquals("foo1or2bar", umstrd.diagnosticDebugName)
assertTrue(i.valid.get)
val expected = <e1>foo1bar</e1>
TestUtils.assertEqualsXMLElements(expected, actual)
}
@Test def testRestrictionOnUnion_03: Unit = {
val (result, actual) = TestUtils.testString(testSchema3, "foo2bar")
val i = result.resultState.asInstanceOf[PState].infoset.asInstanceOf[DIDocument].contents(0).asInstanceOf[DISimple]
val umstrd = i.unionMemberRuntimeData.get
assertEquals("foo1or2bar", umstrd.diagnosticDebugName)
assertTrue(i.valid.get)
val expected = <e1>foo2bar</e1>
TestUtils.assertEqualsXMLElements(expected, actual)
}
@Test def testRestrictionOnUnionFail_01: Unit = {
val (result, _) = TestUtils.testString(testSchema3, "foo4bar")
val i = result.resultState.asInstanceOf[PState].infoset.asInstanceOf[DIDocument].contents(0).asInstanceOf[DISimple]
val Some(dv: String) = Some(i.dataValue.getString)
assertEquals("foo4bar", dv)
assertTrue(i.unionMemberRuntimeData.isEmpty)
assertFalse(i.valid.get)
val ds = result.getDiagnostics
assertTrue(ds.length == 1)
val d = ds.head
assertTrue(d.isInstanceOf[ValidationError])
val msg = d.getMessage()
def die = { println(msg); fail() }
if (!msg.contains("e1"))
die
if (!msg.contains("union members"))
die
if (!msg.contains("foo1or2bar"))
die
if (!msg.contains("foo3or4bar"))
die
if (!msg.contains("failed facet checks"))
die
}
/**
* This test shows that the union isn't even attempted if the
* restriction on the union fails.
*/
@Test def testRestrictionOnUnionFail_02: Unit = {
val (result, _) = TestUtils.testString(testSchema3, "notfoo1bar")
val i = result.resultState.asInstanceOf[PState].infoset.asInstanceOf[DIDocument].contents(0).asInstanceOf[DISimple]
val Some(dv: String) = Some(i.dataValue.getString)
assertEquals("notfoo1bar", dv)
assertTrue(i.unionMemberRuntimeData.isEmpty)
assertFalse(i.valid.get)
val ds = result.getDiagnostics
assertTrue(ds.length == 1)
val d = ds.head
assertTrue(d.isInstanceOf[ValidationError])
val msg = d.getMessage()
def die = { println(msg); fail() }
if (!msg.contains("e1"))
die
if (!msg.contains("facet pattern"))
die
if (!msg.contains("foo[1234]bar"))
die
if (!msg.contains("failed facet checks"))
die
}
}