Skip to content

Commit

Permalink
Implemented dfdl:assert failureType="recoverableError"
Browse files Browse the repository at this point in the history
Simple addition of allowing recoverable errors to occur from
dfdl:assert. Right now it is simply creating a runtime Schema Definition
Warning with the assert failure message.

DAFFODIL-357
  • Loading branch information
jadams-tresys authored and stevedlawrence committed Jun 23, 2020
1 parent 2d8eba2 commit 492e048
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import scala.xml.Node
import scala.xml.NodeSeq.seqToNodeSeq
import org.apache.daffodil.exceptions._
import org.apache.daffodil.schema.annotation.props.gen.TestKind
import org.apache.daffodil.schema.annotation.props.gen.FailureType
import com.ibm.icu.impl.UnicodeRegex
import java.util.regex.PatternSyntaxException
import java.util.regex.Pattern
Expand Down Expand Up @@ -105,6 +106,11 @@ abstract class DFDLAssertionBase(node: Node, decl: AnnotatedSchemaComponent)
case None => TestKind.Expression
}

final lazy val failureType = getAttributeOption("failureType") match {
case Some(str) => FailureType(str, decl)
case None => FailureType.ProcessingError
}

lazy val messageAttrib = getAttributeOption("message")

final lazy val testTxt = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import org.apache.daffodil.processors.unparsers.NewVariableInstanceStartUnparser
import org.apache.daffodil.compiler.ForParser
import org.apache.daffodil.schema.annotation.props.PropertyLookupResult
import org.apache.daffodil.schema.annotation.props.Found
import org.apache.daffodil.schema.annotation.props.gen.FailureType
import org.apache.daffodil.dsom.ExpressionCompilers
import org.apache.daffodil.dsom.DFDLSetVariable
import org.apache.daffodil.dsom.DFDLNewVariableInstance
Expand All @@ -59,16 +60,18 @@ abstract class AssertBase(
scWherePropertyWasLocated: AnnotatedSchemaComponent,
msgOpt: Option[String],
discrim: Boolean, // are we a discriminator or not.
assertKindName: String)
assertKindName: String,
failureType: FailureType)
extends ExpressionEvaluatorBase(scWherePropertyWasLocated) {

def this(
decl: AnnotatedSchemaComponent,
foundProp: Found,
msgOpt: Option[String],
discrim: Boolean, // are we a discriminator or not.
assertKindName: String) =
this(decl, foundProp.value, foundProp.location.namespaces, decl, msgOpt, discrim, assertKindName)
assertKindName: String,
failureType: FailureType) =
this(decl, foundProp.value, foundProp.location.namespaces, decl, msgOpt, discrim, assertKindName, failureType)

override val baseName = assertKindName
override lazy val exprText = exprWithBraces
Expand All @@ -88,7 +91,7 @@ abstract class AssertBase(
}
}

lazy val parser: DaffodilParser = new AssertExpressionEvaluationParser(msgExpr, discrim, decl.runtimeData, expr)
lazy val parser: DaffodilParser = new AssertExpressionEvaluationParser(msgExpr, discrim, decl.runtimeData, expr, failureType)

override def unparser: DaffodilUnparser = hasNoUnparser

Expand All @@ -98,7 +101,7 @@ abstract class AssertBooleanPrimBase(
decl: AnnotatedSchemaComponent,
stmt: DFDLAssertionBase,
discrim: Boolean, // are we a discriminator or not.
assertKindName: String) extends AssertBase(decl, Found(stmt.testTxt, stmt, "test", false), stmt.messageAttrib, discrim, assertKindName)
assertKindName: String) extends AssertBase(decl, Found(stmt.testTxt, stmt, "test", false), stmt.messageAttrib, discrim, assertKindName, stmt.failureType)

