1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
from pathlib import Path
from textwrap import dedent
import pytest
from _pytest.config.findpaths import get_common_ancestor
from _pytest.config.findpaths import get_dirs_from_args
from _pytest.config.findpaths import load_config_dict_from_file
class TestLoadConfigDictFromFile:
def test_empty_pytest_ini(self, tmp_path: Path) -> None:
"""pytest.ini files are always considered for configuration, even if empty"""
fn = tmp_path / "pytest.ini"
fn.write_text("", encoding="utf-8")
assert load_config_dict_from_file(fn) == {}
def test_pytest_ini(self, tmp_path: Path) -> None:
"""[pytest] section in pytest.ini files is read correctly"""
fn = tmp_path / "pytest.ini"
fn.write_text("[pytest]\nx=1", encoding="utf-8")
assert load_config_dict_from_file(fn) == {"x": "1"}
def test_custom_ini(self, tmp_path: Path) -> None:
"""[pytest] section in any .ini file is read correctly"""
fn = tmp_path / "custom.ini"
fn.write_text("[pytest]\nx=1", encoding="utf-8")
assert load_config_dict_from_file(fn) == {"x": "1"}
def test_custom_ini_without_section(self, tmp_path: Path) -> None:
"""Custom .ini files without [pytest] section are not considered for configuration"""
fn = tmp_path / "custom.ini"
fn.write_text("[custom]", encoding="utf-8")
assert load_config_dict_from_file(fn) is None
def test_custom_cfg_file(self, tmp_path: Path) -> None:
"""Custom .cfg files without [tool:pytest] section are not considered for configuration"""
fn = tmp_path / "custom.cfg"
fn.write_text("[custom]", encoding="utf-8")
assert load_config_dict_from_file(fn) is None
def test_valid_cfg_file(self, tmp_path: Path) -> None:
"""Custom .cfg files with [tool:pytest] section are read correctly"""
fn = tmp_path / "custom.cfg"
fn.write_text("[tool:pytest]\nx=1", encoding="utf-8")
assert load_config_dict_from_file(fn) == {"x": "1"}
def test_unsupported_pytest_section_in_cfg_file(self, tmp_path: Path) -> None:
""".cfg files with [pytest] section are no longer supported and should fail to alert users"""
fn = tmp_path / "custom.cfg"
fn.write_text("[pytest]", encoding="utf-8")
with pytest.raises(pytest.fail.Exception):
load_config_dict_from_file(fn)
def test_invalid_toml_file(self, tmp_path: Path) -> None:
""".toml files without [tool.pytest.ini_options] are not considered for configuration."""
fn = tmp_path / "myconfig.toml"
fn.write_text(
dedent(
"""
[build_system]
x = 1
"""
),
encoding="utf-8",
)
assert load_config_dict_from_file(fn) is None
def test_valid_toml_file(self, tmp_path: Path) -> None:
""".toml files with [tool.pytest.ini_options] are read correctly, including changing
data types to str/list for compatibility with other configuration options."""
fn = tmp_path / "myconfig.toml"
fn.write_text(
dedent(
"""
[tool.pytest.ini_options]
x = 1
y = 20.0
values = ["tests", "integration"]
name = "foo"
"""
),
encoding="utf-8",
)
assert load_config_dict_from_file(fn) == {
"x": "1",
"y": "20.0",
"values": ["tests", "integration"],
"name": "foo",
}
class TestCommonAncestor:
def test_has_ancestor(self, tmp_path: Path) -> None:
fn1 = tmp_path / "foo" / "bar" / "test_1.py"
fn1.parent.mkdir(parents=True)
fn1.touch()
fn2 = tmp_path / "foo" / "zaz" / "test_2.py"
fn2.parent.mkdir(parents=True)
fn2.touch()
assert get_common_ancestor([fn1, fn2]) == tmp_path / "foo"
assert get_common_ancestor([fn1.parent, fn2]) == tmp_path / "foo"
assert get_common_ancestor([fn1.parent, fn2.parent]) == tmp_path / "foo"
assert get_common_ancestor([fn1, fn2.parent]) == tmp_path / "foo"
def test_single_dir(self, tmp_path: Path) -> None:
assert get_common_ancestor([tmp_path]) == tmp_path
def test_single_file(self, tmp_path: Path) -> None:
fn = tmp_path / "foo.py"
fn.touch()
assert get_common_ancestor([fn]) == tmp_path
def test_get_dirs_from_args(tmp_path):
"""get_dirs_from_args() skips over non-existing directories and files"""
fn = tmp_path / "foo.py"
fn.touch()
d = tmp_path / "tests"
d.mkdir()
option = "--foobar=/foo.txt"
# xdist uses options in this format for its rsync feature (#7638)
xdist_rsync_option = "popen=c:/dest"
assert get_dirs_from_args(
[str(fn), str(tmp_path / "does_not_exist"), str(d), option, xdist_rsync_option]
) == [fn.parent, d]
|