"""AC-1: project scaffolded matching the layout in AZ-263. Validates folder/file presence + that `pyproject.toml` and the top-level `CMakeLists.txt` + `cmake/{dependencies,build_options}.cmake` parse without error. The CMake configure step is gated on `cmake` being on PATH; when it isn't, the test skips with an explicit prerequisite reason. """ from __future__ import annotations import shutil import subprocess import sys from pathlib import Path import pytest REPO_ROOT = Path(__file__).resolve().parents[2] REQUIRED_PATHS: tuple[str, ...] = ( "pyproject.toml", "CMakeLists.txt", "cmake/dependencies.cmake", "cmake/build_options.cmake", "cmake/strategies.cmake", ".clang-format", ".clang-tidy", ".cmake-format.yaml", ".editorconfig", ".env.example", ".dockerignore", ".gitignore", "README.md", "docker/companion-tier1.Dockerfile", "docker/operator-orchestrator.Dockerfile", "docker/mock-suite-sat-service.Dockerfile", "docker-compose.yml", "docker-compose.test.yml", ".github/workflows/ci.yml", ".github/workflows/ci-tier2.yml", ".github/workflows/release.yml", ".github/workflows/cve-rescan.yml", "ci/sbom_diff.py", "ci/opencv_pin_gate.py", "src/gps_denied_onboard/__init__.py", "src/gps_denied_onboard/runtime_root/__init__.py", "src/gps_denied_onboard/healthcheck.py", "src/gps_denied_onboard/_types/__init__.py", "src/gps_denied_onboard/helpers/__init__.py", "src/gps_denied_onboard/logging/structured.py", "src/gps_denied_onboard/config/loader.py", "src/gps_denied_onboard/fdr_client/client.py", "alembic.ini", "db/migrations/env.py", "db/migrations/versions/0001_initial.py", "scripts/run-tests.sh", "scripts/run-performance-tests.sh", ) COMPONENT_DIRS: tuple[str, ...] = ( "c1_vio", "c2_vpr", "c2_5_rerank", "c3_matcher", "c3_5_adhop", "c4_pose", "c5_state", "c6_tile_cache", "c7_inference", "c8_fc_adapter", "c10_provisioning", "c11_tile_manager", "c12_operator_orchestrator", "c13_fdr", ) @pytest.mark.parametrize("rel_path", REQUIRED_PATHS) def test_required_path_exists(rel_path: str) -> None: # Assert assert (REPO_ROOT / rel_path).exists(), f"missing required path: {rel_path}" @pytest.mark.parametrize("component", COMPONENT_DIRS) def test_component_has_interface_and_init(component: str) -> None: # Assert comp_root = REPO_ROOT / "src" / "gps_denied_onboard" / "components" / component assert (comp_root / "__init__.py").exists(), f"missing __init__.py for {component}" assert (comp_root / "interface.py").exists(), f"missing interface.py for {component}" def test_pyproject_toml_parses() -> None: # Arrange if sys.version_info >= (3, 11): import tomllib else: try: import tomli as tomllib # type: ignore[no-redef] except ImportError: # pragma: no cover - tomli installed in dev extras pytest.skip("tomli/tomllib not available") # Act data = tomllib.loads((REPO_ROOT / "pyproject.toml").read_text()) # Assert assert data["project"]["name"] == "gps-denied-onboard" assert any(dep.startswith("opencv-python") for dep in data["project"]["dependencies"]), ( "opencv-python pin must be in dependencies" ) def test_cmake_files_configure() -> None: # Arrange cmake = shutil.which("cmake") if cmake is None: pytest.skip("cmake not on PATH; CI image installs cmake (Tier-1 ci.yml)") build_dir = REPO_ROOT / "build" / "ac1_smoke" build_dir.mkdir(parents=True, exist_ok=True) # Act result = subprocess.run( [ cmake, "-S", str(REPO_ROOT), "-B", str(build_dir), "-DBUILD_TESTING=OFF", ], capture_output=True, text=True, check=False, ) # Assert assert result.returncode == 0, ( f"cmake configure failed:\nstdout:\n{result.stdout}\nstderr:\n{result.stderr}" )