Files
rar-autopass/tests/test_heldout_eval.py
Claude Agent 3fc53534e2 feat(5.15+5.14): CLOSE — fix-uri code-review + embeddings functional
5.15 (propagare design + dashboard editare) si 5.14 (mapare LLM distilata)
inchise dupa /code-review high. 8 buguri reparate TDD:

- HIGH modal nu se deschidea pe randul slim (base.html: trimitere-slim)
- HIGH /repune trunchia prestatii (declaratie incompleta la RAR) -> iterare
  peste existing, codes pozitional
- HIGH embeddings incarca model ~230MB degeaba pe corpus gol -> poarta has_corpus()
- HIGH picker chips gol pe re-render eroare -> conn/account_id pe toate ramurile
- MED obs re-derivat dupa stergere explicita -> _merge_override pastreaza obs=''
- MED mapare salvata fara denumire poluă GOLD -> _record_gold_validation guard
- MED typo nome_prestatie -> nume_prestatie in select /repune
- MED bucketare timp +3h gresita iarna -> SQLite localtime + TZ=Europe/Bucharest

Embeddings WIRE-uit functional (PRD #15, decizie user): ensure_embeddings_corpus
construieste corpus din nomenclator, gated pe AUTOPASS_EMBEDDINGS_ENABLED (default
off). Marime model corectata ~50MB->~230MB (estimare PRD gresita).

Cleanup: hoist load_* din bucla bulk-fix; import re la top.
Regresie: 1256 passed, 1 deselected (live), 0 failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 20:48:34 +00:00

528 lines
22 KiB
Python

"""Teste TDD pentru tools/mapare-llm/heldout_eval.py (L14-S5).
Fixture sintetic cu predictii+ground_truth cunoscute. Verifica:
- precizie globala
- precizie per-cod (TP/FP/FN per eticheta)
- rata cod-gresit (critic: cod gresit = FINALIZATA ireversibil)
- esantionare stratificata determinista (acelasi seed = aceleasi rezultate)
- kill-criterion (pass/fail pe praguri definite)
Rulare: python3 -m pytest tests/test_heldout_eval.py -v
"""
from __future__ import annotations
import os
import sys
import csv
# Adaugam tools/mapare-llm/ la sys.path (pattern din test_holdout.py)
HERE = os.path.dirname(os.path.abspath(__file__))
TOOLS_DIR = os.path.abspath(os.path.join(HERE, "..", "tools", "mapare-llm"))
if TOOLS_DIR not in sys.path:
sys.path.insert(0, TOOLS_DIR)
import pytest
import heldout_eval as he
# ---------------------------------------------------------------------------
# Fixture sintetic pentru eval_predictions
# ---------------------------------------------------------------------------
# 6 intrari; 3 corecte, 1 cod-gresit (critic), 1 NUL fals-negativ, 1 nerezolvat
PREDS = [
{"denumire": "REVIZIE PERIODICA", "cod_pred": "OE-3"}, # corect
{"denumire": "SCHIMB ULEI MOTOR", "cod_pred": "OE-1"}, # GRESIT: gold=OE-3 (cod gresit!)
{"denumire": "DISCOUNT 10%", "cod_pred": "NUL"}, # corect
{"denumire": "VOPSIRE BARA FATA", "cod_pred": "OE-1"}, # corect
{"denumire": "DIAGNOSTICARE OBD", "cod_pred": "?"}, # nerezolvat
{"denumire": "D/R BARA FATA", "cod_pred": "OE-2"}, # GRESIT: gold=OE-1 (cod gresit!)
]
GOLD = [
{"denumire": "REVIZIE PERIODICA", "cod_gold": "OE-3"},
{"denumire": "SCHIMB ULEI MOTOR", "cod_gold": "OE-3"}, # pred=OE-1, gold=OE-3 -> COD GRESIT
{"denumire": "DISCOUNT 10%", "cod_gold": "NUL"},
{"denumire": "VOPSIRE BARA FATA", "cod_gold": "OE-1"},
{"denumire": "DIAGNOSTICARE OBD", "cod_gold": "OE-4"},
{"denumire": "D/R BARA FATA", "cod_gold": "OE-1"}, # pred=OE-2, gold=OE-1 -> COD GRESIT
]
# total=6, correct=3 (REVIZIE, DISCOUNT, VOPSIRE)
# wrong_code=2 (SCHIMB ULEI: OE-1 vs OE-3; D/R BARA: OE-2 vs OE-1)
# coverage_count=5 (pred!="?"), coverage_rate=5/6
# global_precision=3/6=0.50
# wrong_code_rate=2/6
# ---------------------------------------------------------------------------
# Sectiunea 1: eval_predictions — precizie globala
# ---------------------------------------------------------------------------
class TestEvalPrecizie:
"""Verifica metricile globale returnate de eval_predictions."""
def test_total_items(self):
"""total = numarul de intrari din ground_truth."""
m = he.eval_predictions(PREDS, GOLD)
assert m["total"] == 6
def test_correct_count(self):
"""3 predictii corecte din 6."""
m = he.eval_predictions(PREDS, GOLD)
assert m["correct"] == 3
def test_global_precision(self):
"""global_precision = correct / total = 3/6 = 0.50."""
m = he.eval_predictions(PREDS, GOLD)
assert abs(m["global_precision"] - 0.50) < 1e-9
def test_campuri_obligatorii(self):
"""Rezultatul contine toate campurile definite."""
m = he.eval_predictions(PREDS, GOLD)
obligatorii = [
"total", "correct", "global_precision",
"wrong_code_count", "wrong_code_rate",
"coverage_count", "coverage_rate",
"per_cod", "confusion_matrix",
]
for camp in obligatorii:
assert camp in m, f"Camp lipsa: {camp}"
def test_empty_inputs(self):
"""Input gol -> metrics cu valori zero, fara exceptie."""
m = he.eval_predictions([], [])
assert m["total"] == 0
assert m["global_precision"] == 0.0
assert m["wrong_code_rate"] == 0.0
def test_all_correct(self):
"""Toate corecte -> precision 1.0, wrong_code_rate 0.0."""
preds = [
{"denumire": "REVIZIE", "cod_pred": "OE-3"},
{"denumire": "ITP", "cod_pred": "NUL"},
]
gold = [
{"denumire": "REVIZIE", "cod_gold": "OE-3"},
{"denumire": "ITP", "cod_gold": "NUL"},
]
m = he.eval_predictions(preds, gold)
assert m["global_precision"] == 1.0
assert m["wrong_code_rate"] == 0.0
def test_predictie_lipsa_tratata_ca_nerezolvata(self):
"""Daca o denumire din gold nu e in predictions -> pred='?' (nerezolvat)."""
preds = [
{"denumire": "REVIZIE", "cod_pred": "OE-3"},
# SCHIMB ULEI lipseste din predictii
]
gold = [
{"denumire": "REVIZIE", "cod_gold": "OE-3"},
{"denumire": "SCHIMB ULEI", "cod_gold": "OE-3"},
]
m = he.eval_predictions(preds, gold)
assert m["total"] == 2
assert m["correct"] == 1 # doar REVIZIE
assert m["coverage_count"] == 1 # SCHIMB ULEI e "?"
# ---------------------------------------------------------------------------
# Sectiunea 2: eval_predictions — rata cod-gresit (CRITIC)
# ---------------------------------------------------------------------------
class TestWrongCodeRate:
"""
'Cod gresit' = pred in VALID_RAR, gold in VALID_RAR, pred != gold.
Aceasta situatie ar produce FINALIZATA ireversibil cu cod eronat.
"""
def test_wrong_code_count(self):
"""2 cod-gresit din 6 intrari."""
m = he.eval_predictions(PREDS, GOLD)
assert m["wrong_code_count"] == 2
def test_wrong_code_rate(self):
"""wrong_code_rate = 2/6."""
m = he.eval_predictions(PREDS, GOLD)
assert abs(m["wrong_code_rate"] - 2 / 6) < 1e-9
def test_nul_gresit_nu_e_cod_gresit(self):
"""pred=NUL si gold=OE-3 NU e 'cod gresit' (item merge la needs_mapping, nu la FINALIZATA)."""
preds = [{"denumire": "REVIZIE", "cod_pred": "NUL"}]
gold = [{"denumire": "REVIZIE", "cod_gold": "OE-3"}]
m = he.eval_predictions(preds, gold)
# pred=NUL nu genereaza FINALIZATA -> wrong_code_count=0
assert m["wrong_code_count"] == 0
def test_zero_wrong_code_pe_fixture_corect(self):
"""Pe fixture 'all correct', wrong_code_count = 0."""
preds = [{"denumire": "X", "cod_pred": "OE-1"}]
gold = [{"denumire": "X", "cod_gold": "OE-1"}]
m = he.eval_predictions(preds, gold)
assert m["wrong_code_count"] == 0
assert m["wrong_code_rate"] == 0.0
# ---------------------------------------------------------------------------
# Sectiunea 3: eval_predictions — acoperire (coverage)
# ---------------------------------------------------------------------------
class TestCoverage:
"""coverage = fractia de intrari cu pred != '?' (are un raspuns, fie cod fie NUL)."""
def test_coverage_count(self):
"""5 din 6 au pred != '?'."""
m = he.eval_predictions(PREDS, GOLD)
assert m["coverage_count"] == 5
def test_coverage_rate(self):
"""coverage_rate = 5/6."""
m = he.eval_predictions(PREDS, GOLD)
assert abs(m["coverage_rate"] - 5 / 6) < 1e-9
def test_coverage_zero_pe_toate_nerezolvate(self):
"""Daca toate pred='?' -> coverage=0."""
preds = [{"denumire": "X", "cod_pred": "?"}]
gold = [{"denumire": "X", "cod_gold": "OE-3"}]
m = he.eval_predictions(preds, gold)
assert m["coverage_count"] == 0
assert m["coverage_rate"] == 0.0
# ---------------------------------------------------------------------------
# Sectiunea 4: eval_predictions — per_cod (TP/FP/FN + precision/recall)
# ---------------------------------------------------------------------------
class TestPerCod:
"""Verifica metricile per eticheta (precizie + recall per cod)."""
def test_per_cod_returnat(self):
"""per_cod e un dict cu chei = etichete prezente."""
m = he.eval_predictions(PREDS, GOLD)
assert isinstance(m["per_cod"], dict)
assert len(m["per_cod"]) > 0
def test_per_cod_campuri(self):
"""Fiecare cod are tp, fp, fn, precision, recall."""
m = he.eval_predictions(PREDS, GOLD)
for cod, stats in m["per_cod"].items():
assert "tp" in stats, f"tp lipsa pentru {cod}"
assert "fp" in stats, f"fp lipsa pentru {cod}"
assert "fn" in stats, f"fn lipsa pentru {cod}"
assert "precision" in stats, f"precision lipsa pentru {cod}"
assert "recall" in stats, f"recall lipsa pentru {cod}"
def test_per_cod_oe1_precision(self):
"""OE-1: pred pt [VOPSIRE(corect), D/R BARA(gresit, gold=OE-1 dar pred=OE-2)].
Wait - pred=OE-1 pt VOPSIRE(gold=OE-1 corect) si SCHIMB ULEI(gold=OE-3 gresit).
TP=1(VOPSIRE), FP=1(SCHIMB ULEI pred=OE-1 dar gold=OE-3), FN=1(D/R BARA pred=OE-2 nu OE-1).
precision_OE1 = 1/(1+1) = 0.50
recall_OE1 = 1/(1+1) = 0.50
"""
m = he.eval_predictions(PREDS, GOLD)
oe1 = m["per_cod"].get("OE-1", {})
# TP: VOPSIRE BARA FATA (pred=OE-1, gold=OE-1)
# FP: SCHIMB ULEI MOTOR (pred=OE-1, gold=OE-3)
# FN: D/R BARA FATA (gold=OE-1, pred=OE-2)
assert oe1.get("tp") == 1
assert oe1.get("fp") == 1
assert oe1.get("fn") == 1
assert abs(oe1.get("precision") - 0.50) < 1e-9
assert abs(oe1.get("recall") - 0.50) < 1e-9
def test_per_cod_oe3_precision(self):
"""OE-3: pred pt [REVIZIE(corect)]. gold=OE-3 pt [REVIZIE, SCHIMB ULEI].
TP=1(REVIZIE), FP=0, FN=1(SCHIMB ULEI pred=OE-1).
precision=1.0, recall=0.50
"""
m = he.eval_predictions(PREDS, GOLD)
oe3 = m["per_cod"].get("OE-3", {})
assert oe3.get("tp") == 1
assert oe3.get("fp") == 0
assert oe3.get("fn") == 1
assert abs(oe3.get("precision") - 1.0) < 1e-9
assert abs(oe3.get("recall") - 0.50) < 1e-9
def test_per_cod_precision_none_pe_necunoscut(self):
"""Daca un cod e doar in gold (niciodata prezis) -> precision=None sau 0."""
# OE-4 e gold pt DIAGNOSTICARE, dar pred='?' -> FN=1, TP=0, FP=0
m = he.eval_predictions(PREDS, GOLD)
oe4 = m["per_cod"].get("OE-4", {})
# Precision nedefinita (0/0): None sau 0.0 ambele OK
assert oe4.get("tp") == 0
assert oe4.get("fp") == 0
assert oe4.get("fn") == 1
assert oe4.get("precision") is None or oe4.get("precision") == 0.0
# ---------------------------------------------------------------------------
# Sectiunea 5: eval_predictions — matrice confuzie
# ---------------------------------------------------------------------------
class TestConfusionMatrix:
"""Matricea confuzie indexata ca 'gold->pred'."""
def test_confusion_matrix_returnat(self):
"""confusion_matrix e un dict."""
m = he.eval_predictions(PREDS, GOLD)
assert isinstance(m["confusion_matrix"], dict)
def test_confusion_matrix_cod_gresit_prezent(self):
"""Cazul 'gold=OE-3, pred=OE-1' (SCHIMB ULEI) -> cheie 'OE-3->OE-1' cu count 1."""
m = he.eval_predictions(PREDS, GOLD)
assert m["confusion_matrix"].get("OE-3->OE-1") == 1
def test_confusion_matrix_corect(self):
"""Cazul corect 'gold=OE-3, pred=OE-3' (REVIZIE) -> cheie 'OE-3->OE-3' cu count 1."""
m = he.eval_predictions(PREDS, GOLD)
assert m["confusion_matrix"].get("OE-3->OE-3") == 1
# ---------------------------------------------------------------------------
# Sectiunea 6: sample_stratified — esantionare stratificata determinista
# ---------------------------------------------------------------------------
# Fixture: 20 iteme cu frecvente Zipf-like (suficient pt 3 strate)
SAMPLE_ROWS = [(f"op_{i:02d}", max(1, 2000 - i * 100)) for i in range(20)]
# Sortat descrescator: op_00=2000, op_01=1900, ..., op_19=100
# n=20, head_end = max(1, round(20*0.20)) = 4
# mid_end = max(5, round(20*0.50)) = 10
# cap = [op_00..op_03] (4 items)
# mijloc = [op_04..op_09] (6 items)
# coada = [op_10..op_19] (10 items)
class TestSampleStratified:
"""Verifica proprietatile esantionarii stratificate."""
def test_determinist_acelasi_seed(self):
"""Acelasi seed -> acelasi rezultat (determinist)."""
r1 = he.sample_stratified(SAMPLE_ROWS, n_sample=9, seed=42)
r2 = he.sample_stratified(SAMPLE_ROWS, n_sample=9, seed=42)
assert r1 == r2
def test_seed_diferit_rezultat_diferit(self):
"""Seed diferit -> (de obicei) rezultat diferit."""
r1 = he.sample_stratified(SAMPLE_ROWS, n_sample=9, seed=42)
r2 = he.sample_stratified(SAMPLE_ROWS, n_sample=9, seed=999)
# Nu garanteaza 100% diferenta, dar pe 20 items e practic garantat
assert r1 != r2
def test_items_din_input(self):
"""Toate itemele returnate exista in inputul original."""
result = he.sample_stratified(SAMPLE_ROWS, n_sample=9, seed=42)
input_set = {(d, n) for d, n in SAMPLE_ROWS}
for item in result:
assert (item["denumire"], item["nr"]) in input_set
def test_campuri_obligatorii(self):
"""Fiecare item are: denumire, nr, strat."""
result = he.sample_stratified(SAMPLE_ROWS, n_sample=9, seed=42)
for item in result:
assert "denumire" in item
assert "nr" in item
assert "strat" in item
def test_strat_valid(self):
"""Valorile strat sunt exclusiv din {'cap', 'mijloc', 'coada'}."""
result = he.sample_stratified(SAMPLE_ROWS, n_sample=9, seed=42)
for item in result:
assert item["strat"] in ("cap", "mijloc", "coada")
def test_toate_stratele_reprezentate(self):
"""Cand n_sample e suficient de mare, toate 3 stratele apar in rezultat."""
# n_sample=15 dintr-un total de 20 -> toate stratele au cel putin 1 item
result = he.sample_stratified(SAMPLE_ROWS, n_sample=15, seed=42)
strate_prezente = {item["strat"] for item in result}
assert "cap" in strate_prezente
assert "mijloc" in strate_prezente
assert "coada" in strate_prezente
def test_dimensiune_aproape_de_n_sample(self):
"""Dimensiunea rezultatului e aproape de n_sample (+/- 3 datorita rotunjirii)."""
n_sample = 9
result = he.sample_stratified(SAMPLE_ROWS, n_sample=n_sample, seed=42)
assert abs(len(result) - n_sample) <= 3
def test_fara_duplicate(self):
"""Niciun item nu apare de doua ori in esantion."""
result = he.sample_stratified(SAMPLE_ROWS, n_sample=15, seed=42)
denumiri = [item["denumire"] for item in result]
assert len(denumiri) == len(set(denumiri))
def test_input_gol(self):
"""Input gol -> returneaza lista goala fara exceptie."""
result = he.sample_stratified([], n_sample=10, seed=42)
assert result == []
def test_n_sample_mai_mare_decat_corpus(self):
"""Cand n_sample > len(rows), returneaza cel mult len(rows) items."""
result = he.sample_stratified(SAMPLE_ROWS, n_sample=1000, seed=42)
assert len(result) <= len(SAMPLE_ROWS)
# ---------------------------------------------------------------------------
# Sectiunea 7: export_for_labeling — fisier CSV pt etichetare umana
# ---------------------------------------------------------------------------
class TestExportForLabeling:
"""Exportul CSV contine denumire, nr, strat si coloana cod_gold GOALA."""
def test_fisier_creat(self, tmp_path):
"""Fisierul este creat la calea specificata."""
sample = he.sample_stratified(SAMPLE_ROWS, n_sample=5, seed=42)
path = str(tmp_path / "esantion.csv")
he.export_for_labeling(sample, path)
assert os.path.exists(path)
def test_header_csv(self, tmp_path):
"""CSV-ul are header-ul corect: denumire;nr;strat;cod_gold."""
sample = he.sample_stratified(SAMPLE_ROWS, n_sample=5, seed=42)
path = str(tmp_path / "esantion.csv")
he.export_for_labeling(sample, path)
with open(path, encoding="utf-8-sig") as f:
reader = csv.DictReader(f, delimiter=";")
coloane = reader.fieldnames
assert "denumire" in coloane
assert "nr" in coloane
assert "strat" in coloane
assert "cod_gold" in coloane
def test_cod_gold_gol(self, tmp_path):
"""Coloana cod_gold e goala (de completat de operator uman)."""
sample = he.sample_stratified(SAMPLE_ROWS, n_sample=5, seed=42)
path = str(tmp_path / "esantion.csv")
he.export_for_labeling(sample, path)
with open(path, encoding="utf-8-sig") as f:
reader = csv.DictReader(f, delimiter=";")
for row in reader:
# Coloana cod_gold trebuie sa fie vida (nu etichetata de cod!)
assert row["cod_gold"] == "", (
"cod_gold nu trebuie pre-completat: ar fi 'antrenare pe test' "
"(Decision #19 PRD 5.14)"
)
def test_n_randuri_egal_cu_sample(self, tmp_path):
"""CSV-ul are exact atatea randuri cat esantionul."""
sample = he.sample_stratified(SAMPLE_ROWS, n_sample=5, seed=42)
path = str(tmp_path / "esantion.csv")
he.export_for_labeling(sample, path)
with open(path, encoding="utf-8-sig") as f:
rows = list(csv.DictReader(f, delimiter=";"))
assert len(rows) == len(sample)
# ---------------------------------------------------------------------------
# Sectiunea 8: kill_criterion — pragul de acceptanta (F-E, PRD 5.14)
# ---------------------------------------------------------------------------
class TestKillCriterion:
"""
Kill-criterion (F-E): sistemul TRECE daca
wrong_code_rate < wrong_code_threshold (default 0.5%)
SI coverage_rate > coverage_threshold (default 50%).
Justificare threshold 0.5% (0.005):
Un service cu 200 operatii/zi auto-rezolvate = 1 FINALIZATA gresita/zi.
FINALIZATA e ireversibila (cf. PRD 5.14 Premisa 3 / invariant CLAUDE.md).
Pragul poate fi RELAXAT empiric; nu INASPRIT post-hoc (sesizare-in-timp).
"""
def test_trece_cand_sub_prag(self):
"""Trece cand wrong_code_rate < threshold si coverage_rate > min_coverage."""
metrics = {
"wrong_code_rate": 0.003, # 0.3% < 0.5%
"coverage_rate": 0.70, # 70% > 50%
}
r = he.kill_criterion(metrics)
assert r["passes"] is True
def test_esueaza_cand_wrong_code_prea_mare(self):
"""Esueaza cand wrong_code_rate >= threshold."""
metrics = {
"wrong_code_rate": 0.02, # 2% > 0.5% -> FAIL
"coverage_rate": 0.70,
}
r = he.kill_criterion(metrics)
assert r["passes"] is False
assert "wrong_code" in r["reason"].lower() or "cod gresit" in r["reason"].lower()
def test_esueaza_cand_coverage_prea_mica(self):
"""Esueaza cand coverage_rate < min_coverage_threshold."""
metrics = {
"wrong_code_rate": 0.001,
"coverage_rate": 0.30, # 30% < 50% -> FAIL
}
r = he.kill_criterion(metrics)
assert r["passes"] is False
assert "acoperire" in r["reason"].lower() or "coverage" in r["reason"].lower()
def test_esueaza_pe_ambele_conditii(self):
"""Esueaza cand ambele conditii sunt incalcate."""
metrics = {
"wrong_code_rate": 0.05,
"coverage_rate": 0.10,
}
r = he.kill_criterion(metrics)
assert r["passes"] is False
def test_campuri_obligatorii_in_rezultat(self):
"""Rezultatul are: passes, reason, wrong_code_rate, coverage_rate, thresholds."""
metrics = {"wrong_code_rate": 0.001, "coverage_rate": 0.80}
r = he.kill_criterion(metrics)
for camp in ("passes", "reason", "wrong_code_rate", "coverage_rate", "thresholds"):
assert camp in r, f"Camp lipsa: {camp}"
def test_threshold_customizabil(self):
"""Pragurile pot fi suprascrise."""
metrics = {"wrong_code_rate": 0.05, "coverage_rate": 0.80}
# Cu threshold mai lax, trece
r = he.kill_criterion(metrics, wrong_code_threshold=0.10)
assert r["passes"] is True
def test_exact_pe_prag_nu_trece(self):
"""Pe prag exact (egalitate), nu trece (< e strict)."""
threshold = he.DEFAULT_WRONG_CODE_THRESHOLD
metrics = {"wrong_code_rate": threshold, "coverage_rate": 0.80}
r = he.kill_criterion(metrics)
# wrong_code_rate = threshold -> NU < threshold -> FAIL
assert r["passes"] is False
def test_reason_descrie_starea(self):
"""reason e un string non-gol care descrie de ce trece/esueaza."""
metrics = {"wrong_code_rate": 0.001, "coverage_rate": 0.80}
r = he.kill_criterion(metrics)
assert isinstance(r["reason"], str)
assert len(r["reason"]) > 0
# ---------------------------------------------------------------------------
# Sectiunea 9: constante si metadate modul
# ---------------------------------------------------------------------------
class TestModulMetadata:
"""Verifica existenta constantelor documentate."""
def test_valid_rar_definit(self):
"""VALID_RAR e un set non-gol de coduri RAR."""
assert hasattr(he, "VALID_RAR")
assert isinstance(he.VALID_RAR, frozenset)
assert len(he.VALID_RAR) >= 18
def test_nul_in_all_labels_nu_in_valid_rar(self):
"""NUL e eticheta speciala (supresie), NU e cod RAR valid."""
assert "NUL" not in he.VALID_RAR
# NUL trebuie sa fie accesibil totusi
assert hasattr(he, "NUL")
assert he.NUL == "NUL"
def test_default_seed(self):
"""DEFAULT_SEED exista si e intreg."""
assert hasattr(he, "DEFAULT_SEED")
assert isinstance(he.DEFAULT_SEED, int)
def test_default_thresholds_in_range(self):
"""Pragurile default sunt in (0, 1)."""
assert 0 < he.DEFAULT_WRONG_CODE_THRESHOLD < 1
assert 0 < he.DEFAULT_COVERAGE_THRESHOLD < 1