""" tests/test_validator.py — Tests for post-generation citation validator """ import sys from pathlib import Path import pytest sys.path.insert(0, str(Path(__file__).parent.parent)) from models import EvidenceChunk from generation.validator import CitationValidator, ValidationReport @pytest.fixture def validator(): return CitationValidator() @pytest.fixture def evidence(): return [ EvidenceChunk(chunk_id="aabb001100000000", text="Contract text.", source_file="f.pdf", score=0.9), EvidenceChunk(chunk_id="ccdd002200000000", text="Payment terms.", source_file="f.pdf", score=0.8), ] class TestValidator: def test_fully_cited_draft(self, validator, evidence): draft = ( "## 1. Document Overview\n" "The contract was signed in January. [CHUNK-aabb0011]\n" "## 2. Parties and Roles\n" "Payment is $25,000 monthly. [CHUNK-ccdd0022]\n" "## 3. Key Facts and Dates\n" "The term is 12 months. [CHUNK-aabb0011]\n" "## 4. Obligations and Terms\n" "Late fees apply at 1.5%. [CHUNK-ccdd0022]\n" "## 5. Red Flags and Issues\n" "Limitation clause may be unenforceable. [CHUNK-aabb0011]\n" "## 6. Analyst Notes\n" "Recommend further review of liability cap. [CHUNK-ccdd0022]\n" ) report = validator.validate(draft, evidence) assert report.uncited_ratio < 0.10 assert report.is_clean() assert report.severity() == "green" def test_uncited_sentences_detected(self, validator, evidence): draft = ( "## 1. Document Overview\n" "The contract was signed in January. [CHUNK-aabb0011]\n" "This sentence has no citation and is long enough to count.\n" "Another uncited claim that should be flagged by the validator.\n" ) report = validator.validate(draft, evidence) assert len(report.uncited_sentences) == 2 assert report.uncited_ratio > 0 def test_invalid_citation_detected(self, validator, evidence): draft = "The contract mentions something. [CHUNK-deadbeef]\n" report = validator.validate(draft, evidence) assert len(report.invalid_citations) == 1 def test_not_evidenced_marker(self, validator, evidence): draft = "The jurisdiction is not stated. [NOT EVIDENCED]\n" report = validator.validate(draft, evidence) assert report.not_evidenced_count == 1 assert len(report.uncited_sentences) == 0 def test_section_completeness(self, validator, evidence): draft = "## 1. Document Overview\nSome text. [CHUNK-aabb0011]\n" report = validator.validate(draft, evidence) assert len(report.missing_sections) > 0 assert report.section_completeness < 1.0 def test_empty_draft(self, validator, evidence): report = validator.validate("", evidence) assert report.total_sentences == 0 class TestValidationReport: def test_severity_green(self): r = ValidationReport(uncited_ratio=0.05) assert r.severity() == "green" def test_severity_yellow(self): r = ValidationReport(uncited_ratio=0.15) assert r.severity() == "yellow" def test_severity_red(self): r = ValidationReport(uncited_ratio=0.30) assert r.severity() == "red" def test_to_dict(self): r = ValidationReport(total_sentences=10, cited_sentences=8) d = r.to_dict() assert "total_sentences" in d assert "severity" in d