98 lines
2.5 KiB
Python
98 lines
2.5 KiB
Python
"""
|
|
COMP-3 Packed Decimal Verification for COBOL Migration Platform.
|
|
Validates that binary COMP-3 fields in RATE.dat are correctly encoded.
|
|
|
|
Usage: python verify_comp3.py
|
|
|
|
COMP-3 format: each byte holds 2 nibbles (4-bit digits),
|
|
last nibble = sign (0xC/0xF = positive, 0xD = negative).
|
|
PIC 9(1)V9(4) = 5 digits + sign = 3 bytes.
|
|
"""
|
|
|
|
import struct
|
|
import sys
|
|
|
|
|
|
def unpack_comp3(data: bytes) -> tuple[int, int, str]:
|
|
"""Unpack COMP-3 bytes -> (integer_value, decimal_places, sign)."""
|
|
nibbles = []
|
|
for byte in data:
|
|
nibbles.append((byte >> 4) & 0x0F)
|
|
nibbles.append(byte & 0x0F)
|
|
|
|
sign_nibble = nibbles[-1]
|
|
digit_nibbles = nibbles[:-1]
|
|
|
|
value = 0
|
|
for n in digit_nibbles:
|
|
value = value * 10 + n
|
|
|
|
if sign_nibble in (0xC, 0xF):
|
|
sign = "positive"
|
|
elif sign_nibble == 0xD:
|
|
sign = "negative"
|
|
else:
|
|
sign = f"unknown(0x{sign_nibble:X})"
|
|
|
|
return value, sign, data.hex()
|
|
|
|
|
|
def main():
|
|
rate_path = "D:/jcl-cobol/data/input/rate.dat"
|
|
|
|
with open(rate_path, "rb") as f:
|
|
data = f.read()
|
|
|
|
rec_size = 12 # PIC X(1) + PIC 9(1)V9(4) COMP-3(3) + PIC 9(8)
|
|
num_records = len(data) // rec_size
|
|
|
|
print(f"File: {rate_path}")
|
|
print(f"Size: {len(data)} bytes")
|
|
print(f"Records: {num_records}")
|
|
print()
|
|
|
|
expected = {
|
|
"C": ("Cash rate", 0.0005),
|
|
"O": ("Overdue rate", 0.0500),
|
|
}
|
|
|
|
all_ok = True
|
|
|
|
for i in range(num_records):
|
|
offset = i * rec_size
|
|
rec = data[offset : offset + rec_size]
|
|
|
|
rate_type = chr(rec[0])
|
|
pct_bytes = rec[1:4]
|
|
eff_date = rec[4:12].decode("ascii")
|
|
|
|
value, sign, pct_hex = unpack_comp3(pct_bytes)
|
|
int_part = value // 10000
|
|
dec_part = value % 10000
|
|
pct_float = int_part + dec_part / 10000
|
|
|
|
name, expected_val = expected.get(rate_type, ("Unknown", None))
|
|
|
|
match = abs(pct_float - expected_val) < 0.0001 if expected_val else False
|
|
status = "PASS" if match else "FAIL"
|
|
if not match:
|
|
all_ok = False
|
|
|
|
print(f"[{status}] Record {i+1}: type={rate_type} ({name})")
|
|
print(f" COMP-3 hex: {pct_hex}")
|
|
print(f" packed int: {value}")
|
|
print(f" float val: {pct_float:.4f}")
|
|
print(f" expected: {expected_val}")
|
|
print(f" eff date: {eff_date}")
|
|
print()
|
|
|
|
if all_ok:
|
|
print("=== ALL COMP-3 VALUES VERIFIED ===")
|
|
else:
|
|
print("=== COMP-3 MISMATCH DETECTED ===")
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|