"""Guards for the pytest harness itself. ``tests/conftest.py`` was accidentally deleted in commit edc6e42 while four test modules still depended on its fixtures, which made the suite unrunnable without anything failing loudly in CI. These tests turn that class of regression into an explicit failure, and also catch a stale ``orisys`` install silently shadowing ``src/orisys`` (a real hazard: base/py312 environments have older orisys copies in site-packages). """ from __future__ import annotations import functools import importlib.util from pathlib import Path import pytest REPO_ROOT = Path(__file__).resolve().parents[1] CONFTEST_PATH = Path(__file__).resolve().parent / "conftest.py" # Names that must exist in tests/conftest.py. REQUIRED_CONFTEST_NAMES = ( "DEFAULT_VIDEO_CANDIDATES", "make_sensor", "test_video_path", "test_config_name", "available_backends", "sensor_factory", ) # Fixtures that must be resolvable through pytest. REQUIRED_FIXTURES = ( "test_video_path", "test_config_name", "available_backends", "sensor_factory", ) @functools.lru_cache(maxsize=1) def _load_conftest_module(): """Load tests/conftest.py by path so a deletion is observable here.""" spec = importlib.util.spec_from_file_location("_orisys_conftest_probe", CONFTEST_PATH) if spec is None or spec.loader is None: raise AssertionError(f"Cannot load {CONFTEST_PATH}") module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module def test_conftest_defines_shared_fixtures(): assert CONFTEST_PATH.is_file(), ( f"{CONFTEST_PATH} is missing. test_backends.py, test_smoke_api.py, " "test_errors_and_cleanup.py and test_longrun_stability.py depend on its " "fixtures; it was accidentally deleted in commit edc6e42. Restore it " "instead of deleting it." ) module = _load_conftest_module() missing = [ name for name in REQUIRED_CONFTEST_NAMES if getattr(module, name, None) is None ] assert not missing, ( f"tests/conftest.py no longer defines: {', '.join(missing)}. " "The shared sensor-test fixtures are required by the suite." ) def test_default_test_video_is_reachable(): """At least one default candidate must exist, or every sensor test skips.""" module = _load_conftest_module() candidates = [REPO_ROOT / Path(rel) for rel in module.DEFAULT_VIDEO_CANDIDATES] existing = [path for path in candidates if path.is_file()] assert existing, ( "None of the default test videos exist:\n " + "\n ".join(str(path) for path in candidates) + "\nCommit a sample clip under data/sample/ or set ORISYS_TEST_VIDEO." ) def test_fixtures_are_registered_with_pytest(request): missing: list[str] = [] for name in REQUIRED_FIXTURES: try: request.getfixturevalue(name) except pytest.FixtureLookupError: missing.append(name) assert not missing, ( f"pytest did not register these fixtures: {', '.join(missing)}. " "Check that tests/conftest.py is present and the @pytest.fixture " "decorators are intact." ) def test_import_precedence_is_correct(): """examples/ must beat build/ for `gui`; build/ must beat site-packages. Regression guard: build/gui is a package named `gui`, so if build/ precedes examples/ on sys.path then `import gui.viewer2d` resolves to the build tooling and tests/test_qt_viewer_backend.py fails at collection. """ import common import gui import wheel examples_gui = (REPO_ROOT / "examples" / "gui").resolve() build_root = (REPO_ROOT / "build").resolve() assert Path(gui.__file__).resolve().parent == examples_gui, ( f"`gui` resolved to {gui.__file__} instead of {examples_gui}; " "examples/ must precede build/ on sys.path" ) for module in (common, wheel): resolved = Path(module.__file__).resolve() assert build_root in resolved.parents, ( f"`{module.__name__}` resolved to {resolved}, outside {build_root}; " "build/ must precede site-packages on sys.path" ) def test_tests_run_against_checkout_not_stale_install(): """Fail loudly when an old orisys in site-packages shadows src/orisys.""" src_pkg = (REPO_ROOT / "src" / "orisys").resolve() if not src_pkg.is_dir(): pytest.skip("src/orisys is not present in this checkout layout") import orisys module_file = getattr(orisys, "__file__", None) assert module_file, ( "import orisys resolved to a namespace package (__file__ is None) " f"instead of {src_pkg}. A stale orisys in site-packages is shadowing " "the checkout; run `pip uninstall -y orisys` in this environment." ) resolved_parent = Path(module_file).resolve().parent assert resolved_parent == src_pkg, ( f"import orisys resolved to {resolved_parent} instead of {src_pkg}. " "A stale orisys in site-packages is shadowing the checkout; run " "`pip uninstall -y orisys` in this environment." )