# -*- coding: utf-8 -*- """providers 模块测试:判定 JSON 解析、分类归一化、图片编码、usage 规整。""" import base64 import pytest from violation_detector.providers import CANON, _norm_usage, encode_image, norm_category, parse_judgment GOOD = ('{"文字/图形属性": "黑色T恤印字母", "侵权/违规逻辑": "未授权使用商标", ' '"违规分类": "12. 侵权 - 除人物外的其他侵权"}') def test_parse_plain_json(): r = parse_judgment(GOOD) assert r is not None assert r[0] == "黑色T恤印字母" assert r[1] == "未授权使用商标" assert r[2] == "12. 侵权 - 除人物外的其他侵权" def test_parse_fenced_json(): r = parse_judgment("```json\n" + GOOD + "\n```") assert r is not None and r[2].startswith("12.") def test_parse_json_with_surrounding_text(): r = parse_judgment("分析如下:\n" + GOOD + "\n以上。") assert r is not None def test_parse_invalid(): assert parse_judgment("") is None assert parse_judgment("这不是JSON") is None assert parse_judgment('{"文字/图形属性": "x"}') is None # 缺字段 assert parse_judgment('{"a": [1,2]') is None # 截断 def test_norm_category_variants(): # 不同写法归一到标准 17 类名称 assert norm_category("12. 侵权 - 人物外") == CANON[12] assert norm_category("14脏话、侮辱性") == CANON[14] assert norm_category("5. 负向敏感") == CANON[5] # 非编号类原样保留 assert norm_category("无违规") == "无违规" assert norm_category("违规不明") == "违规不明" # 未知编号保留原文 assert norm_category("99. 未来分类") == "99. 未来分类" def test_encode_image_roundtrip(tmp_path): img = tmp_path / "a.jpg" img.write_bytes(b"\xff\xd8\xff\xe0fake") url = encode_image(str(img)) assert url.startswith("data:image/jpeg;base64,") assert base64.b64decode(url.split(",", 1)[1]) == b"\xff\xd8\xff\xe0fake" def test_encode_image_unsupported(tmp_path): p = tmp_path / "a.txt" p.write_text("x", encoding="utf-8") with pytest.raises(ValueError): encode_image(str(p)) def test_norm_usage_handles_missing_details(): assert _norm_usage({"prompt_tokens": 100, "completion_tokens": 50}) == { "prompt": 100, "completion": 50, "cached": 0} assert _norm_usage({}) == {"prompt": None, "completion": None, "cached": 0} assert _norm_usage({"prompt_tokens": 100, "prompt_tokens_details": {"cached_tokens": 80}})["cached"] == 80