Spaces:
Sleeping
Sleeping
| import asyncio | |
| import sys | |
| import types | |
| # L'environnement local de test peut ne pas contenir FastAPI. | |
| # Le module endpoint utilise uniquement HTTPException ; ce substitut | |
| # permet donc de tester son contrat sans modifier le code de production. | |
| try: | |
| import fastapi # noqa: F401 | |
| except ModuleNotFoundError: | |
| fastapi_stub = types.ModuleType("fastapi") | |
| class HTTPException(Exception): | |
| def __init__( | |
| self, | |
| status_code: int, | |
| detail: str, | |
| ) -> None: | |
| super().__init__(detail) | |
| self.status_code = status_code | |
| self.detail = detail | |
| fastapi_stub.HTTPException = HTTPException | |
| sys.modules["fastapi"] = fastapi_stub | |
| from endpoints.validate_numeric import post_validate_numeric | |
| from numeric_core import extract, validate_numeric | |
| EVIDENCE = ( | |
| "Effect sizes were 1.19 and 0.57. " | |
| "There were 22 studies. " | |
| "The response rate was 20%. " | |
| "The dose was 1.5 mg. " | |
| "The 95% CI was 0.74 to 1.64." | |
| ) | |
| def test_decimal_point_with_final_period(): | |
| values = extract("Effect size 1.19.") | |
| assert len(values) == 1 | |
| assert values[0].kind == "scalar" | |
| assert values[0].lo == 1.19 | |
| def test_decimal_comma_with_final_period(): | |
| values = extract("Taille d'effet 1,19.") | |
| assert len(values) == 1 | |
| assert values[0].kind == "scalar" | |
| assert values[0].lo == 1.19 | |
| def test_two_plain_decimals_are_extracted(): | |
| values = extract("Values were 1.19 and 0.57.") | |
| assert [item.lo for item in values] == [1.19, 0.57] | |
| def test_french_decimals_match_exactly(): | |
| result = validate_numeric( | |
| "Les tailles d'effet étaient 1,19 et 0,57.", | |
| EVIDENCE, | |
| rel_tol=0.0, | |
| ) | |
| assert result["has_numbers"] is True | |
| assert result["numeric_ok"] is True | |
| assert result["unparsed_numeric"] is False | |
| def test_modified_decimal_is_rejected_exactly(): | |
| result = validate_numeric( | |
| "Effect sizes were 1.20 and 0.57.", | |
| EVIDENCE, | |
| rel_tol=0.0, | |
| ) | |
| assert result["numeric_ok"] is False | |
| def test_close_decimal_is_allowed_at_two_percent(): | |
| result = validate_numeric( | |
| "Effect sizes were 1.20 and 0.57.", | |
| EVIDENCE, | |
| rel_tol=0.02, | |
| ) | |
| assert result["numeric_ok"] is True | |
| def test_large_decimal_difference_is_rejected(): | |
| result = validate_numeric( | |
| "Effect sizes were 1.30 and 0.57.", | |
| EVIDENCE, | |
| rel_tol=0.02, | |
| ) | |
| assert result["numeric_ok"] is False | |
| def test_specialized_numeric_types_are_preserved(): | |
| assert extract("Dose 1,5 mg.")[0].kind == "dose" | |
| assert extract("Response 20,5%.")[0].kind == "percent" | |
| assert extract("95% IC 0,74 à 1,64.")[0].kind == "ci" | |
| def test_contextual_integer_mismatch_is_rejected(): | |
| result = validate_numeric( | |
| "There were 23 studies.", | |
| EVIDENCE, | |
| rel_tol=0.0, | |
| ) | |
| assert result["numeric_ok"] is False | |
| def test_endpoint_contract_uses_exact_mode(): | |
| payload = { | |
| "items": [ | |
| { | |
| "id": 1, | |
| "claim": "Effect sizes were 1.19 and 0.57.", | |
| "evidence": EVIDENCE, | |
| }, | |
| { | |
| "id": 2, | |
| "claim": "Effect sizes were 1.20 and 0.57.", | |
| "evidence": EVIDENCE, | |
| }, | |
| ], | |
| "relative_tolerance": 0.0, | |
| } | |
| response = asyncio.run( | |
| post_validate_numeric(payload) | |
| ) | |
| assert response["results"][0]["numeric_ok"] is True | |
| assert response["results"][1]["numeric_ok"] is False | |