"""Shared fixtures for web services tests.""" import pytest from unittest.mock import Mock, MagicMock, patch @pytest.fixture(autouse=True) def _allow_socket_subscribe(): """Mock the chat-mode socket-subscribe ownership check. See the matching conftest in ``tests/web/services/conftest.py`` for full context. Pre-existing socket tests in this directory don't set up a Flask request context, so without this autouse fixture the new ``session.get("username")`` lookup in ``__handle_subscribe`` raises ``RuntimeError: Working outside of request context``. Tests in this directory import via ``local_deep_research.web...`` (no ``src.`` prefix). Patch BOTH paths because Python may treat the two import paths as distinct module identities depending on how the package is installed. """ # Resolve the module from whichever path is importable. try: from local_deep_research.web.services.socket_service import ( SocketIOService, ) module_path = "local_deep_research.web.services.socket_service" except ImportError: from src.local_deep_research.web.services.socket_service import ( SocketIOService, ) module_path = "src.local_deep_research.web.services.socket_service" with ( patch(f"{module_path}.session", {"username": "test-owner"}), patch.object(SocketIOService, "_user_owns_research", return_value=True), ): yield @pytest.fixture def sample_markdown(): """Sample markdown content for testing.""" return """# Test Document This is a test document with **bold** and *italic* text. ## Section 1 A paragraph with some content. | Column 1 | Column 2 | |----------|----------| | Data 1 | Data 2 | ## Section 2 - Item 1 - Item 2 - Item 3 ```python def example(): return "code block" ``` """ @pytest.fixture def simple_markdown(): """Minimal markdown for basic tests.""" return "# Hello World\n\nThis is a test." @pytest.fixture def markdown_with_special_chars(): """Markdown with special characters.""" return """# Special Characters Testing: <>&"' Unicode: café, naïve, 日本語 Symbols: © ® ™ € £ ¥ """ @pytest.fixture def sample_metadata(): """Sample metadata for PDF generation.""" return { "author": "Test Author", "date": "2024-01-15", "subject": "Test Subject", } @pytest.fixture def custom_css(): """Custom CSS for PDF styling.""" return """ body { font-family: 'Times New Roman', serif; font-size: 12pt; } h1 { color: navy; } """ @pytest.fixture def valid_pdf_bytes(): """Generate valid minimal PDF bytes for testing extraction.""" # This is a minimal valid PDF structure pdf_content = b"""%PDF-1.4 1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj 2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj 3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >> endobj 4 0 obj << /Length 44 >> stream BT /F1 12 Tf 100 700 Td (Hello World) Tj ET endstream endobj 5 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> endobj xref 0 6 0000000000 65535 f 0000000009 00000 n 0000000058 00000 n 0000000115 00000 n 0000000266 00000 n 0000000359 00000 n trailer << /Size 6 /Root 1 0 R >> startxref 434 %%EOF""" return pdf_content @pytest.fixture def invalid_pdf_bytes(): """Invalid/corrupted PDF bytes.""" return b"This is not a valid PDF file" @pytest.fixture def empty_file_bytes(): """Empty file bytes.""" return b"" @pytest.fixture def mock_flask_app(): """Mock Flask app for socket service testing.""" app = Mock() app.config = {} return app @pytest.fixture def mock_socketio(): """Mock SocketIO instance.""" socketio = Mock() socketio.emit = Mock(return_value=None) socketio.on = Mock(return_value=lambda f: f) socketio.on_error = Mock(return_value=lambda f: f) socketio.on_error_default = Mock(return_value=lambda f: f) socketio.run = Mock() return socketio @pytest.fixture def mock_request(): """Mock Flask request object.""" request = Mock() request.sid = "test-session-id-123" return request @pytest.fixture def sample_research_id(): """Sample research ID for testing.""" return "research-abc-123" @pytest.fixture def sample_sources(): """Sample sources for research sources service.""" return [ { "title": "Source 1", "url": "https://example.com/source1", "snippet": "This is the first source snippet.", "full_content": "Full content of source 1.", }, { "link": "https://example.com/source2", # Alternative key "name": "Source 2", # Alternative key "snippet": "Second source snippet.", }, { "title": "Source 3", "url": "https://example.com/source3", "snippet": "Third source with a very long snippet that should be truncated " * 50, }, ] @pytest.fixture def mock_db_session(): """Mock database session.""" session = MagicMock() session.__enter__ = Mock(return_value=session) session.__exit__ = Mock(return_value=False) return session @pytest.fixture def mock_research_resource(): """Mock ResearchResource model instance.""" resource = Mock() resource.id = 1 resource.research_id = "research-abc-123" resource.title = "Test Resource" resource.url = "https://example.com/resource" resource.content_preview = "Preview content" resource.source_type = "web" resource.resource_metadata = {"key": "value"} return resource