v1: executing-plans 模式生成,54 文件 1320 行 Python

This commit is contained in:
hangshuo652
2026-05-24 10:02:52 +08:00
commit 06b295f780
55 changed files with 1749 additions and 0 deletions
+45
View File
@@ -0,0 +1,45 @@
import sys, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
from comparator.aligner import align_records
def test_align_by_key():
cobol = [{"CUST-ID": "C001", "AMT": 100}, {"CUST-ID": "C002", "AMT": 200}]
spark = [{"CUST-ID": "C002", "AMT": 200}, {"CUST-ID": "C001", "AMT": 100}]
result = align_records(cobol, spark, key_field="CUST-ID")
assert len(result) == 2
assert all(s == "MATCHED" for _, _, s in result)
def test_missing_in_spark():
cobol = [{"CUST-ID": "C001"}, {"CUST-ID": "C002"}]
spark = [{"CUST-ID": "C001"}]
result = align_records(cobol, spark, key_field="CUST-ID")
statuses = [s for _, _, s in result]
assert "MISSING_IN_SPARK" in statuses
def test_extra_in_spark():
cobol = [{"CUST-ID": "C001"}]
spark = [{"CUST-ID": "C001"}, {"CUST-ID": "C002"}]
result = align_records(cobol, spark, key_field="CUST-ID")
statuses = [s for _, _, s in result]
assert "EXTRA_IN_SPARK" in statuses
def test_empty_inputs():
assert align_records([], [], "key") == []
def test_duplicate_keys():
cobol = [{"ID": "K1", "V": 1}, {"ID": "K1", "V": 2}]
java = [{"ID": "K1", "V": 1}, {"ID": "K1", "V": 2}]
result = align_records(cobol, java, key_field="ID")
assert len(result) == 2
def test_align_none_key():
cobol = [{"ID": None, "V": 1}]
java = [{"ID": None, "V": 1}]
result = align_records(cobol, java, key_field="ID")
assert len(result) == 1
+18
View File
@@ -0,0 +1,18 @@
import sys, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from comparator.aligner import align_records
def test_align_empty_key_value():
cobol = [{"ID": "", "V": 1}]
java = [{"ID": "", "V": 1}]
result = align_records(cobol, java, key_field="ID")
assert len(result) == 1
def test_align_very_large_key_set():
cobol = [{"ID": f"K{i:04d}", "V": i} for i in range(100)]
java = [{"ID": f"K{i:04d}", "V": i} for i in range(100)]
result = align_records(cobol, java, key_field="ID")
assert len(result) == 100
assert all(s == "MATCHED" for _, _, s in result)
+23
View File
@@ -0,0 +1,23 @@
import sys, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
from comparator.field_compare import compare_field
def test_negative_numbers():
r = compare_field("AMT", "-1500", "-1500", "decimal")
assert r.status == "PASS"
def test_mixed_precision():
r = compare_field("AMT", "1500.00", "1500", "decimal", tolerance=0.01)
assert r.status == "PASS"
def test_non_numeric_in_numeric_field():
r = compare_field("AMT", "ABC", "1500", "decimal")
assert r.status in ("MISMATCH", "NOT_SET")
def test_very_large_number():
r = compare_field("AMT", "9999999999", "9999999999", "decimal")
assert r.status == "PASS"
+49
View File
@@ -0,0 +1,49 @@
import sys, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
from comparator.field_compare import compare_field, DEFAULT_TOLERANCE
def test_exact_match():
r = compare_field("BR-AMT", "1500000", "1500000", "decimal")
assert r.status == "PASS"
def test_within_tolerance():
r = compare_field("BR-AMT", "1500000", "1499999.99", "decimal", tolerance=DEFAULT_TOLERANCE)
assert r.status == "TOLERATED"
def test_beyond_tolerance():
r = compare_field("BR-AMT", "1500000", "1000000", "decimal", tolerance=DEFAULT_TOLERANCE)
assert r.status == "MISMATCH"
def test_string_trim():
r = compare_field("BR-STATUS", "A ", "A", "string")
assert r.status == "PASS"
def test_date_normalization():
r = compare_field("BR-DATE", "20260522", "2026-05-22", "date")
assert r.status == "PASS"
def test_cobol_default():
from decimal import Decimal, ROUND_DOWN
r = compare_field("BR-AMT", "\x00\x00\x00\x00\x00", "0", "decimal")
assert r.status in ("PASS", "TOLERATED")
def test_java_null_vs_value():
r = compare_field("BR-AMT", "1500000", "None", "decimal")
assert r.status in ("MISMATCH", "NOT_SET")
def test_negative_numbers():
r = compare_field("AMT", "-1500", "-1500", "decimal")
assert r.status == "PASS"
def test_mixed_precision():
r = compare_field("AMT", "1500.00", "1500", "decimal", tolerance=DEFAULT_TOLERANCE)
assert r.status == "PASS"
+47
View File
@@ -0,0 +1,47 @@
import sys, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
from comparator.normalizer import Normalizer
def test_ebcdic_to_ascii():
n = Normalizer()
assert n.normalize_encoding(b'\xc1\xc2', "EBCDIC") == "AB"
def test_ascii_passthrough():
n = Normalizer()
assert n.normalize_encoding(b"hello", "ASCII") == "hello"
def test_comp3_to_decimal():
n = Normalizer()
assert n.normalize_comp3(b'\x15\x00\x0C') == "1500"
def test_comp3_negative():
n = Normalizer()
assert n.normalize_comp3(b'\x15\x00\x1D') == "-1500"
def test_ir_record_creation():
n = Normalizer()
ir = n.to_ir_record(
field_name="BR-AMT", raw_hex="15000C",
decoded_value="1500", encoding="EBCDIC",
field_type="COMP3", length=5, scale=2, signed=True)
assert ir.field_name == "BR-AMT"
assert ir.cobol.decoded_value == "1500"
assert ir.cobol.encoding == "EBCDIC"
def test_date_iso_normalization():
n = Normalizer()
assert n.normalize_date("20260522") == "2026-05-22"
assert n.normalize_date("2026-05-22") == "2026-05-22"
def test_null_ir_record():
n = Normalizer()
ir = n.to_null_ir("BR-DATE", side="java")
assert ir.field_name == "BR-DATE"
assert ir.java is None
+24
View File
@@ -0,0 +1,24 @@
import sys, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
from comparator.rounding_detect import detect_rounding, RoundingResult
def test_truncation_detected():
r = detect_rounding("1500000", "1499999")
assert r.mode in ("TRUNCATE", "HALF_UP")
def test_exact_match():
r = detect_rounding("1500000", "1500000")
assert r.mode == "EXACT"
assert r.confidence == 1.0
def test_low_confidence_small_diff():
r = detect_rounding("1500", "1498")
assert r.confidence < 1.0
def test_suggestion_generated():
r = detect_rounding("1500000", "1499999")
assert len(r.suggestion) > 0