#!/usr/bin/env python3 """ Unit tests for CrossFitBooker session-related methods """ import pytest import os import sys from unittest.mock import patch, Mock from datetime import datetime, timedelta, date import pytz # Add the parent directory to the path sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from src.auth import AuthHandler from src.booker import Booker from src.session_notifier import SessionNotifier from src.session_manager import SessionManager class TestCrossFitBookerGetAvailableSessions: """Test cases for get_available_sessions method""" def test_get_available_sessions_no_auth(self): """Test get_available_sessions without authentication""" with patch.dict(os.environ, { 'CROSSFIT_USERNAME': 'test_user', 'CROSSFIT_PASSWORD': 'test_pass' }): auth_handler = AuthHandler('test_user', 'test_pass') session_manager = SessionManager(auth_handler) result = session_manager.get_available_sessions(date(2025, 7, 24), date(2025, 7, 25)) assert result is None @patch('requests.Session.post') def test_get_available_sessions_success(self, mock_post): """Test successful get_available_sessions""" mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = { "success": True, "data": { "activities_calendar": [ {"id": "1", "name": "Test Session"} ] } } mock_post.return_value = mock_response with patch.dict(os.environ, { 'CROSSFIT_USERNAME': 'test_user', 'CROSSFIT_PASSWORD': 'test_pass' }): auth_handler = AuthHandler('test_user', 'test_pass') auth_handler.auth_token = "test_token" auth_handler.user_id = "12345" session_manager = SessionManager(auth_handler) result = session_manager.get_available_sessions(date(2025, 7, 24), date(2025, 7, 25)) assert result is not None assert result["success"] is True @patch('requests.Session.post') def test_get_available_sessions_401_error(self, mock_post): """Test get_available_sessions with 401 error""" mock_response = Mock() mock_response.status_code = 401 mock_post.return_value = mock_response with patch.dict(os.environ, { 'CROSSFIT_USERNAME': 'test_user', 'CROSSFIT_PASSWORD': 'test_pass' }): auth_handler = AuthHandler('test_user', 'test_pass') session_manager = SessionManager(auth_handler) auth_handler.auth_token = "test_token" auth_handler.user_id = "12345" result = session_manager.get_available_sessions(date(2025, 7, 24), date(2025, 7, 25)) assert result is None class TestCrossFitBookerBookSession: """Test cases for book_session method""" def test_book_session_no_auth(self): """Test book_session without authentication""" with patch.dict(os.environ, { 'CROSSFIT_USERNAME': 'test_user', 'CROSSFIT_PASSWORD': 'test_pass' }): auth_handler = AuthHandler('test_user', 'test_pass') session_manager = SessionManager(auth_handler) result = session_manager.book_session("session_123") assert result is False @patch('requests.Session.post') def test_book_session_success(self, mock_post): """Test successful book_session""" mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"success": True} mock_post.return_value = mock_response with patch.dict(os.environ, { 'CROSSFIT_USERNAME': 'test_user', 'CROSSFIT_PASSWORD': 'test_pass' }): auth_handler = AuthHandler('test_user', 'test_pass') auth_handler.auth_token = "test_token" auth_handler.user_id = "12345" session_manager = SessionManager(auth_handler) result = session_manager.book_session("session_123") assert result is True @patch('requests.Session.post') def test_book_session_api_failure(self, mock_post): """Test book_session with API failure""" mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"success": False, "error": "Session full"} mock_post.return_value = mock_response with patch.dict(os.environ, { 'CROSSFIT_USERNAME': 'test_user', 'CROSSFIT_PASSWORD': 'test_pass' }): auth_handler = AuthHandler('test_user', 'test_pass') auth_handler.auth_token = "test_token" auth_handler.user_id = "12345" session_manager = SessionManager(auth_handler) result = session_manager.book_session("session_123") assert result is False class TestCrossFitBookerIsSessionBookable: """Test cases for is_session_bookable method""" def test_is_session_bookable_can_join_true(self): """Test session bookable with can_join=True""" with patch.dict(os.environ, { 'CROSSFIT_USERNAME': 'test_user', 'CROSSFIT_PASSWORD': 'test_pass' }): auth_handler = AuthHandler('test_user', 'test_pass') session_manager = SessionManager(auth_handler) session = {"user_info": {"can_join": True}} current_time = datetime.now(pytz.timezone("Europe/Paris")) result = session_manager.is_session_bookable(session, current_time) assert result is True def test_is_session_bookable_booking_window_past(self): """Test session bookable with booking window in past""" with patch.dict(os.environ, { 'CROSSFIT_USERNAME': 'test_user', 'CROSSFIT_PASSWORD': 'test_pass' }): auth_handler = AuthHandler('test_user', 'test_pass') session_manager = SessionManager(auth_handler) session = { "user_info": { "can_join": False, "unableToBookUntilDate": "01-01-2020", "unableToBookUntilTime": "10:00" } } current_time = datetime.now(pytz.timezone("Europe/Paris")) result = session_manager.is_session_bookable(session, current_time) assert result is True def test_is_session_bookable_booking_window_future(self): """Test session not bookable with booking window in future""" with patch.dict(os.environ, { 'CROSSFIT_USERNAME': 'test_user', 'CROSSFIT_PASSWORD': 'test_pass' }): auth_handler = AuthHandler('test_user', 'test_pass') session_manager = SessionManager(auth_handler) session = { "user_info": { "can_join": False, "unableToBookUntilDate": "01-01-2030", "unableToBookUntilTime": "10:00" } } current_time = datetime.now(pytz.timezone("Europe/Paris")) result = session_manager.is_session_bookable(session, current_time) assert result is False class TestCrossFitBookerMatchesPreferredSession: """Test cases for matches_preferred_session method""" def test_matches_preferred_session_exact_match(self): """Test exact match with preferred session""" with patch.dict(os.environ, { 'CROSSFIT_USERNAME': 'test_user', 'CROSSFIT_PASSWORD': 'test_pass' }): auth_handler = AuthHandler('test_user', 'test_pass') session_manager = SessionManager(auth_handler) session = { "start_timestamp": "2025-07-30 18:30:00", "name_activity": "CONDITIONING" } current_time = datetime(2025, 7, 30, 12, 0, 0, tzinfo=pytz.timezone("Europe/Paris")) # Mock PREFERRED_SESSIONS with patch('src.session_manager.PREFERRED_SESSIONS', [(2, "18:30", "CONDITIONING")]): result = session_manager.matches_preferred_session(session, current_time) assert result is True def test_matches_preferred_session_fuzzy_match(self): """Test fuzzy match with preferred session""" with patch.dict(os.environ, { 'CROSSFIT_USERNAME': 'test_user', 'CROSSFIT_PASSWORD': 'test_pass' }): auth_handler = AuthHandler('test_user', 'test_pass') session_manager = SessionManager(auth_handler) session = { "start_timestamp": "2025-07-30 18:30:00", "name_activity": "CONDITIONING WORKOUT" } current_time = datetime(2025, 7, 30, 12, 0, 0, tzinfo=pytz.timezone("Europe/Paris")) # Mock PREFERRED_SESSIONS with patch('src.session_manager.PREFERRED_SESSIONS', [(2, "18:30", "CONDITIONING")]): result = session_manager.matches_preferred_session(session, current_time) assert result is True def test_matches_preferred_session_no_match(self): """Test no match with preferred session""" with patch.dict(os.environ, { 'CROSSFIT_USERNAME': 'test_user', 'CROSSFIT_PASSWORD': 'test_pass' }): auth_handler = AuthHandler('test_user', 'test_pass') session_manager = SessionManager(auth_handler) session = { "start_timestamp": "2025-07-30 18:30:00", "name_activity": "YOGA" } current_time = datetime(2025, 7, 30, 12, 0, 0, tzinfo=pytz.timezone("Europe/Paris")) # Mock PREFERRED_SESSIONS with patch('src.session_manager.PREFERRED_SESSIONS', [(2, "18:30", "CONDITIONING")]): result = session_manager.matches_preferred_session(session, current_time) assert result is False