From 8ca117983ffca19c52e37018f43f56c13fa3761c Mon Sep 17 00:00:00 2001 From: domenico Date: Tue, 25 Feb 2025 15:09:10 +0100 Subject: [PATCH 1/2] Add test case --- .../rpgparser/smeup/MULANGT10BaseCodopTest.kt | 10 + .../test/resources/smeup/MUDRNRAPU00284.rpgle | 14 ++ .../resources/smeup/metadata/C5RITE0F.json | 231 ++++++++++++++++++ 3 files changed, 255 insertions(+) create mode 100644 rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00284.rpgle create mode 100644 rpgJavaInterpreter-core/src/test/resources/smeup/metadata/C5RITE0F.json diff --git a/rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/smeup/MULANGT10BaseCodopTest.kt b/rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/smeup/MULANGT10BaseCodopTest.kt index 0d8477603..f41606d29 100644 --- a/rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/smeup/MULANGT10BaseCodopTest.kt +++ b/rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/smeup/MULANGT10BaseCodopTest.kt @@ -998,4 +998,14 @@ open class MULANGT10BaseCodopTest : MULANGTTest() { val expected = listOf("300.000000") assertEquals(expected, "smeup/MUDRNRAPU001106".outputOf()) } + + /** + * Decode a packed encoded with a scale smaller than what its type expects + * @see #LS25001002 + */ + @Test + fun executeMUDRNRAPU00284() { + val expected = listOf(".010000") + assertEquals(expected, "smeup/MUDRNRAPU00284".outputOf(configuration = smeupConfig)) + } } \ No newline at end of file diff --git a/rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00284.rpgle b/rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00284.rpgle new file mode 100644 index 000000000..a2dcb3f0c --- /dev/null +++ b/rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00284.rpgle @@ -0,0 +1,14 @@ + V* ============================================================== + V* 25/02/2025 APU002 Creation + V* ============================================================== + O * PROGRAM GOAL + O * Decode a packed encoded with a scale smaller than what its + O * type expects + V* ============================================================== + O * JARIKO ANOMALY + O * Before the fix, we had an out of bound error + V* ============================================================== + DC5RITE E DS EXTNAME(C5RITE0F) INZ + C EVAL P5IMNS = '.010000' + C P5IMNS DSPLY + diff --git a/rpgJavaInterpreter-core/src/test/resources/smeup/metadata/C5RITE0F.json b/rpgJavaInterpreter-core/src/test/resources/smeup/metadata/C5RITE0F.json new file mode 100644 index 000000000..eb5c6fa5d --- /dev/null +++ b/rpgJavaInterpreter-core/src/test/resources/smeup/metadata/C5RITE0F.json @@ -0,0 +1,231 @@ +{"name": "C5RITE0F", + "tableName": "C5RITE0F", + "recordFormat": "C5RITER", + "fields": [ + { "fieldName": "P5AZIE", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":2, "varying":false}} + , { "fieldName": "P5DIVI", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":3, "varying":false}} + , { "fieldName": "P5ESER", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":10, "varying":false}} + , { "fieldName": "P5TPOR", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":12, "varying":false}} + , { "fieldName": "P5CDOR", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5TPOG", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":12, "varying":false}} + , { "fieldName": "P5CDOG", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5TPCN", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":3, "varying":false}} + , { "fieldName": "P5SOGG", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5TSOG", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5LIVE", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5STAT", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":2, "varying":false}} + , { "fieldName": "P5TRIB", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":6, "varying":false}} + , { "fieldName": "P5CAPR", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":4, "varying":false}} + , { "fieldName": "P5CRIT", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5CRPR", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5NDOC", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":20, "varying":false}} + , { "fieldName": "P5DTDO", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5DTCO", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5DTVR", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5DTCP", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5IMTT", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5IMPA", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5IMSG", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5IMNS", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5RAP1", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":3, "decimalDigits":2, "rpgType":"P"}} + , { "fieldName": "P5IMRA", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5RAP2", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":3, "decimalDigits":2, "rpgType":"P"}} + , { "fieldName": "P5IMPO", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5RPP1", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":3, "decimalDigits":2, "rpgType":"P"}} + , { "fieldName": "P5IMRP", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5RPP2", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":3, "decimalDigits":2, "rpgType":"P"}} + , { "fieldName": "P5RIPR", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5RPP3", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":3, "decimalDigits":2, "rpgType":"P"}} + , { "fieldName": "P5RPCP", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5ENCP", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5ENAZ", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5ENAN", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5VALU", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":4, "varying":false}} + , { "fieldName": "P5CAMB", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":6, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5IVTT", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5IVPA", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5IVSG", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5IVNS", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5IVRA", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5IMVA", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5IVRP", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5RIPV", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5RPCV", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5EVCP", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5EVAZ", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5EVAN", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5IMPR", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":15, "decimalDigits":6, "rpgType":"P"}} + , { "fieldName": "P5BANC", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":3, "varying":false}} + , { "fieldName": "P5ABCB", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5NUVE", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":10, "varying":false}} + , { "fieldName": "P5NUCE", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":10, "varying":false}} + , { "fieldName": "P5DT01", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5DT02", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5DT03", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5DT04", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5DT05", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5DT06", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5DT07", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5DT08", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5DT09", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5DT10", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5AA01", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5AA02", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5AA03", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5AA04", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5AA05", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5AA06", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5AA07", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5AA08", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5AA09", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5AA10", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":15, "varying":false}} + , { "fieldName": "P5NU01", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":10, "decimalDigits":5, "rpgType":"P"}} + , { "fieldName": "P5NU02", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":10, "decimalDigits":5, "rpgType":"P"}} + , { "fieldName": "P5NU03", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":10, "decimalDigits":5, "rpgType":"P"}} + , { "fieldName": "P5NU04", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":10, "decimalDigits":5, "rpgType":"P"}} + , { "fieldName": "P5NU05", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":10, "decimalDigits":5, "rpgType":"P"}} + , { "fieldName": "P5NU06", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":10, "decimalDigits":5, "rpgType":"P"}} + , { "fieldName": "P5NU07", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":10, "decimalDigits":5, "rpgType":"P"}} + , { "fieldName": "P5NU08", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":10, "decimalDigits":5, "rpgType":"P"}} + , { "fieldName": "P5NU09", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":10, "decimalDigits":5, "rpgType":"P"}} + , { "fieldName": "P5NU10", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":10, "decimalDigits":5, "rpgType":"P"}} + , { "fieldName": "P5FL01", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL02", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL03", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL04", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL05", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL06", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL07", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL08", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL09", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL10", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL11", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL12", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL13", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL14", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL15", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL16", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL17", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL18", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL19", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5FL20", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":1, "varying":false}} + , { "fieldName": "P5DTIN", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5ORIN", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":6, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5USIN", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":10, "varying":false}} + , { "fieldName": "P5DTAG", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":8, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5ORAG", + "type":{"type":"com.smeup.rpgparser.interpreter.NumberType","entireDigits":6, "decimalDigits":0, "rpgType":"P"}} + , { "fieldName": "P5USAG", + "type":{"type":"com.smeup.rpgparser.interpreter.StringType","length":10, "varying":false}} + ], "accessFields": []} From f507706ef586e48eac8408e26e9aee5e7fcb3420 Mon Sep 17 00:00:00 2001 From: domenico Date: Tue, 25 Feb 2025 15:09:22 +0100 Subject: [PATCH 2/2] Cover missing case in decode logic --- .../smeup/rpgparser/interpreter/data_definitions.kt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/data_definitions.kt b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/data_definitions.kt index 7639f1eda..f0019835d 100644 --- a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/data_definitions.kt +++ b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/data_definitions.kt @@ -799,11 +799,18 @@ fun decodeFromPacked(value: String, digits: Int, scale: Int): BigDecimal { if (nibble <= 9) { number.append((nibble or 0x30).toChar()) } - // adjust the scale + // If extracted number is less than the scale it means the value has to be prepended with 0 to match the scale + // E.g. we extracted 10000 with a scale 6 -> encoded value was 0.010000 + if (scale > number.length) { + val delta = scale - number.length + number.insert(0, "0".repeat(delta)) + } + + // Position decimal mark depending on the scale if needed if (scale > 0 && number.toString() != "0") { - val len = number.length - number.insert(len - scale, ".") + number.insert(number.length - scale, ".") } + number.insert(0, sign) return number.toString().toBigDecimal() }