|
18 | 18 | Windows, |
19 | 19 | get_win_folder, |
20 | 20 | get_win_folder_from_env_vars, |
| 21 | + get_win_folder_from_registry, |
21 | 22 | get_win_folder_if_csidl_name_not_env_var, |
22 | 23 | ) |
23 | 24 |
|
@@ -111,6 +112,11 @@ def test_windows(params: dict[str, Any], func: str) -> None: |
111 | 112 | assert result == expected_map[func] |
112 | 113 |
|
113 | 114 |
|
| 115 | +def test_user_desktop_dir() -> None: |
| 116 | + # The shared PROPS fixture skips this one, so Windows would otherwise never exercise the property. |
| 117 | + assert Windows().user_desktop_dir == os.path.normpath(_WIN_FOLDERS["CSIDL_DESKTOPDIRECTORY"]) |
| 118 | + |
| 119 | + |
114 | 120 | def test_roaming_uses_appdata(mocker: MockerFixture) -> None: |
115 | 121 | mock = mocker.patch("platformdirs.windows.get_win_folder", side_effect=lambda csidl: _WIN_FOLDERS[csidl]) |
116 | 122 | _result = Windows(appname="foo", roaming=True).user_data_dir |
@@ -154,6 +160,7 @@ def test_get_win_folder_from_env_vars_direct( |
154 | 160 | pytest.param("CSIDL_MYPICTURES", "Pictures", id="pictures"), |
155 | 161 | pytest.param("CSIDL_MYVIDEO", "Videos", id="video"), |
156 | 162 | pytest.param("CSIDL_MYMUSIC", "Music", id="music"), |
| 163 | + pytest.param("CSIDL_DESKTOPDIRECTORY", "Desktop", id="desktop"), |
157 | 164 | ] |
158 | 165 |
|
159 | 166 |
|
@@ -334,6 +341,39 @@ def test_get_win_folder_via_ctypes_null_result(mocker: MockerFixture) -> None: |
334 | 341 | _cleanup_ctypes_mocks() |
335 | 342 |
|
336 | 343 |
|
| 344 | +def test_get_win_folder_from_registry_unknown() -> None: |
| 345 | + # The lookup table is consulted before the platform guard, so this holds off Windows too. |
| 346 | + with pytest.raises(ValueError, match="Unknown CSIDL name: CSIDL_NOT_A_FOLDER"): |
| 347 | + get_win_folder_from_registry("CSIDL_NOT_A_FOLDER") |
| 348 | + |
| 349 | + |
| 350 | +@pytest.mark.skipif(sys.platform == "win32", reason="on Windows the resolver reads the registry instead of raising") |
| 351 | +@pytest.mark.parametrize("csidl_name", sorted(_KNOWN_FOLDER_GUIDS)) |
| 352 | +def test_get_win_folder_from_registry_knows_every_known_folder(csidl_name: str) -> None: |
| 353 | + # Reaching the platform guard proves the name is in the lookup table; a missing one raises ValueError instead. |
| 354 | + with pytest.raises(NotImplementedError): |
| 355 | + get_win_folder_from_registry(csidl_name) |
| 356 | + |
| 357 | + |
| 358 | +@pytest.mark.skipif(sys.platform != "win32", reason="reads the live registry") |
| 359 | +@pytest.mark.parametrize("csidl_name", sorted(_KNOWN_FOLDER_GUIDS)) |
| 360 | +def test_get_win_folder_from_registry_real(csidl_name: str) -> None: |
| 361 | + assert Path(get_win_folder_from_registry(csidl_name)).is_absolute() |
| 362 | + |
| 363 | + |
| 364 | +@pytest.mark.parametrize("csidl_name", sorted(_KNOWN_FOLDER_GUIDS)) |
| 365 | +def test_get_win_folder_from_env_vars_knows_every_known_folder( |
| 366 | + monkeypatch: pytest.MonkeyPatch, csidl_name: str |
| 367 | +) -> None: |
| 368 | + # Every folder the ctypes resolver finds must also be reachable without it; desktop was missing from both |
| 369 | + # fallbacks, so user_desktop_dir raised ValueError on a Windows build without ctypes. |
| 370 | + monkeypatch.setenv("USERPROFILE", r"C:\Users\Test") |
| 371 | + monkeypatch.setenv("APPDATA", r"C:\Users\Test\AppData\Roaming") |
| 372 | + monkeypatch.setenv("LOCALAPPDATA", r"C:\Users\Test\AppData\Local") |
| 373 | + monkeypatch.setenv("ALLUSERSPROFILE", r"C:\ProgramData") |
| 374 | + assert get_win_folder_from_env_vars(csidl_name).startswith("C:") |
| 375 | + |
| 376 | + |
337 | 377 | def test_known_folder_guids_has_all_csidl_names() -> None: |
338 | 378 | expected = { |
339 | 379 | "CSIDL_APPDATA", |
|
0 commit comments