"""Tests for TheTVDB client.""" from unittest.mock import Mock, patch import pytest from tvh2jellyfin.tvdb import EpisodeInfo, TVDBClient, TVDBConfig class TestEpisodeInfo: """Tests for EpisodeInfo dataclass.""" def test_formatted_episode_single_digit(self): """Test SxxExx formatting with single digit numbers.""" info = EpisodeInfo( series_id=123, series_name="Test Show", season=1, episode=5, episode_name="Pilot", air_date="2024-01-15", ) assert info.formatted_episode == "S01E05" def test_formatted_episode_double_digit(self): """Test SxxExx formatting with double digit numbers.""" info = EpisodeInfo( series_id=123, series_name="Test Show", season=12, episode=25, episode_name="Episode", air_date="2024-01-15", ) assert info.formatted_episode == "S12E25" def test_formatted_episode_large_numbers(self): """Test formatting with season/episode > 99.""" info = EpisodeInfo( series_id=123, series_name="Long Running Show", season=67, episode=125, episode_name="Episode", air_date="2024-01-15", ) assert info.formatted_episode == "S67E125" class TestTVDBClient: """Tests for TVDB API client.""" @pytest.fixture def config(self): return TVDBConfig( api_key="test_key", pin="", cache_ttl=3600, show_mapping_file=None, enabled=True, ) @pytest.fixture def client(self, config): with patch.object(TVDBClient, "_authenticate"): return TVDBClient(config) def test_cache_valid(self, client): """Test cache validity check.""" import time # Recent timestamp should be valid assert client._is_cache_valid(time.time() - 100) # Old timestamp should be invalid assert not client._is_cache_valid(time.time() - 7200) @patch("requests.Session.post") def test_authenticate(self, mock_post, config): """Test authentication flow.""" mock_post.return_value.json.return_value = {"data": {"token": "test_token"}} mock_post.return_value.raise_for_status = Mock() client = TVDBClient(config) client._authenticate() assert client._token == "test_token" mock_post.assert_called_once() @patch("requests.Session.get") @patch("requests.Session.post") def test_search_series_success(self, mock_post, mock_get, config): """Test successful series search.""" mock_post.return_value.json.return_value = {"data": {"token": "test_token"}} mock_post.return_value.raise_for_status = Mock() mock_get.return_value.json.return_value = { "data": [{"tvdb_id": 456, "name": "The Test Show"}] } mock_get.return_value.raise_for_status = Mock() client = TVDBClient(config) result = client.search_series("Test Show") assert result is not None assert result[0] == 456 assert result[1] == "The Test Show" @patch("requests.Session.get") @patch("requests.Session.post") def test_search_series_not_found(self, mock_post, mock_get, config): """Test series search with no results.""" mock_post.return_value.json.return_value = {"data": {"token": "test_token"}} mock_post.return_value.raise_for_status = Mock() mock_get.return_value.json.return_value = {"data": []} mock_get.return_value.raise_for_status = Mock() client = TVDBClient(config) result = client.search_series("Nonexistent Show") assert result is None @patch("tvh2jellyfin.tvdb.requests.Session") def test_lookup_episode_success(self, mock_session_class, config): """Test successful episode lookup.""" from datetime import datetime mock_session = Mock() mock_session_class.return_value = mock_session # Use a timestamp and derive the expected air date from it timestamp = 1767744000 expected_air_date = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d") # Mock authentication mock_session.post.return_value.json.return_value = {"data": {"token": "test_token"}} mock_session.post.return_value.raise_for_status = Mock() # Mock search and episode responses mock_session.get.return_value.raise_for_status = Mock() mock_session.get.return_value.json.side_effect = [ {"data": [{"tvdb_id": 456, "name": "Coronation Street"}]}, { "data": { "name": "Coronation Street", "episodes": [ { "seasonNumber": 67, "number": 4, "name": "Episode 4", "aired": expected_air_date, } ], }, "links": {}, }, ] client = TVDBClient(config) result = client.lookup_episode("Coronation Street", timestamp) assert result is not None assert result.season == 67 assert result.episode == 4 assert result.formatted_episode == "S67E04" def test_show_mapping_file(self, tmp_path, config): """Test show name mapping from file.""" mapping_file = tmp_path / "mapping.json" mapping_file.write_text('{"Doctor Who": "Doctor Who (2005)"}') config.show_mapping_file = str(mapping_file) with patch.object(TVDBClient, "_authenticate"): client = TVDBClient(config) assert client._show_mapping.get("Doctor Who") == "Doctor Who (2005)" def test_caching_prevents_duplicate_calls(self, client): """Test that cache prevents duplicate API calls.""" import time # Manually populate cache client._series_cache["test show"] = (123, "Test Show", time.time()) # Search should use cache, not make API call result = client.search_series("test show") assert result == (123, "Test Show")