import pytest from unittest.mock import Mock, patch, MagicMock from datetime import datetime, timedelta from app.email_processor import EmailProcessor from app.models import User, Folder, ProcessedEmail def test_email_processor_initialization(): """Test that EmailProcessor initializes correctly.""" # Create a mock user mock_user = Mock(spec=User) mock_user.id = 1 mock_user.email = 'test@example.com' mock_user.imap_config = {'username': 'user', 'password': 'pass'} # Initialize processor processor = EmailProcessor(mock_user) # Verify initialization assert processor.user == mock_user assert processor.logger is not None @patch('app.email_processor.EmailProcessor._process_email_batch') def test_process_folder_emails_no_pending(mock_batch): """Test processing a folder with no pending emails.""" # Create mocks mock_user = Mock(spec=User) mock_user.id = 1 mock_folder = Mock(spec=Folder) mock_folder.id = 1 mock_folder.name = 'Test Folder' mock_folder.rule_text = 'move to Archive' # Mock the processed emails service with patch('app.email_processor.ProcessedEmailsService') as mock_service: mock_service_instance = mock_service.return_value mock_service_instance.get_pending_emails.return_value = [] # Initialize processor processor = EmailProcessor(mock_user) result = processor.process_folder_emails(mock_folder) # Verify results assert result['processed_count'] == 0 assert result['error_count'] == 0 assert mock_batch.called is False @patch('app.email_processor.EmailProcessor._process_email_batch') def test_process_folder_emails_with_pending(mock_batch): """Test processing a folder with pending emails.""" # Create mocks mock_user = Mock(spec=User) mock_user.id = 1 mock_folder = Mock(spec=Folder) mock_folder.id = 1 mock_folder.name = 'Test Folder' mock_folder.rule_text = 'move to Archive' # Mock the processed emails service with patch('app.email_processor.ProcessedEmailsService') as mock_service: mock_service_instance = mock_service.return_value mock_service_instance.get_pending_emails.return_value = ['1', '2', '3'] # Setup batch processing mock mock_batch.return_value = {'processed_count': 3, 'error_count': 0} # Initialize processor processor = EmailProcessor(mock_user) result = processor.process_folder_emails(mock_folder) # Verify results assert result['processed_count'] == 3 assert result['error_count'] == 0 mock_batch.assert_called_once() @patch('app.email_processor.EmailProcessor._update_folder_counts') def test_process_user_emails_no_folders(mock_update): """Test processing user emails with no folders to process.""" # Create mock user mock_user = Mock(spec=User) mock_user.id = 1 mock_user.email = 'test@example.com' # Mock the database query with patch('app.email_processor.Folder') as mock_folder: mock_folder.query.filter_by.return_value.order_by.return_value.all.return_value = [] # Initialize processor processor = EmailProcessor(mock_user) result = processor.process_user_emails() # Verify results assert result['success_count'] == 0 assert result['error_count'] == 0 assert len(result['processed_folders']) == 0 mock_update.assert_not_called() @patch('app.email_processor.EmailProcessor._update_folder_counts') def test_process_user_emails_with_folders(mock_update): """Test processing user emails with folders to process.""" # Create mock user mock_user = Mock(spec=User) mock_user.id = 1 mock_user.email = 'test@example.com' # Create mock folder mock_folder = Mock(spec=Folder) mock_folder.id = 1 mock_folder.name = 'Test Folder' mock_folder.rule_text = 'move to Archive' mock_folder.priority = 1 # Mock the database query with patch('app.email_processor.Folder') as mock_folder_class: mock_folder_class.query.filter_by.return_value.order_by.return_value.all.return_value = [mock_folder] # Mock the process_folder_emails method with patch('app.email_processor.EmailProcessor.process_folder_emails') as mock_process: mock_process.return_value = { 'processed_count': 5, 'error_count': 0 } # Initialize processor processor = EmailProcessor(mock_user) result = processor.process_user_emails() # Verify results assert result['success_count'] == 5 assert result['error_count'] == 0 assert len(result['processed_folders']) == 1 mock_process.assert_called_once() @patch('app.email_processor.EmailProcessor._move_email') def test_process_email_batch_success(mock_move): """Test processing an email batch successfully.""" # Create mocks mock_user = Mock(spec=User) mock_user.id = 1 mock_user.imap_config = {'username': 'user', 'password': 'pass'} mock_folder = Mock(spec=Folder) mock_folder.id = 1 mock_folder.name = 'Source' mock_folder.rule_text = 'move to Archive' # Mock IMAP service with patch('app.email_processor.IMAPService') as mock_imap: mock_imap_instance = mock_imap.return_value mock_imap_instance._connect.return_value = None mock_imap_instance.connection.login.return_value = ('OK', []) mock_imap_instance.connection.select.return_value = ('OK', []) mock_imap_instance.get_email_headers.return_value = { 'subject': 'Test Email', 'from': 'sender@example.com' } # Mock rule evaluation with patch('app.email_processor.EmailProcessor._evaluate_rules') as mock_evaluate: mock_evaluate.return_value = 'Archive' mock_move.return_value = True # Mock processed emails service with patch('app.email_processor.ProcessedEmailsService') as mock_service: mock_service_instance = mock_service.return_value mock_service_instance.mark_emails_processed.return_value = 1 # Initialize processor processor = EmailProcessor(mock_user) result = processor._process_email_batch(mock_folder, ['1']) # Verify results assert result['processed_count'] == 1 assert result['error_count'] == 0 mock_move.assert_called_once() def test_evaluate_rules_no_rule_text(): """Test rule evaluation with no rule text.""" # Create mocks mock_user = Mock(spec=User) mock_folder = Mock(spec=Folder) # Initialize processor processor = EmailProcessor(mock_user) # Test with None rule text result = processor._evaluate_rules({'subject': 'Test'}, None) assert result is None # Test with empty rule text result = processor._evaluate_rules({'subject': 'Test'}, '') assert result is None def test_evaluate_rules_with_move_to(): """Test rule evaluation with 'move to' directive.""" # Create mocks mock_user = Mock(spec=User) mock_folder = Mock(spec=Folder) # Initialize processor processor = EmailProcessor(mock_user) # Test with simple move to result = processor._evaluate_rules({'subject': 'Test'}, 'move to Archive') assert result == 'Archive' # Test with punctuation result = processor._evaluate_rules({'subject': 'Test'}, 'move to Archive.') assert result == 'Archive' # Test with extra spaces result = processor._evaluate_rules({'subject': 'Test'}, 'move to Archive ') assert result == 'Archive' @patch('app.email_processor.ProcessedEmailsService') def test_update_folder_counts(mock_service): """Test updating folder counts after processing.""" # Create mocks mock_user = Mock(spec=User) mock_folder = Mock(spec=Folder) mock_folder.name = 'Test Folder' mock_folder.pending_count = 5 mock_folder.total_count = 10 # Mock service methods mock_service_instance = mock_service.return_value mock_service_instance.get_pending_count.return_value = 3 with patch('app.email_processor.EmailProcessor._get_imap_connection') as mock_imap: mock_imap.return_value.get_folder_email_count.return_value = 12 # Initialize processor processor = EmailProcessor(mock_user) processor._update_folder_counts(mock_folder) # Verify counts were updated assert mock_folder.pending_count == 3 assert mock_folder.total_count == 12