aucourt-ingest/tests/test_outcome_parser.py

118 lines
4.1 KiB
Python
Raw Permalink Normal View History

"""Tests for OutcomeParser."""
import json
import pytest
from aucourt_ingest.processing.outcome_parser import OutcomeParser, VALID_VERDICTS
@pytest.fixture
def parser():
return OutcomeParser()
class TestHeadnotePattern:
def test_held_conviction_quashed(self, parser):
text = "HELD: conviction quashed. The appeal is allowed."
result = parser.parse(text)
assert result["verdict"] == "conviction_quashed"
assert result["resolution_method"] == "held"
def test_held_acquittal(self, parser):
text = "HELD: the accused is acquitted of all charges."
result = parser.parse(text)
assert result["verdict"] == "not_guilty"
class TestAppealPatterns:
def test_appeal_allowed(self, parser):
text = "The Court orders that the appeal is allowed."
result = parser.parse(text)
assert result["verdict"] == "appeal_allowed"
def test_appeal_dismissed(self, parser):
text = "The appeal is dismissed."
result = parser.parse(text)
assert result["verdict"] == "appeal_dismissed"
def test_convictions_quashed(self, parser):
text = "Appeal allowed. Convictions on counts 1 and 3 are quashed."
result = parser.parse(text)
# "Appeal allowed" matches first — this is correct priority behavior
assert result["verdict"] == "appeal_allowed"
def test_set_aside(self, parser):
text = "The convictions are set aside."
result = parser.parse(text)
assert result["verdict"] == "conviction_quashed"
class TestGuiltyNotGuiltyPatterns:
def test_guilty(self, parser):
text = "The jury returns a verdict of guilty on the charge of murder."
result = parser.parse(text)
assert result["verdict"] == "guilty"
def test_not_guilty(self, parser):
text = "The jury returns a verdict of not guilty."
result = parser.parse(text)
assert result["verdict"] == "not_guilty"
def test_found_guilty(self, parser):
text = "The Court found the accused guilty."
result = parser.parse(text)
assert result["verdict"] == "guilty"
class TestHungJury:
def test_hung_jury(self, parser):
text = "After three days of deliberation, the jury was unable to reach a verdict and was discharged."
result = parser.parse(text)
assert result["verdict"] == "hung"
class TestSentenceExtraction:
def test_sentence_found(self, parser):
text = "I sentence the offender to imprisonment for 25 years."
result = parser.parse(text)
assert result["sentence"] is not None
assert "25" in result["sentence"]
class TestExonerationSources:
def test_exoneration_lookup(self, tmp_path):
exon_data = {"john smith_2015": {"verdict": "conviction_quashed", "notes": "Wrongful conviction"}}
p = tmp_path / "exoneration.json"
p.write_text(json.dumps(exon_data))
parser = OutcomeParser()
parser.load_exoneration_sources(p)
result = parser.parse("some text", case_name="John Smith", year=2015)
assert result["verdict"] == "conviction_quashed"
assert result["resolution_method"] == "exoneration"
class TestAppealCrossReference:
def test_appeal_allowed_updates_original(self, parser):
updated = parser.apply_appeal_cross_reference("guilty", "appeal_allowed")
assert updated == "conviction_quashed"
def test_appeal_dismissed_keeps_original(self, parser):
updated = parser.apply_appeal_cross_reference("guilty", "appeal_dismissed")
assert updated == "guilty"
def test_no_appeal_keeps_original(self, parser):
updated = parser.apply_appeal_cross_reference("not_guilty", None)
assert updated == "not_guilty"
class TestNoMatch:
def test_no_verdict_found(self, parser):
text = "The Court heard submissions from both parties regarding procedural matters."
result = parser.parse(text)
assert result["verdict"] is None
assert result["resolution_method"] is None
def test_empty_text(self, parser):
result = parser.parse("")
assert result["verdict"] is None