This is an automated email from the ASF dual-hosted git repository.
mbeckerle 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 03a2a5b Fix initiatedContent="yes" with zero-length initiator
03a2a5b is described below
commit 03a2a5b5e16885cd58812f86a5a8e4aa0e2dbe91
Author: John Interrante <[email protected]>
AuthorDate: Fri May 22 17:29:51 2020 -0400
Fix initiatedContent="yes" with zero-length initiator
A group with initiatedContent="yes" but a zero-length initiator should
be a schema definition error. Fix the bug and add four TDML tests to
DelimiterProperties.tdml to check that it is fixed.
Refactor two methods and one field to make their purpose clearer:
- ElementBase: initTermTestExpression renamed to hasNonEmptyDelimiter
- ConstantExpression: value pulled into CompiledExpression
- ConstantExpression: isKnownNonEmpty pulled into CompiledExpression
- RuntimeExpressionDPath: isKnownNonEmpty pulled into CompiledExpression
- CompiledExpression: isKnownNonEmpty renamed to isConstantEmptyString
- CompiledExpression: valueForDebugPrinting renamed to value
Define three new methods to implement the check:
- InitiatedTerminatedMixin: hasNonZeroLengthInitiator
- InitiatedTerminatedMixin: mustMatchNonZeroData
- CompiledExpression: isKnownCanMatchEmptyString
Pass e.mustMatchNonZeroData to DelimiterTextParse constructor.
Add compile-time and run-time checks to the right places:
- ModelGroup: initiatedContentCheck
- DelimiterTextParse: parse
Fix a few misspellings, update comments, etc.
DAFFODIL-2199
---
.../org/apache/daffodil/dsom/ElementBase.scala | 22 +++---
.../daffodil/dsom/InitiatedTerminatedMixin.scala | 24 +++++-
.../org/apache/daffodil/dsom/ModelGroup.scala | 9 ++-
.../daffodil/grammar/SequenceGrammarMixin.scala | 2 +-
.../primitives/DelimiterAndEscapeRelated.scala | 28 +++----
.../grammar/primitives/PrimitivesDelimiters.scala | 2 +-
.../scala/org/apache/daffodil/dpath/DPath.scala | 6 +-
.../apache/daffodil/dsom/CompiledExpression1.scala | 26 +++---
.../apache/daffodil/processors/EvDelimiters.scala | 2 +-
.../processors/parsers/DelimiterParsers.scala | 9 ++-
.../delimiter_properties/DelimiterProperties.tdml | 92 ++++++++++++++++++++++
.../TestDelimiterProperties.scala | 5 ++
12 files changed, 174 insertions(+), 53 deletions(-)
diff --git
a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala
b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala
index a0e9fff..d92e27c 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala
@@ -686,8 +686,8 @@ trait ElementBase
private def NVDP = NilValueDelimiterPolicy
private def EVDP = EmptyValueDelimiterPolicy
- protected final lazy val hasNilValueInitiator =
initTermTestExpression(initiatorParseEv, nilValueDelimiterPolicy, NVDP.Both,
NVDP.Initiator)
- protected final lazy val hasNilValueTerminator =
initTermTestExpression(terminatorParseEv, nilValueDelimiterPolicy, NVDP.Both,
NVDP.Terminator)
+ protected final lazy val hasNilValueInitiator =
hasNonEmptyDelimiter(initiatorParseEv, nilValueDelimiterPolicy, NVDP.Both,
NVDP.Initiator)
+ protected final lazy val hasNilValueTerminator =
hasNonEmptyDelimiter(terminatorParseEv, nilValueDelimiterPolicy, NVDP.Both,
NVDP.Terminator)
/**
* We need the nil values in raw form for diagnostic messages.
@@ -729,19 +729,19 @@ trait ElementBase
// cause a nil value to be created.
(isDefinedNilValue && (isSimpleType && (simpleType.primType =:=
PrimType.String || simpleType.primType =:= PrimType.HexBinary) &&
!hasESNilValue)))
- final lazy val hasEmptyValueInitiator =
initTermTestExpression(initiatorParseEv, emptyValueDelimiterPolicy, EVDP.Both,
EVDP.Initiator)
- final lazy val hasEmptyValueTerminator =
initTermTestExpression(terminatorParseEv, emptyValueDelimiterPolicy, EVDP.Both,
EVDP.Terminator)
+ final lazy val hasEmptyValueInitiator =
hasNonEmptyDelimiter(initiatorParseEv, emptyValueDelimiterPolicy, EVDP.Both,
EVDP.Initiator)
+ final lazy val hasEmptyValueTerminator =
hasNonEmptyDelimiter(terminatorParseEv, emptyValueDelimiterPolicy, EVDP.Both,
EVDP.Terminator)
// See how this function takes the prop: => Any that is pass by name (aka
lazy pass).
// That allows us to not require the property to exist at all if
- // expr.isKnownNotEmpty turns out to be false.
- private def initTermTestExpression(expr: DelimiterParseEv, prop: => Any,
true1: Any, true2: Any): Boolean = {
+ // expr.isConstantEmptyString turns out to be true.
+ private def hasNonEmptyDelimiter(expr: DelimiterParseEv, prop: => Any,
true1: Any, true2: Any): Boolean = {
// changed from a match on a 2-tuple to if-then-else logic because we
don't even want to ask for
- // prop's value at all unless the first test is true.
- if (expr.isKnownNonEmpty)
- if (prop == true1 || prop == true2) true
- else false
- else false
+ // prop's value at all unless the first test is false.
+ if (expr.isConstantEmptyString)
+ false
+ else
+ prop == true1 || prop == true2
}
/**
diff --git
a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/InitiatedTerminatedMixin.scala
b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/InitiatedTerminatedMixin.scala
index e8c7f9c..bbc1e85 100644
---
a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/InitiatedTerminatedMixin.scala
+++
b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/InitiatedTerminatedMixin.scala
@@ -44,15 +44,31 @@ trait InitiatedTerminatedMixin
* True if the term has an initiator expressed on it.
*
* Do not confuse with the concept of the delimiter being able to match or
not match zero-length data.
- * Whether the representation of a term in the data stream "has an
initiator", as in the initator
+ * Whether the representation of a term in the data stream "has an
initiator", as in the initiator
* occupies a non-zero number of bits in the data stream, is an entirely
different question.
*/
lazy val hasInitiator = {
- val hasOne = initiatorExpr.isKnownNonEmpty
+ val hasOne = !initiatorExpr.isConstantEmptyString
hasOne
}
/**
+ * True if the term's initiator cannot match zero-length data. This answers
the entirely different
+ * question of whether the initiator occupies a non-zero number of bits in
the data stream.
+ */
+ lazy val hasNonZeroLengthInitiator = {
+ val hasOne = !initiatorExpr.isKnownCanMatchEmptyString
+ hasOne
+ }
+
+ /**
+ * True if the term is inside an immediately enclosing model group which has
the initiatedContent
+ * property set to "yes". This tells us whether we need to verify that a
runtime expression defining
+ * the initiator matches a non-zero number of bits in the data stream.
+ */
+ lazy val mustMatchNonZeroData = parentSaysInitiatedContent
+
+ /**
* True if the term has a terminator expressed on it.
*
* Do not confuse with the concept of the delimiter being able to match or
not match zero-length data.
@@ -60,8 +76,8 @@ trait InitiatedTerminatedMixin
* occupies a non-zero number of bits, is an entirely different question.
*/
lazy val hasTerminator = {
- val res = terminatorExpr.isKnownNonEmpty
- res
+ val hasOne = !terminatorExpr.isConstantEmptyString
+ hasOne
}
private lazy val isInitiatedContentChoice: Boolean = {
diff --git
a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ModelGroup.scala
b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ModelGroup.scala
index 3f1f6d7..3148d27 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ModelGroup.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ModelGroup.scala
@@ -354,8 +354,13 @@ abstract class ModelGroup(index: Int)
lazy val initiatedContentCheck: Unit = {
if (initiatedContent eq YesNo.Yes) {
- groupMembers.foreach { term =>
- term.schemaDefinitionUnless(term.hasInitiator, "Enclosing group has
initiatedContent='yes', but initiator is not defined.")
+ groupMembers.foreach {
+ term => {
+ term.schemaDefinitionUnless(term.hasInitiator,
+ "Enclosing group has initiatedContent='yes', but initiator is not
defined.")
+ term.schemaDefinitionUnless(term.hasNonZeroLengthInitiator,
+ "Enclosing group has initiatedContent='yes', but initiator can
match zero-length data.")
+ }
}
}
}
diff --git
a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/SequenceGrammarMixin.scala
b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/SequenceGrammarMixin.scala
index e30a12d..642a44d 100644
---
a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/SequenceGrammarMixin.scala
+++
b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/SequenceGrammarMixin.scala
@@ -181,7 +181,7 @@ trait SequenceGrammarMixin
* Whether the representation of a term in the data stream "has a
separator", as in a specific separator
* occupies a non-zero number of bits, is an entirely different question.
*/
- lazy val hasSeparator = separatorParseEv.isKnownNonEmpty
+ lazy val hasSeparator = !separatorParseEv.isConstantEmptyString
lazy val sequenceSeparator = prod("separator", hasSeparator) {
delimMTA ~ SequenceSeparator(this)
diff --git
a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/DelimiterAndEscapeRelated.scala
b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/DelimiterAndEscapeRelated.scala
index faa3dbd..0f6ad9b 100644
---
a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/DelimiterAndEscapeRelated.scala
+++
b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/DelimiterAndEscapeRelated.scala
@@ -30,13 +30,13 @@ import org.apache.daffodil.util.Misc
import org.apache.daffodil.xml.XMLUtils
case class DelimiterStackCombinatorSequence(sq: SequenceTermBase, body: Gram)
extends Terminal(sq, !body.isEmpty) {
- lazy val pInit = if (sq.initiatorParseEv.isKnownNonEmpty)
One(sq.initiatorParseEv) else Nope
- lazy val pSep = if (sq.hasSeparator && sq.separatorParseEv.isKnownNonEmpty)
One(sq.separatorParseEv) else Nope
- lazy val pTerm = if (sq.terminatorParseEv.isKnownNonEmpty)
One(sq.terminatorParseEv) else Nope
+ lazy val pInit = if (sq.initiatorParseEv.isConstantEmptyString) Nope else
One(sq.initiatorParseEv)
+ lazy val pSep = if (sq.hasSeparator &&
!sq.separatorParseEv.isConstantEmptyString) One(sq.separatorParseEv) else Nope
+ lazy val pTerm = if (sq.terminatorParseEv.isConstantEmptyString) Nope else
One(sq.terminatorParseEv)
- lazy val uInit = if (sq.initiatorParseEv.isKnownNonEmpty)
One(sq.initiatorUnparseEv) else Nope
- lazy val uSep = if (sq.hasSeparator && sq.separatorParseEv.isKnownNonEmpty)
One(sq.separatorUnparseEv) else Nope
- lazy val uTerm = if (sq.terminatorParseEv.isKnownNonEmpty)
One(sq.terminatorUnparseEv) else Nope
+ lazy val uInit = if (sq.initiatorParseEv.isConstantEmptyString) Nope else
One(sq.initiatorUnparseEv)
+ lazy val uSep = if (sq.hasSeparator &&
!sq.separatorParseEv.isConstantEmptyString) One(sq.separatorUnparseEv) else Nope
+ lazy val uTerm = if (sq.terminatorParseEv.isConstantEmptyString) Nope else
One(sq.terminatorUnparseEv)
lazy val parser: DaffodilParser = new DelimiterStackParser((pInit.toList ++
pSep.toList ++ pTerm.toList).toArray, sq.runtimeData, body.parser)
@@ -44,11 +44,11 @@ case class DelimiterStackCombinatorSequence(sq:
SequenceTermBase, body: Gram) ex
}
case class DelimiterStackCombinatorChoice(ch: ChoiceTermBase, body: Gram)
extends Terminal(ch, !body.isEmpty) {
- lazy val pInit = if (ch.initiatorParseEv.isKnownNonEmpty)
One(ch.initiatorParseEv) else Nope
- lazy val pTerm = if (ch.terminatorParseEv.isKnownNonEmpty)
One(ch.terminatorParseEv) else Nope
+ lazy val pInit = if (ch.initiatorParseEv.isConstantEmptyString) Nope else
One(ch.initiatorParseEv)
+ lazy val pTerm = if (ch.terminatorParseEv.isConstantEmptyString) Nope else
One(ch.terminatorParseEv)
- lazy val uInit = if (ch.initiatorParseEv.isKnownNonEmpty)
One(ch.initiatorUnparseEv) else Nope
- lazy val uTerm = if (ch.terminatorParseEv.isKnownNonEmpty)
One(ch.terminatorUnparseEv) else Nope
+ lazy val uInit = if (ch.initiatorParseEv.isConstantEmptyString) Nope else
One(ch.initiatorUnparseEv)
+ lazy val uTerm = if (ch.terminatorParseEv.isConstantEmptyString) Nope else
One(ch.terminatorUnparseEv)
lazy val parser: DaffodilParser = new DelimiterStackParser((pInit.toList ++
pTerm.toList).toArray, ch.runtimeData, body.parser)
@@ -56,11 +56,11 @@ case class DelimiterStackCombinatorChoice(ch:
ChoiceTermBase, body: Gram) extend
}
case class DelimiterStackCombinatorElement(e: ElementBase, body: Gram) extends
Terminal(e, !body.isEmpty) {
- lazy val pInit = if (e.initiatorParseEv.isKnownNonEmpty)
One(e.initiatorParseEv) else Nope
- lazy val pTerm = if (e.terminatorParseEv.isKnownNonEmpty)
One(e.terminatorParseEv) else Nope
+ lazy val pInit = if (e.initiatorParseEv.isConstantEmptyString) Nope else
One(e.initiatorParseEv)
+ lazy val pTerm = if (e.terminatorParseEv.isConstantEmptyString) Nope else
One(e.terminatorParseEv)
- lazy val uInit = if (e.initiatorParseEv.isKnownNonEmpty)
One(e.initiatorUnparseEv) else Nope
- lazy val uTerm = if (e.terminatorParseEv.isKnownNonEmpty)
One(e.terminatorUnparseEv) else Nope
+ lazy val uInit = if (e.initiatorParseEv.isConstantEmptyString) Nope else
One(e.initiatorUnparseEv)
+ lazy val uTerm = if (e.terminatorParseEv.isConstantEmptyString) Nope else
One(e.terminatorUnparseEv)
lazy val delims = (pInit.toList ++ pTerm.toList)
diff --git
a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/PrimitivesDelimiters.scala
b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/PrimitivesDelimiters.scala
index 9b1e211..0614258 100644
---
a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/PrimitivesDelimiters.scala
+++
b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/PrimitivesDelimiters.scala
@@ -60,7 +60,7 @@ abstract class DelimiterText(e: Term, eb: Term,
delimiterType: DelimiterTextType
case _ => false
}
- override lazy val parser: DaffodilParser = new
DelimiterTextParser(e.termRuntimeData, textParser, delimiterType, isDelimited)
+ override lazy val parser: DaffodilParser = new
DelimiterTextParser(e.termRuntimeData, textParser, delimiterType, isDelimited,
e.mustMatchNonZeroData)
override lazy val unparser: DaffodilUnparser = new
DelimiterTextUnparser(e.termRuntimeData, delimiterType)
}
diff --git
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/dpath/DPath.scala
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/dpath/DPath.scala
index 0e6061c..991d8cc 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/dpath/DPath.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/dpath/DPath.scala
@@ -80,8 +80,8 @@ final class RuntimeExpressionDPath[T <: AnyRef](qn:
NamedQName, tt: NodeInfo.Kin
override def targetType = tt
- // TODO: fix this check below. There is a unierse of target types which is
- // muuch smaller than the set of all types, so some check is useful to be
sure
+ // TODO: fix this check below. There is a universe of target types which is
+ // much smaller than the set of all types, so some check is useful to be sure
// we stay within the subset of types that are actually used as target types.
// Assert.usage(targetType == NodeInfo.AnyType // used by debugger eval stmt
// || targetType == NodeInfo.NonEmptyString // string-valued properties
@@ -93,8 +93,6 @@ final class RuntimeExpressionDPath[T <: AnyRef](qn:
NamedQName, tt: NodeInfo.Kin
override lazy val prettyExpr = dpathText
- def isKnownNonEmpty = true // expressions are not allowed to return empty
string
-
private def UE(e: Throwable, maybeCL: Maybe[DataLocation]) =
throw new UnparseError(One(ci.schemaFileLocation), maybeCL, e)
diff --git
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/dsom/CompiledExpression1.scala
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/dsom/CompiledExpression1.scala
index ac3dd3d..6d08e63 100644
---
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/dsom/CompiledExpression1.scala
+++
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/dsom/CompiledExpression1.scala
@@ -68,10 +68,10 @@ trait ContentValueReferencedElementInfoMixin {
*/
abstract class CompiledExpression[+T <: AnyRef](
val qName: NamedQName,
- valueForDebugPrinting: AnyRef)
+ value: AnyRef)
extends ContentValueReferencedElementInfoMixin with Serializable {
- DataValue.assertValueIsNotDataValue(valueForDebugPrinting)
+ DataValue.assertValueIsNotDataValue(value)
final def toBriefXML(depth: Int = -1) = {
"'" + prettyExpr + "'"
@@ -83,17 +83,19 @@ abstract class CompiledExpression[+T <: AnyRef](
* particularly for `Array[Byte]`. It prints a useless thing like
"[@0909280".
* Use of `stringOf` prints "Array(....)".
*/
- lazy val prettyExpr = stringOf(valueForDebugPrinting)
+ lazy val prettyExpr = stringOf(value)
/**
- * tells us if the property is non-empty. This is true if it is a constant
non-empty expression
- * (that is, is not ""), but it is also true if it is evaluated as a runtime
expression that it is
- * not allowed to return "".
- *
- * Issue: are there properties which are string-valued, and where "" can in
fact be returned at run time?
- * Assumed no. This was clarified in an errata to the DFDL spec.
+ * Tells us if the expression is the constant empty string (that is, it is
"").
*/
- def isKnownNonEmpty: Boolean
+ final lazy val isConstantEmptyString = value == ""
+
+ /**
+ * Tells us if the expression can match the empty string. We know it can if
the expression
+ * is a DFDL entity like %ES; or %WSP*. We do not know whether it can if it
is a more
+ * complicated constant or runtime expression.
+ */
+ final lazy val isKnownCanMatchEmptyString = value == "%ES;" || value ==
"%WSP*;"
/**
* used to obtain a constant value.
@@ -124,7 +126,7 @@ abstract class CompiledExpression[+T <: AnyRef](
*/
def evaluateForwardReferencing(state: ParseOrUnparseState,
whereBlockedLocation: Suspension): Maybe[T]
- override def toString(): String = "CompiledExpression(" +
valueForDebugPrinting.toString + ")"
+ override def toString(): String = "CompiledExpression(" + value.toString +
")"
}
@@ -143,8 +145,6 @@ final case class ConstantExpression[+T <: AnyRef](
lazy val sourceType: NodeInfo.Kind = NodeInfo.fromObject(value)
- def isKnownNonEmpty = value != ""
-
override def evaluate(state: ParseOrUnparseState) = value
def evaluate(dstate: DState, state: ParseOrUnparseState) = {
diff --git
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/EvDelimiters.scala
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/EvDelimiters.scala
index 7077def..6086514 100644
---
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/EvDelimiters.scala
+++
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/EvDelimiters.scala
@@ -33,7 +33,7 @@ import org.apache.daffodil.processors.parsers.PState
trait DelimiterEvMixin[+T <: AnyRef]
extends ExprEvalMixin[String] { self: Evaluatable[T] =>
- final def isKnownNonEmpty = expr.isKnownNonEmpty
+ final def isConstantEmptyString = expr.isConstantEmptyString
def expr: CompiledExpression[String]
def converter: Converter[String, List[String]]
diff --git
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/DelimiterParsers.scala
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/DelimiterParsers.scala
index 4bfc156..267e667 100644
---
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/DelimiterParsers.scala
+++
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/DelimiterParsers.scala
@@ -42,7 +42,8 @@ class DelimiterTextParser(
rd: TermRuntimeData,
textParser: TextParser,
delimiterType: DelimiterTextType.Type,
- isDelimited: Boolean)
+ isDelimited: Boolean,
+ mustMatchNonZeroData: Boolean)
extends TextPrimParser {
override lazy val runtimeDependencies = rd.encodingInfo.runtimeDependencies
@@ -95,8 +96,12 @@ class DelimiterTextParser(
return
}
- // Consume the found local delimiter
+ // Consume the found local delimiter but also check if it was supposed
to match
+ // a non-zero number of bits and throw a runtime SDE if necessary
val nChars = foundDelimiter.get.matchedDelimiterValue.get.length
+ if (mustMatchNonZeroData && nChars == 0) {
+ start.SDE("The initiator must match non-zero length data when
dfdl:initiatedContent is 'yes'.")
+ }
val wasDelimiterTextSkipped = start.dataInputStream.skipChars(nChars,
start)
Assert.invariant(wasDelimiterTextSkipped)
start.clearDelimitedParseResult()
diff --git
a/daffodil-test/src/test/resources/org/apache/daffodil/section12/delimiter_properties/DelimiterProperties.tdml
b/daffodil-test/src/test/resources/org/apache/daffodil/section12/delimiter_properties/DelimiterProperties.tdml
index 5d18b81..b30e9e2 100644
---
a/daffodil-test/src/test/resources/org/apache/daffodil/section12/delimiter_properties/DelimiterProperties.tdml
+++
b/daffodil-test/src/test/resources/org/apache/daffodil/section12/delimiter_properties/DelimiterProperties.tdml
@@ -908,4 +908,96 @@
</tdml:errors>
</tdml:parserTestCase>
+ <tdml:defineSchema name="emptyInitiator">
+ <xs:include
schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
+ <dfdl:format ref="ex:GeneralFormat" />
+
+ <xs:element name="zeroLengthString">
+ <xs:complexType>
+ <xs:sequence dfdl:initiatedContent="yes">
+ <xs:element name="s1" type="xs:string" dfdl:lengthKind="delimited"
dfdl:initiator="" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="emptyEntity">
+ <xs:complexType>
+ <xs:sequence dfdl:initiatedContent="yes">
+ <xs:element name="s1" type="xs:string" dfdl:lengthKind="delimited"
dfdl:initiator="%ES;" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="emptyOrWhitespaceEntity">
+ <xs:complexType>
+ <xs:sequence dfdl:initiatedContent="yes">
+ <xs:element name="s1" type="xs:string" dfdl:lengthKind="delimited"
dfdl:initiator="%WSP*;" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="runtimeEvaluatedInitiator">
+ <xs:complexType>
+ <xs:sequence dfdl:initiatedContent="yes">
+ <xs:element name="s1" type="xs:string" dfdl:lengthKind="delimited"
dfdl:initiator="{ if (fn:nilled(.)) then '%ES;' else '%WSP*;' }" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </tdml:defineSchema>
+
+ <tdml:parserTestCase name="emptyInitiator1"
+ model="emptyInitiator"
+ description="An initiator that is '' causes an error"
+ root="zeroLengthString">
+ <tdml:document><![CDATA[foo]]></tdml:document>
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>initiatedContent</tdml:error>
+ <tdml:error>yes</tdml:error>
+ <tdml:error>initiator</tdml:error>
+ <tdml:error>not defined</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="emptyInitiator2"
+ model="emptyInitiator"
+ description="An initiator that is '%ES;' causes an
error"
+ root="emptyEntity">
+ <tdml:document><![CDATA[foo]]></tdml:document>
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>initiatedContent</tdml:error>
+ <tdml:error>yes</tdml:error>
+ <tdml:error>initiator</tdml:error>
+ <tdml:error>zero</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="emptyInitiator3"
+ model="emptyInitiator"
+ description="An initiator that is '%WSP*;' causes an
error"
+ root="emptyOrWhitespaceEntity">
+ <tdml:document><![CDATA[foo]]></tdml:document>
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>initiatedContent</tdml:error>
+ <tdml:error>yes</tdml:error>
+ <tdml:error>initiator</tdml:error>
+ <tdml:error>zero</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="emptyInitiator4"
+ model="emptyInitiator"
+ description="A runtime-evaluated initiator that matches
zero-length data causes an error"
+ root="runtimeEvaluatedInitiator">
+ <tdml:document><![CDATA[foo]]></tdml:document>
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>initiatedContent</tdml:error>
+ <tdml:error>yes</tdml:error>
+ <tdml:error>initiator</tdml:error>
+ <tdml:error>zero</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
</tdml:testSuite>
diff --git
a/daffodil-test/src/test/scala/org/apache/daffodil/section12/delimiter_properties/TestDelimiterProperties.scala
b/daffodil-test/src/test/scala/org/apache/daffodil/section12/delimiter_properties/TestDelimiterProperties.scala
index d477fab..b4aa7ea 100644
---
a/daffodil-test/src/test/scala/org/apache/daffodil/section12/delimiter_properties/TestDelimiterProperties.scala
+++
b/daffodil-test/src/test/scala/org/apache/daffodil/section12/delimiter_properties/TestDelimiterProperties.scala
@@ -79,4 +79,9 @@ class TestDelimiterProperties {
@Test def test_percentTerminator() = {
runner_02.runOneTest("percentTerminator") }
@Test def test_percentTerminator2() = {
runner_02.runOneTest("percentTerminator2") }
@Test def test_percentExpression() = {
runner_02.runOneTest("percentExpression") }
+
+ @Test def test_emptyInitiator1() = { runner_02.runOneTest("emptyInitiator1")
}
+ @Test def test_emptyInitiator2() = { runner_02.runOneTest("emptyInitiator2")
}
+ @Test def test_emptyInitiator3() = { runner_02.runOneTest("emptyInitiator3")
}
+ @Test def test_emptyInitiator4() = { runner_02.runOneTest("emptyInitiator4")
}
}