You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@daffodil.apache.org by bt...@apache.org on 2019/06/27 13:53:43 UTC
[incubator-daffodil] branch master updated: Add
dfdlx:choiceBranchKeyRanges
This is an automated email from the ASF dual-hosted git repository.
btsloane pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-daffodil.git
The following commit(s) were added to refs/heads/master by this push:
new efa1613 Add dfdlx:choiceBranchKeyRanges
efa1613 is described below
commit efa1613a04dd51169d5e7c3d884a640f073f09c0
Author: Brandon Sloane <bs...@tresys.com>
AuthorDate: Wed Jun 19 17:56:41 2019 -0400
Add dfdlx:choiceBranchKeyRanges
DAFFODIL-2157
---
.../apache/daffodil/dsom/RestrictionUnion.scala | 2 +-
.../org/apache/daffodil/dsom/SimpleTypes.scala | 26 +-
.../grammar/primitives/ChoiceCombinator.scala | 48 ++-
.../org/apache/daffodil/cookers/Cookers.scala | 30 ++
.../org/apache/daffodil/util/RangeBound.scala | 111 +++++++
.../apache/daffodil/xsd/DFDL_part2_attributes.xsd | 2 +
.../resources/org/apache/daffodil/xsd/dfdlx.xsd | 3 +
.../daffodil/processors/TypeCalculator.scala | 82 +----
.../processors/parsers/ElementKindParsers.scala | 18 +-
.../choiceBranchRanges/choiceBranchKeyRanges.tdml | 331 +++++++++++++++++++++
.../daffodil/section15/choice_groups/choice.tdml | 3 +-
.../extensions/TestChoiceBranchKeyRanges.scala | 45 +++
12 files changed, 578 insertions(+), 123 deletions(-)
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/RestrictionUnion.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/RestrictionUnion.scala
index 2d772ce..f49475c 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/RestrictionUnion.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/RestrictionUnion.scala
@@ -31,11 +31,11 @@ import com.ibm.icu.util.TimeZone
import org.apache.daffodil.dpath.NodeInfo.PrimType
import org.apache.daffodil.processors.RepValueSet
import org.apache.daffodil.processors.RepValueSetCompiler
-import org.apache.daffodil.processors.RangeBound
import org.apache.daffodil.util.Maybe
import org.apache.daffodil.dsom.FacetTypes.ElemFacets
import org.apache.daffodil.dsom.FacetTypes.FacetValue
import org.apache.daffodil.processors.RepValueSet
+import org.apache.daffodil.util.RangeBound
/**
* A schema component for simple type restrictions
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SimpleTypes.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SimpleTypes.scala
index 118b6ff..c22bb7a 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SimpleTypes.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SimpleTypes.scala
@@ -44,7 +44,6 @@ import scala.xml.Elem
import scala.xml.MetaData
import scala.xml.UnprefixedAttribute
import scala.xml.Null
-import org.apache.daffodil.processors.RangeBound
import org.apache.daffodil.util.Maybe
import org.apache.daffodil.xml.GlobalQName
import org.apache.daffodil.xml.XMLUtils
@@ -52,6 +51,8 @@ import scala.xml.NamespaceBinding
import org.apache.daffodil.processors.IdentifyTypeCalculator
import org.apache.daffodil.xml.NS
import org.apache.daffodil.exceptions.SchemaFileLocation
+import org.apache.daffodil.cookers.IntRangeCooker
+import org.apache.daffodil.util.RangeBound
trait TypeBase {
def optRestriction: Option[Restriction] = None
@@ -86,33 +87,16 @@ sealed trait HasRepValueAttributes extends AnnotatedSchemaComponent
case Some(repType) => {
val repValueSetRaw = findPropertyOption("repValues").toOption
.map(_.split("\\s+").toSeq).getOrElse(Seq())
- val repValueRangesRaw = findPropertyOption("repValueRanges").toOption
- .map(_.split("\\s+").toSeq).getOrElse(Seq())
+ val repValueRangesRaw = findPropertyOption("repValueRanges").toOption.getOrElse("")
repType.primType match {
case PrimType.String => {
if (repValueRangesRaw.size > 0) SDE("repValueRanges set when using a string repType")
- val repValueSetCooked = repValueRangesRaw.map(RepValueCooker.convertConstant(_, this, false))
+ val repValueSetCooked = repValueSetRaw.map(RepValueCooker.convertConstant(_, this, false))
(repValueSetCooked, Seq())
}
case _: NodeInfo.Integer.Kind => {
- if (repValueRangesRaw.size % 2 != 0) SDE("repValueRanges must have an even number of elements")
val ans1 = repValueSetRaw.map(BigInt(_))
- def cookRepValueRanges(xs: Seq[String]): Seq[(RangeBound[BigInt], RangeBound[BigInt])] = {
- xs match {
- case Seq() => Seq()
- case a +: b +: rest => {
- val a2 = BigInt(a)
- val b2 = BigInt(b)
- if (a2.compare(b2) > 0) {
- SDE("min value must not be greater than max value")
- }
- val a3 = new RangeBound(Maybe(a2), true)
- val b3 = new RangeBound(Maybe(b2), true)
- (a3, b3) +: cookRepValueRanges(rest)
- }
- }
- }
- val ans2 = cookRepValueRanges(repValueRangesRaw)
+ val ans2 = IntRangeCooker.convertConstant(repValueRangesRaw, this, false)
(ans1, ans2)
}
case x => SDE("repType must be either String or Integer type")
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/ChoiceCombinator.scala b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/ChoiceCombinator.scala
index 1eaed1d..e20b8f9 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/ChoiceCombinator.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/ChoiceCombinator.scala
@@ -34,9 +34,10 @@ import scala.util.Failure
import scala.util.Success
import scala.math.BigInt
import org.apache.daffodil.cookers.RepValueCooker
-import org.apache.daffodil.processors.RangeBound
import org.apache.daffodil.util.Maybe
import org.apache.daffodil.util.MaybeInt
+import org.apache.daffodil.util.RangeBound
+import org.apache.daffodil.cookers.IntRangeCooker
/*
* The purpose of the ChoiceCombinator (and the parsers it creates) is to
@@ -83,6 +84,15 @@ case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: Seq[Gram])
case ChoiceLengthKind.Explicit => new SpecifiedLengthChoiceParser(cp, ch.choiceRuntimeData, choiceLengthInBits.get)
}
} else {
+ //Verify that every alternative has some form of branch key
+ alternatives.map{ alt =>
+ val keyTerm = alt.context.asInstanceOf[Term]
+ val hasBranchKey = keyTerm.findPropertyOption("choiceBranchKey").isDefined
+ val hasBranchKeyRanges = keyTerm.findPropertyOption("choiceBranchKeyRanges").isDefined
+ if(!hasBranchKey && !hasBranchKeyRanges && ch.defaultableChoiceBranchKeyKind != ChoiceKeyKindType.ByType){
+ keyTerm.SDE("Neither dfdl:choiceBranchKey nor dfdlx:choiceBranchKeyRanges is defined.")
+ }
+ }
val dispatchBranchKeyValueTuples: Seq[(String, Gram)] = alternatives.flatMap { alt =>
val keyTerm = alt.context.asInstanceOf[Term]
val uncookedBranchKeys =
@@ -95,9 +105,8 @@ case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: Seq[Gram])
val ans = repValueSet.valueSet.toSeq.map(_.toString).mkString(" ")
ans
}
- case ChoiceKeyKindType.Explicit => keyTerm.choiceBranchKey
- case ChoiceKeyKindType.Implicit => keyTerm.choiceBranchKey
- case ChoiceKeyKindType.Speculative => keyTerm.choiceBranchKey
+ case ChoiceKeyKindType.Explicit | ChoiceKeyKindType.Implicit => keyTerm.findPropertyOption("choiceBranchKey").toOption.getOrElse("")
+ case ChoiceKeyKindType.Speculative => Assert.invariantFailed("Cannot have choiceKeyKind==speculative with direct dispatch")
}
val cbks = {
if(uncookedBranchKeys.isEmpty){
@@ -113,31 +122,39 @@ case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: Seq[Gram])
//Since there is not a choiceBranchKeyRanges attribute, this can only currently be populated by repType
val dispatchBranchKeyRangeTuples: Seq[(RangeBound[BigInt], RangeBound[BigInt], Parser, Boolean)] = alternatives.flatMap { alt =>
val keyTerm = alt.context.asInstanceOf[Term]
- val branchKeyRanges:Set[(RangeBound[BigInt],RangeBound[BigInt])] = ch.defaultableChoiceBranchKeyKind match {
+ val branchKeyRanges:Seq[(RangeBound[BigInt],RangeBound[BigInt])] = ch.defaultableChoiceBranchKeyKind match {
case ChoiceKeyKindType.ByType => {
val keyTerm_ = keyTerm.asInstanceOf[ElementBase]
- keyTerm_.simpleType.optRepValueSet.get.valueRanges.map(x=>{
+ keyTerm_.simpleType.optRepValueSet.get.valueRanges.toSeq.map(x=>{
val x_ = x.asInstanceOf[(RangeBound[BigInt],RangeBound[BigInt])]
(x_._1,x_._2)
})
}
- case ChoiceKeyKindType.Explicit => Set()
- case ChoiceKeyKindType.Implicit => Set()
- case ChoiceKeyKindType.Speculative => Set()
+ case ChoiceKeyKindType.Explicit | ChoiceKeyKindType.Implicit =>
+ IntRangeCooker.convertConstant(keyTerm.findPropertyOption("choiceBranchKeyRanges").toOption.getOrElse(""), context, false)
+ case ChoiceKeyKindType.Speculative => Assert.invariantFailed("Cannot have choiceKeyKind==speculative with direct dispatch")
}
branchKeyRanges.toSeq.map(x=>(x._1, x._2, alt.parser, alt.context.enclosingTerm.get.isRepresented))
}
- // check for duplicate dfdl:choiceBranchKeys
+ // check for duplicate branch keys
// Our handling of ranges here is definantly suboptimal, but hopefully
// we don't see enough distinct ranges on a single element for this to be an issue
+ // Additionally, at this point, the keys could be comming from either the choiceBranchKey family of attributes
+ // or the repValue family of attributes
+ val (branchKeyAttribute, branchKeyRangeAttribute) = ch.defaultableChoiceBranchKeyKind match{
+ case ChoiceKeyKindType.ByType => ("dfdlx:repValues","dfdlx:repValueRanges")
+ case ChoiceKeyKindType.Explicit | ChoiceKeyKindType.Implicit => ("dfdl:choiceBranchKey","dfdlx:choiceBranchKeyRanges")
+ case ChoiceKeyKindType.Speculative => Assert.invariantFailed("Cannot have choiceKeyKind==speculative with direct dispatch")
+ }
val groupedByKey = dispatchBranchKeyValueTuples.groupBy(_._1)
groupedByKey.foreach {
case (k, kvs) =>
if (kvs.length > 1) {
SDE(
- "dfdl:choiceBranchKey value (%s) is not unique across all branches of a direct dispatch choice. Offending branches are:\n%s",
- k, kvs.map(_._2.context.runtimeData).map(rd => rd.diagnosticDebugName + " " + rd.schemaFileLocation.locationDescription).mkString("- ", "\n- ", ""))
+ "%s value (%s) is not unique across all branches of a direct dispatch choice. Offending branches are:\n%s",
+ branchKeyAttribute, k,
+ kvs.map(_._2.context.runtimeData).map(rd => rd.diagnosticDebugName + " " + rd.schemaFileLocation.locationDescription).mkString("- ", "\n- ", ""))
}
Try(k.toLong) match {
case Success(v) => {
@@ -145,8 +162,8 @@ case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: Seq[Gram])
val conflictingRanges = dispatchBranchKeyRangeTuples.filter({ case (min, max, _, _) => min.testAsLower(asBigInt) && max.testAsUpper(asBigInt) })
if (conflictingRanges.length > 0) {
SDE(
- "dfdl:choiceBranchKey (%s) conflicts with dfdl:choiceBranchKeyRanges. Offending branches are:\n%s\n%s",
- k,
+ "%s (%s) conflicts with %s. Offending branches are:\n%s\n%s",
+ branchKeyAttribute, k, branchKeyRangeAttribute,
kvs.map(_._2.context.runtimeData).map(rd => rd.diagnosticDebugName + " " + rd.schemaFileLocation.locationDescription).mkString("- ", "\n- ", ""),
conflictingRanges.map(_._3.context).map(rd => rd.diagnosticDebugName + " " + rd.schemaFileLocation.locationDescription).mkString("- ", "\n- ", ""))
}
@@ -167,7 +184,8 @@ case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: Seq[Gram])
val conflictingRanges = (conflictingRanges1 ++ conflictingRanges2).toSet
if (conflictingRanges.size > 1) {
SDE(
- "dfdl:choiceBranchKeyRanges (%s, %s) conflicts with other ranges. Offending branches are:\n%s",
+ "%s (%s, %s) conflicts with other ranges. Offending branches are:\n%s",
+ branchKeyRangeAttribute,
min, max,
conflictingRanges.map(_._3.context).map(rd => rd.diagnosticDebugName + " " + rd.schemaFileLocation.locationDescription).mkString("- ", "\n- ", ""))
}
diff --git a/daffodil-lib/src/main/scala/org/apache/daffodil/cookers/Cookers.scala b/daffodil-lib/src/main/scala/org/apache/daffodil/cookers/Cookers.scala
index 47c8fe2..0d8592e 100644
--- a/daffodil-lib/src/main/scala/org/apache/daffodil/cookers/Cookers.scala
+++ b/daffodil-lib/src/main/scala/org/apache/daffodil/cookers/Cookers.scala
@@ -17,6 +17,11 @@
package org.apache.daffodil.cookers
+import org.apache.daffodil.util.RangeBound
+import org.apache.daffodil.util.RangeBound.Range
+import org.apache.daffodil.exceptions.ThrowsSDE
+import org.apache.daffodil.util.Maybe
+
object TextStandardInfinityRepCooker extends StringLiteralNonEmptyNoCharClassEntitiesNoByteEntities()
object TextStandardNaNRepCooker extends StringLiteralNonEmptyNoCharClassEntitiesNoByteEntities()
@@ -84,3 +89,28 @@ object ChoiceBranchKeyCooker extends ListOfStringLiteralNonEmptyNoCharClassEntit
object RepValueCooker extends ListOfStringLiteralNonEmptyNoCharClassEntitiesNoByteEntities()
object UpperCaseTokenCooker extends UpperCaseToken
+
+object IntRangeCooker extends Converter[String, Seq[Range[BigInt]]] {
+ protected def convert(input: String, context: ThrowsSDE, forUnparse: Boolean): Seq[Range[BigInt]] = {
+ def run(xs: Seq[String]): Seq[(RangeBound[BigInt], RangeBound[BigInt])] = {
+ xs match {
+ case Seq() => Seq()
+ case a +: b +: rest => {
+ val a2 = BigInt(a)
+ val b2 = BigInt(b)
+ if (a2.compare(b2) > 0) {
+ context.SDE("min value (%s) is greater than max value (%s)", a2, b2)
+ }
+ val a3 = new RangeBound(Maybe(a2), true)
+ val b3 = new RangeBound(Maybe(b2), true)
+ (a3, b3) +: run(rest)
+ }
+ }
+ }
+ val asSeq = input.split("\\s+").toSeq.filter(!_.isEmpty)
+ if(asSeq.length % 2 != 0){
+ context.SDE("Integer range sets must specify an even number of endpoints")
+ }
+ run(asSeq)
+ }
+}
\ No newline at end of file
diff --git a/daffodil-lib/src/main/scala/org/apache/daffodil/util/RangeBound.scala b/daffodil-lib/src/main/scala/org/apache/daffodil/util/RangeBound.scala
new file mode 100644
index 0000000..5a1f8e7
--- /dev/null
+++ b/daffodil-lib/src/main/scala/org/apache/daffodil/util/RangeBound.scala
@@ -0,0 +1,111 @@
+/*
+ * 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.util
+
+import java.lang.{ Long => JLong }
+import org.apache.daffodil.exceptions.Assert
+import org.apache.daffodil.cookers.Converter
+import org.apache.daffodil.exceptions.ThrowsSDE
+import org.apache.daffodil.util.RangeBound.Range
+
+object RangeBound {
+ type Range[A <: AnyRef] = (RangeBound[A], RangeBound[A])
+}
+
+class RangeBound[A <: AnyRef](val maybeBound: Maybe[A], val isInclusive: Boolean)
+ extends Serializable {
+
+ lazy val isEmpty = maybeBound.isEmpty
+ lazy val isDefined = maybeBound.isDefined
+
+ override def toString(): String = {
+ if (maybeBound.isDefined) {
+ maybeBound.get.toString + "_" + (if (isInclusive) "inclusive" else "exclusive")
+ } else {
+ "Nope"
+ }
+ }
+
+ def intersectsWithOtherBounds(lower: RangeBound[A], upper: RangeBound[A]): Boolean = {
+ if (maybeBound.isEmpty) {
+ false
+ } else {
+ val bound = maybeBound.get
+ val inBounds = lower.testAsLower(bound) && upper.testAsUpper(bound)
+ val atBoundery = maybeBound == lower.maybeBound || maybeBound == upper.maybeBound
+ inBounds && (isInclusive || !atBoundery)
+ }
+ }
+
+ /*
+ * It should be the case that x is either a BigInt, or a Long
+ */
+
+ def testAsLower(x: A): Boolean = {
+ if (maybeBound.isEmpty) {
+ true
+ } else {
+ if (isInclusive) {
+ le(maybeBound.get, x)
+ } else {
+ lt(maybeBound.get, x)
+ }
+ }
+ }
+ def testAsUpper(x: A): Boolean = {
+ if (maybeBound.isEmpty) {
+ true
+ } else {
+ val bound = maybeBound.get
+ if (isInclusive) {
+ le(x, maybeBound.get)
+ } else {
+ lt(x, maybeBound.get)
+ }
+ }
+ }
+
+ private def le(x: A, y: A): Boolean = {
+ if (x.isInstanceOf[BigInt] && y.isInstanceOf[BigInt]) {
+ x.asInstanceOf[BigInt] <= y.asInstanceOf[BigInt]
+ } else if (x.isInstanceOf[JLong] && y.isInstanceOf[JLong]) {
+ x.asInstanceOf[JLong] <= y.asInstanceOf[JLong]
+ } else if (x.isInstanceOf[BigInt] && y.isInstanceOf[JLong]) {
+ x.asInstanceOf[BigInt] <= BigInt(y.asInstanceOf[JLong])
+ } else if (x.isInstanceOf[JLong] && y.isInstanceOf[BigInt]) {
+ BigInt(x.asInstanceOf[JLong]) <= y.asInstanceOf[BigInt]
+ } else {
+ Assert.invariantFailed("Illegal type passed to RangeBound.le")
+ }
+ }
+
+ private def lt(x: A, y: A): Boolean = {
+ if (x.isInstanceOf[BigInt] && y.isInstanceOf[BigInt]) {
+ x.asInstanceOf[BigInt] < y.asInstanceOf[BigInt]
+ } else if (x.isInstanceOf[JLong] && y.isInstanceOf[JLong]) {
+ x.asInstanceOf[JLong] < y.asInstanceOf[JLong]
+ } else if (x.isInstanceOf[BigInt] && y.isInstanceOf[JLong]) {
+ x.asInstanceOf[BigInt] < BigInt(y.asInstanceOf[JLong])
+ } else if (x.isInstanceOf[JLong] && y.isInstanceOf[BigInt]) {
+ BigInt(x.asInstanceOf[JLong]) < y.asInstanceOf[BigInt]
+ } else {
+ Assert.invariantFailed("Illegal type passed to RangeBound.lt")
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/DFDL_part2_attributes.xsd b/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/DFDL_part2_attributes.xsd
index 32271e2..cebc507 100644
--- a/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/DFDL_part2_attributes.xsd
+++ b/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/DFDL_part2_attributes.xsd
@@ -108,6 +108,7 @@
<xsd:attribute name="encodingErrorPolicy" type="dfdl:EncodingErrorPolicyEnum"/>
<xsd:attribute name="ignoreCase" type="dfdl:YesNoEnum" />
<xsd:attribute name="choiceBranchKey" type="dfdl:ListOfDFDLStringLiteral" />
+ <xsd:attribute ref="dfdlx:choiceBranchKeyRanges" />
<xsd:attribute name="textBidi" type="dfdl:YesNoEnum"/>
</xsd:attributeGroup>
@@ -680,6 +681,7 @@
type="dfdl:YesNoEnum" />
<xsd:attribute form="qualified" name="choiceBranchKey"
type="dfdl:ListOfDFDLStringLiteral" />
+ <xsd:attribute ref="dfdlx:choiceBranchKeyRanges" />
</xsd:attributeGroup>
<!-- 12.1 Aligned Data -->
diff --git a/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dfdlx.xsd b/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dfdlx.xsd
index 2d743c1..7bee32b 100644
--- a/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dfdlx.xsd
+++ b/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dfdlx.xsd
@@ -35,6 +35,7 @@
<xs:simpleType name="PropertyNameType">
<xs:restriction base="xs:string">
<xs:enumeration value="dfdlx:choiceBranchKeyKind" />
+ <xs:enumeration value="dfdlx:choiceBranchKeyRanges" />
<xs:enumeration value="dfdlx:choiceDispatchKeyKind" />
<xs:enumeration value="dfdlx:emptyElementParsePolicy"/>
<xs:enumeration value="dfdlx:inputTypeCalc"/>
@@ -73,6 +74,8 @@
<xs:enumeration value="implicit"/>
</xs:restriction>
</xs:simpleType>
+
+ <xs:attribute name="choiceBranchKeyRanges" type="dfdl:NonEmptyListOfInteger" />
<xs:attributeGroup name="SimpleTypeValueCalcAG">
<xs:attribute form="qualified" name="repType" type="dfdl:DFDLQName" />
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/TypeCalculator.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/TypeCalculator.scala
index 5ebce0c..7bc2759 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/TypeCalculator.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/TypeCalculator.scala
@@ -38,6 +38,7 @@ import org.apache.daffodil.processors.parsers.ParseError
import org.apache.daffodil.util.Maybe.One
import org.apache.daffodil.dpath.NodeInfo.Kind
import org.apache.daffodil.dpath.NodeInfo
+import org.apache.daffodil.util.RangeBound
abstract class TypeCalculator[A <: AnyRef, B <: AnyRef](val srcType: NodeInfo.Kind, val dstType: NodeInfo.Kind)
extends Serializable {
@@ -274,87 +275,6 @@ class UnionTypeCalculator[A <: AnyRef, B <: AnyRef](subCalculators: Seq[(RepValu
}
-class RangeBound[A <: AnyRef](val maybeBound: Maybe[A], val isInclusive: Boolean) extends Serializable {
- lazy val isEmpty = maybeBound.isEmpty
- lazy val isDefined = maybeBound.isDefined
-
- override def toString(): String = {
- if (maybeBound.isDefined) {
- maybeBound.get.toString + "_" + (if (isInclusive) "inclusive" else "exclusive")
- } else {
- "Nope"
- }
- }
-
- def intersectsWithOtherBounds(lower: RangeBound[A], upper: RangeBound[A]): Boolean = {
- if (maybeBound.isEmpty) {
- false
- } else {
- val bound = maybeBound.get
- val inBounds = lower.testAsLower(bound) && upper.testAsUpper(bound)
- val atBoundery = maybeBound == lower.maybeBound || maybeBound == upper.maybeBound
- inBounds && (isInclusive || !atBoundery)
- }
- }
-
- /*
- * It should be the case that x is either a BigInt, or a Long
- */
-
- def testAsLower(x: A): Boolean = {
- if (maybeBound.isEmpty) {
- true
- } else {
- if (isInclusive) {
- le(maybeBound.get, x)
- } else {
- lt(maybeBound.get, x)
- }
- }
- }
- def testAsUpper(x: A): Boolean = {
- if (maybeBound.isEmpty) {
- true
- } else {
- val bound = maybeBound.get
- if (isInclusive) {
- le(x, maybeBound.get)
- } else {
- lt(x, maybeBound.get)
- }
- }
- }
-
- private def le(x: A, y: A): Boolean = {
- if (x.isInstanceOf[BigInt] && y.isInstanceOf[BigInt]) {
- x.asInstanceOf[BigInt] <= y.asInstanceOf[BigInt]
- } else if (x.isInstanceOf[JLong] && y.isInstanceOf[JLong]) {
- x.asInstanceOf[JLong] <= y.asInstanceOf[JLong]
- } else if (x.isInstanceOf[BigInt] && y.isInstanceOf[JLong]) {
- x.asInstanceOf[BigInt] <= BigInt(y.asInstanceOf[JLong])
- } else if (x.isInstanceOf[JLong] && y.isInstanceOf[BigInt]) {
- BigInt(x.asInstanceOf[JLong]) <= y.asInstanceOf[BigInt]
- } else {
- Assert.invariantFailed("Illegal type passed to RangeBound.le")
- }
- }
-
- private def lt(x: A, y: A): Boolean = {
- if (x.isInstanceOf[BigInt] && y.isInstanceOf[BigInt]) {
- x.asInstanceOf[BigInt] < y.asInstanceOf[BigInt]
- } else if (x.isInstanceOf[JLong] && y.isInstanceOf[JLong]) {
- x.asInstanceOf[JLong] < y.asInstanceOf[JLong]
- } else if (x.isInstanceOf[BigInt] && y.isInstanceOf[JLong]) {
- x.asInstanceOf[BigInt] < BigInt(y.asInstanceOf[JLong])
- } else if (x.isInstanceOf[JLong] && y.isInstanceOf[BigInt]) {
- BigInt(x.asInstanceOf[JLong]) < y.asInstanceOf[BigInt]
- } else {
- Assert.invariantFailed("Illegal type passed to RangeBound.lt")
- }
- }
-
-}
-
/*
* Since we can inherit the restriction from xsd facets, we also need to be able to support an
* aribitrary subset of: minInclusive, minExclusive, maxInclusive, and maxExclusive
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ElementKindParsers.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ElementKindParsers.scala
index 793ebe8..06c5ee4 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ElementKindParsers.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ElementKindParsers.scala
@@ -21,6 +21,7 @@ import org.apache.daffodil.processors._
import org.apache.daffodil.util.LogLevel
import org.apache.daffodil.util.Maybe
import org.apache.daffodil.exceptions.Assert
+import org.apache.daffodil.util.RangeBound
class ComplexTypeParser(rd: RuntimeData, bodyParser: Parser)
extends CombinatorParser(rd) {
@@ -177,9 +178,13 @@ abstract class ChoiceDispatchCombinatorParserBase(rd: TermRuntimeData,
parserOpt1
} else{
if(!dispatchKeyRangeMap.isEmpty){
- val keyAsBigInt = BigInt(key)
- val optAns1= dispatchKeyRangeMap.filter({case(min,max,_,_) => min.testAsLower(keyAsBigInt) && max.testAsUpper(keyAsBigInt)}).headOption
- optAns1.map({case(_,_,parser,isRepresented)=>(parser,isRepresented)})
+ try{
+ val keyAsBigInt = BigInt(key)
+ val optAns1= dispatchKeyRangeMap.find({case(min,max,_,_) => min.testAsLower(keyAsBigInt) && max.testAsUpper(keyAsBigInt)})
+ optAns1.map({case(_,_,parser,isRepresented)=>(parser,isRepresented)})
+ } catch{
+ case _:NumberFormatException => None
+ }
}else{
None
}
@@ -221,11 +226,16 @@ abstract class ChoiceDispatchCombinatorParserBase(rd: TermRuntimeData,
}
} finally {
if (!freedInitialState) {
- Assert.invariant(pstate.processorStatus ne Success)
//Since we failed, it does not matter what state we are actually in, as our caller will backtrack anyway
//What does matter is that we return the mark to the pool
pstate.discard(initialState)
freedInitialState = true
+
+ /* It is important to put this check after cleaning up the initial state.
+ * If this check fails, before cleaning up the mark, then the error will be
+ * hidden by another error complaining about us not cleaning up the mark
+ */
+ Assert.invariant(pstate.processorStatus ne Success)
}
}
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/extensions/choiceBranchRanges/choiceBranchKeyRanges.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/extensions/choiceBranchRanges/choiceBranchKeyRanges.tdml
new file mode 100644
index 0000000..1b9f2ee
--- /dev/null
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/extensions/choiceBranchRanges/choiceBranchKeyRanges.tdml
@@ -0,0 +1,331 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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 xmlns:ex="http://example.com" xmlns="http://example.com"
+ xmlns:tns="http://example.com"
+ xmlns:tdml="http://www.ibm.com/xmlns/dfdl/testData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/" xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:dfdlx="http://www.ogf.org/dfdl/dfdl-1.0/extensions"
+ xmlns:fn="http://www.w3.org/2005/xpath-functions"
+ >
+
+ <tdml:defineSchema name="choiceBranchKeyRanges-Embedded.dfdl.xsd">
+
+ <xs:include schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
+ <dfdl:format ref="ex:GeneralFormat"
+ lengthUnits="bits"
+ dfdlx:emptyElementParsePolicy="treatAsEmpty"
+ representation="binary"
+ />
+
+ <xs:simpleType name="uint8" dfdl:lengthKind="explicit" dfdl:length="8">
+ <xs:restriction base="xs:unsignedInt"/>
+ </xs:simpleType>
+
+ <xs:simpleType name="emptyElt" dfdl:lengthKind="explicit" dfdl:length="0">
+ <xs:restriction base="xs:hexBinary"/>
+ </xs:simpleType>
+
+ <xs:element name="choiceBranchKeyRanges_01">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="byte" maxOccurs="unbounded" dfdl:occursCountKind="parsed">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="tag" type="tns:uint8"/>
+ <xs:choice dfdl:choiceDispatchKey="{ tns:tag }" >
+ <xs:element name="a" type="tns:emptyElt" dfdl:choiceBranchKey="0"/>
+ <xs:element name="b" type="tns:emptyElt" dfdl:choiceBranchKey="1 5" dfdlx:choiceBranchKeyRanges="10 100 110 255"/>
+ <xs:element name="c" type="tns:emptyElt" dfdl:choiceBranchKey="2 3 4"/>
+ <xs:element name="d" type="tns:emptyElt" dfdlx:choiceBranchKeyRanges="6 9"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="choiceBranchKeyRanges_overlap_01">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="byte">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="tag" type="tns:uint8"/>
+ <xs:choice dfdl:choiceDispatchKey="{ tns:tag }" >
+ <xs:element name="a" type="tns:emptyElt" dfdl:choiceBranchKey="0"/>
+ <xs:element name="b" type="tns:emptyElt" dfdlx:choiceBranchKeyRanges="0 255"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="choiceBranchKeyRanges_overlap_02">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="byte">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="tag" type="tns:uint8"/>
+ <xs:choice dfdl:choiceDispatchKey="{ tns:tag }" >
+ <xs:element name="a" type="tns:emptyElt" dfdl:choiceBranchKey="10"/>
+ <xs:element name="b" type="tns:emptyElt" dfdlx:choiceBranchKeyRanges="0 4 7 20 25 100"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="choiceBranchKeyRanges_overlap_03">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="byte">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="tag" type="tns:uint8"/>
+ <xs:choice dfdl:choiceDispatchKey="{ tns:tag }" >
+ <xs:element name="a" type="tns:emptyElt" dfdlx:choiceBranchKeyRanges="5 24 100 255"/>
+ <xs:element name="b" type="tns:emptyElt" dfdlx:choiceBranchKeyRanges="0 4 25 100"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="choiceBranchKeyRanges_oddLength_01">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="byte">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="tag" type="tns:uint8"/>
+ <xs:choice dfdl:choiceDispatchKey="{ tns:tag }" >
+ <xs:element name="a" type="tns:emptyElt" dfdlx:choiceBranchKeyRanges="5 24 25 100 255"/>
+ <xs:element name="b" type="tns:emptyElt" dfdlx:choiceBranchKeyRanges="0 4 25 100"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="choiceBranchKeyRanges_badOrder_01">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="byte">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="tag" type="tns:uint8"/>
+ <xs:choice dfdl:choiceDispatchKey="{ tns:tag }" >
+ <xs:element name="a" type="tns:emptyElt" dfdlx:choiceBranchKeyRanges="24 5 100 255"/>
+ <xs:element name="b" type="tns:emptyElt" dfdlx:choiceBranchKeyRanges="0 4 25 100"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="choiceBranchKeyRanges_nonintDispatch_01">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="byte">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:choice dfdl:choiceDispatchKey="{ 'x' }" >
+ <xs:element name="a" type="tns:emptyElt" dfdl:choiceBranchKey="x" dfdlx:choiceBranchKeyRanges="5 24 100 255"/>
+ <xs:element name="b" type="tns:emptyElt" dfdlx:choiceBranchKeyRanges="0 4 25 99"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="choiceBranchKeyRanges_nonintDispatch_02">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="byte">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:choice dfdl:choiceDispatchKey="{ 'x' }" >
+ <xs:element name="a" type="tns:emptyElt" dfdlx:choiceBranchKeyRanges="5 24 100 255"/>
+ <xs:element name="b" type="tns:emptyElt" dfdlx:choiceBranchKeyRanges="0 4 25 99"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ </tdml:defineSchema>
+
+ <tdml:parserTestCase name="choiceBranchKeyRanges_01"
+ root="choiceBranchKeyRanges_01" model="choiceBranchKeyRanges-Embedded.dfdl.xsd" description="Extensions - choiceBranchKeyRanges">
+
+ <tdml:document>
+ <tdml:documentPart type="byte">
+ 00
+ 01 05 0a 32 64 6e c8 ff
+ 02 03 04
+ 06 07 08 09
+ </tdml:documentPart>
+ </tdml:document>
+ <tdml:infoset>
+ <tdml:dfdlInfoset xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <choiceBranchKeyRanges_01>
+ <byte><tag>0</tag><a/></byte>
+
+ <byte><tag>1</tag><b/></byte>
+ <byte><tag>5</tag><b/></byte>
+ <byte><tag>10</tag><b/></byte>
+ <byte><tag>50</tag><b/></byte>
+ <byte><tag>100</tag><b/></byte>
+ <byte><tag>110</tag><b/></byte>
+ <byte><tag>200</tag><b/></byte>
+ <byte><tag>255</tag><b/></byte>
+
+ <byte><tag>2</tag><c/></byte>
+ <byte><tag>3</tag><c/></byte>
+ <byte><tag>4</tag><c/></byte>
+
+ <byte><tag>6</tag><d/></byte>
+ <byte><tag>7</tag><d/></byte>
+ <byte><tag>8</tag><d/></byte>
+ <byte><tag>9</tag><d/></byte>
+ </choiceBranchKeyRanges_01>
+ </tdml:dfdlInfoset>
+ </tdml:infoset>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="choiceBranchKeyRanges_overlap_01"
+ root="choiceBranchKeyRanges_overlap_01" model="choiceBranchKeyRanges-Embedded.dfdl.xsd" description="Extensions - choiceBranchKeyRanges">
+
+ <tdml:document>
+ <tdml:documentPart type="byte">
+ </tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>dfdl:choiceBranchKey</tdml:error>
+ <tdml:error>conflicts with</tdml:error>
+ <tdml:error>dfdlx:choiceBranchKeyRanges</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="choiceBranchKeyRanges_overlap_02"
+ root="choiceBranchKeyRanges_overlap_02" model="choiceBranchKeyRanges-Embedded.dfdl.xsd" description="Extensions - choiceBranchKeyRanges">
+
+ <tdml:document>
+ <tdml:documentPart type="byte">
+ </tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>dfdl:choiceBranchKey</tdml:error>
+ <tdml:error>conflicts with</tdml:error>
+ <tdml:error>dfdlx:choiceBranchKeyRanges</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="choiceBranchKeyRanges_overlap_03"
+ root="choiceBranchKeyRanges_overlap_03" model="choiceBranchKeyRanges-Embedded.dfdl.xsd" description="Extensions - choiceBranchKeyRanges">
+
+ <tdml:document>
+ <tdml:documentPart type="byte">
+ </tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>dfdlx:choiceBranchKeyRanges</tdml:error>
+ <tdml:error>conflicts with</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="choiceBranchKeyRanges_oddLength_01"
+ root="choiceBranchKeyRanges_oddLength_01" model="choiceBranchKeyRanges-Embedded.dfdl.xsd" description="Extensions - choiceBranchKeyRanges">
+
+ <tdml:document>
+ <tdml:documentPart type="byte">
+ </tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>Integer range</tdml:error>
+ <tdml:error>even</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="choiceBranchKeyRanges_badOrder_01"
+ root="choiceBranchKeyRanges_badOrder_01" model="choiceBranchKeyRanges-Embedded.dfdl.xsd" description="Extensions - choiceBranchKeyRanges">
+
+ <tdml:document>
+ <tdml:documentPart type="byte">
+ </tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>min value (24)</tdml:error>
+ <tdml:error>max value (5)</tdml:error>
+ <tdml:error>greater</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="choiceBranchKeyRanges_nonintDispatch_01"
+ root="choiceBranchKeyRanges_nonintDispatch_01" model="choiceBranchKeyRanges-Embedded.dfdl.xsd" description="Extensions - choiceBranchKeyRanges">
+
+ <tdml:document>
+ <tdml:documentPart type="byte">
+ </tdml:documentPart>
+ </tdml:document>
+ <tdml:infoset>
+ <tdml:dfdlInfoset>
+ <choiceBranchKeyRanges_nonintDispatch_01>
+ <byte><a/></byte>
+ </choiceBranchKeyRanges_nonintDispatch_01>
+ </tdml:dfdlInfoset>
+ </tdml:infoset>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="choiceBranchKeyRanges_nonintDispatch_02"
+ root="choiceBranchKeyRanges_nonintDispatch_02" model="choiceBranchKeyRanges-Embedded.dfdl.xsd" description="Extensions - choiceBranchKeyRanges">
+
+ <tdml:document>
+ <tdml:documentPart type="byte">
+ </tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>Parse Error</tdml:error>
+ <tdml:error>Choice dispatch key (x) failed to match any of the branch keys</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+</tdml:testSuite>
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section15/choice_groups/choice.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section15/choice_groups/choice.tdml
index 165ec38..e08bc78 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/section15/choice_groups/choice.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/section15/choice_groups/choice.tdml
@@ -1838,7 +1838,8 @@ it sure is/
<tdml:errors>
<tdml:error>Schema Definition Error</tdml:error>
<tdml:error>choiceBranchKey</tdml:error>
- <tdml:error>not defined</tdml:error>
+ <tdml:error>choiceBranchKeyRanges</tdml:error>
+ <tdml:error>defined</tdml:error>
</tdml:errors>
</tdml:parserTestCase>
diff --git a/daffodil-test/src/test/scala/org/apache/daffodil/extensions/TestChoiceBranchKeyRanges.scala b/daffodil-test/src/test/scala/org/apache/daffodil/extensions/TestChoiceBranchKeyRanges.scala
new file mode 100644
index 0000000..4f43047
--- /dev/null
+++ b/daffodil-test/src/test/scala/org/apache/daffodil/extensions/TestChoiceBranchKeyRanges.scala
@@ -0,0 +1,45 @@
+/*
+ * 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.extensions
+
+import org.apache.daffodil.tdml.Runner
+import org.junit.AfterClass
+import org.junit.Test
+
+object TestChoiceBranchKeyRanges {
+ val testDir = "/org/apache/daffodil/extensions/choiceBranchRanges/"
+
+ val runner = Runner(testDir, "choiceBranchKeyRanges.tdml", validateTDMLFile = true)
+
+ @AfterClass def shutDown {
+ runner.reset
+ }
+
+}
+
+class TestChoiceBranchKeyRanges {
+ import TestChoiceBranchKeyRanges._
+
+ @Test def test_choiceBranchKeyRanges_01() { runner.runOneTest("choiceBranchKeyRanges_01") }
+ @Test def test_choiceBranchKeyRanges_overlap_01() { runner.runOneTest("choiceBranchKeyRanges_overlap_01") }
+ @Test def test_choiceBranchKeyRanges_overlap_02() { runner.runOneTest("choiceBranchKeyRanges_overlap_02") }
+ @Test def test_choiceBranchKeyRanges_overlap_03() { runner.runOneTest("choiceBranchKeyRanges_overlap_03") }
+ @Test def test_choiceBranchKeyRanges_oddLength_01() { runner.runOneTest("choiceBranchKeyRanges_oddLength_01") }
+ @Test def test_choiceBranchKeyRanges_badOrder_01() { runner.runOneTest("choiceBranchKeyRanges_badOrder_01") }
+ @Test def test_choiceBranchKeyRanges_nonintDispatch_01() { runner.runOneTest("choiceBranchKeyRanges_nonintDispatch_01") }
+ @Test def test_choiceBranchKeyRanges_nonintDispatch_02() { runner.runOneTest("choiceBranchKeyRanges_nonintDispatch_02") }
+}
\ No newline at end of file