"""人工创作入口使用真实owner、元数据、S01和隔离PG;不需要模型评分。""" import pytest from muse.作品规划.接口 import 作品服务, 档案保存, 登记作品参与者 from muse.元数据.接口 import 元数据服务, 导入内置结构 from muse.共享.标识 import 任务标识 from muse.共享.调用身份 import 内容用途, 用途, 调用身份 from muse.正式变更.接口 import 参与者目录, 正式变更服务 pytestmark = pytest.mark.数据库 @pytest.fixture def 作品环境(应用测试库): with 应用测试库[用途.维护].连接() as 连, 连.transaction(): 导入内置结构(元数据服务(连)) 目录 = 参与者目录() from muse.任务运行.接口 import 任务服务, 登记任务参与者 from muse.编排.接口 import 流程登记 登记任务参与者(目录, 任务服务(应用测试库[用途.生产], 流程登记())) 登记作品参与者(目录) 正式 = 正式变更服务(应用测试库[用途.生产], 目录) 服务 = 作品服务(应用测试库[用途.生产], 正式) 作者 = 调用身份("author", 任务标识("manual-create"), 用途.生产, 内容用途.规划) 结构 = 服务.新档案结构(作者, "work-new", "work_core", 1) 输入 = 档案保存( "work-new", 0, {"名称": "新故事", "题材定位": "未定题材", "主题立意": "关于选择"}, 结构 ) return 服务, 作者, 输入, 应用测试库 def test_创建动态作品档案经S01且同命令不重复__aa1101(作品环境): 服务, 作者, 输入, 应用测试库 = 作品环境 回执 = 服务.保存档案(作者, "create-work", 输入) assert 服务.保存档案(作者, "create-work", 输入) == 回执 作品 = 服务.读取作品(作者, "work-new") assert 作品["revision"] == 1 assert 作品["content"] == {"名称": "新故事", "题材定位": "未定题材", "主题立意": "关于选择"} assert 作品["schema_binding"]["schema_id"] == "work_core" with 应用测试库[用途.生产].连接() as 连: assert 连.execute("SELECT count(*) FROM muse_work_version").fetchone()[0] == 1 def test_章节重排只改目录顺序保留稳定身份__aa1102(作品环境): 服务, 作者, 输入, _ = 作品环境 服务.保存档案(作者, "create-work", 输入) 服务.添加章节(作者, "chapter-A", "work-new", "chapter-a", "开篇", 预期目录版本=0) 服务.添加章节(作者, "chapter-B", "work-new", "chapter-b", "随后", 预期目录版本=1) 回执 = 服务.重排章节(作者, "reorder", "work-new", ("chapter-b", "chapter-a"), 预期目录版本=2) assert ( 服务.重排章节(作者, "reorder", "work-new", ("chapter-b", "chapter-a"), 预期目录版本=2) == 回执 ) 目录 = 服务.读取目录(作者, "work-new") assert 目录["revision"] == 3 assert [(v["chapter_id"], v["title"], v["position"]) for v in 目录["chapters"]] == [ ("chapter-b", "随后", 1), ("chapter-a", "开篇", 2), ] def test_人工正文保存重开与回退保留中文和历史__aa1103(作品环境): from dataclasses import replace from muse.正式变更.接口 import 变更错误 from muse.正文写作.接口 import 可见文本, 文本节点, 正文服务, 正文草稿, 段落, 登记正文参与者 作品, 作者, 输入, 库 = 作品环境 登记正文参与者(作品.正式.目录) 作品.保存档案(作者, "create-work", 输入) 作品.添加章节(作者, "chapter-A", "work-new", "chapter-a", "开篇", 预期目录版本=0) 正文 = 正文服务(库[用途.生产], 作品.正式) 草稿 = 正文草稿( ( 段落("p1", (文本节点(" 「中文」 e\u0301 🧑‍🏽 "),)), 段落("p2", ()), 段落("p3", (文本节点("最后一段。"),)), ) ) 首次 = 正文.保存人工(作者, "save-1", "chapter-a", 0, 草稿) assert 正文.保存人工(作者, "save-1", "chapter-a", 0, 草稿) == 首次 重开 = 正文.读取正文(作者, "chapter-a") assert 重开["revision"] == 1 and 重开["visible_text"] == 可见文本(草稿) assert [p["paragraph_id"] for p in 重开["document"]["paragraphs"]] == ["p1", "p2", "p3"] 第二稿 = replace( 草稿, paragraphs=(*草稿.paragraphs[:2], 段落("p3", (文本节点("作者更新的末段。"),))) ) 正文.保存人工(作者, "save-2", "chapter-a", 1, 第二稿) 回退 = 正文.回退正文(作者, "restore-1", "chapter-a", 2, 1) assert 回退["results"][0]["revision"] == 3 assert 正文.读取正文(作者, "chapter-a")["visible_text"] == 可见文本(草稿) assert 正文.读取正文(作者, "chapter-a", 版本=2)["visible_text"] == 可见文本(第二稿) with pytest.raises(变更错误) as 捕获: 正文.保存人工(作者, "stale-save", "chapter-a", 1, 第二稿) assert 捕获.value.错误码 == "REVISION_CONFLICT" assert 正文.读取正文(作者, "chapter-a")["revision"] == 3 def test_人工正文CLI使用实际装配并返回相同文稿__aa1104(作品环境, tmp_path): 文稿 = _核对CLI正文(作品环境, tmp_path, " CLI 原文「保持不变」🧑‍🏽\n") assert 文稿["visible_text"] == " CLI 原文「保持不变」🧑‍🏽\n" def test_大段中文引号换行与反斜杠经CLI和PG往返__125b0c(作品环境, tmp_path): big = '中文"引号"\n换行\\反斜杠' * 5000 文稿 = _核对CLI正文(作品环境, tmp_path, big) assert 文稿["visible_text"] == big def _核对CLI正文(作品环境, tmp_path, 原文): import json import subprocess import sys from dataclasses import asdict from muse.正文写作.接口 import 文本节点, 正文草稿, 段落 作品, 作者, 输入, _ = 作品环境 作品.保存档案(作者, "create-work", 输入) 作品.添加章节(作者, "chapter-A", "work-new", "chapter-a", "开篇", 预期目录版本=0) 配置文件 = tmp_path / "人工.toml" 配置文件.write_text("""["数据库"] "取值方式"="受控存储" "位置"="production.txt" ["资源"] "发布身份"="test" ["HTTP"] "口令文件"="作者口令.txt" "作者ID"="author" """) 草稿 = 正文草稿( tuple(段落(f"cli-p{i}", (文本节点(行),)) for i, 行 in enumerate(原文.split("\n"))) ) 请求文件 = tmp_path / "正文请求.json" 请求文件.write_text( json.dumps( { "command_id": "cli-save", "chapter_id": "chapter-a", "expected_revision": 0, "document": asdict(草稿), }, ensure_ascii=False, ) ) base = [sys.executable, "-m", "muse", "作品", str(配置文件)] def 执行(*args): p = subprocess.run([*base, *args], cwd="/", capture_output=True, text=True, timeout=15) assert p.returncode == 0, p.stderr return json.loads(p.stdout) 回执 = 执行("保存正文", str(请求文件)) assert 执行("保存正文", str(请求文件)) == 回执 文稿 = 执行("正文", "chapter-a") assert 文稿["revision"] == 1 return 文稿 def test_档案读取当前绑定而不沿用上次写值结构__aa1105(作品环境): from dataclasses import replace from muse.作品规划.接口 import 档案保存, 档案结构 from muse.元数据.接口 import 值规则, 启用命令, 字段定义 作品, 作者, 输入, 库 = 作品环境 作品.保存档案(作者, "create-work", 输入) # 这里只设置已完成的兼容升级;作者升级确认旅程由W11另验。 with 库[用途.维护].连接() as 连, 连.transaction(): 元数据 = 元数据服务(连) 旧 = 元数据.读取结构("work_core", 1) 新 = replace( 旧, schema_version=2, 父版本=1, 字段=(*旧.字段, 字段定义("work_core.读者约定", "读者约定", "读者约定", 值规则("text"))), ) 元数据.登记结构候选(新) 元数据.发布结构("work_core", 2, 新.内容哈希) 有效 = 元数据.读取有效结构("work_core", 2) 元数据.启用绑定( "work:work-new", "work-new", 有效, 启用命令( "synthetic-upgrade", 有效.effective_schema_hash, 1, "synthetic-reviewed-upgrade", "work:work-new", ), ) 当前 = 作品.读取作品(作者, "work-new") assert 当前["revision"] == 1 and 当前["schema_binding"]["base_version"] == 2 frame = 当前["schema_binding"] 结构 = 档案结构( frame["schema_id"], frame["base_version"], frame["effective_schema_hash"], 当前["projection_version"], frame["extension_version"], ) 作品.保存档案( 作者, "save-new-field", 档案保存("work-new", 1, {"读者约定": "先抛问题,再给答案"}, 结构) ) assert 作品.读取作品(作者, "work-new")["content"]["读者约定"] == "先抛问题,再给答案"