"""TAF 结构体解析韧性:尾部未建模字段(服务端新增/ZERO)与通用响应回落。 回归来源(2026-10-15 真机):`checkUserBindGameAccount` 响应结构尾部多了 tag6 (ZERO 类型),旧解析直接抛 "期望 STRUCT_END, 实际 0x0c",导致整个 RPC 返回 None、 工作台「查询角色」永远失败。修法:按 TAF 语义跳过未建模的尾部字段。 """ from core.huya.activity_structs import CheckUserBindGameAccountResp from core.huya.shop_structs import ShopRawRsp from core.huya.taf_protocol import TafInputStream, TafOutputStream, TafType # 真机响应(checkUserBindGameAccount,UID 1199665170519,bActId 9271) BIND_RESP_HEX = ( "0a0100c816002a0001100120013a060016002602717136004612e6b3aae6958fe6849fe" "79a84e59b9ee5bf86560066000b4a06001612e6b3aae99ba8e585a8e698afe8b08ee8a8" "802604e6898b51360be88bb9e69e9c28694f53294600560066000b526a2595806c0b36" "0ce5928ce5b9b3e7b2bee88bb1460050070b" ) def test_bind_response_with_zero_tail_field_parses(): stream = TafInputStream(bytes.fromhex(BIND_RESP_HEX)) tag, dtype = stream.read_head() assert (tag, dtype) == (0, TafType.STRUCT_BEGIN) resp = CheckUserBindGameAccountResp() resp.read_from(stream) assert resp.status == 200 assert resp.gameName == "和平精英" assert resp.accountData.isBindAcount == 1 assert resp.accountData.isBindRole == 1 assert resp.accountData.gameAccount.nick == "泪敏感的回忆" assert resp.accountData.gameRole.roleName == "泪雨全是谎言" assert resp.accountData.gameRole.areaName == "手Q" assert resp.accountData.gameRole.platName == "苹果(iOS)" # 外层结构正常收尾(内层 tag6=ZERO 已由 read_struct 跳过) _end_tag, end_type = stream.read_head() assert end_type == TafType.STRUCT_END def test_skip_to_struct_end_skips_zero_field(): output = TafOutputStream() output.write_struct_begin(0) output.write_int32(0, 1) output.write_int32(6, 0) # ZERO 类型(0x6c) output.write_struct_end() stream = TafInputStream(output.get_bytes()) stream.read_head() # STRUCT_BEGIN assert stream.read_int32(0) == 1 assert stream.skip_to_struct_end() == 1 _tag, dtype = stream.read_head() assert dtype == TafType.STRUCT_END def test_shop_raw_rsp_from_payload_flat_and_nested(): flat = ShopRawRsp.from_payload({"tag0": 200, "tag1": "success"}) assert (flat.code, flat.message) == (200, "success") nested = ShopRawRsp.from_payload({"tag0": {"tag0": 200, "tag1": "成功"}}) assert (nested.code, nested.message) == (200, "成功") assert ShopRawRsp.from_payload(None).code == 0