File size: 4,930 Bytes
43afaf6
 
 
 
 
 
 
 
 
 
 
 
 
 
4d7e198
43afaf6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
894cbe3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
"""
Tests de chargement et validation des profils JSON — un test par profil.
"""
# 1. stdlib
import json
from pathlib import Path

# 2. third-party
import pytest
from pydantic import ValidationError

# 3. local
from app.schemas.corpus_profile import CorpusProfile, LayerType, ScriptType

PROFILES_DIR = Path(__file__).resolve().parent.parent.parent / "profiles"
PROFILE_FILES = [
    "medieval-illuminated.json",
    "medieval-textual.json",
    "early-modern-print.json",
    "modern-handwritten.json",
]


def load_profile(filename: str) -> CorpusProfile:
    path = PROFILES_DIR / filename
    with path.open(encoding="utf-8") as f:
        data = json.load(f)
    return CorpusProfile.model_validate(data)


# ---------------------------------------------------------------------------
# Tests de chargement
# ---------------------------------------------------------------------------

def test_medieval_illuminated_loads():
    profile = load_profile("medieval-illuminated.json")
    assert profile.profile_id == "medieval-illuminated"
    assert profile.script_type == ScriptType.CAROLINE


def test_medieval_textual_loads():
    profile = load_profile("medieval-textual.json")
    assert profile.profile_id == "medieval-textual"
    assert profile.script_type == ScriptType.GOTHIC


def test_early_modern_print_loads():
    profile = load_profile("early-modern-print.json")
    assert profile.profile_id == "early-modern-print"
    assert profile.script_type == ScriptType.PRINT


def test_modern_handwritten_loads():
    profile = load_profile("modern-handwritten.json")
    assert profile.profile_id == "modern-handwritten"
    assert profile.script_type == ScriptType.CURSIVE


# ---------------------------------------------------------------------------
# Tests de cohérence
# ---------------------------------------------------------------------------

@pytest.mark.parametrize("filename", PROFILE_FILES)
def test_profile_has_required_fields(filename: str):
    profile = load_profile(filename)
    assert profile.profile_id
    assert profile.label
    assert len(profile.language_hints) >= 1
    assert len(profile.active_layers) >= 1
    assert "primary" in profile.prompt_templates


@pytest.mark.parametrize("filename", PROFILE_FILES)
def test_profile_active_layers_are_valid_layer_types(filename: str):
    profile = load_profile(filename)
    valid_values = {lt.value for lt in LayerType}
    for layer in profile.active_layers:
        assert layer.value in valid_values


@pytest.mark.parametrize("filename", PROFILE_FILES)
def test_profile_uncertainty_config_bounds(filename: str):
    profile = load_profile(filename)
    assert 0.0 <= profile.uncertainty_config.flag_below <= 1.0
    assert 0.0 <= profile.uncertainty_config.min_acceptable <= 1.0
    assert profile.uncertainty_config.min_acceptable <= profile.uncertainty_config.flag_below


@pytest.mark.parametrize("filename", PROFILE_FILES)
def test_profile_is_frozen(filename: str):
    profile = load_profile(filename)
    with pytest.raises((TypeError, ValidationError)):
        profile.label = "Hacked"  # type: ignore[misc]


@pytest.mark.parametrize("filename", PROFILE_FILES)
def test_profile_prompt_templates_point_to_txt_files(filename: str):
    profile = load_profile(filename)
    for key, path in profile.prompt_templates.items():
        assert path.endswith(".txt"), f"Template '{key}' doit pointer vers un .txt"
        assert path.startswith("prompts/"), f"Template '{key}' doit être dans prompts/"


def test_medieval_illuminated_has_iconography():
    profile = load_profile("medieval-illuminated.json")
    assert LayerType.ICONOGRAPHY_DETECTION in profile.active_layers


def test_medieval_illuminated_has_iconography_prompt():
    profile = load_profile("medieval-illuminated.json")
    assert "iconography" in profile.prompt_templates


def test_early_modern_print_no_iconography():
    profile = load_profile("early-modern-print.json")
    assert LayerType.ICONOGRAPHY_DETECTION not in profile.active_layers


def test_modern_handwritten_no_iconography():
    profile = load_profile("modern-handwritten.json")
    assert LayerType.ICONOGRAPHY_DETECTION not in profile.active_layers


# ---------------------------------------------------------------------------
# Tests UncertaintyConfig cross-field validation
# ---------------------------------------------------------------------------

def test_uncertainty_config_flag_below_must_exceed_min():
    """flag_below < min_acceptable doit lever une erreur."""
    from app.schemas.corpus_profile import UncertaintyConfig
    with pytest.raises(ValidationError):
        UncertaintyConfig(flag_below=0.2, min_acceptable=0.5)


def test_uncertainty_config_valid():
    """flag_below >= min_acceptable est accepté."""
    from app.schemas.corpus_profile import UncertaintyConfig
    uc = UncertaintyConfig(flag_below=0.5, min_acceptable=0.3)
    assert uc.flag_below == 0.5