test_config.py
1 """Tests for the configuration module.""" 2 3 import os 4 import sys 5 from pathlib import Path 6 from arxiv_mcp_server.config import Settings 7 from unittest.mock import patch 8 9 10 @patch.object(Path, "mkdir") 11 @patch.object(Path, "resolve") 12 def test_storage_path_default(mock_resolve, mock_mkdir): 13 """Test that the default storage path is correctly constructed.""" 14 # Setup the mock to return the path itself when resolved 15 mock_resolve.side_effect = lambda: Path.home() / ".arxiv-mcp-server" / "papers" 16 17 settings = Settings() 18 expected_path = Path.home() / ".arxiv-mcp-server" / "papers" 19 assert settings.STORAGE_PATH == expected_path.resolve() 20 # Verify mkdir was called with parents=True and exist_ok=True 21 mock_mkdir.assert_called_once_with(parents=True, exist_ok=True) 22 23 24 @patch.object(Path, "mkdir") 25 @patch.object(Path, "resolve") 26 def test_storage_path_from_args(mock_resolve, mock_mkdir): 27 """Test that the storage path from command line args is correctly parsed.""" 28 test_path = "/tmp/test_storage" 29 mock_resolve.side_effect = lambda: Path(test_path) 30 31 with patch.object(sys, "argv", ["program", "--storage-path", test_path]): 32 settings = Settings() 33 assert settings.STORAGE_PATH == Path(test_path).resolve() 34 mock_mkdir.assert_called_once_with(parents=True, exist_ok=True) 35 36 37 @patch.object(Path, "mkdir") 38 @patch.object(Path, "resolve") 39 def test_storage_path_platform_compatibility(mock_resolve, mock_mkdir): 40 """Test that the storage path works correctly on different platforms.""" 41 # Test with a path format that would be valid on both Windows and Unix 42 test_paths = [ 43 # Unix-style path 44 "/path/to/storage", 45 # Windows-style path 46 "C:\\path\\to\\storage", 47 # Path with spaces 48 "/path with spaces/to/storage", 49 # Path with non-ASCII characters 50 "/path/to/störâgè", 51 ] 52 53 for test_path in test_paths: 54 # Reset mocks for each iteration 55 mock_resolve.reset_mock() 56 mock_mkdir.reset_mock() 57 58 # Set up the mock to return the path itself 59 mock_resolve.side_effect = lambda: Path(test_path) 60 61 with patch.object(sys, "argv", ["program", "--storage-path", test_path]): 62 settings = Settings() 63 resolved_path = settings.STORAGE_PATH 64 65 # Verify that Path constructor was called with the test path 66 assert resolved_path == Path(test_path).resolve() 67 68 # Verify that mkdir was called 69 mock_mkdir.assert_called_once_with(parents=True, exist_ok=True) 70 71 72 def test_storage_path_creates_missing_directory(): 73 """Test that directories are actually created for the storage path.""" 74 import tempfile 75 76 # Create a temporary directory for our test 77 with tempfile.TemporaryDirectory() as tmpdir: 78 # Create a path that doesn't exist yet 79 test_path = os.path.join(tmpdir, "deeply", "nested", "directory", "structure") 80 81 # Make sure it doesn't exist yet 82 assert not os.path.exists(test_path) 83 84 # Patch the arguments to use this path 85 with patch.object(sys, "argv", ["program", "--storage-path", test_path]): 86 # Access the STORAGE_PATH property which should create the directories 87 settings = Settings() 88 storage_path = settings.STORAGE_PATH 89 90 # Verify the directory was created 91 assert os.path.exists(test_path) 92 assert os.path.isdir(test_path) 93 94 # Verify the paths refer to the same location 95 # Use Path.samefile to handle symlinks (like /var -> /private/var on macOS) 96 assert Path(storage_path).samefile(test_path) 97 98 99 def test_path_normalization_with_windows_paths(): 100 """Test Windows-specific path handling using string operations only.""" 101 # Windows-style paths - we'll test the normalization and joining logic 102 windows_style_paths = [ 103 # Drive letter with backslashes 104 "C:\\Users\\username\\Documents\\Papers", 105 # UNC path (network share) 106 "\\\\server\\share\\papers", 107 # Drive letter with forward slashes (also valid on Windows) 108 "C:/Users/username/Documents/Papers", 109 # Windows-style path with spaces 110 "C:\\Program Files\\arXiv\\papers", 111 # Windows-style path with mixed slashes 112 "C:\\Users/username\\Documents/Papers", 113 ] 114 115 # Test that our config works with these path formats 116 for windows_path in windows_style_paths: 117 assert Path(windows_path) # This should not raise an error 118 119 # Test path joining logic works correctly 120 subpath = Path(windows_path) / "subdir" 121 assert str(subpath).endswith("subdir") 122 123 # The following check is problematic on real Windows systems 124 # where the path separator may be different 125 # Check only that the base path is contained in the result (ignoring separator differences) 126 base_path_norm = windows_path.replace("\\", "/").replace("//", "/") 127 subpath_norm = str(subpath).replace("\\", "/").replace("//", "/") 128 assert base_path_norm in subpath_norm 129 130 # Instead of checking exact string equality, verify the Path objects are equivalent 131 assert subpath == Path(windows_path).joinpath("subdir")