初始化提交
This commit is contained in:
commit
887c1f449e
963 files changed
+166869
No files matched your search
@@ -0,0 +1,104 @@
|
||||
"""角色卡解析器单元测试。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import io
|
||||
import json
|
||||
import struct
|
||||
import zipfile
|
||||
import zlib
|
||||
|
||||
from app.modules.imports.card_parser import parse_character_card
|
||||
|
||||
|
||||
def _make_png_text(keyword: str, text: str) -> bytes:
|
||||
"""构造含一个 tEXt chunk 的最小 PNG。"""
|
||||
|
||||
def chunk(ctype: bytes, data: bytes) -> bytes:
|
||||
body = ctype + data
|
||||
return struct.pack(">I", len(data)) + body + struct.pack(">I", zlib.crc32(body) & 0xFFFFFFFF)
|
||||
|
||||
payload = keyword.encode("latin-1") + b"\x00" + text.encode("latin-1")
|
||||
return b"\x89PNG\r\n\x1a\n" + chunk(b"tEXt", payload) + chunk(b"IEND", b"")
|
||||
|
||||
|
||||
def test_parse_v2_json() -> None:
|
||||
card = {"spec": "chara_card_v2", "spec_version": "2.0", "data": {"name": "狂三", "description": "desc", "personality": "腹黑"}}
|
||||
parsed = parse_character_card(json.dumps(card).encode("utf-8"))
|
||||
assert parsed.name == "狂三"
|
||||
assert parsed.personality == "腹黑"
|
||||
assert parsed.spec_version == "2.0"
|
||||
|
||||
|
||||
def test_parse_v1_flat_normalized() -> None:
|
||||
card = {"name": "V1角色", "description": "d", "personality": "p"}
|
||||
parsed = parse_character_card(json.dumps(card).encode("utf-8"))
|
||||
assert parsed.name == "V1角色"
|
||||
assert parsed.spec_version == "1"
|
||||
|
||||
|
||||
def test_parse_png_chara_chunk() -> None:
|
||||
card = {"spec": "chara_card_v2", "spec_version": "2.0", "data": {"name": "PNG卡"}}
|
||||
text = base64.b64encode(json.dumps(card).encode("utf-8")).decode("ascii")
|
||||
parsed = parse_character_card(_make_png_text("chara", text))
|
||||
assert parsed.name == "PNG卡"
|
||||
|
||||
|
||||
def test_parse_png_ccv3_preferred_over_chara() -> None:
|
||||
# 同时含 chara(V2) 和 ccv3(V3),优先 ccv3
|
||||
card_v3 = {"spec_version": "3.0", "data": {"name": "V3卡", "nickname": "三三"}}
|
||||
|
||||
def chunk(ctype: bytes, data: bytes) -> bytes:
|
||||
body = ctype + data
|
||||
return struct.pack(">I", len(data)) + body + struct.pack(">I", zlib.crc32(body) & 0xFFFFFFFF)
|
||||
|
||||
v3_text = base64.b64encode(json.dumps(card_v3).encode()).decode()
|
||||
payload_chara = b"chara\x00" + base64.b64encode(json.dumps({"data": {"name": "旧"}}).encode())
|
||||
payload_ccv3 = b"ccv3\x00" + v3_text.encode("latin-1")
|
||||
png = b"\x89PNG\r\n\x1a\n" + chunk(b"tEXt", payload_chara) + chunk(b"tEXt", payload_ccv3) + chunk(b"IEND", b"")
|
||||
parsed = parse_character_card(png)
|
||||
assert parsed.name == "V3卡"
|
||||
assert parsed.nickname == "三三"
|
||||
|
||||
|
||||
def test_parse_charx_zip() -> None:
|
||||
card = {"spec_version": "3.0", "data": {"name": "CHARX卡"}}
|
||||
buf = io.BytesIO()
|
||||
with zipfile.ZipFile(buf, "w") as zf:
|
||||
zf.writestr("card.json", json.dumps(card))
|
||||
parsed = parse_character_card(buf.getvalue())
|
||||
assert parsed.name == "CHARX卡"
|
||||
|
||||
|
||||
def test_character_book_preserved() -> None:
|
||||
card = {
|
||||
"spec": "chara_card_v2",
|
||||
"spec_version": "2.0",
|
||||
"data": {
|
||||
"name": "x",
|
||||
"character_book": {"entries": [{"keys": ["a"], "content": "b"}]},
|
||||
},
|
||||
}
|
||||
parsed = parse_character_card(json.dumps(card).encode())
|
||||
assert parsed.character_book is not None
|
||||
assert parsed.character_book["entries"][0]["keys"] == ["a"]
|
||||
|
||||
|
||||
def test_alternate_greetings_and_tags() -> None:
|
||||
card = {"spec_version": "2.0", "data": {"name": "x", "alternate_greetings": ["hi", "yo"], "tags": ["anime"]}}
|
||||
parsed = parse_character_card(json.dumps(card).encode())
|
||||
assert parsed.alternate_greetings == ["hi", "yo"]
|
||||
assert parsed.tags == ["anime"]
|
||||
|
||||
|
||||
def test_png_without_metadata_raises() -> None:
|
||||
import pytest
|
||||
|
||||
def chunk(ctype: bytes, data: bytes) -> bytes:
|
||||
body = ctype + data
|
||||
return struct.pack(">I", len(data)) + body + struct.pack(">I", zlib.crc32(body) & 0xFFFFFFFF)
|
||||
|
||||
png = b"\x89PNG\r\n\x1a\n" + chunk(b"IEND", b"")
|
||||
with pytest.raises(ValueError):
|
||||
parse_character_card(png)
|
||||
Reference in new issue
Block a user