case class AssertBooleanPrim(
decl: AnnotatedSchemaComponent,
Expand Down Expand Up @@ -302,7 +305,7 @@ abstract class AssertPatternPrimBase(decl: Term, stmt: DFDLAssertionBase, discri

override val forWhat = ForParser

lazy val parser: DaffodilParser = new AssertPatternParser(decl.termRuntimeData, discrim, testPattern, msgExpr)
lazy val parser: DaffodilParser = new AssertPatternParser(decl.termRuntimeData, discrim, testPattern, msgExpr, stmt.failureType)

override def unparser: DaffodilUnparser = Assert.invariantFailed("should not request unparser for asserts/discriminators")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,13 @@
</xsd:restriction>
</xsd:simpleType>

<xsd:simpleType name="FailureTypeEnum">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="processingError" />
<xsd:enumeration value="recoverableError" />
</xsd:restriction>
</xsd:simpleType>

<!-- A pattern is used instead of an enumeration for compactness -->
<xsd:simpleType name="BinaryPackedSignCodes">
<xsd:restriction base="dfdl:DFDLStringLiteral">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@
<xsd:attribute name="testKind" type="dfdl:TestKindEnum" />
<xsd:attribute name="testPattern" type="dfdl:DFDLRegularExpression" />
<xsd:attribute name="message" type="xsd:string" />
<xsd:attribute name="failureType" type="dfdl:FailureTypeEnum" />
</xsd:attributeGroup>

<xsd:complexType name="TestCondition">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import org.apache.daffodil.dsom.SchemaDefinitionDiagnosticBase
import org.apache.daffodil.processors._
import org.apache.daffodil.util.LogLevel
import org.apache.daffodil.util.OnStack
import org.apache.daffodil.schema.annotation.props.gen.FailureType

trait AssertMessageEvaluationMixin {
def messageExpr: CompiledExpression[AnyRef]
Expand Down Expand Up @@ -53,7 +54,8 @@ class AssertPatternParser(
override val context: TermRuntimeData,
override val discrim: Boolean,
testPattern: String,
override val messageExpr: CompiledExpression[AnyRef])
override val messageExpr: CompiledExpression[AnyRef],
failureType: FailureType)
extends PrimParser
with AssertMessageEvaluationMixin {
override lazy val runtimeDependencies = Vector()
Expand All @@ -75,8 +77,11 @@ class AssertPatternParser(
val isMatch = dis.lookingAt(m, start)
if (!isMatch) {
val message = getAssertFailureMessage(start)
val diag = new AssertionFailed(context.schemaFileLocation, start, message)
start.setFailed(diag)
if (failureType == FailureType.ProcessingError) {
val diag = new AssertionFailed(context.schemaFileLocation, start, message)
start.setFailed(diag)
} else
start.SDW(message)
} else if (discrim) {
// Only want to set the discriminator if there was a match.
start.setDiscriminator(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import org.apache.daffodil.processors.Success
import org.apache.daffodil.processors.TypeCalculator
import org.apache.daffodil.processors.VariableRuntimeData
import org.apache.daffodil.util.LogLevel
import org.apache.daffodil.schema.annotation.props.gen.FailureType

/**
* Common parser base class for any parser that evaluates an expression.
Expand Down Expand Up @@ -175,7 +176,8 @@ class AssertExpressionEvaluationParser(
override val messageExpr: CompiledExpression[String],
override val discrim: Boolean, // are we a discriminator or not.
decl: RuntimeData,
expr: CompiledExpression[AnyRef])
expr: CompiledExpression[AnyRef],
failureType: FailureType)
extends ExpressionEvaluationParser(expr, decl)
with AssertMessageEvaluationMixin {

Expand Down Expand Up @@ -209,8 +211,11 @@ class AssertExpressionEvaluationParser(
start.setDiscriminator(discrim)
} else {
val message = getAssertFailureMessage(start)
val diag = new AssertionFailed(decl.schemaFileLocation, start, message)
start.setFailed(diag)
if (failureType == FailureType.ProcessingError) {
val diag = new AssertionFailed(decl.schemaFileLocation, start, message)
start.setFailed(diag)
} else
start.SDW("Assertion " + message)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,25 @@
</xs:complexType>
</xs:element>

<xs:element name="e3r"><!-- like e2, but assert uses a path to a
peer element and should just issue a warning -->
<xs:complexType>
<xs:sequence>
<xs:element name="v" type="xs:int"
dfdl:inputValueCalc="{ 42 }" />
<xs:element name="a" type="xs:string"
dfdl:inputValueCalc="{ 'ok' }">
<xs:annotation>
<xs:appinfo source="http://www.ogf.org/dfdl/">
<dfdl:assert failureType="recoverableError"><![CDATA[{ xs:int(../ex:v) ne 42 }]]></dfdl:assert>
</xs:appinfo>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>


<xs:element name="e4" type="xs:int" dfdl:lengthKind="delimited">
<xs:annotation>
<xs:appinfo source="http://www.ogf.org/dfdl/">
Expand Down Expand Up @@ -104,6 +123,17 @@
</xs:appinfo>
</xs:annotation>
</xs:element>
<xs:element name="e6r" type="xs:int" dfdl:lengthKind="pattern"
dfdl:lengthPattern="\d\d" dfdl:terminator=": ,">
<xs:annotation>
<xs:appinfo source="http://www.ogf.org/dfdl/">
<dfdl:assert testKind="pattern" testPattern="\d\d" failureType="recoverableError"
message="Assertion failed for pattern '\d\d'" />
<dfdl:assert testKind="pattern" testPattern="\d\d:" failureType="recoverableError"
message="Assertion failed for pattern '\d\d:'" />
</xs:appinfo>
</xs:annotation>
</xs:element>

<xs:element name="e7" type="xs:string" dfdl:lengthKind="delimited">
<xs:annotation>
Expand Down Expand Up @@ -355,6 +385,23 @@
</tdml:errors>
</tdml:parserTestCase>

<tdml:parserTestCase name="assertFail2_recoverable" root="e3r"
model="s1" roundTrip="false"
description="Section 7 - negative test for assert expression - DFDL-7-043R">
<tdml:document />
<tdml:infoset>
<tdml:dfdlInfoset>
<e3r>
<v>42</v>
<a>ok</a>
</e3r>
</tdml:dfdlInfoset>
</tdml:infoset>
<tdml:warnings>
<tdml:warning>Assertion</tdml:warning>
</tdml:warnings>
</tdml:parserTestCase>

<!--
Test name: assertFailShowsValue
Schema: s1
Expand Down Expand Up @@ -602,6 +649,28 @@
</tdml:errors>
</tdml:parserTestCase>

<!--
Test name: assertPatternFail2_recoverable
Schema: s1
Purpose: This document demonstrates the use of multiple pattern assertions
regarding a value in a document and should parse with a warning.
-->

<tdml:parserTestCase name="assertPatternFail2_recoverable"
root="e6r" model="s1" roundTrip="false"
description="Section 7 - assert pattern fail multiple assert - DFDL-7-053R">
<tdml:document>43,</tdml:document>
<tdml:warnings>
<tdml:warning>Assert</tdml:warning>
<tdml:warning>pattern</tdml:warning>
</tdml:warnings>
<tdml:infoset>
<tdml:dfdlInfoset>
<e6r>43</e6r>
</tdml:dfdlInfoset>
</tdml:infoset>
</tdml:parserTestCase>

<!--
Test name: assertPatternPass3
Schema: s1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class TestAssertions {
@Test def test_assertPass(): Unit = { runner.runOneTest("assertPass") }
@Test def test_assertFail1(): Unit = { runner.runOneTest("assertFail1") }
@Test def test_assertFail2(): Unit = { runner.runOneTest("assertFail2") }
@Test def test_assertFail2_recoverable(): Unit = { runner.runOneTest("assertFail2_recoverable") }

// DAFFODIL-752
//@Test def test_assertFailShowsValue() { runner.runOneTest("assertFailShowsValue") }
Expand All @@ -59,6 +60,7 @@ class TestAssertions {
@Test def test_assertPatternPass2(): Unit = { runner.runOneTest("assertPatternPass2") }
@Test def test_assertPatternPass3(): Unit = { runner.runOneTest("assertPatternPass3") }
@Test def test_assertPatternFail2(): Unit = { runner.runOneTest("assertPatternFail2") }
@Test def test_assertPatternFail2_recoverable(): Unit = { runner.runOneTest("assertPatternFail2_recoverable") }
@Test def test_assertPatternInitsTerms(): Unit = { runner.runOneTest("assertPatternInitsTerms") }
@Test def test_assertOnSequence(): Unit = { runner.runOneTest("assertOnSequence") }

Expand Down

0 comments on commit 492e048

Please sign in to comment.