"""测试 type=48 (微信位置消息) 解析与渲染。 5 个 fixture **全部合成**,无任何真实地理 / 商户 / 行政区划信息。设计原则:保留 真实 schema 的字段形态 (attr 顺序、占位符、空字符串、enum 漂移、多段 category), 但 POI 名 / 地址 / 城市名 / phone / 坐标全部用合成占位符。fixture 的能力是验证 解析与渲染逻辑,无需绑定任何具体真实数据。 覆盖 5 种 schema 形态: A: 全字段 new schema (有 poiCategoryTips/poiPhone/adcode/cityname, label 空) B: 带 infourl 占位的 mid schema (infourl 出现但全 corpus 0% 非空, label 空) C: qqmap_ poiid 变体 + buildingId/floorName 实际填了的稀有 case (poiname+label 都填) D: 极简 old schema + poiname="[位置]" 占位符 (用户手扔图钉,必须 fallback 到 label) E: maptype="0" + 三段 poiCategoryTips + adcode/cityname 都空 """ import unittest from mcp_server import ( _extract_location_info, _format_location_text, _is_location_poiname_placeholder, ) FIXTURE_A = ''' \t ''' FIXTURE_B = '''''' FIXTURE_C = ''' \t ''' FIXTURE_D = ''' \t ''' FIXTURE_E = ''' \t ''' class FormatLocationRenderTests(unittest.TestCase): """单行 chat-history 渲染:只挑 category / poiname / label 三个信号。""" def test_a_full_schema_label_empty(self): # label 空 → 渲染只用 category + poiname,不带 @ 地址段 self.assertEqual(_format_location_text(FIXTURE_A), '[位置·示例主类A] 示例POI-A') def test_b_mid_schema_with_empty_infourl(self): # infourl 是 schema 占位符,不影响渲染 self.assertEqual(_format_location_text(FIXTURE_B), '[位置·示例主类B] 示例POI-B') def test_c_full_schema_with_address(self): # poiname 与 label 都填,label 是地址 → 用 "@ 地址" 拼接 self.assertEqual( _format_location_text(FIXTURE_C), '[位置·示例主类C] 示例POI-C @ 示例市示例区示例路 1 号示例楼 L5' ) def test_d_placeholder_poiname_falls_back_to_label(self): # poiname="[位置]" 是手扔图钉时客户端填的占位符,必须用 label 渲染 self.assertEqual(_format_location_text(FIXTURE_D), '[位置] 示例区(近示例公交站)') def test_e_maptype_zero_still_renders(self): # maptype="0" 是另一种 enum,不影响渲染选择;poiCategoryTips 有多层(主:子:孙) # 取顶层主类 self.assertEqual( _format_location_text(FIXTURE_E), '[位置·示例主类E] 示例POI-E @ 示例市示例区示例路 2 号' ) def test_minimal_no_poiname_no_label(self): # 极端兜底:poiname 与 label 都缺,不堆 lat/lng 数字 xml = '' self.assertEqual(_format_location_text(xml), '[位置]') def test_no_category(self): # poiCategoryTips 缺失 → 渲染前缀退到 [位置] (不带 ·xxx) xml = '' self.assertEqual(_format_location_text(xml), '[位置] 示例POI-X') def test_missing_location_node(self): # 内没有 → None, caller 退到 "[位置]" 兜底 self.assertIsNone(_format_location_text('')) def test_invalid_xml(self): self.assertIsNone(_format_location_text('')) self.assertIsNone(_format_location_text('not xml at all')) class ExtractLocationInfoTests(unittest.TestCase): """结构化层:decode_location 拿全字段,字段语义边界检查。""" def test_a_all_user_shared_fields_extracted(self): info = _extract_location_info(FIXTURE_A) self.assertEqual(info['poiname'], '示例POI-A') self.assertEqual(info['poiid'], 'nearby_000000000000000000') self.assertEqual(info['poiCategoryTips'], '示例主类A:示例子类') self.assertEqual(info['category_top'], '示例主类A') self.assertEqual(info['poiPhone'], '0000-00000000') self.assertEqual(info['cityname'], '城市A') self.assertEqual(info['adcode'], '000000') self.assertEqual(info['isFromPoiList'], 'false') # 经纬度:x→lat, y→lng self.assertAlmostEqual(info['lat'], 0.0, places=4) self.assertAlmostEqual(info['lng'], 0.0, places=4) # defensive 字段:empty in fixture A but present in dict self.assertEqual(info['infourl'], '') self.assertEqual(info['floorName'], '') def test_b_empty_infourl_preserved_in_structured_layer(self): # infourl 在本 corpus 全部空字符串,但 decode_location 仍要暴露 schema slot info = _extract_location_info(FIXTURE_B) self.assertEqual(info['infourl'], '') self.assertEqual(info['poiCategoryTips'], '示例主类B:示例子类') self.assertEqual(info['category_top'], '示例主类B') def test_c_rare_building_floor_filled(self): # buildingId 和 floorName 在 corpus 里只有 ~1% 非空,但 C 是稀有真实案例 info = _extract_location_info(FIXTURE_C) self.assertEqual(info['buildingId'], '000000000000') self.assertEqual(info['floorName'], 'L5') self.assertEqual(info['poiBusinessHour'], '00:00-24:00') self.assertEqual(info['poiPriceTips'], '100') self.assertEqual(info['poiid'], 'qqmap_000000000000000000') def test_d_dropped_pin_minimal(self): info = _extract_location_info(FIXTURE_D) self.assertEqual(info['poiname'], '[位置]') self.assertEqual(info['label'], '示例区(近示例公交站)') # 字段缺失 → 空串(跟 _extract_transfer_info 风格一致) self.assertEqual(info['poiCategoryTips'], '') self.assertEqual(info['poiPhone'], '') self.assertEqual(info['poiid'], '') def test_e_multi_segment_category(self): # 三段 "主:子:孙" → category_top 仍只取主类 info = _extract_location_info(FIXTURE_E) self.assertEqual(info['poiCategoryTips'], '示例主类E:示例子类:示例孙类') self.assertEqual(info['category_top'], '示例主类E') def test_missing_location_node_returns_none(self): self.assertIsNone(_extract_location_info('')) self.assertIsNone(_extract_location_info('')) def test_invalid_coordinates_become_none(self): xml = '' info = _extract_location_info(xml) self.assertIsNone(info['lat']) self.assertIsNone(info['lng']) class PlaceholderDetectionTests(unittest.TestCase): def test_recognized_placeholders(self): self.assertTrue(_is_location_poiname_placeholder('[位置]')) self.assertTrue(_is_location_poiname_placeholder('[Location]')) self.assertTrue(_is_location_poiname_placeholder('[]')) self.assertTrue(_is_location_poiname_placeholder('')) def test_real_poi_names_not_placeholder(self): self.assertFalse(_is_location_poiname_placeholder('示例POI-A')) self.assertFalse(_is_location_poiname_placeholder('示例POI-B')) # 中括号在 POI 名中间不算占位符 self.assertFalse(_is_location_poiname_placeholder('示例POI [子]总店')) if __name__ == '__main__': unittest.main()