in daffodil-tdml-lib/src/main/scala/org/apache/daffodil/tdml/TDMLRunner.scala [1361:1545]
def runParseExpectSuccess(
dataToParse: InputStream,
lengthLimitInBits: Long,
warnings: Option[Seq[ExpectedWarnings]],
validationErrors: Option[Seq[ExpectedValidationErrors]],
validationMode: ValidationMode.Type,
roundTripArg: RoundTrip,
implString: Option[String],
compileWarnings: Seq[Diagnostic]
): Unit = {
val roundTrip =
roundTripArg // change to OnePassRoundTrip to force all parse tests to round trip (to see which fail to round trip)
processor = processor.withValidationMode(validationMode)
val firstParseTestData = IOUtils.toByteArray(dataToParse)
val testInfoset = optExpectedInfoset.get
val firstParseResult =
doParseExpectSuccess(firstParseTestData, testInfoset, lengthLimitInBits, implString)
roundTrip match {
case NoRoundTrip | OnePassRoundTrip => {
verifyParseResults(compileWarnings, firstParseResult, testInfoset, implString)
verifyLeftOverData(firstParseResult, lengthLimitInBits, implString)
}
case TwoPassRoundTrip => {
// don't compare first parse pass. Because it may or may not match.
//
// There's really two different kinds of tests here that we're not distinguishing, which
// are
// (a) those where the infoset is what is expected, but doesn't unparse to the same
// data as original, which then still reparses to that same infoset.
// (b) those where the infoset isn't what is expected, but unparses to something which
// then parses to what is expected.
}
case ThreePassRoundTrip => {
//
// Arguably, there are two different kinds of tests here that we've selected just
// one of:
// (a) the original infoset is NOT a match. The later steady-state infoset
// differs from this original infoset and matches the expected
// (b) the original infoset is a match, and reflects steady state. Just the unparse from it
// doesn't match the original input data stream. But reparsing that data stream produces the same
// infoset which demonstrates steady state.
//
// We can tell these apart, by just remembering whether this infoset matches or not
// rather than reporting a problem here. If after the reparse we get the expected
// infoset also, then this was NOT an error, and having the same infoset indicates
// steady state. If after the reparse we get the expected
// infoset but this one was NOT matching the expected, then we must unparse again to be sure we
// are at steady state.
//
// Instead we choose to just not check this initial infoset at all, and always behave
// as if it was NOT a match.
//
// val isFirstParseInfosetMatching =
// try {
// verifyParseResults(compileWarnings, processor, firstParseResult, testInfoset, implString)
// verifyLeftOverData(firstParseResult, lengthLimitInBits, implString)
// true
// } catch {
// case t: TDMLException =>
// false
// }
// if (isFirstParseInfosetMatching) {
// val msg = ("Expected infoset from first parse of data to NOT match expected infoset, but it did match." +
// "\nShould this really be a %s test?").format(roundTrip.propValueName)
// throw TDMLException(msg, implString)
// }
}
}
// if we get here, the parse test passed. If we don't get here then some exception was
// thrown either during the run of the test or during the comparison.
roundTrip match {
case NoRoundTrip => {
// done. Do nothing else.
// Done with the first parse result, safe to clean up blobs if there
// was success. This won't get called on failure, which is fine--leave
// blobs around for debugging
firstParseResult.cleanUp()
}
case OnePassRoundTrip => {
val outStream = new java.io.ByteArrayOutputStream()
doOnePassRoundTripUnparseExpectSuccess(outStream, firstParseResult, implString)
// It has to work, as this is one pass round trip. We expect it to unparse
// directly back to the original input form.
VerifyTestCase.verifyUnparserTestData(
new ByteArrayInputStream(firstParseTestData),
outStream,
implString
)
// Done with the first parse result, safe to clean up blobs if there
// was success. This won't get called on failure, which is fine--leave
// blobs around for debugging
firstParseResult.cleanUp()
}
case TwoPassRoundTrip => {
//
// In two-pass, the unparse comparison of data from first unparse
// to the original input data MUST fail.
// We need to unparse, then parse again to have the comparison work
// thereby showing that while the output data is different, it is
// equivalent in that re-parsing that data produces the same infoset
// that parsing the original data did.
//
val (actual, _, reParseTestDataLength) =
doTwoPassRoundTripExpectSuccess(
implString,
firstParseResult,
firstParseTestData,
testInfoset
)
verifyParseResults(compileWarnings, actual, testInfoset, implString)
verifyLeftOverData(actual, reParseTestDataLength, implString)
// if it doesn't pass, it will throw out of here.
// Done with the first and second parse resultrs, safe to clean up
// blobs if there was success. This won't get called on failure, which
// is fine--leave blobs around for debugging
firstParseResult.cleanUp()
actual.cleanUp()
}
case ThreePassRoundTrip => {
//
// In three-pass, the unparse comparison of data from first unparse
// to the original input data MUST fail.
// We need to unparse, then parse again and the infoset comparison
// must ALSO fail.
// Then we unparse again, and get same data as the first unparse.
// At that point we're in steady state.
//
// This mode is needed due to asymmetric separator suppression policies
// like anyEmpty which allow a separator for a zero-length optional element to
// appear in the data, but when unparsing will not output this separator,
// so when reparsed, the infoset won't have the element.
//
val (secondParseResult, reParseTestData, reParseTestDataLength) =
doTwoPassRoundTripExpectSuccess(
implString,
firstParseResult,
firstParseTestData,
testInfoset,
ThreePassRoundTrip.propValueName
)
//
// The infoset from the reparse should be the final
// steady state infoset, which is what the test case
// should put as the expected infoset.
//
// So we just verify normally here.
//
verifyParseResults(compileWarnings, secondParseResult, testInfoset, implString)
verifyLeftOverData(secondParseResult, reParseTestDataLength, implString)
//
// So now we do the third pass unparse and compare this output with the
// first unparsed output.
//
// We get to reuse the one-pass code here.
val thirdPassOutStream = new java.io.ByteArrayOutputStream()
doOnePassRoundTripUnparseExpectSuccess(thirdPassOutStream, firstParseResult, implString)
VerifyTestCase.verifyUnparserTestData(
new ByteArrayInputStream(reParseTestData),
thirdPassOutStream,
implString
)
// Done with the first parse result and second parse results. Safe to
// clean up blobs if there was success. Leave them around for debugging
// if there was a failure
firstParseResult.cleanUp()
secondParseResult.cleanUp()
}
}
}