Files
WeChatDataAnalysis/tests/test_parse_app_message.py
T
2977094657 16a13af18a feat(chat): 支持位置消息与小程序卡片解析展示
- 新增位置消息解析,补充经纬度、地点名和地址字段
- 修复小程序分享 type 识别,避免嵌套 type 干扰
- 聊天页新增位置卡片展示,并补充小程序卡片样式
- 导出、搜索和会话预览同步支持位置消息
- 补充位置导出与小程序解析测试
2026-03-06 21:19:15 +08:00

144 lines
7.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import sys
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
from wechat_decrypt_tool.chat_helpers import _parse_app_message
class TestParseAppMessage(unittest.TestCase):
def test_mini_program_type_33_parses_as_link(self):
# 小程序分享是 appmsg type=33/36。部分 payload 会在 <weappinfo> 内嵌一个 <type>0</type>
# 并且出现在外层 <type>33</type> 之前,因此解析必须避免被嵌套 <type> 误导。
raw_text = (
"<msg><appmsg appid='' sdkver='0'>"
"<title>锦城苑房源详情分享给你,点击查看哦~</title>"
"<des></des>"
"<weappinfo>"
"<type>0</type>"
"<username><![CDATA[gh_xxx@app]]></username>"
"<weappiconurl><![CDATA[https://example.com/icon.png]]></weappiconurl>"
"</weappinfo>"
"<type>33</type>"
"<url></url>"
"<thumburl>https://example.com/thumb.jpg</thumburl>"
"<sourcedisplayname><![CDATA[成都购房通]]></sourcedisplayname>"
"</appmsg></msg>"
)
parsed = _parse_app_message(raw_text)
self.assertEqual(parsed.get("renderType"), "link")
self.assertEqual(parsed.get("linkType"), "mini_program")
self.assertEqual(parsed.get("title"), "锦城苑房源详情分享给你,点击查看哦~")
self.assertEqual(parsed.get("from"), "成都购房通")
self.assertEqual(parsed.get("fromUsername"), "gh_xxx@app")
self.assertEqual(parsed.get("thumbUrl"), "https://example.com/thumb.jpg")
def test_quote_type_57_nested_refermsg_uses_inner_title(self):
raw_text = (
'<msg><appmsg appid="" sdkver="0">'
'<title>一松一紧</title><des></des><action></action><type>57</type>'
'<showtype>0</showtype><soundtype>0</soundtype><mediatagname></mediatagname>'
'<messageext></messageext><messageaction></messageaction><content></content>'
'<url></url><appattach><totallen>0</totallen><attachid></attachid><fileext></fileext></appattach>'
'<extinfo></extinfo><sourceusername></sourceusername><sourcedisplayname></sourcedisplayname>'
'<commenturl></commenturl><refermsg>'
'<type>57</type><svrid>1173057991425172913</svrid>'
'<fromusr>44372432598@chatroom</fromusr><chatusr>44372432598@chatroom</chatusr>'
'<displayname><![CDATA[ㅤ磁父]]></displayname>'
'<content><![CDATA[<msg><appmsg appid="" sdkver="0"><title>那里紧?哪里张?</title><des></des>'
'<action></action><type>57</type><showtype>0</showtype><soundtype>0</soundtype>'
'<mediatagname></mediatagname><messageext></messageext><messageaction></messageaction>'
'<content></content><url></url><appattach><totallen>0</totallen><attachid></attachid>'
'<fileext></fileext></appattach><extinfo></extinfo><sourceusername></sourceusername>'
'<sourcedisplayname></sourcedisplayname><commenturl></commenturl></appmsg></msg>]]></content>'
'</refermsg></appmsg></msg>'
)
parsed = _parse_app_message(raw_text)
self.assertEqual(parsed.get("renderType"), "quote")
self.assertEqual(parsed.get("content"), "一松一紧")
self.assertEqual(parsed.get("quoteType"), "57")
self.assertEqual(parsed.get("quoteContent"), "那里紧?哪里张?")
def test_quote_type_57_plain_text_refermsg_keeps_text(self):
raw_text = (
'<msg><appmsg appid="" sdkver="0">'
'<title>回复</title><type>57</type>'
'<refermsg><type>57</type><content><![CDATA[普通文本引用]]></content></refermsg>'
'</appmsg></msg>'
)
parsed = _parse_app_message(raw_text)
self.assertEqual(parsed.get("renderType"), "quote")
self.assertEqual(parsed.get("quoteContent"), "普通文本引用")
def test_quote_type_49_nested_xml_refermsg_uses_inner_title(self):
raw_text = (
'<msg><appmsg appid="" sdkver="0">'
'<title>这种傻逼公众号怎么还在看</title><type>57</type>'
'<refermsg><type>49</type><displayname><![CDATA[水豚喧喧]]></displayname>'
'<content><![CDATA[wxid_gryaI8aopjio22: <?xml version="1.0"?><msg><appmsg appid="" sdkver="0">'
'<title>为自己的美丽漂亮善良知性发声😊</title><des></des>'
'<type>5</type><url>https://mp.weixin.qq.com/s/example</url>'
'<thumburl>https://mmbiz.qpic.cn/some-thumb.jpg</thumburl>'
'</appmsg></msg>]]></content></refermsg></appmsg></msg>'
)
parsed = _parse_app_message(raw_text)
self.assertEqual(parsed.get("renderType"), "quote")
self.assertEqual(parsed.get("quoteType"), "49")
self.assertEqual(parsed.get("quoteTitle"), "水豚喧喧")
self.assertEqual(parsed.get("quoteContent"), "[链接] 为自己的美丽漂亮善良知性发声😊")
self.assertEqual(parsed.get("quoteThumbUrl"), "https://mmbiz.qpic.cn/some-thumb.jpg")
def test_public_account_link_exposes_link_type_and_style(self):
raw_text = (
'<msg><appmsg appid="" sdkver="0">'
'<title>为自己的美丽漂亮善良知性发声😊</title>'
'<des>#日常穿搭灵感 #白色蕾丝裙穿搭 #知性美女</des>'
'<type>5</type>'
'<url>http://mp.weixin.qq.com/s?__biz=xx&mid=1</url>'
'<thumburl>http://mmbiz.qpic.cn/abc/640?wx_fmt=jpeg</thumburl>'
'<sourceusername>gh_0cef8eaa987d</sourceusername>'
'<sourcedisplayname>草莓不甜芒果甜</sourcedisplayname>'
'</appmsg></msg>'
)
parsed = _parse_app_message(raw_text)
self.assertEqual(parsed.get("renderType"), "link")
self.assertEqual(parsed.get("linkType"), "official_article")
self.assertEqual(parsed.get("linkStyle"), "cover")
def test_quote_type_5_nested_xml_refermsg_uses_inner_title(self):
raw_text = (
'<msg><appmsg appid="" sdkver="0">'
'<title>这个年龄有点大啊</title><type>57</type>'
'<refermsg><type>5</type><displayname><![CDATA[水豚噜噜]]></displayname>'
'<content><![CDATA[wxid_qrval8aopiio22:\n<?xml version="1.0"?>\n<msg><appmsg appid="" sdkver="0">'
'<title>谁说冬天不能穿裙子?</title><des></des><type>5</type>'
'<thumburl>https://mmbiz.qpic.cn/some-thumb2.jpg</thumburl>'
'<url>https://mp.weixin.qq.com/s/example2</url>'
'</appmsg></msg>]]></content></refermsg></appmsg></msg>'
)
parsed = _parse_app_message(raw_text)
self.assertEqual(parsed.get("renderType"), "quote")
self.assertEqual(parsed.get("quoteType"), "5")
self.assertEqual(parsed.get("quoteTitle"), "水豚噜噜")
self.assertEqual(parsed.get("quoteContent"), "[链接] 谁说冬天不能穿裙子?")
self.assertEqual(parsed.get("quoteThumbUrl"), "https://mmbiz.qpic.cn/some-thumb2.jpg")
if __name__ == "__main__":
unittest.main()