Spaces:
Running on Zero
Running on Zero
File size: 6,451 Bytes
0539596 | 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 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | from __future__ import annotations
import pytest
from pydantic import ValidationError
from gcmd_classifier.llm.schemas import (
CandidateDecision,
TermResponse,
TopicResponse,
VariableResponse,
)
CANDIDATE = {
"candidate_id": "topic-atmosphere",
"confidence": 0.91,
"evidence": "The article discusses atmospheric composition.",
"support_type": "explicit",
"reason": "Primary subject is atmospheric science.",
}
SECOND_CANDIDATE = {
"candidate_id": "topic-oceans",
"confidence": None,
"evidence": "Ocean observations are also central to the article.",
"support_type": "mixed",
}
def test_valid_topic_response_with_one_selected_candidate() -> None:
response = TopicResponse.model_validate(
{
"selected": [CANDIDATE],
"ambiguous_alternatives": [],
"no_selection_reason": None,
}
)
assert response.selected[0].candidate_id == "topic-atmosphere"
assert response.selected[0].confidence == 0.91
def test_valid_topic_response_with_multiple_selected_candidates() -> None:
response = TopicResponse.model_validate(
{
"selected": [CANDIDATE, SECOND_CANDIDATE],
"ambiguous_alternatives": ["topic-cryosphere"],
}
)
assert [candidate.candidate_id for candidate in response.selected] == [
"topic-atmosphere",
"topic-oceans",
]
assert response.selected[1].confidence is None
def test_valid_topic_response_with_no_selected_candidates_and_reason() -> None:
response = TopicResponse.model_validate(
{
"selected": [],
"ambiguous_alternatives": [],
"no_selection_reason": "No supplied Topic is supported by the title or abstract.",
}
)
assert response.selected == []
assert response.no_selection_reason is not None
def test_valid_term_response_selecting_candidates() -> None:
response = TermResponse.model_validate(
{
"selected": [CANDIDATE, SECOND_CANDIDATE],
"stop_at_parent": False,
"stop_reason": None,
"ambiguous_alternatives": [],
}
)
assert len(response.selected) == 2
assert response.stop_at_parent is False
def test_valid_term_response_stopping_at_parent() -> None:
response = TermResponse.model_validate(
{
"selected": [],
"stop_at_parent": True,
"stop_reason": "No child Term is adequately supported.",
"ambiguous_alternatives": ["term-weather-events"],
}
)
assert response.stop_at_parent is True
assert response.selected == []
@pytest.mark.parametrize(
"payload",
[
{
"selected": [CANDIDATE],
"stop_at_parent": True,
"stop_reason": "Contradictory response.",
"ambiguous_alternatives": [],
},
{
"selected": [CANDIDATE],
"stop_at_parent": True,
"stop_reason": None,
"ambiguous_alternatives": [],
},
],
)
def test_invalid_term_response_with_stop_and_selected(payload: dict) -> None:
with pytest.raises(ValidationError):
TermResponse.model_validate(payload)
@pytest.mark.parametrize("stop_reason", [None, ""])
def test_invalid_term_response_stopping_without_stop_reason(stop_reason: str | None) -> None:
with pytest.raises(ValidationError):
TermResponse.model_validate(
{
"selected": [],
"stop_at_parent": True,
"stop_reason": stop_reason,
"ambiguous_alternatives": [],
}
)
def test_valid_variable_response_selecting_candidates() -> None:
response = VariableResponse.model_validate(
{
"selected": [CANDIDATE],
"stop_at_parent": False,
"stop_reason": None,
"ambiguous_alternatives": [],
}
)
assert response.selected[0].support_type.value == "explicit"
def test_valid_variable_response_stopping_at_parent() -> None:
response = VariableResponse.model_validate(
{
"selected": [],
"stop_at_parent": True,
"stop_reason": "Variable children are too specific for the evidence.",
"ambiguous_alternatives": [],
}
)
assert response.stop_at_parent is True
@pytest.mark.parametrize(
"payload",
[
{
"selected": [CANDIDATE],
"stop_at_parent": True,
"stop_reason": "Contradictory response.",
"ambiguous_alternatives": [],
},
{
"selected": [CANDIDATE],
"stop_at_parent": True,
"stop_reason": None,
"ambiguous_alternatives": [],
},
],
)
def test_invalid_variable_response_with_stop_and_selected(payload: dict) -> None:
with pytest.raises(ValidationError):
VariableResponse.model_validate(payload)
@pytest.mark.parametrize("stop_reason", [None, ""])
def test_invalid_variable_response_stopping_without_stop_reason(stop_reason: str | None) -> None:
with pytest.raises(ValidationError):
VariableResponse.model_validate(
{
"selected": [],
"stop_at_parent": True,
"stop_reason": stop_reason,
"ambiguous_alternatives": [],
}
)
@pytest.mark.parametrize("confidence", [-0.01, 1.01])
def test_invalid_confidence_range(confidence: float) -> None:
payload = CANDIDATE | {"confidence": confidence}
with pytest.raises(ValidationError):
CandidateDecision.model_validate(payload)
def test_valid_missing_confidence() -> None:
payload = CANDIDATE.copy()
del payload["confidence"]
decision = CandidateDecision.model_validate(payload)
assert decision.confidence is None
def test_unknown_fields_rejected() -> None:
with pytest.raises(ValidationError):
TopicResponse.model_validate({"selected": [], "ambiguous_alternatives": [], "extra": "bad"})
def test_malformed_candidate_decision_rejected() -> None:
payload = CANDIDATE.copy()
del payload["evidence"]
with pytest.raises(ValidationError):
CandidateDecision.model_validate(payload)
def test_empty_candidate_id_rejected() -> None:
with pytest.raises(ValidationError):
CandidateDecision.model_validate(CANDIDATE | {"candidate_id": ""})
|