-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun_topic_tests.py
More file actions
executable file
·108 lines (84 loc) · 2.97 KB
/
run_topic_tests.py
File metadata and controls
executable file
·108 lines (84 loc) · 2.97 KB
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
#!/usr/bin/env python3
"""Run topic exercise tests sequentially.
This repository stores many files named tests/test_basic.py. Running pytest
against multiple topics in one collection pass can trigger module name
collisions, so this helper executes one test file at a time.
"""
from __future__ import annotations
import argparse
import subprocess
import sys
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
def discover_test_files() -> list[Path]:
return sorted(REPO_ROOT.glob("**/tests/test_basic.py"))
def resolve_target(target: str) -> list[Path]:
path = (REPO_ROOT / target).resolve()
if not path.exists():
raise FileNotFoundError(f"Target not found: {target}")
if path.is_file():
if path.name != "test_basic.py":
raise ValueError("Only tests/test_basic.py files are supported")
return [path]
tests_dir = path / "tests"
direct_test = tests_dir / "test_basic.py"
if direct_test.exists():
return [direct_test]
return sorted(path.glob("**/tests/test_basic.py"))
def run_test_file(test_file: Path, verbose: bool) -> int:
cmd = [sys.executable, "-m", "pytest"]
if not verbose:
cmd.append("-q")
cmd.extend(["-o", "addopts=", str(test_file)])
return subprocess.run(cmd, cwd=REPO_ROOT).returncode # noqa: S603
def main() -> int:
parser = argparse.ArgumentParser(
description=("Run topic tests one file at a time to avoid pytest collisions."),
)
parser.add_argument(
"targets",
nargs="*",
help=("Optional topic/module paths or specific tests/test_basic.py files."),
)
parser.add_argument(
"--fail-fast",
action="store_true",
help="Stop after the first failing test file.",
)
parser.add_argument(
"--verbose",
action="store_true",
help="Use normal pytest output instead of -q.",
)
args = parser.parse_args()
try:
files = []
if args.targets:
for target in args.targets:
files.extend(resolve_target(target))
else:
files = discover_test_files()
except (FileNotFoundError, ValueError) as exc:
print(f"ERROR: {exc}")
return 2
unique_files = sorted({path.resolve() for path in files})
if not unique_files:
print("ERROR: no tests/test_basic.py files found for the given target(s)")
return 2
failures = 0
for test_file in unique_files:
rel = test_file.relative_to(REPO_ROOT)
print(f"== {rel} ==")
exit_code = run_test_file(test_file, verbose=args.verbose)
if exit_code == 0:
print("PASS\n")
continue
failures += 1
print(f"FAIL (exit {exit_code})\n")
if args.fail_fast:
break
passed = len(unique_files) - failures
print(f"Summary: {passed}/{len(unique_files)} test files passed")
return 0 if failures == 0 else 1
if __name__ == "__main__":
raise SystemExit(main())