|
1 | 1 | """Defines shared fixtures and hooks for pytest.""" |
2 | 2 |
|
3 | | -import hashlib |
4 | | -import json |
5 | 3 | import logging |
6 | 4 | import os |
7 | 5 | import shutil |
|
10 | 8 |
|
11 | 9 | import pytest |
12 | 10 |
|
13 | | -from codesectools.utils import USER_CACHE_DIR |
14 | | - |
15 | 11 | # Fix: I/O operation on closed (https://github.com/pallets/click/issues/824) |
16 | 12 | logging.getLogger("matplotlib").setLevel(logging.ERROR) |
17 | 13 |
|
18 | | -test_type = os.environ.get("TEST_TYPE") |
19 | | -state_file = Path(f".pytest_cache/state_{test_type}.json") |
20 | | - |
21 | | - |
22 | | -def gen_state() -> dict[str, str]: |
23 | | - """Generate a state dictionary of source file paths and their SHA256 hashes. |
24 | | -
|
25 | | - Monitors .py files in 'codesectools' and 'tests' directories. |
26 | | - """ |
27 | | - state = {} |
28 | | - for directory in ["codesectools", "tests"]: |
29 | | - for code_path in Path(directory).rglob("*.py"): |
30 | | - path = str(code_path) |
31 | | - file_hash = hashlib.sha256(code_path.read_bytes()).hexdigest() |
32 | | - state[path] = file_hash |
33 | | - |
34 | | - return state |
35 | | - |
36 | | - |
37 | | -def source_code_changed() -> bool: |
38 | | - """Check if monitored source code has changed since the last successful test run. |
39 | | -
|
40 | | - Compares the current state with a saved state in '.pytest_cache/state.json'. |
41 | | - """ |
42 | | - if not state_file.is_file(): |
43 | | - return True |
44 | | - |
45 | | - with state_file.open("r") as f: |
46 | | - try: |
47 | | - old_state = json.load(f) |
48 | | - except json.JSONDecodeError: |
49 | | - return True |
50 | | - |
51 | | - new_state = gen_state() |
52 | | - |
53 | | - return new_state != old_state |
54 | | - |
55 | 14 |
|
56 | 15 | def pytest_sessionstart(session: pytest.Session) -> None: |
57 | | - """Pytest hook that runs at the beginning of a test session. |
58 | | -
|
59 | | - Skips the entire test session if no source files have changed. |
60 | | - """ |
61 | | - if USER_CACHE_DIR.is_dir(): |
62 | | - for child in USER_CACHE_DIR.iterdir(): |
63 | | - if child.is_file(): |
64 | | - child.unlink() |
65 | | - elif child.is_dir(): |
66 | | - shutil.rmtree(child) |
67 | | - |
68 | | - if not source_code_changed(): |
69 | | - pytest.exit("No changes in source code, skipping test session.", returncode=0) |
| 16 | + """Initialize the test session by copying test codes to a temporary directory.""" |
| 17 | + shutil.copytree(Path("tests/testcodes"), Path("/tmp/tests/testcodes")) |
70 | 18 |
|
71 | 19 |
|
72 | 20 | @pytest.fixture(autouse=True, scope="session") |
73 | 21 | def constant_random() -> GeneratorType: |
74 | 22 | """Set a constant random seed for reproducible tests.""" |
75 | 23 | os.environ["CONSTANT_RANDOM"] = os.urandom(16).hex() |
76 | 24 | yield |
77 | | - |
78 | | - |
79 | | -def pytest_sessionfinish(session: pytest.Session) -> None: |
80 | | - """Pytest hook that runs at the end of a test session. |
81 | | -
|
82 | | - Saves the current source code state if the test session was successful. |
83 | | - """ |
84 | | - if session.testscollected > 0 and session.testsfailed == 0: |
85 | | - new_state = gen_state() |
86 | | - state_file.parent.mkdir(exist_ok=True, parents=True) |
87 | | - with state_file.open("w") as f: |
88 | | - json.dump(new_state, f, indent=2) |
0 commit comments