Files
TextNLPClassifierApp/tests/test_classifier.py
T
andreferraro 6a45368cb0 feat(extractor): implement multi-engine article content extractor
- Added scripts/extract_article_contents.py for batch scraping with stealth Foxcape and triple extraction (Trafilatura, Newspaper4k, Readability)
- Created unit, integration, and E2E test suite in tests/test_extract_article_contents.py (90/90 passing)
- Updated specs/003-article-content-extractor and README.md with usage documentation and CLI contracts
- Passed ruff linting/formatting and mypy type checking cleanly
2026-08-20 19:22:20 -03:00

101 lines
3.7 KiB
Python

"""Unit tests for deterministic classification decision logic."""
import pytest
from src.classifier import InherenceClassifier
from src.models import DecisionCategory, ECPSnapshot, RelatedEntity
@pytest.fixture
def petrobras_ecp():
return ECPSnapshot(
target_entity_id="ent_petrobras",
target_name="Petrobras",
aliases=["Petróleo Brasileiro S.A.", "Petrobras", "Petrobrás"],
domain="Oil & Gas",
anchors=["pré-sal", "refinaria", "combustíveis", "petróleo", "exploração"],
negative_anchors=["posto de combustíveis pirata"],
graph_version="1.0.0",
related_entities=[
RelatedEntity(
entity_id="ent_transpetro",
name="Transpetro",
relation_type="SUBSIDIARY_OF",
weight=0.85,
aliases=[],
scope="logistics",
confidence=1.0,
)
],
)
def test_direct_inherent(petrobras_ecp):
classifier = InherenceClassifier()
content = (
"# Expansão da Produção Nacional\n\n"
"A Petrobras anunciou um aumento expressivo na produção de petróleo na camada pré-sal. "
"Os investimentos em novas plataformas devem acelerar a exploração offshore."
)
result = classifier.classify(petrobras_ecp, content)
assert result.decision == DecisionCategory.DIRECT_INHERENT
assert result.is_inherent is True
assert result.confidence >= 0.85
assert result.detected_language == "pt"
assert "Petrobras" in result.matched_anchors
assert len(result.evidence) > 0
def test_contextual_inherent(petrobras_ecp):
classifier = InherenceClassifier()
content = (
"# Logística de Combustíveis no Brasil\n\n"
"A Transpetro ampliou a sua frota de navios para o transporte de combustíveis e derivados "
"pelo litoral brasileiro, reforçando a infraestrutura energética."
)
result = classifier.classify(petrobras_ecp, content)
assert result.decision == DecisionCategory.CONTEXTUAL_INHERENT
assert result.is_inherent is True
assert result.confidence >= 0.70
assert len(result.graph_matches) == 1
assert result.graph_matches[0]["name"] == "Transpetro"
def test_tangential_inherent(petrobras_ecp):
classifier = InherenceClassifier()
content = (
"# Crônica de Viagem pelo Interior\n\n"
"Passamos perto de um prédio da Petrobras enquanto procurávamos um café na praça central. "
"A tarde estava quente e os pássaros cantavam nas árvores antigas."
)
result = classifier.classify(petrobras_ecp, content)
assert result.decision == DecisionCategory.TANGENTIAL
assert result.is_inherent is False
assert result.confidence < 0.60
assert len(result.warnings) > 0
def test_not_related(petrobras_ecp):
classifier = InherenceClassifier()
content = (
"# Como Fazer Bolo de Cenoura com Cobertura de Chocolate\n\n"
"Bata as cenouras raladas no liquidificador com os ovos e o óleo. "
"Acrescente a farinha de trigo e o açúcar aos poucos até obter uma massa homogênea."
)
result = classifier.classify(petrobras_ecp, content)
assert result.decision == DecisionCategory.NOT_RELATED
assert result.is_inherent is False
assert result.confidence >= 0.85
def test_negative_anchor_suppression(petrobras_ecp):
classifier = InherenceClassifier()
content = (
"# Operação Policial Fecha Estabelecimento\n\n"
"A polícia interditou um posto de combustíveis pirata na rodovia estadual por adulteração."
)
result = classifier.classify(petrobras_ecp, content)
assert result.decision == DecisionCategory.NOT_RELATED
assert result.is_inherent is False
assert len(result.negative_matches) > 0