"""Unit tests for anime key rename logic and validation.""" import pytest from pydantic import ValidationError from src.server.models.anime import AnimeMetadataUpdate, KEY_PATTERN class TestKeyValidation: """Tests for AnimeMetadataUpdate key validation.""" def test_valid_key_simple(self): """Test simple valid key.""" model = AnimeMetadataUpdate(key="attack-on-titan") assert model.key == "attack-on-titan" def test_valid_key_single_char(self): """Test single character key is valid.""" model = AnimeMetadataUpdate(key="a") assert model.key == "a" def test_valid_key_numbers(self): """Test key with numbers.""" model = AnimeMetadataUpdate(key="86-eighty-six") assert model.key == "86-eighty-six" def test_valid_key_allows_hyphens(self): """Test hyphens in key are allowed.""" model = AnimeMetadataUpdate(key="my-anime-key") assert model.key == "my-anime-key" def test_valid_key_normalizes_to_lowercase(self): """Test key is normalized to lowercase.""" model = AnimeMetadataUpdate(key="Attack-On-Titan") assert model.key == "attack-on-titan" def test_valid_key_strips_whitespace(self): """Test key strips leading/trailing whitespace.""" model = AnimeMetadataUpdate(key=" my-key ") assert model.key == "my-key" def test_invalid_key_spaces(self): """Test key with spaces is rejected.""" with pytest.raises(ValidationError) as exc_info: AnimeMetadataUpdate(key="my anime key") assert "Key must contain only" in str(exc_info.value) def test_invalid_key_uppercase_special(self): """Test key with special characters is rejected.""" with pytest.raises(ValidationError) as exc_info: AnimeMetadataUpdate(key="anime!@#key") assert "Key must contain only" in str(exc_info.value) def test_invalid_key_empty(self): """Test empty key is rejected.""" with pytest.raises(ValidationError) as exc_info: AnimeMetadataUpdate(key="") assert "cannot be empty" in str(exc_info.value) def test_invalid_key_only_whitespace(self): """Test whitespace-only key is rejected.""" with pytest.raises(ValidationError) as exc_info: AnimeMetadataUpdate(key=" ") assert "cannot be empty" in str(exc_info.value) def test_invalid_key_starts_with_hyphen(self): """Test key starting with hyphen is rejected.""" with pytest.raises(ValidationError): AnimeMetadataUpdate(key="-my-key") def test_invalid_key_ends_with_hyphen(self): """Test key ending with hyphen is rejected.""" with pytest.raises(ValidationError): AnimeMetadataUpdate(key="my-key-") def test_key_none_is_allowed(self): """Test None key (no change requested) is allowed.""" model = AnimeMetadataUpdate(key=None) assert model.key is None def test_key_omitted_is_allowed(self): """Test omitting key entirely is allowed.""" model = AnimeMetadataUpdate(tmdb_id=1234) assert model.key is None class TestTmdbIdValidation: """Tests for tmdb_id validation.""" def test_valid_tmdb_id(self): """Test valid positive TMDB ID.""" model = AnimeMetadataUpdate(tmdb_id=1429) assert model.tmdb_id == 1429 def test_tmdb_id_none(self): """Test None tmdb_id is allowed.""" model = AnimeMetadataUpdate(tmdb_id=None) assert model.tmdb_id is None def test_tmdb_id_negative_rejected(self): """Test negative tmdb_id is rejected.""" with pytest.raises(ValidationError): AnimeMetadataUpdate(tmdb_id=-1) def test_tmdb_id_zero_rejected(self): """Test zero tmdb_id is rejected.""" with pytest.raises(ValidationError): AnimeMetadataUpdate(tmdb_id=0) class TestTvdbIdValidation: """Tests for tvdb_id validation.""" def test_valid_tvdb_id(self): """Test valid positive TVDB ID.""" model = AnimeMetadataUpdate(tvdb_id=267440) assert model.tvdb_id == 267440 def test_tvdb_id_none(self): """Test None tvdb_id is allowed.""" model = AnimeMetadataUpdate(tvdb_id=None) assert model.tvdb_id is None def test_tvdb_id_negative_rejected(self): """Test negative tvdb_id is rejected.""" with pytest.raises(ValidationError): AnimeMetadataUpdate(tvdb_id=-5) def test_tvdb_id_zero_rejected(self): """Test zero tvdb_id is rejected.""" with pytest.raises(ValidationError): AnimeMetadataUpdate(tvdb_id=0) class TestKeyPattern: """Tests for the KEY_PATTERN regex directly.""" @pytest.mark.parametrize("key", [ "a", "abc", "attack-on-titan", "86-eighty-six", "a1b2c3", "x", "1", ]) def test_valid_patterns(self, key): """Test keys that should match the pattern.""" assert KEY_PATTERN.match(key) is not None @pytest.mark.parametrize("key", [ "-start", "end-", "has space", "UPPER", "special!char", "under_score", "", ]) def test_invalid_patterns(self, key): """Test keys that should not match the pattern.""" assert KEY_PATTERN.match(key) is None