import os import shutil import sys import tempfile import zipfile from pathlib import Path sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) from docx_comments import apply_docx_comments from models import ReviewFinding def _finding( *, finding_id: str = "test_finding_1", paragraph_id: str = "P_0008", target_text: str = "", anchor_mode: str = "paragraph", ) -> ReviewFinding: return ReviewFinding( id=finding_id, risk_level="high", clause_type="Indemnification", issue="Test issue", comment="This is a test comment from the Mike system.", review_reasoning={"clause_section": "test", "violated_standard": "test", "zamil_exposure": "Manual test run"}, target_text=target_text, anchor_mode=anchor_mode, start_paragraph_id=paragraph_id, end_paragraph_id=paragraph_id, start_anchor=target_text[:220], end_anchor=target_text[-220:] if target_text else "", before_anchor="", after_anchor="", confidence=1.0, ) def _write_minimal_table_docx(path: Path) -> None: path.parent.mkdir(parents=True, exist_ok=True) with zipfile.ZipFile(path, "w") as zf: zf.writestr( "[Content_Types].xml", """ """, ) zf.writestr( "_rels/.rels", """ """, ) zf.writestr( "word/document.xml", """Body paragraph.Table cell clause.""", ) def test_apply_paragraph_comment_without_target_text(): if shutil.which("dotnet") is None: import pytest pytest.skip("dotnet is required for the DOCX commenter integration test") root = Path(__file__).resolve().parents[1] sample_docx = root / "data" / "uploads" / "run_20260508_120049_e4b2552b55" / "test_contract.docx" output_docx = root / "data" / "artifacts" / "test_comments_output.docx" work_dir = root / "data" / "artifacts" / "test_comments_work" findings = [_finding(target_text="")] assert sample_docx.exists(), f"Missing test DOCX fixture: {sample_docx}" import tempfile with tempfile.TemporaryDirectory() as tmpdir: work_dir = Path(tmpdir) results = apply_docx_comments( input_docx=sample_docx, output_docx=output_docx, findings=findings, work_dir=work_dir, ) assert results assert results[0].id == "test_finding_1" assert results[0].status == "applied" assert results[0].failure_code == "editable" assert results[0].resolve_strategy == "paragraph_anchor" def test_apply_paragraph_comment_ignores_non_matching_quote_hint(): if shutil.which("dotnet") is None: import pytest pytest.skip("dotnet is required for the DOCX commenter integration test") root = Path(__file__).resolve().parents[1] sample_docx = root / "data" / "uploads" / "run_20260508_120049_e4b2552b55" / "test_contract.docx" output_docx = root / "data" / "artifacts" / "test_comments_output.docx" with tempfile.TemporaryDirectory() as tmpdir: results = apply_docx_comments( input_docx=sample_docx, output_docx=output_docx, findings=[_finding(target_text="this exact quote does not exist")], work_dir=Path(tmpdir), ) assert results[0].status == "applied" def test_apply_exact_comment_still_uses_target_text(): if shutil.which("dotnet") is None: import pytest pytest.skip("dotnet is required for the DOCX commenter integration test") root = Path(__file__).resolve().parents[1] sample_docx = root / "data" / "uploads" / "run_20260508_120049_e4b2552b55" / "test_contract.docx" output_docx = root / "data" / "artifacts" / "test_comments_output.docx" with tempfile.TemporaryDirectory() as tmpdir: results = apply_docx_comments( input_docx=sample_docx, output_docx=output_docx, findings=[_finding(paragraph_id="P_0007", target_text="Article 3: Indemnification", anchor_mode="exact")], work_dir=Path(tmpdir), ) assert results[0].status == "applied" assert results[0].resolve_strategy == "exact" def test_apply_paragraph_comment_invalid_block_id(): if shutil.which("dotnet") is None: import pytest pytest.skip("dotnet is required for the DOCX commenter integration test") root = Path(__file__).resolve().parents[1] sample_docx = root / "data" / "uploads" / "run_20260508_120049_e4b2552b55" / "test_contract.docx" output_docx = root / "data" / "artifacts" / "test_comments_output.docx" with tempfile.TemporaryDirectory() as tmpdir: results = apply_docx_comments( input_docx=sample_docx, output_docx=output_docx, findings=[_finding(paragraph_id="P_9999")], work_dir=Path(tmpdir), ) assert results[0].status == "not_applied" assert results[0].failure_code == "paragraph_not_found" def test_apply_paragraph_comment_hash_mismatch_reports_expected_and_actual(): if shutil.which("dotnet") is None: import pytest pytest.skip("dotnet is required for the DOCX commenter integration test") root = Path(__file__).resolve().parents[1] sample_docx = root / "data" / "uploads" / "run_20260508_120049_e4b2552b55" / "test_contract.docx" output_docx = root / "data" / "artifacts" / "test_comments_output.docx" finding = _finding().model_copy(update={"text_hash": "definitely_wrong"}) with tempfile.TemporaryDirectory() as tmpdir: results = apply_docx_comments( input_docx=sample_docx, output_docx=output_docx, findings=[finding], work_dir=Path(tmpdir), ) assert results[0].status == "not_applied" assert results[0].failure_code == "anchor_stale" assert results[0].expected_text_hash == "definitely_wrong" assert results[0].actual_text_hash assert results[0].actual_text_hash != results[0].expected_text_hash def test_apply_paragraph_comment_inside_table_cell(): if shutil.which("dotnet") is None: import pytest pytest.skip("dotnet is required for the DOCX commenter integration test") with tempfile.TemporaryDirectory() as tmpdir: tmp = Path(tmpdir) input_docx = tmp / "table.docx" output_docx = tmp / "table_commented.docx" _write_minimal_table_docx(input_docx) results = apply_docx_comments( input_docx=input_docx, output_docx=output_docx, findings=[_finding(paragraph_id="P_0002")], work_dir=tmp / "work", ) assert results[0].status == "applied" assert results[0].paragraph_id == "P_0002" if __name__ == "__main__": test_apply_paragraph_comment_without_target_text()