from unittest.mock import MagicMock, patch from datetime import datetime from app.domain.compliance.ports import ( AnalysisRecord, FindingRecord, ComplianceRepository, ) def _mock_pool(): """Return a mock psycopg2 ThreadedConnectionPool.""" conn = MagicMock() cursor = MagicMock() cursor.__enter__ = MagicMock(return_value=cursor) cursor.__exit__ = MagicMock(return_value=False) conn.cursor.return_value = cursor pool = MagicMock() pool.getconn.return_value = conn return pool, conn, cursor @patch("app.infrastructure.compliance.repository.psycopg2.pool.ThreadedConnectionPool") def test_save_analysis_returns_uuid(mock_pool_cls): from app.infrastructure.compliance.repository import PostgresComplianceRepository pool, conn, cursor = _mock_pool() mock_pool_cls.return_value = pool cursor.fetchone.return_value = {"id": "abc-123"} repo = PostgresComplianceRepository( host="localhost", port=5432, user="u", password="p", dbname="db" ) record = AnalysisRecord( id="", created_at=datetime.utcnow(), created_by="user1", doc_name="doc.pdf", standard_name="EU AI Act", risk_score=50, conclusion="OK", actions=[], para_text="p", highlight_terms=[], findings=[], ) result = repo.save_analysis(record) assert result == "abc-123" def test_analysis_record_construction(): record = AnalysisRecord( id="", created_at=datetime.utcnow(), created_by="user1", doc_name="test.pdf", standard_name="EU AI Act", risk_score=72, conclusion="Several gaps found.", actions=[{"label": "Fix", "value": "Update docs"}], para_text="The system shall...", highlight_terms=["CSMS", "ISO 21434"], findings=[ FindingRecord( id="", analysis_id="", seq=0, title="Missing CSMS", description="No CSMS certification found.", status="risk", clause_ref="Art.9.1", ) ], ) assert record.doc_name == "test.pdf" assert len(record.findings) == 1 assert record.findings[0].status == "risk" def test_compliance_repository_is_abstract(): import inspect assert inspect.isabstract(ComplianceRepository) def test_generate_docx_returns_bytes(): from app.infrastructure.compliance.docx_export import generate_docx record = AnalysisRecord( id="test-id", created_at=datetime(2026, 6, 8), created_by="user1", doc_name="test.pdf", standard_name="EU AI Act", risk_score=72, conclusion="Several gaps found.", actions=[{"label": "Fix", "value": "Update CSMS docs"}], para_text="The system shall implement CSMS.", highlight_terms=["CSMS"], findings=[ FindingRecord( id="f1", analysis_id="test-id", seq=0, title="Missing CSMS", description="No CSMS cert.", status="risk", clause_ref="Art.9.1", ) ], ) data = generate_docx(record) assert isinstance(data, bytes) assert len(data) > 1000 # DOCX is at minimum a ZIP with ~1 KB overhead # Verify it's a valid ZIP (DOCX = ZIP container) import zipfile, io assert zipfile.is_zipfile(io.BytesIO(data))