in daffodil-tdml-lib/src/main/scala/org/apache/daffodil/tdml/TDMLRunner.scala [1617:1724]
def runUnparserExpectSuccess(
expectedData: InputStream,
optWarnings: Option[Seq[ExpectedWarnings]],
optValidationErrors: Option[Seq[ExpectedValidationErrors]],
roundTrip: RoundTrip,
implString: Option[String],
compileWarnings: Seq[Diagnostic]
): Unit = {
Assert.usage(roundTrip ne TwoPassRoundTrip) // not supported for unparser test cases.
val infosetXML: Node = inputInfoset.dfdlInfoset.contents
val outStream = new java.io.ByteArrayOutputStream()
val actual =
try {
processor = processor.withExternalDFDLVariables(externalVarBindings)
processor.unparse(infosetXML, outStream)
} catch {
case t: Throwable => toss(t, implString)
}
if (actual.isProcessingError)
throw TDMLException(actual.getDiagnostics, implString)
//
// Test that we are getting the number of full bytes needed.
val testData = outStream.toByteArray
val testDataLength = actual.finalBitPos0b
if (testDataLength >= 0) {
val fullBytesNeeded = (testDataLength + 7) / 8
if (testData.length != fullBytesNeeded) {
throw TDMLException(
"Unparse result data was %d bytes, but the result length (%d bits) requires %d bytes."
.format(testData.length, testDataLength, fullBytesNeeded),
implString
)
}
}
if (actual.isScannable) {
// all textual in one encoding, so we can do display of results
// in terms of text so the user can see what is going on.
VerifyTestCase.verifyTextData(expectedData, outStream, actual.encodingName, implString)
} else {
// data is not all textual, or in mixture of encodings
// So while we can still use the encoding as a heuristic,
// we will need to treat as Hex bytes as well.
VerifyTestCase.verifyBinaryOrMixedData(expectedData, outStream, implString)
}
val allDiags = actual.getDiagnostics ++ compileWarnings
checkDiagnosticMessages(
allDiags,
None,
optWarnings,
optValidationErrors,
implString
)
if (roundTrip eq OnePassRoundTrip) {
val parseActual =
try {
processor.parse(new ByteArrayInputStream(outStream.toByteArray), testDataLength)
} catch {
case t: Throwable => toss(t, implString)
}
if (parseActual.isProcessingError) {
// Means there was an error, not just warnings.
val diagObjs = parseActual.getDiagnostics
if (diagObjs.length == 1) throw diagObjs.head
val diags = parseActual.getDiagnostics.map(_.getMessage()).mkString("\n")
throw TDMLException(diags, implString)
}
val loc: DataLocation = parseActual.currentLocation
val leftOverException = if (loc.bitPos1b >= 0 && loc.bitPos1b < testDataLength) {
//
// For this to happen (and have test coverage) we need an unparserTestCase
// which is roundTrip onePass, and where the parse doesn't consume all
// the data.
//
val leftOverMsg =
"Left over data. Consumed %s bit(s) with %s bit(s) remaining.".format(
loc.bitPos1b - 1,
testDataLength - (loc.bitPos1b - 1)
)
Some(TDMLException(leftOverMsg, implString))
} else None
val xmlNode = parseActual.getResult
VerifyTestCase.verifyParserTestData(xmlNode, inputInfoset, implString)
leftOverException.map {
throw _
} // if we get here, throw the left over data exception.
// Done with the parse results, safe to clean up blobs if there was
// success. This won't get called on failure, which is fine--leave blobs
// around for debugging
parseActual.cleanUp()
}
// Done with the unparse results, safe to clean up any temporary files
// if they were not already cleaned up by parseActual.cleanUp() above
actual.cleanUp()
}