# -*- coding: utf-8 -*- """Java 实现与线上 PHP 黄金样本逐字段对比。 用法:python compare_batch.py [名称...] """ import sys import json import requests from pathlib import Path from _root import ROOT GOLDEN = Path(str(ROOT / "golden")) BASE = "http://localhost:18080" TOKEN = "testsession123" # 本地服务不走系统代理(沙箱代理会把 127.0.0.1 转发成 502) SESSION = requests.Session() SESSION.trust_env = False # (黄金样本名, Java 路径, 参数) CASES = [ ("store_info", "/store/store/info", None), ("store_menu_list", "/store/store.menu/list", None), ("store_role_list", "/store/store.role/list", None), ("store_user_list", "/store/store.user/list", {"page": 1}), ("store_address_all", "/store/store.address/all", None), ("category_list", "/store/category/list", None), ("goods_service_list", "/store/goods.service/list", {"page": 1}), ("goods_service_all", "/store/goods.service/all", None), ("files_list", "/store/files/list", {"page": 1}), ("files_group_list", "/store/files.group/list", None), ("region_all", "/store/region/all", None), ("region_tree", "/store/region/tree", None), ("user_list", "/store/user/list", {"page": 1}), ("user_grade_all", "/store/user.grade/all", None), ("order_list", "/store/order/list", {"page": 1, "dataType": "all"}), ("setting_detail", "/store/setting/detail", {"key": "store"}), ("setting_cache_items", "/store/setting.cache/items", None), ("setting_delivery_all", "/store/setting.delivery/all", None), ("setting_express_all", "/store/setting.express/all", None), ("setting_printer_all", "/store/setting.printer/all", None), ("page_list", "/store/page/list", {"page": 1}), ("market_coupon_list", "/store/market.coupon/list", {"page": 1}), ("market_coupon_detail_10001", "/store/market.coupon/detail", {"couponId": 10001}), ("market_coupon_detail_10002", "/store/market.coupon/detail", {"couponId": 10002}), ("market_coupon_detail_0", "/store/market.coupon/detail", {"couponId": 99999}), ("market_points_log", "/store/market.points/log", {"page": 1}), ("recharge_plan_list", "/store/market.recharge.plan/list", {"page": 1}), ("article_list", "/store/content.article/list", {"page": 1}), ("article_category_list", "/store/content.article.category/list", None), ("help_list", "/store/content.help/list", {"page": 1}), ("user_balance_log", "/store/user.balance/log", {"page": 1}), ] def diff(a, b, path="$", out=None, limit=12): out = out if out is not None else [] if len(out) >= limit: return out if type(a) != type(b): # int/float 视为同类数值 if isinstance(a, (int, float)) and isinstance(b, (int, float)) and not isinstance(a, bool) and not isinstance(b, bool): if float(a) != float(b): out.append(f"{path}: php={a!r} java={b!r}") return out out.append(f"{path}: 类型不同 php={type(a).__name__} java={type(b).__name__} (php={a!r} java={b!r})") return out if isinstance(a, dict): for k in a: if k not in b: out.append(f"{path}.{k}: Java 缺失 (php={a[k]!r})") else: diff(a[k], b[k], f"{path}.{k}", out, limit) for k in b: if k not in a: out.append(f"{path}.{k}: Java 多出 (java={b[k]!r})") return out if isinstance(a, list): if len(a) != len(b): out.append(f"{path}: 长度不同 php={len(a)} java={len(b)}") for i in range(min(len(a), len(b))): diff(a[i], b[i], f"{path}[{i}]", out, limit) return out if a != b: out.append(f"{path}: php={a!r} java={b!r}") return out def main(): only = set(sys.argv[1:]) ok = fail = skip = 0 for name, path, params in CASES: if only and name not in only: continue golden_file = GOLDEN / f"{name}.json" if not golden_file.exists(): print(f"[skip] {name} 无黄金样本") skip += 1 continue php = json.loads(golden_file.read_text(encoding="utf-8")) r = SESSION.get(BASE + path, headers={"Access-Token": TOKEN}, params=params or {}, timeout=90) try: java = r.json() except Exception: print(f"[FAIL] {name}: 非 JSON HTTP={r.status_code} {r.text[:150]}") fail += 1 continue if java.get("status") != 200: print(f"[FAIL] {name}: java status={java.get('status')} msg={java.get('message')}") fail += 1 continue diffs = diff(php.get("data"), java.get("data")) if diffs: fail += 1 print(f"[DIFF] {name} ({len(diffs)}+ 处)") for d in diffs: print(" ", d) else: ok += 1 print(f"[PASS] {name}") print(f"\n通过 {ok} / 差异 {fail} / 跳过 {skip}") if __name__ == "__main__": main()