209 lines
9.1 KiB
Python
209 lines
9.1 KiB
Python
"""人工创作入口使用真实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"]["读者约定"] == "先抛问题,再给答案"
|