"""材料装配的必读优先、UTF-8 字节预算与省略原因;离线纯函数合同。 字节期望值按 UTF-8 逐字写死,不由被测函数自身推算,避免同源计算自证。 """ import dataclasses import pytest from muse.上下文.接口 import 上下文错误, 装配材料 @pytest.mark.case_id( "NC-ctx-budget-priority", environment="离线纯函数", given="必读来源与多个可选材料的有序映射", when="按 64 字节上限装配材料", then=[ "必读最先入选,可选按输入顺序整项加入并以两个换行分隔", "字节数按 UTF-8 写死核算,结果不可变", ], contract="docs/系统架构/新版设计/模块设计/B09-上下文.md", ) def test_必读优先且可选按原顺序整项加入__1c4a9e() -> None: 材料 = {"可选甲": "甲文", "必读": "必读文", "可选乙": "乙文"} 结果 = 装配材料(材料, ("必读",), 字节上限=64) assert 结果.入选来源 == ("必读", "可选甲", "可选乙") assert 结果.文本 == "必读文\n\n甲文\n\n乙文" assert 结果.字节数 == 25 # 三个片段 9+6+6 字节加两处分隔符 assert 结果.省略 == () with pytest.raises(dataclasses.FrozenInstanceError): 结果.文本 = "改写" @pytest.mark.case_id( "NC-ctx-budget-utf8", environment="离线纯函数", given="含四字节 emoji 与组合字符的中文材料", when="分别在恰好容纳与差一字节的上限下装配", then=[ "中文与 emoji 逐字按 UTF-8 计数且含分隔符", "差一字节时可选整项省略并给出 BUDGET_EXCEEDED,不截断中文", ], contract="docs/系统架构/新版设计/模块设计/B09-上下文.md", ) def test_中文与emoji按utf8字节计数含分隔符__5d1c47() -> None: 原文 = "第1章:雨。🌧" 仅必读 = 装配材料({"历史": 原文}, ("历史",), 字节上限=20) assert 仅必读.文本 == 原文 assert 仅必读.字节数 == 20 # 含四字节 emoji 材料 = {"历史": 原文, "旁观": "他站着"} 齐 = 装配材料(材料, ("历史",), 字节上限=31) assert 齐.入选来源 == ("历史", "旁观") assert 齐.字节数 == 31 # 20 + 分隔符 2 + 9 assert 齐.文本 == f"{原文}\n\n他站着" 缺一字节 = 装配材料(材料, ("历史",), 字节上限=30) assert 缺一字节.入选来源 == ("历史",) assert 缺一字节.文本 == 原文 assert 缺一字节.省略 == (("旁观", "BUDGET_EXCEEDED"),) @pytest.mark.case_id( "NC-ctx-budget-required-missing", environment="离线纯函数", given="必读来源不在材料映射或只有空白", when="装配材料", then=["整体拒绝并返回 CONTEXT_REQUIRED_MISSING,说明点名缺失的具体来源身份"], contract="docs/系统架构/新版设计/模块设计/B09-上下文.md", ) @pytest.mark.parametrize( ("材料", "必读"), [({}, ("孤本第三章",)), ({"孤本第三章": " \n "}, ("孤本第三章",))], ids=["missing", "blank"], ) def test_必读缺失或空白拒绝__a7e903(材料: dict[str, str], 必读: tuple[str, ...]) -> None: with pytest.raises(上下文错误) as 异常: 装配材料(材料, 必读, 字节上限=64) assert 异常.value.错误码 == "CONTEXT_REQUIRED_MISSING" assert "孤本第三章" in 异常.value.说明 @pytest.mark.case_id( "NC-ctx-budget-required-over", environment="离线纯函数", given="两份必读合计 20 字节、上限 19 与恰好 20 两种", when="装配材料", then=[ "必读放不下整体拒绝并返回 CONTEXT_BUDGET_EXCEEDED 与实际需要字节数", "恰好等于上限时必读全部入选,可选按 BUDGET_EXCEEDED 省略", ], contract="docs/系统架构/新版设计/模块设计/B09-上下文.md", ) def test_必读整体超预算拒绝__c9e51f() -> None: 材料 = {"甲": "必读甲", "乙": "必读乙", "可选": "可选丙"} with pytest.raises(上下文错误) as 异常: 装配材料(材料, ("甲", "乙"), 字节上限=19) assert 异常.value.错误码 == "CONTEXT_BUDGET_EXCEEDED" assert "20" in 异常.value.说明 恰好 = 装配材料(材料, ("甲", "乙"), 字节上限=20) # 9 + 分隔符 2 + 9 assert 恰好.入选来源 == ("甲", "乙") assert 恰好.字节数 == 20 assert 恰好.省略 == (("可选", "BUDGET_EXCEEDED"),) @pytest.mark.case_id( "NC-ctx-budget-omission", environment="离线纯函数", given="必读、空白可选、超长可选与可入选可选并存", when="按紧预算装配", then=["省略条目按输入顺序分别给出 EMPTY 与 BUDGET_EXCEEDED 原因"], contract="docs/系统架构/新版设计/模块设计/B09-上下文.md", ) def test_可选空白与超预算分别给出省略原因__4f8ab2() -> None: 材料 = {"必读": "必读文", "空白": " ", "太长": "长" * 40, "入选": "短文"} 结果 = 装配材料(材料, ("必读",), 字节上限=17) # 9 + 分隔符 2 + 6 assert 结果.入选来源 == ("必读", "入选") assert 结果.省略 == (("空白", "EMPTY"), ("太长", "BUDGET_EXCEEDED")) @pytest.mark.case_id( "NC-ctx-budget-invalid-input", environment="离线纯函数", given="字节上限为零、负数、True 或必读身份重复", when="装配材料", then=["一律返回 CONTEXT_INPUT_INVALID;True 是 bool 不被当作正整数预算"], contract="docs/系统架构/新版设计/模块设计/B09-上下文.md", ) @pytest.mark.parametrize( ("字节上限", "必读"), [(0, ("必读",)), (-3, ("必读",)), (True, ("必读",)), (64, ("必读", "必读"))], ids=["zero", "negative", "boolean", "duplicate"], ) def test_非法预算或重复必读身份拒绝__e2168c(字节上限: int, 必读: tuple[str, ...]) -> None: with pytest.raises(上下文错误) as 异常: 装配材料({"必读": "必读文"}, 必读, 字节上限=字节上限) assert 异常.value.错误码 == "CONTEXT_INPUT_INVALID" @pytest.mark.case_id( "NC-ctx-budget-verbatim", environment="离线纯函数", given="首尾空白、制表符与换行并存的材料原文", when="装配材料", then=["入选文本与原文逐字一致,不 trim、不截断,字节数按原文 UTF-8 核算"], contract="docs/系统架构/新版设计/模块设计/B09-上下文.md", ) def test_原文不裁剪空白且按原字节保留__b4d7a1() -> None: 原文 = " 第1章 \n雨还在下。\t\n" 结果 = 装配材料({"历史": 原文}, ("历史",), 字节上限=29) assert 结果.文本 == 原文 assert 结果.字节数 == 29