"""正文结构的独立接缝:中文原文、段落身份与结构/可见哈希。""" import json from pathlib import Path from muse.正文写作.接口 import 可见文本, 文本节点, 正文结构哈希, 正文草稿, 段落 def test_正文不擅自改写NFC与换行__7d1f17(): from muse.正文写作.接口 import 可见文本哈希, 换行节点 原文 = "Cafe\u0301\r\n第二行\r第三行" 规范表示 = "Café\n第二行\n第三行" 草稿 = 正文草稿( ( 段落( "p1", ( 文本节点("Cafe\u0301"), 换行节点("\r\n"), 文本节点("第二行"), 换行节点("\r"), 文本节点("第三行"), ), ), ) ) 对照 = 正文草稿( ( 段落( "p1", ( 文本节点("Café"), 换行节点("\n"), 文本节点("第二行"), 换行节点("\n"), 文本节点("第三行"), ), ), ) ) assert 可见文本(草稿) == 原文 and 可见文本(对照) == 规范表示 assert 可见文本哈希(草稿) != 可见文本哈希(对照) assert 正文结构哈希(草稿) != 正文结构哈希(对照) def test_中文夹具往返保留空段落与原码点__aa1001(): 样本 = json.loads((Path(__file__).parents[1] / "夹具/中文正文.json").read_text())["samples"] for 项 in 样本: 段 = tuple(段落(f"p-{i}", (文本节点(文本),)) for i, 文本 in enumerate(项["paragraphs"])) 草稿 = 正文草稿(段) assert 可见文本(草稿) == "\n".join(项["paragraphs"]) for 选区 in 项.get("selections", []): 文本 = 可见文本(正文草稿((段[选区["paragraph_index"]],))) assert 文本[选区["start"] : 选区["end"]] == 选区["expected_text"] 另名 = 正文草稿(tuple(段落("new-" + p.paragraph_id, p.content) for p in 段)) assert 可见文本(草稿) == 可见文本(另名) assert 正文结构哈希(草稿) != 正文结构哈希(另名) def test_正文外壳拒绝额外节点属性__aa1002(): import pytest from pydantic import TypeAdapter, ValidationError 合同 = TypeAdapter(正文草稿) 输入 = { "paragraphs": [ { "paragraph_id": "p1", "content": [{"type": "text", "text": "文字", "html": "