File size: 3,098 Bytes
0e6887b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
"""相容性知识库数据文件加载 / 校验 / 降级测试(compatibility-engine-upgrade 任务 1.4)。

覆盖需求 1.2(外置数据文件、加载失败优雅降级、结构可校验)。
"""

from __future__ import annotations

import os

from skills.compatibility import rules
from skills.compatibility.knowledge_base import KnowledgeBase, get_default_kb


def test_default_kb_loads_data_files_without_degradation():
    """默认数据目录下三份 yaml 应正常加载,辅料 / 反应部分不降级。"""
    kb = KnowledgeBase.load()
    # 辅料与反应来自数据文件(非内置降级)。
    assert "excipients" not in kb.degraded
    assert "reactions" not in kb.degraded
    assert len(kb.excipients()) >= 1
    assert len(kb.rules()) >= 1


def test_kb_validate_reports_no_problems():
    """打包的数据文件应通过结构校验(必填字段、枚举合法、定量字段带 source)。"""
    kb = KnowledgeBase.load()
    problems = kb.validate()
    assert problems == [], f"知识库校验应无问题,实际:{problems}"


def test_missing_data_dir_degrades_to_builtin_without_crash():
    """数据目录缺失 → 降级到内置最小集,不抛异常,仍可用。"""
    kb = KnowledgeBase.load(data_dir=os.path.join(os.sep, "nonexistent_kb_dir_xyz"))
    assert "excipients" in kb.degraded
    assert "reactions" in kb.degraded
    # 降级后仍能解析与评估。
    profile = kb.resolve("乳糖")
    assert profile.known is True
    assert "reducing_sugar" in profile.tags
    assert len(kb.rules()) == len(rules.RULES)


def test_resolve_equivalent_to_builtin_for_known_excipients():
    """数据文件解析结果与内置最小集对已知辅料等价(任务 1.1 只搬运、不改判定)。"""
    kb = KnowledgeBase.load()
    for name in ["乳糖", "硬脂酸镁", "微晶纤维素", "聚维酮", "magnesium stearate"]:
        from_kb = kb.resolve(name)
        builtin = rules._resolve_builtin(name)
        assert from_kb.known == builtin.known, name
        assert set(from_kb.tags) == set(builtin.tags), name


def test_unknown_excipient_marked_not_known():
    kb = KnowledgeBase.load()
    profile = kb.resolve("某种不存在的辅料XYZ")
    assert profile.known is False
    assert profile.tags == frozenset()


def test_wildcard_group_ids_expanded_to_all_groups():
    """reactions.yaml 中 group_ids: '*'(吸附规则)应展开为全部已知官能团。"""
    kb = KnowledgeBase.load()
    adsorption_rules = [r for r in kb.rules() if r.reaction == "adsorption"]
    assert adsorption_rules, "应存在吸附规则"
    assert adsorption_rules[0].group_ids == frozenset(rules.FUNCTIONAL_GROUP_META.keys())


def test_evaluate_uses_knowledge_base_path():
    """evaluate 经知识库路径产出与历史一致的经典判定(胺 + 乳糖 → 高风险美拉德)。"""
    assessment = rules.evaluate([{"id": "primary_amine"}], ["乳糖"])
    assert assessment.overall_risk == rules.RISK_HIGH
    er = assessment.excipient_results[0]
    assert "maillard" in [r.reaction for r in er.reactions]