From 250eaef221f08e6d09c027cab1f2e59def32836d Mon Sep 17 00:00:00 2001 From: olabusayoT <50379531+olabusayoT@users.noreply.github.com> Date: Mon, 25 Mar 2024 15:28:41 -0400 Subject: [PATCH] Add support for validation of length facet - add support for length facet, setting minLength and maxLength with the value of length, when hasLength is true, and those variables are queried - ensure length and minLength and maxLength facets are not declared together (Xerces Error, but we have asserts in case Xerces validation is turned off) - fix error message for isSimpleType check in computeMinMaxLength definition - add tests for validation=limited and validation=on - added hexBinary tests including test with length=0 - remove greater than or equal to zero checks for check[Length,MinLength,MaxLength] functions - remove some commented out code - add test to verify local facet len must be equal to base restriction length - add test that ensures dfdl:length is not less than base length facet - add reptype tests - convert SDE to Assert.invariantFailed for the case when hasLength is true and minLen/maxLen is anything but false DAFFODIL-2842 --- .../daffodil/core/dsom/ElementBase.scala | 45 +-- .../apache/daffodil/core/dsom/Facets.scala | 65 +++- .../daffodil/core/dsom/RestrictionUnion.scala | 7 + .../daffodil/core/dsom/SimpleTypes.scala | 2 +- .../grammar/ElementBaseGrammarMixin.scala | 20 +- .../runtime1/SimpleTypeRuntime1Mixin.scala | 1 + .../daffodil/runtime1/dsom/Facets1.scala | 1 + .../runtime1/processors/RuntimeData.scala | 52 ++- .../daffodil/extensions/repType/repType.tdml | 85 ++++- .../validation_errors/Validation.tdml | 304 +++++++++++++++++- .../TextNumberPropsUnparse.tdml | 27 +- .../daffodil/extensions/TestRepType.scala | 9 + .../validation_errors/TestValidationErr.scala | 35 ++ .../TestTextNumberPropsUnparse.scala | 1 + 14 files changed, 583 insertions(+), 71 deletions(-) diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/ElementBase.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/ElementBase.scala index 15740e4e8f..a8c8f35f15 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/ElementBase.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/ElementBase.scala @@ -83,8 +83,8 @@ trait ElementBase requiredEvaluationsIfActivated(isSimpleType) requiredEvaluationsIfActivated(if (hasPattern) patternValues) requiredEvaluationsIfActivated(if (hasEnumeration) enumerationValues) - requiredEvaluationsIfActivated(if (hasMinLength) minLength) - requiredEvaluationsIfActivated(if (hasMaxLength) maxLength) + requiredEvaluationsIfActivated(if (hasMinLength || hasLength) minLength) + requiredEvaluationsIfActivated(if (hasMaxLength || hasLength) maxLength) requiredEvaluationsIfActivated(if (hasMinInclusive) minInclusive) requiredEvaluationsIfActivated(if (hasMaxInclusive) maxInclusive) requiredEvaluationsIfActivated(if (hasMinExclusive) minExclusive) @@ -711,8 +711,8 @@ trait ElementBase Assert.invariant(repElement.lengthKind =:= LengthKind.Implicit) // it's a string with implicit length. get from facets schemaDefinitionUnless( - repElement.hasMaxLength, - "String with dfdl:lengthKind='implicit' must have an XSD maxLength facet value.", + repElement.hasMaxLength || repElement.hasLength, + "String with dfdl:lengthKind='implicit' must have a length or maxLength facet value.", ) val ml = repElement.maxLength ml.longValue() @@ -941,8 +941,9 @@ trait ElementBase private lazy val hasPattern: Boolean = typeDef.optRestriction.exists(_.hasPattern) private lazy val hasEnumeration: Boolean = typeDef.optRestriction.exists(_.hasEnumeration) - protected lazy val hasMinLength = typeDef.optRestriction.exists(_.hasMinLength) - protected lazy val hasMaxLength = typeDef.optRestriction.exists(_.hasMaxLength) + protected lazy val hasLength: Boolean = typeDef.optRestriction.exists(_.hasLength) + protected lazy val hasMinLength: Boolean = typeDef.optRestriction.exists(_.hasMinLength) + protected lazy val hasMaxLength: Boolean = typeDef.optRestriction.exists(_.hasMaxLength) private lazy val hasMinInclusive = typeDef.optRestriction.exists(_.hasMinInclusive) private lazy val hasMaxInclusive = typeDef.optRestriction.exists(_.hasMaxInclusive) private lazy val hasMinExclusive = typeDef.optRestriction.exists(_.hasMinExclusive) @@ -963,18 +964,19 @@ trait ElementBase /** * Compute minLength and maxLength together to share error-checking * and case dispatch that would otherwise have to be repeated. + * + * Also set them to the value of length, in the case we've used the length facet */ final lazy val (minLength: java.math.BigDecimal, maxLength: java.math.BigDecimal) = computeMinMaxLength - // TODO: why are we using java.math.BigDecimal, when scala has a much - // nicer decimal class? + private val zeroBD = new java.math.BigDecimal(0) private val unbBD = new java.math.BigDecimal(-1) // TODO: should this be a tunable limit? private def computeMinMaxLength: (java.math.BigDecimal, java.math.BigDecimal) = { schemaDefinitionUnless( isSimpleType, - "Facets minLength and maxLength are allowed only on types string and hexBinary.", + "The length facet or minLength/maxLength facets are not allowed on complex types", ) typeDef match { case _ if hasRepType => { @@ -986,7 +988,7 @@ trait ElementBase val pt = prim.primType schemaDefinitionWhen( (pt == PrimType.String || pt == PrimType.HexBinary) && lengthKind == LengthKind.Implicit, - "Facets minLength and maxLength must be defined for type %s with lengthKind='implicit'", + "The length facet or minLength/maxLength facets must be defined for type %s with lengthKind='implicit'", pt.name, ) // @@ -1001,12 +1003,17 @@ trait ElementBase val pt = st.primType val typeOK = pt == PrimType.String || pt == PrimType.HexBinary schemaDefinitionWhen( - !typeOK && (hasMinLength || hasMaxLength), - "Facets minLength and maxLength are not allowed on types derived from type %s.\nThey are allowed only on typed derived from string and hexBinary.", + !typeOK && (hasLength || hasMinLength || hasMaxLength), + "The length facet or minLength/maxLength facets are not allowed on types derived from type %s.\nThey are allowed only on types derived from string and hexBinary.", pt.name, ) - val res = (hasMinLength, hasMaxLength, lengthKind) match { - case (true, true, LengthKind.Implicit) => { + val res = (hasLength, hasMinLength, hasMaxLength, lengthKind) match { + case (true, false, false, _) => (r.lengthValue, r.lengthValue) + case (true, _, _, _) => + Assert.invariantFailed( + "Facet length cannot be defined with minLength and maxLength facets", + ) + case (false, true, true, LengthKind.Implicit) => { schemaDefinitionUnless( r.minLengthValue.compareTo(r.maxLengthValue) == 0, "The minLength and maxLength must be equal for type %s with lengthKind='implicit'. Values were minLength of %s, maxLength of %s.", @@ -1016,7 +1023,7 @@ trait ElementBase ) (r.minLengthValue, r.maxLengthValue) } - case (true, true, _) => { + case (false, true, true, _) => { schemaDefinitionWhen( r.minLengthValue.compareTo(r.maxLengthValue) > 0, // always true, so we don't bother to specify the type in the message. @@ -1026,13 +1033,13 @@ trait ElementBase ) (r.minLengthValue, r.maxLengthValue) } - case (_, _, LengthKind.Implicit) => + case (false, _, _, LengthKind.Implicit) => SDE( "When lengthKind='implicit', both minLength and maxLength facets must be specified.", ) - case (false, true, _) => (zeroBD, r.maxLengthValue) - case (false, false, _) => (zeroBD, unbBD) - case (true, false, _) => (r.minLengthValue, unbBD) + case (false, false, true, _) => (zeroBD, r.maxLengthValue) + case (false, false, false, _) => (zeroBD, unbBD) + case (false, true, false, _) => (r.minLengthValue, unbBD) case _ => Assert.impossible() } res diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/Facets.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/Facets.scala index 0c448f106d..3cdf64f16c 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/Facets.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/Facets.scala @@ -51,6 +51,9 @@ trait Facets { self: Restriction => private def fractionDigits(xml: Node): String = { retrieveFacetValueFromRestrictionBase(xml, Facet.fractionDigits) } + private def length(xml: Node): String = { + retrieveFacetValueFromRestrictionBase(xml, Facet.length) + } private def maxExclusive(xml: Node): String = { retrieveFacetValueFromRestrictionBase(xml, Facet.maxExclusive) } @@ -93,8 +96,27 @@ trait Facets { self: Restriction => final lazy val localMaxInclusiveValue: String = maxInclusive(xml) final lazy val localMinExclusiveValue: String = minExclusive(xml) final lazy val localMaxExclusiveValue: String = maxExclusive(xml) - final lazy val localMinLengthValue: String = minLength(xml) - final lazy val localMaxLengthValue: String = maxLength(xml) + final lazy val localLengthValue: String = length(xml) + final lazy val localMinLengthValue: String = { + val ml = minLength(xml) + // Xerces checks for the case where length and min/maxLength are used together, + // so we won't get to this code in those cases unless Xerces validation is turned off + Assert.usage( + ml.isEmpty || localLengthValue.isEmpty, + "Facets length and minLength cannot be specified together", + ) + ml + } + final lazy val localMaxLengthValue: String = { + val ml = maxLength(xml) + // Xerces checks for the case where length and min/maxLength are used together, + // so we won't get to this code in those cases unless Xerces validation is turned off + Assert.usage( + ml.isEmpty || localLengthValue.isEmpty, + "Facets length and maxLength cannot be specified together", + ) + ml + } final lazy val localTotalDigitsValue: String = totalDigits(xml) final lazy val localFractionDigitsValue: String = fractionDigits(xml) final lazy val localEnumerationValue: String = { @@ -140,6 +162,8 @@ trait Facets { self: Restriction => (localEnumerationValue.length > 0) || (getRemoteFacetValues(Facet.enumeration).size > 0) final lazy val hasPattern: Boolean = (localPatternValue.length > 0) || (getRemoteFacetValues(Facet.pattern).size > 0) + final lazy val hasLength: Boolean = + (localLengthValue != "") || (getRemoteFacetValues(Facet.length).size > 0) final lazy val hasMinLength: Boolean = (localMinLengthValue != "") || (getRemoteFacetValues(Facet.minLength).size > 0) final lazy val hasMaxLength: Boolean = @@ -230,6 +254,8 @@ trait Facets { self: Restriction => // TODO: Tidy up. Can likely replace getFacetValue with a similar call to combinedBaseFacets // as combinedBaseFacets should contain the 'narrowed' values. // + final lazy val lengthValue: java.math.BigDecimal = + getFacetValue(localLengthValue, Facet.length, hasLength) final lazy val minLengthValue: java.math.BigDecimal = getFacetValue(localMinLengthValue, Facet.minLength, hasMinLength) final lazy val maxLengthValue: java.math.BigDecimal = @@ -247,12 +273,6 @@ trait Facets { self: Restriction => final lazy val fractionDigitsValue: java.math.BigDecimal = getFacetValue(localFractionDigitsValue, Facet.fractionDigits, hasFractionDigits) - // private def errorOnLocalLessThanBaseFacet(local: Long, base: Long, theFacetType: Facet.Type) = { - // if (local < base) SDE("SimpleTypes: The local %s (%s) was less than the base %s (%s) ", theFacetType, local, theFacetType, base) - // } - // private def errorOnLocalGreaterThanBaseFacet(local: Long, base: Long, theFacetType: Facet.Type) = { - // if (local > base) SDE("SimpleTypes: The local %s (%s) was greater than the base %s (%s) ", theFacetType, local, theFacetType, base) - // } private def errorOnLocalLessThanBaseFacet( local: BigInteger, base: BigInteger, @@ -313,14 +333,21 @@ trait Facets { self: Restriction => base, ) } - - // private def getRemoteFacets(theFacetType: Facet.Type): Seq[FacetValueR] = { - // val remoteValues = remoteBaseFacets.filter { case (f, _) => f == theFacetType } - // if (remoteValues.size > 0) { - // val res: Seq[FacetValueR] = remoteValues.map { case (f, v) => (f, v.r) } - // res - // } else Seq.empty - // } + private def errorOnLocalNotEqualToBaseFacet( + local: BigInteger, + base: BigInteger, + theFacetType: Facet.Type, + ) = { + val res = local.compareTo(base) + if (res != 0) + SDE( + "SimpleTypes: The local %s (%s) was not equal to the base %s (%s) ", + theFacetType, + local, + theFacetType, + base, + ) + } private def getRemoteFacetValues(theFacetType: Facet.Type): Seq[FacetValue] = { val res = remoteBaseFacets.filter { case (f, _) => f == theFacetType } @@ -387,6 +414,10 @@ trait Facets { self: Restriction => errorOnLocalLessThanBaseFacet(theLocalFacet, theRemoteFacet, facetType) localFacet } + case Facet.length => { + errorOnLocalNotEqualToBaseFacet(theLocalFacet, theRemoteFacet, facetType) + localFacet + } case Facet.maxLength | Facet.fractionDigits => { errorOnLocalGreaterThanBaseFacet(theLocalFacet, theRemoteFacet, facetType) localFacet @@ -679,7 +710,7 @@ trait Facets { self: Restriction => // a negative number, zero, or a positive number as this BigInteger is numerically less than, // equal to, or greater than o, which must be a BigInteger. facetType match { - case Facet.minLength | Facet.maxLength | Facet.fractionDigits => { + case Facet.length | Facet.minLength | Facet.maxLength | Facet.fractionDigits => { // Non-negative Integers. BigInt narrowNonNegativeFacets(localFacet, remoteFacet, facetType) } diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/RestrictionUnion.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/RestrictionUnion.scala index 2bd168fea9..72a49cdba6 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/RestrictionUnion.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/RestrictionUnion.scala @@ -118,6 +118,9 @@ final class Restriction private (xmlArg: Node, val simpleTypeDef: SimpleTypeDefB lazy val localBaseFacets: ElemFacets = { val myFacets: Queue[FacetValue] = Queue.empty // val not var - it's a mutable collection if (localPatternValue.length > 0) { myFacets.enqueue((Facet.pattern, localPatternValue)) } + if (localLengthValue.length > 0) { + myFacets.enqueue((Facet.length, localLengthValue)) + } if (localMinLengthValue.length > 0) { myFacets.enqueue((Facet.minLength, localMinLengthValue)) } @@ -163,6 +166,10 @@ final class Restriction private (xmlArg: Node, val simpleTypeDef: SimpleTypeDefB val cPattern = lPattern.union(rPattern) cPattern.foreach(x => combined.enqueue(x)) } + if (hasLength) { + val cValue = getCombinedValue(Facet.length) + combined.enqueue((Facet.length, cValue.toString())) + } if (hasMinLength) { val cValue = getCombinedValue(Facet.minLength) combined.enqueue((Facet.minLength, cValue.toString())) diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SimpleTypes.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SimpleTypes.scala index 7541ee4958..7462251ecf 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SimpleTypes.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SimpleTypes.scala @@ -147,7 +147,7 @@ abstract class SimpleTypeDefBase(xml: Node, lexicalParent: SchemaComponent) optRestriction .map { r => if ( - r.hasPattern || r.hasEnumeration || r.hasMinLength || r.hasMaxLength || + r.hasPattern || r.hasEnumeration || r.hasLength || r.hasMinLength || r.hasMaxLength || r.hasMinInclusive || r.hasMaxInclusive || r.hasMinExclusive || r.hasMaxExclusive || r.hasTotalDigits || r.hasFractionDigits ) false diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ElementBaseGrammarMixin.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ElementBaseGrammarMixin.scala index f94daf1536..9177c7d258 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ElementBaseGrammarMixin.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ElementBaseGrammarMixin.scala @@ -1616,29 +1616,33 @@ trait ElementBaseGrammarMixin * the type is a type that respects minLength and maxLength, and the constant length * is not in range. */ - val isTypeUsingMinMaxLengthFacets = typeDef.typeNode match { + val isTypeUsingLengthOrMinMaxLengthFacets = typeDef.typeNode match { case s: NodeInfo.String.Kind => true case s: NodeInfo.HexBinary.Kind => true case _ => false } if ( (lengthKind eq LengthKind.Explicit) && - isTypeUsingMinMaxLengthFacets && + isTypeUsingLengthOrMinMaxLengthFacets && optLengthConstant.isDefined ) { val len = optLengthConstant.get - val maxLengthLong = maxLength.longValueExact - val minLengthLong = minLength.longValueExact + lazy val maxLengthLong = maxLength.longValueExact + lazy val minLengthLong = minLength.longValueExact def warn(m: String, value: Long): Unit = SDW( WarnID.FacetExplicitLengthOutOfRange, - "Explicit dfdl:length of %s is out of range for facet %sLength='%s'.", + "Explicit dfdl:length of %s is out of range for facet %s='%s'.", len, m, value, ) - if (maxLengthLong != -1 && len > maxLengthLong) warn("max", maxLengthLong) - Assert.invariant(minLengthLong >= 0) - if (minLengthLong > 0 && len < minLengthLong) warn("min", minLengthLong) + if (hasLength && len != minLengthLong && len != maxLengthLong) + warn("length", minLengthLong) + else if (hasMinLength || hasMaxLength) { + if (maxLengthLong != -1 && len > maxLengthLong) warn("maxLength", maxLengthLong) + Assert.invariant(minLengthLong >= 0) + if (minLengthLong > 0 && len < minLengthLong) warn("minLength", minLengthLong) + } } /* diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/runtime1/SimpleTypeRuntime1Mixin.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/runtime1/SimpleTypeRuntime1Mixin.scala index e16efdda3b..ca61e68b15 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/runtime1/SimpleTypeRuntime1Mixin.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/runtime1/SimpleTypeRuntime1Mixin.scala @@ -34,6 +34,7 @@ trait SimpleTypeRuntime1Mixin { self: SimpleTypeDefBase => noFacetChecks, optRestriction.toSeq.flatMap { r => if (r.hasPattern) r.patternValues else Nil }, optRestriction.flatMap { r => toOpt(r.hasEnumeration, r.enumerationValues.get) }, + optRestriction.flatMap { r => toOpt(r.hasLength, r.lengthValue) }, optRestriction.flatMap { r => toOpt(r.hasMinLength, r.minLengthValue) }, optRestriction.flatMap { r => toOpt(r.hasMaxLength, r.maxLengthValue) }, optRestriction.flatMap { r => toOpt(r.hasMinInclusive, r.minInclusiveValue) }, diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dsom/Facets1.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dsom/Facets1.scala index 76c889430c..15bf73f7dd 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dsom/Facets1.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dsom/Facets1.scala @@ -24,6 +24,7 @@ object Facet extends Enum { sealed abstract trait Type extends EnumValueType case object enumeration extends Type case object fractionDigits extends Type + case object length extends Type case object maxExclusive extends Type case object maxInclusive extends Type case object maxLength extends Type diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/RuntimeData.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/RuntimeData.scala index 08135c1f10..f7fd63a6fd 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/RuntimeData.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/RuntimeData.scala @@ -229,6 +229,7 @@ final class SimpleTypeRuntimeData( val noFacetChecks: Boolean, val patternValues: Seq[FacetTypes.FacetValueR], val enumerationValues: Option[String], + val length: Option[java.math.BigDecimal], val minLength: Option[java.math.BigDecimal], val maxLength: Option[java.math.BigDecimal], val minInclusive: Option[java.math.BigDecimal], @@ -345,24 +346,20 @@ final class SimpleTypeRuntimeData( return Error("facet enumeration(s): %s".format(e.enumerationValues.mkString(","))) } } - + // Check length + e.length.foreach { length => + if (!checkLength(currentElement, length, e, primType)) + return Error("facet length (%s)".format(length)) + } // Check minLength e.minLength.foreach { minLength => - val minAsLong = minLength.longValue() - val isMinLengthGreaterThanEqToZero = minAsLong.compareTo(0L) >= 0 - if (isMinLengthGreaterThanEqToZero) { - if (!checkMinLength(currentElement, minLength, e, primType)) - return Error("facet minLength (%s)".format(minLength)) - } + if (!checkMinLength(currentElement, minLength, e, primType)) + return Error("facet minLength (%s)".format(minLength)) } // Check maxLength e.maxLength.foreach { maxLength => - val maxAsLong = maxLength.longValue() - val isMaxLengthGreaterThanEqToZero = maxAsLong.compareTo(0L) >= 0 - if (isMaxLengthGreaterThanEqToZero) { - if (!checkMaxLength(currentElement, maxLength, e, primType)) - return Error("facet maxLength (%s)".format(maxLength)) - } + if (!checkMaxLength(currentElement, maxLength, e, primType)) + return Error("facet maxLength (%s)".format(maxLength)) } // Check minInclusive e.minInclusive.foreach { minInclusive => @@ -407,7 +404,32 @@ final class SimpleTypeRuntimeData( // Note: dont check occurs counts // if(!checkMinMaxOccurs(e, pstate.arrayIterationPos)) { return java.lang.Boolean.FALSE } OK } + private def checkLength( + diNode: DISimple, + lenValue: java.math.BigDecimal, + e: ThrowsSDE, + primType: PrimType, + ): java.lang.Boolean = { + val lenAsLong = lenValue.longValueExact() + primType match { + case PrimType.String => { + val data = diNode.dataValue.getString + val dataLen = data.length.toLong + val isDataLengthEqual = dataLen.compareTo(lenAsLong) == 0 + if (isDataLengthEqual) java.lang.Boolean.TRUE + else java.lang.Boolean.FALSE + } + case PrimType.HexBinary => { + val data = diNode.dataValue.getByteArray + val dataLen = data.length.toLong + val isDataLengthEqual = dataLen.compareTo(lenAsLong) == 0 + if (isDataLengthEqual) java.lang.Boolean.TRUE + else java.lang.Boolean.FALSE + } + case _ => e.SDE("Facet length is only valid for string and hexBinary.") + } + } private def checkMinLength( diNode: DISimple, minValue: java.math.BigDecimal, @@ -431,7 +453,7 @@ final class SimpleTypeRuntimeData( if (isDataLengthEqual) java.lang.Boolean.TRUE else java.lang.Boolean.FALSE } - case _ => e.SDE("MinLength facet is only valid for string and hexBinary.") + case _ => e.SDE("Facet minLength is only valid for string and hexBinary.") } } @@ -460,7 +482,7 @@ final class SimpleTypeRuntimeData( if (isDataLengthEqual) java.lang.Boolean.TRUE else java.lang.Boolean.FALSE } - case _ => e.SDE("MaxLength facet is only valid for string and hexBinary.") + case _ => e.SDE("Facet maxLength is only valid for string and hexBinary.") } } diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/extensions/repType/repType.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/extensions/repType/repType.tdml index b1b21f8b45..6c1f9f5497 100644 --- a/daffodil-test/src/test/resources/org/apache/daffodil/extensions/repType/repType.tdml +++ b/daffodil-test/src/test/resources/org/apache/daffodil/extensions/repType/repType.tdml @@ -758,7 +758,7 @@ - + @@ -771,9 +771,29 @@ + + + + + + + + + + + + + + + + + + - + 01 @@ -786,7 +806,9 @@ - + 02 @@ -804,7 +826,9 @@ - + 03 @@ -822,6 +846,59 @@ + + + 01 + + + + + one + + + + + ex:field + facet length (1) + + + + + + 02 + + + + + t + + + + + + + + 03 + + + + + three + + + + + ex:field + facet length (1) + + + diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section02/validation_errors/Validation.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section02/validation_errors/Validation.tdml index 25c6c677ae..982cd1b29e 100644 --- a/daffodil-test/src/test/resources/org/apache/daffodil/section02/validation_errors/Validation.tdml +++ b/daffodil-test/src/test/resources/org/apache/daffodil/section02/validation_errors/Validation.tdml @@ -385,7 +385,24 @@ - + + + + + + + + + + + + + + + + + + @@ -396,7 +413,7 @@ - + @@ -407,8 +424,47 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -643,7 +699,111 @@ - + + + + + deadbeefdafada + + + + + DEADBEEFDAFADA + + + + + + + + + deadbeefdafada + + + + + DEADBEEFDAFADA + + + + + + + + deadbeefdafada + + + + + DEADBEEFDAFADA + + + + + + eHexBinary_len0 + failed facet checks + facet length (0) + + + + + + + 12 + + + 12 + + + + + + + + + + + + + + + + + + + + + + + + + 12 + + + Schema Definition Error + length-valid-restriction + value of length + must be = the value of that of the base type + + + + + + Schema Definition Error + due to length-minLength-maxLength + not have a minLength facet if the current restriction has the minLength facet + and the current restriction or base has the length facet + + + + + + + + deadbeef + + + + + Schema Definition Error + due to length-minLength-maxLength + not have a minLength facet if the current restriction has the minLength facet + and the current restriction or base has the length facet + + + + + diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section13/text_number_props/TextNumberPropsUnparse.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section13/text_number_props/TextNumberPropsUnparse.tdml index f274703fdd..da2cadfba7 100644 --- a/daffodil-test/src/test/resources/org/apache/daffodil/section13/text_number_props/TextNumberPropsUnparse.tdml +++ b/daffodil-test/src/test/resources/org/apache/daffodil/section13/text_number_props/TextNumberPropsUnparse.tdml @@ -96,6 +96,12 @@ + + + + + + @@ -117,7 +123,9 @@ - + + + @@ -441,6 +449,23 @@ O# + + + + O + + + + Schema Definition Warning + Explicit dfdl:length + out of range + facet length + + O# + +