Skip to content

Commit 21b588a

Browse files
CodeRabbit Generated Unit Tests: Add pytest tests for discover_tests_candidates: globs, unicode
1 parent 62b3de7 commit 21b588a

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# Tests for discover_tests_candidates
2+
# Framework: pytest (preferred) with standard assertions and parametrization.
3+
# If your project uses unittest, these tests can be adapted to TestCase easily.
4+
5+
import os
6+
import sys
7+
from pathlib import Path
8+
9+
import pytest
10+
11+
try:
12+
# Try common import paths; adjust as needed if your module path differs.
13+
from discover import discover_tests_candidates
14+
except ImportError:
15+
try:
16+
from discovery import discover_tests_candidates
17+
except ImportError as err:
18+
# Fallback to project-local packages; this keeps tests resilient across refactors.
19+
from importlib import import_module as _imp
20+
_candidates = None
21+
for mod in (
22+
"src.discover",
23+
"src.discovery",
24+
"project.discover",
25+
"project.discovery",
26+
"tools.discover",
27+
):
28+
try:
29+
_m = _imp(mod)
30+
_candidates = getattr(_m, "discover_tests_candidates", None)
31+
if _candidates:
32+
discover_tests_candidates = _candidates # type: ignore
33+
break
34+
except ImportError:
35+
continue
36+
if not _candidates:
37+
raise ImportError() from err
38+
39+
40+
def _touch(p: Path, text: str = "") -> None:
41+
p.parent.mkdir(parents=True, exist_ok=True)
42+
p.write_text(text, encoding="utf-8")
43+
44+
45+
@pytest.fixture
46+
def tmp_tree(tmp_path: Path):
47+
# Create a representative test tree with various files and patterns
48+
files = {
49+
"tests/test_alpha.py": "def test_a(): pass\n",
50+
"tests/test_beta.py": "def test_b(): pass\n",
51+
"tests/helpers/util.py": "def helper(): pass\n",
52+
"package/module_test.py": "def test_c(): pass\n",
53+
"package/not_a_test.txt": "content\n",
54+
"nested/deep/test_gamma.py": "def test_g(): pass\n",
55+
"nested/deep/_private_test.py": "def test_p(): pass\n",
56+
"nested/deep/test_🌟.py": "def test_unicode(): pass\n",
57+
"nested/deep/__init__.py": "",
58+
"README.md": "# docs\n",
59+
}
60+
for rel, content in files.items():
61+
_touch(tmp_path / rel, content)
62+
return tmp_path
63+
64+
65+
def norm(p: Path) -> str:
66+
return str(p).replace("\\", "/")
67+
68+
69+
@pytest.mark.parametrize(
70+
"inputs,expected_contains,expected_absent",
71+
[
72+
# Happy path: standard tests/ directory with test_*.py
73+
(["tests/"], ["tests/test_alpha.py", "tests/test_beta.py"], ["tests/helpers/util.py"]),
74+
# Glob patterns
75+
(["**/test_*.py"], ["tests/test_alpha.py", "nested/deep/test_gamma.py"], ["package/not_a_test.txt"]),
76+
# Mixed files and dirs
77+
(["tests/test_beta.py", "nested/"], ["tests/test_beta.py", "nested/deep/test_gamma.py"], ["package/module_test.py"]),
78+
# File with unicode name
79+
(["nested/deep/"], ["nested/deep/test_🌟.py"], []),
80+
],
81+
)
82+
def test_discover_candidates_basic_patterns(tmp_tree: Path, inputs, expected_contains, expected_absent):
83+
cwd = os.getcwd()
84+
try:
85+
os.chdir(tmp_tree)
86+
results = list(discover_tests_candidates(inputs))
87+
results_n = sorted(norm(Path(p)) for p in results)
88+
for exp in expected_contains:
89+
assert any(r.endswith(exp) for r in results_n), f"Expected {exp} in {results_n}"
90+
for bad in expected_absent:
91+
assert all(not r.endswith(bad) for r in results_n), f"Did not expect {bad} in {results_n}"
92+
finally:
93+
os.chdir(cwd)
94+
95+
def test_discover_candidates_ignores_non_python_files(tmp_tree: Path):
96+
cwd = os.getcwd()
97+
try:
98+
os.chdir(tmp_tree)
99+
results = list(discover_tests_candidates(["."]))
100+
assert all(r.endswith(".py") for r in results), f"Non-Python files leaked into results: {results}"
101+
finally:
102+
os.chdir(cwd)
103+
104+
@pytest.mark.parametrize(
105+
"inputs",
106+
[
107+
([]),
108+
(["nonexistent_dir/"]),
109+
(["README.md"]),
110+
],
111+
)
112+
def test_discover_candidates_empty_or_invalid_inputs(tmp_tree: Path, inputs):
113+
cwd = os.getcwd()
114+
try:
115+
os.chdir(tmp_tree)
116+
results = list(discover_tests_candidates(inputs))
117+
# Either empty or gracefully handles invalid paths without raising
118+
assert isinstance(results, list) or hasattr(results, "__iter__")
119+
# Count should be zero for no valid candidates
120+
assert len(list(results)) == 0
121+
finally:
122+
os.chdir(cwd)
123+
124+
def test_discover_candidates_deduplicates_and_sorts(tmp_tree: Path):
125+
cwd = os.getcwd()
126+
try:
127+
os.chdir(tmp_tree)
128+
res = list(discover_tests_candidates(["tests/test_alpha.py", "tests/", "tests/test_alpha.py"]))
129+
# Expect no duplicates
130+
normed = [norm(Path(p)) for p in res]
131+
assert len(normed) == len(set(normed)), f"Duplicates found: {normed}"
132+
# Many implementations return deterministic order; if not, we at least check that sorting is stable
133+
assert sorted(normed) == sorted(set(normed))
134+
finally:
135+
os.chdir(cwd)
136+
137+
def test_discover_candidates_recurses_directories_respecting_test_naming(tmp_tree: Path):
138+
cwd = os.getcwd()
139+
try:
140+
os.chdir(tmp_tree)
141+
res = list(discover_tests_candidates(["package/"]))
142+
normed = [norm(Path(p)) for p in res]
143+
assert any(p.endswith("package/module_test.py") for p in normed), f"Expected module_test.py, got {normed}"
144+
assert all(not p.endswith("package/not_a_test.txt") for p in normed)
145+
finally:
146+
os.chdir(cwd)

0 commit comments

Comments
 (0)