"""Unit tests for path and URL validation functionality.""" import os import tempfile from pathlib import Path import pytest from src.security.secure_config import ( validate_path, validate_youtube_url, sanitize_filename, ) class TestPathValidation: """Test cases for path validation functions.""" def setup_method(self): """Set up test fixtures.""" self.temp_dir = tempfile.mkdtemp() self.test_file = Path(self.temp_dir) / "test.txt" self.test_file.write_text("test content") def teardown_method(self): """Clean up test fixtures.""" import shutil if self.temp_dir and os.path.exists(self.temp_dir): shutil.rmtree(self.temp_dir) def test_validate_path_allows_user_directories(self): """Test that validate_path allows paths in user directories.""" user_dirs = [ "~/Documents", "~/Downloads", "~/Desktop", "~/Music", "~/Videos", "~/.trax", ] for user_dir in user_dirs: test_path = f"{user_dir}/test_file.txt" assert validate_path(test_path) is True def test_validate_path_blocks_directory_traversal(self): """Test that validate_path blocks directory traversal attempts.""" malicious_paths = [ "../../../etc/passwd", "~/Documents/../../../etc/shadow", "/tmp/../../../root/.ssh/id_rsa", "~/Downloads/..//..//..//var/log/auth.log", "~/Desktop/../../../../etc/hosts", ] for path in malicious_paths: assert validate_path(path) is False def test_validate_path_blocks_system_directories(self): """Test that validate_path blocks access to system directories.""" system_paths = [ "/etc/passwd", "/var/log/auth.log", "/root/.ssh/id_rsa", "/tmp/malicious_file", "/usr/bin/evil", "/bin/bash", ] for path in system_paths: assert validate_path(path) is False def test_validate_path_allows_current_directory(self): """Test that validate_path allows paths in current working directory.""" # Create a file in current directory test_file = "test_current_dir.txt" with open(test_file, "w") as f: f.write("test") try: assert validate_path(test_file) is True assert validate_path("./test_current_dir.txt") is True assert validate_path("../test_current_dir.txt") is False finally: os.remove(test_file) def test_validate_path_handles_edge_cases(self): """Test that validate_path handles edge cases properly.""" edge_cases = [ "", # Empty string None, # None value " ", # Whitespace only ".", # Current directory "..", # Parent directory ] for path in edge_cases: assert validate_path(path) is False def test_validate_path_handles_absolute_paths(self): """Test that validate_path handles absolute paths correctly.""" # Test with actual user home directory home = os.path.expanduser("~") safe_absolute_paths = [ f"{home}/Documents/test.txt", f"{home}/Downloads/file.mp4", f"{home}/.trax/config.json", ] for path in safe_absolute_paths: assert validate_path(path) is True def test_validate_path_handles_special_characters(self): """Test that validate_path handles special characters in paths.""" special_paths = [ "~/Documents/file with spaces.txt", "~/Downloads/file-with-dashes.mp4", "~/Desktop/file_with_underscores.pdf", "~/Music/song (remix).mp3", ] for path in special_paths: assert validate_path(path) is True class TestURLValidation: """Test cases for URL validation functions.""" def test_validate_youtube_url_allows_valid_urls(self): """Test that validate_youtube_url allows valid YouTube URLs.""" valid_urls = [ "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "https://youtu.be/dQw4w9WgXcQ", "http://www.youtube.com/watch?v=dQw4w9WgXcQ", "https://youtube.com/watch?v=dQw4w9WgXcQ", "https://www.youtube.com/embed/dQw4w9WgXcQ", "https://www.youtube.com/v/dQw4w9WgXcQ", "https://www.youtube.com/playlist?list=PL123456", ] for url in valid_urls: assert validate_youtube_url(url) is True def test_validate_youtube_url_blocks_invalid_urls(self): """Test that validate_youtube_url blocks invalid URLs.""" invalid_urls = [ "https://www.google.com", "https://malicious-site.com/fake-youtube", "ftp://youtube.com/video", "javascript:alert('xss')", "data:text/html,", "file:///etc/passwd", "https://www.youtube.com.evil.com/watch?v=123", "https://youtube.com.evil.com/watch?v=123", ] for url in invalid_urls: assert validate_youtube_url(url) is False def test_validate_youtube_url_handles_edge_cases(self): """Test that validate_youtube_url handles edge cases.""" edge_cases = [ "", # Empty string None, # None value "not_a_url", # Plain text "youtube.com", # Missing protocol "https://", # Incomplete URL "https://youtube.com", # Missing path ] for url in edge_cases: assert validate_youtube_url(url) is False def test_validate_youtube_url_handles_complex_urls(self): """Test that validate_youtube_url handles complex YouTube URLs.""" complex_urls = [ "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=30s", "https://youtu.be/dQw4w9WgXcQ?t=30", "https://www.youtube.com/watch?v=dQw4w9WgXcQ&list=PL123456&index=1", "https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=share", "https://www.youtube.com/embed/dQw4w9WgXcQ?autoplay=1", ] for url in complex_urls: assert validate_youtube_url(url) is True def test_validate_youtube_url_handles_different_protocols(self): """Test that validate_youtube_url handles different protocols.""" protocols = [ "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "http://www.youtube.com/watch?v=dQw4w9WgXcQ", "https://youtu.be/dQw4w9WgXcQ", "http://youtu.be/dQw4w9WgXcQ", ] for url in protocols: assert validate_youtube_url(url) is True def test_validate_youtube_url_handles_subdomains(self): """Test that validate_youtube_url handles YouTube subdomains.""" subdomain_urls = [ "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "https://m.youtube.com/watch?v=dQw4w9WgXcQ", "https://music.youtube.com/watch?v=dQw4w9WgXcQ", ] for url in subdomain_urls: assert validate_youtube_url(url) is True class TestFilenameSanitization: """Test cases for filename sanitization.""" def test_sanitize_filename_removes_dangerous_characters(self): """Test that sanitize_filename removes dangerous characters.""" dangerous_filenames = [ "file<>:\"/\\|?*.txt", "file with spaces.txt", "file.with.dots.txt", "file with (parentheses).txt", "file with [brackets].txt", "file with {braces}.txt", ] for filename in dangerous_filenames: sanitized = sanitize_filename(filename) assert "<" not in sanitized assert ">" not in sanitized assert ":" not in sanitized assert '"' not in sanitized assert "/" not in sanitized assert "\\" not in sanitized assert "|" not in sanitized assert "?" not in sanitized assert "*" not in sanitized def test_sanitize_filename_handles_edge_cases(self): """Test that sanitize_filename handles edge cases.""" edge_cases = [ "", # Empty string None, # None value " ", # Whitespace only ".", # Just a dot "..", # Just dots " . ", # Whitespace and dots ] for filename in edge_cases: sanitized = sanitize_filename(filename) assert sanitized == "unnamed_file" def test_sanitize_filename_preserves_safe_characters(self): """Test that sanitize_filename preserves safe characters.""" safe_filenames = [ "normal_file.txt", "file_with_underscores.txt", "file-with-dashes.txt", "file123.txt", "FILE.TXT", "file.txt", ] for filename in safe_filenames: sanitized = sanitize_filename(filename) assert sanitized == filename def test_sanitize_filename_limits_length(self): """Test that sanitize_filename limits filename length.""" long_filename = "a" * 300 + ".txt" sanitized = sanitize_filename(long_filename) assert len(sanitized) <= 255 assert sanitized.endswith(".txt") def test_sanitize_filename_removes_leading_trailing_dots(self): """Test that sanitize_filename removes leading and trailing dots.""" dot_filenames = [ ".hidden_file.txt", "file.txt.", ".file.txt.", "...file.txt...", ] expected_results = [ "hidden_file.txt", "file.txt", "file.txt", "file.txt", ] for filename, expected in zip(dot_filenames, expected_results): sanitized = sanitize_filename(filename) assert sanitized == expected def test_sanitize_filename_handles_multiple_extensions(self): """Test that sanitize_filename handles multiple extensions.""" multi_ext_filenames = [ "file.txt.bak", "file.tar.gz", "file.backup.old", ] for filename in multi_ext_filenames: sanitized = sanitize_filename(filename) assert sanitized == filename