"""领域入口拒绝无效输入,不将内部错误伪装成空结果。""" from types import SimpleNamespace import pytest from muse.作品规划.接口 import 节奏分布 from muse.作品规划.模型 import 作品错误 from muse.元数据.接口 import 元数据错误 from muse.故事世界 import 人物关系, 设定修订 from muse.故事世界.模型 import 事实错误 from muse.正式变更.接口 import 变更错误 from muse.正文写作.正式提交 import _核对必需检查 @pytest.mark.case_id("NC-O09-RHYTHM-EMPTY") def test_节奏空输入拒绝非空保留比例(): with pytest.raises(作品错误) as 错误: 节奏分布((), frozenset({"日常"})) assert 错误.value.错误码 == "RHYTHM_INVALID" assert 节奏分布( ({"节奏": ("日常",)}, {"节奏": ("冲突", "日常")}), frozenset({"日常", "冲突"}) ) == {"日常": 1.0, "冲突": 0.5} @pytest.mark.case_id("NC-O09-REFERENCE-FAIL-CLOSED") def test_无效关系引用结构不返回空端点(monkeypatch): row = { "schema_binding": { "schema_id": "relation", "base_version": 1, "effective_schema_hash": "hash", }, "instance_family": "relation", "content": {}, } monkeypatch.setattr(设定修订, "读取事实结构", lambda *a: (None, None, None)) monkeypatch.setattr(人物关系, "读取作品范围", lambda *a: None) monkeypatch.setattr(人物关系, "故事存储", lambda *a: SimpleNamespace(列出对象=lambda *a: [row])) def invalid(*a): raise 元数据错误("FIELD_INVALID", "缺引用字段") monkeypatch.setattr(人物关系, "校验值", invalid) with pytest.raises(事实错误) as 错误: 人物关系.列出关系(None, "author", "work") assert 错误.value.错误码 == "FACT_REFERENCE_INVALID" assert isinstance(错误.value.__cause__, 元数据错误) def broken(*a): raise RuntimeError("unexpected") monkeypatch.setattr(人物关系, "校验值", broken) with pytest.raises(RuntimeError, match="unexpected"): 人物关系.列出关系(None, "author", "work") @pytest.mark.case_id("NC-O09-CHECK-OWNER") @pytest.mark.parametrize( "结论,代码", [(None, "CHECK_MISSING"), ("failed", "CHECK_FAILED"), ("passed", None)] ) def test_模型候选只经B06读取对应版本检查(monkeypatch, 结论, 代码): import muse.审校修订.接口 as 审校 调用 = [] def read(conn, candidate_id, candidate_revision): 调用.append((conn, candidate_id, candidate_revision)) return 结论 monkeypatch.setattr(审校, "读取必需检查结论于", read, raising=False) class 连: def execute(self, sql, params): assert "muse_writing_candidate" in sql and "muse_review_report" not in sql return SimpleNamespace(fetchone=lambda: ("model",)) conn = 连() if 代码: with pytest.raises(变更错误) as 错误: _核对必需检查(conn, {"candidate_id": "candidate", "revision": 3}) assert 错误.value.错误码 == 代码 else: _核对必需检查(conn, {"candidate_id": "candidate", "revision": 3}) assert 调用 == [(conn, "candidate", 3)] @pytest.mark.case_id("NC-O09-MANUAL-CHECK") def test_人工候选不借用模型必需检查(monkeypatch): import muse.审校修订.接口 as 审校 monkeypatch.setattr( 审校, "读取必需检查结论于", lambda *a: pytest.fail("不应读取模型检查"), raising=False ) conn = SimpleNamespace(execute=lambda *a: SimpleNamespace(fetchone=lambda: ("manual",))) _核对必需检查(conn, {"candidate_id": "manual", "revision": 1}) @pytest.mark.case_id("NC-O09-MISSING-WORK") def test_探索交接缺失作品显式拒绝(monkeypatch): import muse.作品规划.探索交接 as 交接 monkeypatch.setattr(交接, "读取作者目录", lambda *a: None) monkeypatch.setattr( 交接, "作品存储", lambda *a: SimpleNamespace(读取探索选定=lambda *a: None, 读取=lambda *a: None), ) monkeypatch.setattr(交接.探索选定入口, "_取得稿", lambda *a: {}) 入口 = object.__new__(交接.探索选定入口) 请求 = SimpleNamespace(target_ref="exploration-selection:missing", work_id="missing") with pytest.raises(作品错误) as 错误: 入口.查看( None, SimpleNamespace(作者="author"), SimpleNamespace(业务请求=请求, 目标=请求.target_ref), ) assert 错误.value.错误码 == "WORK_NOT_FOUND"