|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
| 3 | +import os |
| 4 | +import sys |
3 | 5 | from typing import TYPE_CHECKING |
4 | 6 |
|
| 7 | +import pytest |
| 8 | + |
| 9 | +from tox.config.source.discover import discover_source |
| 10 | +from tox.report import HandledError |
| 11 | + |
5 | 12 | if TYPE_CHECKING: |
6 | 13 | from pathlib import Path |
7 | 14 |
|
8 | 15 | from tox.pytest import ToxProjectCreator |
9 | 16 |
|
10 | 17 |
|
| 18 | +# Root ignores the permission bits, and Windows does not model them this way, |
| 19 | +# so the file stays readable and there is nothing to assert. |
| 20 | +unreadable_files_possible = pytest.mark.skipif( |
| 21 | + sys.platform == "win32" or os.getuid() == 0, |
| 22 | + reason="cannot make a file unreadable as root or on Windows", |
| 23 | +) |
| 24 | + |
| 25 | + |
11 | 26 | def out_no_src(path: Path) -> str: |
12 | 27 | return ( |
13 | 28 | f"ROOT: No loadable tox.ini or setup.cfg or pyproject.toml or tox.toml found, assuming empty tox.ini at {path}" |
@@ -50,6 +65,30 @@ def test_bad_src_content(tox_project: ToxProjectCreator, tmp_path: Path) -> None |
50 | 65 | assert outcome.out == f"ROOT: HandledError| config file {tmp_path / 'setup.cfg'} does not exist\n" |
51 | 66 |
|
52 | 67 |
|
| 68 | +@unreadable_files_possible |
| 69 | +@pytest.mark.parametrize("named", [True, False], ids=["explicit-path", "discovery"]) |
| 70 | +def test_unreadable_config_raises_handled_error(tmp_path: Path, monkeypatch: pytest.MonkeyPatch, named: bool) -> None: |
| 71 | + """Reading the file raises an OSError subclass, not ValueError. |
| 72 | +
|
| 73 | + Without handling it, discovery lets PermissionError escape and the CLI prints a traceback instead of the one-line |
| 74 | + error used for malformed files. |
| 75 | +
|
| 76 | + This exercises discover_source directly: the tox_project fixture converts exceptions on its own, so it cannot tell |
| 77 | + the two cases apart. |
| 78 | +
|
| 79 | + """ |
| 80 | + config = tmp_path / "tox.ini" |
| 81 | + config.write_text("[tox]\nenv_list = py\n") |
| 82 | + config.chmod(0o000) |
| 83 | + monkeypatch.chdir(tmp_path) |
| 84 | + |
| 85 | + try: |
| 86 | + with pytest.raises(HandledError, match="failed loading"): |
| 87 | + discover_source(config if named else None, None) |
| 88 | + finally: |
| 89 | + config.chmod(0o644) |
| 90 | + |
| 91 | + |
53 | 92 | def test_malformed_config_does_not_prevent_help(tox_project: ToxProjectCreator) -> None: |
54 | 93 | project = tox_project({"tox.toml": "deps =\n mypy\n"}) |
55 | 94 | outcome = project.run("--help") |
|
0 commit comments