"""Unit tests for withdrawal service.""" from datetime import datetime from unittest.mock import patch import pytest from src.services.withdrawal import WithdrawalError, withdraw_participant def test_withdraw_participant_success(participant_factory, db, app): # noqa: ARG001 """Test successful withdrawal.""" with app.app_context(): participant = participant_factory() with patch("src.services.withdrawal.EmailService") as mock_email_service: withdraw_participant(participant) assert participant.withdrawn_at is not None mock_email_service.return_value.send_withdrawal_confirmation.assert_called_once() def test_withdraw_participant_already_withdrawn(participant_factory, app): """Test error when already withdrawn.""" with app.app_context(): participant = participant_factory(withdrawn_at=datetime.utcnow()) with pytest.raises(WithdrawalError, match="already withdrawn"): withdraw_participant(participant) def test_withdraw_participant_registration_closed( exchange_factory, participant_factory, app ): """Test error when registration is closed.""" with app.app_context(): exchange = exchange_factory(state="registration_closed") participant = participant_factory(exchange=exchange) with pytest.raises(WithdrawalError, match="Registration has closed"): withdraw_participant(participant) def test_withdraw_participant_after_matching( exchange_factory, participant_factory, app ): """Test error when matching has occurred.""" with app.app_context(): exchange = exchange_factory(state="matched") participant = participant_factory(exchange=exchange) with pytest.raises(WithdrawalError, match="Matching has already occurred"): withdraw_participant(participant) def test_withdraw_participant_sets_timestamp(participant_factory, db, app): # noqa: ARG001 """Test that withdrawal sets timestamp correctly.""" with app.app_context(): participant = participant_factory() with patch("src.services.withdrawal.EmailService"): before = datetime.utcnow() withdraw_participant(participant) after = datetime.utcnow() assert participant.withdrawn_at is not None assert before <= participant.withdrawn_at <= after