"""Extended tests for app/tasks/imap_tasks.py module.""" import json import os from email.message import EmailMessage from unittest.mock import MagicMock, patch import pytest from app.tasks.imap_tasks import ( fetch_attachments_and_enqueue, find_all_mail_xlist, save_processed_emails, ) @pytest.mark.unit class TestSaveProcessedEmails: """Tests for save_processed_emails function.""" @patch("app.tasks.imap_tasks.CACHE_FILE", "/tmp/test_save_processed.json") def test_saves_to_file(self): """Test that processed emails are saved to file.""" emails = {"msg-1": "2024-01-01T00:00:00", "msg-2": "2024-01-02T00:00:00"} save_processed_emails(emails) assert os.path.exists("/tmp/test_save_processed.json") with open("/tmp/test_save_processed.json") as f: loaded = json.load(f) assert loaded == emails os.remove("/tmp/test_save_processed.json") @pytest.mark.unit class TestFetchAttachmentsExtended: """Extended tests for fetch_attachments_and_enqueue.""" @patch("app.tasks.imap_tasks.process_document") @patch("app.tasks.imap_tasks.convert_to_pdf") def test_processes_pdf_by_extension(self, mock_convert, mock_process, tmp_path): """Test PDF detection by extension even with wrong MIME type.""" msg = EmailMessage() msg["Subject"] = "Test" # Create attachment with wrong MIME type but .pdf extension msg.add_attachment(b"%PDF-1.4", maintype="application", subtype="octet-stream", filename="invoice.pdf") with patch("app.tasks.imap_tasks.settings") as mock_settings: mock_settings.workdir = str(tmp_path) result = fetch_attachments_and_enqueue(msg) assert result is True mock_process.delay.assert_called_once() @patch("app.tasks.imap_tasks.process_document") @patch("app.tasks.imap_tasks.convert_to_pdf") def test_processes_text_attachment(self, mock_convert, mock_process, tmp_path): """Test text/plain attachment is sent for conversion.""" msg = EmailMessage() msg["Subject"] = "Test" msg.add_attachment(b"Hello world", maintype="text", subtype="plain", filename="notes.txt") with patch("app.tasks.imap_tasks.settings") as mock_settings: mock_settings.workdir = str(tmp_path) result = fetch_attachments_and_enqueue(msg) assert result is True mock_convert.delay.assert_called_once() @patch("app.tasks.imap_tasks.process_document") @patch("app.tasks.imap_tasks.convert_to_pdf") def test_skips_multipart(self, mock_convert, mock_process): """Test that multipart parts are skipped.""" msg = EmailMessage() msg["Subject"] = "Test" msg.set_content("Hello body") # multipart text is skipped result = fetch_attachments_and_enqueue(msg) assert result is False @patch("app.tasks.imap_tasks.process_document") @patch("app.tasks.imap_tasks.convert_to_pdf") def test_no_attachments(self, mock_convert, mock_process): """Test email with no attachments.""" msg = EmailMessage() msg["Subject"] = "No attachments" msg.set_content("Plain text body") result = fetch_attachments_and_enqueue(msg) assert result is False @pytest.mark.unit class TestFindAllMailXlist: """Tests for find_all_mail_xlist function.""" def test_finds_all_mail_via_xlist(self): """Test finding All Mail folder via XLIST.""" mock_mail = MagicMock() mock_mail._new_tag.return_value = b"A001" # Simulate XLIST response mock_mail.readline.side_effect = [ b'* XLIST (\\AllMail) "/" "[Gmail]/All Mail"\r\n', b"A001 OK XLIST completed\r\n", ] result = find_all_mail_xlist(mock_mail) assert result == "[Gmail]/All Mail" def test_returns_none_when_no_allmail(self): """Test returns None when XLIST doesn't find All Mail.""" mock_mail = MagicMock() mock_mail._new_tag.return_value = b"A001" mock_mail.readline.side_effect = [ b'* XLIST (\\Inbox) "/" "INBOX"\r\n', b"A001 OK XLIST completed\r\n", ] result = find_all_mail_xlist(mock_mail) assert result is None