""" Unit tests for key generation utilities. """ import pytest from src.server.utils.key_utils import ( generate_key_from_folder, normalize_key, is_valid_key, sanitize_key_for_url, validate_key_uniqueness, ) class TestGenerateKeyFromFolder: """Test generate_key_from_folder function with edge cases.""" def test_standard_folder_name(self): """Test standard folder name with year.""" key = generate_key_from_folder("Attack on Titan (2013)") assert key == "attack-on-titan-2013" assert is_valid_key(key) def test_a_time_called_you(self): """Test 'A Time Called You (2023)' - the specific failing case.""" key = generate_key_from_folder("A Time Called You (2023)") assert key is not None assert key != "" assert is_valid_key(key) def test_andor_2022(self): """Test 'Andor (2022)' - the specific failing case.""" key = generate_key_from_folder("Andor (2022)") assert key is not None assert key != "" assert is_valid_key(key) def test_japanese_mixed_folder(self): """Test '25-sai no Joshikousei (2018)' - Japanese + Latin mixed.""" key = generate_key_from_folder("25-sai no Joshikousei (2018)") assert key is not None assert key != "" assert is_valid_key(key) def test_folder_with_only_special_characters(self): """Test folder that would slugify to empty string.""" key = generate_key_from_folder("!!!@@@###") assert key is not None assert key != "" # Should use UUID fallback def test_folder_with_only_numbers(self): """Test folder that is just numbers.""" key = generate_key_from_folder("12345") assert key is not None assert key != "" assert is_valid_key(key) def test_folder_with_parentheses_and_year(self): """Test folder with parentheses containing year.""" key = generate_key_from_folder("My Series (2020)") assert key is not None assert key != "" assert is_valid_key(key) def test_folder_with_brackets(self): """Test folder with square brackets.""" key = generate_key_from_folder("My Series [Special] (2021)") assert key is not None assert key != "" assert is_valid_key(key) def test_unicode_characters(self): """Test folder with various Unicode characters.""" key = generate_key_from_folder("Héros Légende (2022)") assert key is not None assert key != "" assert is_valid_key(key) def test_korean_characters(self): """Test folder with Korean characters.""" key = generate_key_from_folder("나의 애니메이션 (2023)") assert key is not None assert key != "" def test_chinese_characters(self): """Test folder with Chinese characters.""" key = generate_key_from_folder("我的动漫 (2024)") assert key is not None assert key != "" def test_empty_string_input(self): """Test empty string input raises ValueError.""" with pytest.raises(ValueError, match="Folder name cannot be empty"): generate_key_from_folder("") def test_only_whitespace_input(self): """Test whitespace-only input raises ValueError.""" with pytest.raises(ValueError, match="Folder name cannot be empty"): generate_key_from_folder(" ") def test_single_character_folder(self): """Test single character folder name.""" key = generate_key_from_folder("X") assert key is not None assert key != "" assert is_valid_key(key) def test_very_long_folder_name(self): """Test very long folder name.""" long_name = "A" * 200 key = generate_key_from_folder(long_name) assert key is not None assert key != "" def test_multiple_spaces(self): """Test folder with multiple consecutive spaces.""" key = generate_key_from_folder("My Series Name") assert key is not None assert key != "" def test_leading_trailing_spaces(self): """Test folder with leading and trailing spaces.""" key = generate_key_from_folder(" My Series ") assert key is not None assert key != "" def test_diacritics_normalization(self): """Test that diacritics are properly normalized.""" key = generate_key_from_folder("Animé (2023)") assert key is not None assert is_valid_key(key) class TestNormalizeKey: """Test normalize_key function.""" def test_normalize_standard_key(self): """Test normalizing a standard key.""" result = normalize_key("Attack-on-Titan") assert result == "attack-on-titan" def test_normalize_with_underscores(self): """Test normalizing key with underscores.""" result = normalize_key("attack_on_titan") assert result == "attack-on-titan" def test_normalize_mixed_case(self): """Test normalizing mixed case key.""" result = normalize_key("Attack_On_Titan") assert result == "attack-on-titan" def test_normalize_with_spaces(self): """Test normalizing key with spaces.""" result = normalize_key("attack on titan") assert result == "attack-on-titan" def test_normalize_empty_string(self): """Test normalizing empty string returns empty.""" result = normalize_key("") assert result == "" def test_normalize_only_special_chars(self): """Test normalizing string with only special characters.""" result = normalize_key("!!!@@@") assert result == "" class TestIsValidKey: """Test is_valid_key function.""" def test_valid_simple_key(self): """Test valid simple key.""" assert is_valid_key("attack-on-titan") def test_valid_key_with_numbers(self): """Test valid key with numbers.""" assert is_valid_key("a-time-called-you-2023") def test_valid_key_with_underscores(self): """Test valid key with underscores.""" assert is_valid_key("a_time_called_you_2023") def test_valid_key_starting_with_number(self): """Test valid key starting with number.""" assert is_valid_key("25-sai-no-joshikousei-2018") def test_invalid_empty_key(self): """Test invalid empty key.""" assert not is_valid_key("") def test_invalid_key_with_spaces(self): """Test invalid key with spaces.""" assert not is_valid_key("attack on titan") def test_invalid_key_with_special_chars(self): """Test invalid key with special characters.""" assert not is_valid_key("attack@titan") def test_invalid_key_with_unicode(self): """Test invalid key with unstripped unicode.""" assert not is_valid_key("attack\u00a0titan") # Non-breaking space def test_invalid_single_char(self): """Test invalid single character key.""" assert not is_valid_key("a") def test_valid_two_char_key(self): """Test valid two character key.""" assert is_valid_key("ab") def test_invalid_key_starting_with_hyphen(self): """Test invalid key starting with hyphen.""" assert not is_valid_key("-attack") class TestSanitizeKeyForUrl: """Test sanitize_key_for_url function.""" def test_standard_key_unchanged(self): """Test standard key remains unchanged.""" result = sanitize_key_for_url("attack-on-titan-2013") assert result == "attack-on-titan-2013" def test_spaces_replaced(self): """Test spaces are replaced with hyphens.""" result = sanitize_key_for_url("attack on titan") assert result == "attack-on-titan" def test_uppercase_preserved(self): """Test uppercase is preserved (use normalize_key for lowercase).""" result = sanitize_key_for_url("AttackOnTitan") # sanitize_key_for_url preserves case, only removes special chars assert result == "AttackOnTitan" def test_special_chars_removed(self): """Test special characters are removed.""" result = sanitize_key_for_url("Attack@#@On!Titan") assert result == "AttackOnTitan" def test_accents_preserved(self): """Test accented characters are preserved (use normalize_key for full normalization).""" result = sanitize_key_for_url("AttäckÖnTïtan") # Only removes truly problematic chars, preserves accented letters assert "AttäckÖnTïtan" in result def test_multiple_hyphens_collapses(self): """Test multiple hyphens are collapsed.""" result = sanitize_key_for_url("attack---on---titan") assert result == "attack-on-titan" def test_leading_trailing_hyphens_removed(self): """Test leading and trailing hyphens are removed.""" result = sanitize_key_for_url("-attack-on-titan-") assert result == "attack-on-titan" class TestValidateKeyUniqueness: """Test validate_key_uniqueness function.""" def test_unique_key(self): """Test key that is unique.""" existing_keys = {"attack-on-titan", "one-piece", "naruto"} is_valid, error = validate_key_uniqueness("new-series", existing_keys) assert is_valid is True assert error == "" def test_duplicate_key(self): """Test key that already exists.""" existing_keys = {"attack-on-titan", "one-piece", "naruto"} is_valid, error = validate_key_uniqueness("one-piece", existing_keys) assert is_valid is False assert "already in use" in error def test_empty_existing_set(self): """Test with empty existing keys set.""" is_valid, error = validate_key_uniqueness("new-series", set()) assert is_valid is True assert error == "" def test_key_differs_only_by_case(self): """Test key that differs only by case is NOT flagged by utility (API layer handles case-insensitivity).""" existing_keys = {"attack-on-titan"} # lowercase in set is_valid, error = validate_key_uniqueness("Attack-on-Titan", existing_keys) # Utility function does case-sensitive check; API layer handles case-insensitivity assert is_valid is True assert error == "" def test_same_key_same_case(self): """Test same key in existing set is flagged.""" existing_keys = {"my-series"} is_valid, error = validate_key_uniqueness("my-series", existing_keys) assert is_valid is False