test: cover between/hostvar/gcov-merge, class conditions, schema drop-tables, gixsql fixes
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
r"""DB2 schema 限定表名(SCHEMA.TABLE)在数据生成层的归一化测试。
|
||||
|
||||
根因:`FROM SALARYDB.EMP-MASTER` 中 `SALARYDB.` 限定符使 core.py 表名正则
|
||||
`(\w[\w-]*)` 遇 `.` 即停,把种子表解析为 `SALARYDB`;build_db_input 把 24 条
|
||||
EMP 种子行挂到不存在的 `SALARYDB` 表键下,插入时被丢弃 → EMP_MASTER 未播种,
|
||||
运行时 EMP 正常路径(SEARCH/EVALUATE)无法覆盖。
|
||||
|
||||
修复(分层,通用):
|
||||
- core.py `_parse_sql` 各表名正则捕获完整限定名(SCHEMA.TABLE 不丢失)。
|
||||
- to_sql.py `collect_sql_meta` 用 `_norm_table` 剥掉限定符取末段(EMP-MASTER),
|
||||
与 YAML schema 表名一致;种子键归一,`_populate_database` 正常插入。
|
||||
"""
|
||||
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
|
||||
from cobol_testgen.core import extract_sql_assignments
|
||||
from cobol_testgen.to_sql import collect_sql_meta, build_db_input
|
||||
|
||||
_SRC_DECLARE = (
|
||||
" PROCEDURE DIVISION.\n"
|
||||
" EXEC SQL\n"
|
||||
" DECLARE C2 CURSOR FOR\n"
|
||||
" SELECT EMP-ID, EMP-NAME, DEPT-CODE, BASE-SALARY\n"
|
||||
" FROM SALARYDB.EMP-MASTER\n"
|
||||
" ORDER BY EMP-ID\n"
|
||||
" END-EXEC.\n"
|
||||
)
|
||||
|
||||
|
||||
def test_extract_sql_assignments_keeps_full_qualified_table():
|
||||
"""core.py 表名正则须捕获完整限定名(不丢失 .EMP-MASTER)。"""
|
||||
assignments = extract_sql_assignments(_SRC_DECLARE)
|
||||
tables = [a.get("table") for a in assignments.values() for a in a]
|
||||
assert "SALARYDB.EMP-MASTER" in tables, f"qualified table lost: {tables}"
|
||||
|
||||
|
||||
def test_collect_sql_meta_normalizes_schema_qualified_table():
|
||||
"""collect_sql_meta 把 SCHEMA.TABLE 归一化为末段表名。"""
|
||||
assignments = {
|
||||
"__SQL_CURSOR_C2": [{
|
||||
"type": "exec_sql_select",
|
||||
"table": "SALARYDB.EMP-MASTER",
|
||||
"select_list": "EMP-ID, EMP-NAME, DEPT-CODE, BASE-SALARY",
|
||||
"into_vars": ["DBV-EMP-ID", "DBV-EMP-NAME", "DBV-DEPT-CODE", "DBV-BASE-SALARY"],
|
||||
"where": "",
|
||||
"sql_text": "DECLARE C2 CURSOR FOR SELECT EMP-ID FROM SALARYDB.EMP-MASTER",
|
||||
}],
|
||||
}
|
||||
declared = {"EMP-MASTER": [
|
||||
{"name": "EMP-ID", "db_type": "CHAR", "size": 8},
|
||||
{"name": "EMP-NAME", "db_type": "CHAR", "size": 40},
|
||||
{"name": "DEPT-CODE", "db_type": "CHAR", "size": 2},
|
||||
{"name": "BASE-SALARY", "db_type": "CHAR", "size": 9},
|
||||
]}
|
||||
sql_meta = collect_sql_meta(assignments, declared)
|
||||
assert len(sql_meta) == 1
|
||||
assert sql_meta[0]["table"] == "EMP-MASTER", sql_meta[0]["table"]
|
||||
|
||||
|
||||
def test_build_db_input_seeds_emp_master_not_salarydb():
|
||||
"""种子行键必须是 EMP-MASTER(而非 SALARYDB),否则插入时被丢弃。"""
|
||||
branch_paths = [
|
||||
([('SQLCODE', '=', '0', True)], {}),
|
||||
]
|
||||
records = [{
|
||||
"DBV-EMP-ID": "A0000001",
|
||||
"DBV-EMP-NAME": "TANAKA",
|
||||
"DBV-DEPT-CODE": "01",
|
||||
"DBV-BASE-SALARY": "429010",
|
||||
}]
|
||||
declared = {"EMP-MASTER": [
|
||||
{"name": "EMP-ID", "db_type": "CHAR", "size": 8},
|
||||
{"name": "EMP-NAME", "db_type": "CHAR", "size": 40},
|
||||
{"name": "DEPT-CODE", "db_type": "CHAR", "size": 2},
|
||||
{"name": "BASE-SALARY", "db_type": "CHAR", "size": 9},
|
||||
]}
|
||||
assignments = {
|
||||
"__SQL_CURSOR_C2": [{
|
||||
"type": "exec_sql_select",
|
||||
"table": "SALARYDB.EMP-MASTER",
|
||||
"select_list": "EMP-ID, EMP-NAME, DEPT-CODE, BASE-SALARY",
|
||||
"into_vars": ["DBV-EMP-ID", "DBV-EMP-NAME", "DBV-DEPT-CODE", "DBV-BASE-SALARY"],
|
||||
"where": "",
|
||||
"sql_text": "DECLARE C2 CURSOR FOR SELECT EMP-ID FROM SALARYDB.EMP-MASTER",
|
||||
}],
|
||||
}
|
||||
db_input = build_db_input(
|
||||
branch_paths, [], assignments,
|
||||
collect_sql_meta(assignments, declared),
|
||||
declared,
|
||||
records=records,
|
||||
)
|
||||
assert "SALARYDB" not in db_input, f"wrong table key: {list(db_input.keys())}"
|
||||
assert "EMP-MASTER" in db_input, f"missing EMP-MASTER key: {list(db_input.keys())}"
|
||||
|
||||
|
||||
def test_select_where_accept_fed_hostvar_uses_runtime_default():
|
||||
"""WHERE 宿主变量由 ACCEPT FROM COMMAND-LINE 馈入时,种子必须用运行时
|
||||
缺省值(如 SHA02MNC RATES 的 WRK-YEAR-MONTH='202605'),而非记录里的
|
||||
合成值('I00001')。否则 EFFECTIVE-FROM/TO 不满足 WHERE,RATES 不装载,
|
||||
SEARCH/EVALUATE 无法覆盖。"""
|
||||
branch_paths = [
|
||||
([('SQLCODE', '=', '0', True)], {}),
|
||||
]
|
||||
records = [{"WRK-YEAR-MONTH": "I00001"}]
|
||||
assignments = {
|
||||
"WRK-YEAR-MONTH": [
|
||||
{"type": "accept", "from": "COMMAND-LINE"},
|
||||
{"type": "move_literal", "literal": "202605"},
|
||||
],
|
||||
}
|
||||
sql_meta = [{
|
||||
"type": "exec_sql_select",
|
||||
"table": "INSURANCE-RATES",
|
||||
"select_list": "EFFECTIVE-FROM, EFFECTIVE-TO",
|
||||
"into_vars": [],
|
||||
"where": "EFFECTIVE-FROM <= :WRK-YEAR-MONTH AND EFFECTIVE-TO >= :WRK-YEAR-MONTH",
|
||||
"where_constraints": [
|
||||
{"col": "EFFECTIVE-FROM", "type": "host_var", "host_var": "WRK-YEAR-MONTH", "op": "<="},
|
||||
{"col": "EFFECTIVE-TO", "type": "host_var", "host_var": "WRK-YEAR-MONTH", "op": ">="},
|
||||
],
|
||||
}]
|
||||
declared = {"INSURANCE-RATES": [
|
||||
{"name": "EFFECTIVE-FROM", "db_type": "CHAR", "size": 6},
|
||||
{"name": "EFFECTIVE-TO", "db_type": "CHAR", "size": 6},
|
||||
]}
|
||||
db_input = build_db_input(
|
||||
branch_paths, [], assignments, sql_meta, declared, records=records,
|
||||
)
|
||||
rows = db_input.get("INSURANCE-RATES", [])
|
||||
assert rows, "no INSURANCE-RATES seed rows"
|
||||
assert rows[0]["EFFECTIVE-FROM"].strip() == "202605", (
|
||||
f"seed EFFECTIVE-FROM={rows[0]['EFFECTIVE-FROM']!r} not runtime default"
|
||||
)
|
||||
assert rows[0]["EFFECTIVE-TO"].strip() == "202605"
|
||||
Reference in New Issue
Block a user