Source layer (5 court sources), processing pipeline (parse/extract/chunk/embed/graph), property graph with 8 node types, juror subgraph queries with 6 personas, orchestrator with bootstrap/watch/backfill/audit/process modes, 170 tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
117 lines
4.1 KiB
Python
117 lines
4.1 KiB
Python
"""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
|