mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
Merge pull request #73 from JonanOribe/main
This commit is contained in:
@@ -31,6 +31,9 @@ dependencies = [
|
||||
"pyserial>=3.5",
|
||||
"Werkzeug>=3.1.5",
|
||||
"flask-limiter>=2.5.4",
|
||||
"bleak>=0.21.0",
|
||||
"flask-sock",
|
||||
"requests>=2.28.0",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
flask>=2.0.0
|
||||
flask-limiter>=2.5.4
|
||||
requests>=2.28.0
|
||||
Werkzeug>=3.1.5
|
||||
|
||||
# BLE scanning with manufacturer data detection (optional - for TSCM)
|
||||
bleak>=0.21.0
|
||||
|
||||
109
tests/test_requirements.py
Normal file
109
tests/test_requirements.py
Normal file
@@ -0,0 +1,109 @@
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
import importlib.metadata
|
||||
import tomllib # Standard in Python 3.11+
|
||||
|
||||
def get_root_path():
|
||||
return Path(__file__).parent.parent
|
||||
|
||||
def _clean_string(req):
|
||||
"""Normalizes a requirement string (lowercase and removes spaces)."""
|
||||
return req.strip().lower().replace(" ", "")
|
||||
|
||||
def parse_txt_requirements(file_path):
|
||||
"""Extracts full requirement strings (name + version) from a .txt file."""
|
||||
if not file_path.exists():
|
||||
return set()
|
||||
packages = set()
|
||||
with open(file_path, "r") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
# Ignore empty lines, comments, and recursive/local flags
|
||||
if not line or line.startswith(("#", "-e", "git+", "-r")):
|
||||
continue
|
||||
packages.add(_clean_string(line))
|
||||
return packages
|
||||
|
||||
def parse_toml_section(data, section_type="main"):
|
||||
"""Extracts full requirement strings from pyproject.toml."""
|
||||
packages = set()
|
||||
if section_type == "main":
|
||||
deps = data.get("project", {}).get("dependencies", [])
|
||||
else:
|
||||
# Check optional-dependencies or dependency-groups
|
||||
deps = data.get("project", {}).get("optional-dependencies", {}).get("dev", [])
|
||||
if not deps:
|
||||
deps = data.get("dependency-groups", {}).get("dev", [])
|
||||
|
||||
for req in deps:
|
||||
packages.add(_clean_string(req))
|
||||
return packages
|
||||
|
||||
def test_dependency_files_integrity():
|
||||
"""1. Verifies that .txt files and pyproject.toml have identical names AND versions."""
|
||||
root = get_root_path()
|
||||
toml_path = root / "pyproject.toml"
|
||||
assert toml_path.exists(), "Missing pyproject.toml"
|
||||
|
||||
with open(toml_path, "rb") as f:
|
||||
toml_data = tomllib.load(f)
|
||||
|
||||
# Validate Production Sync
|
||||
txt_main = parse_txt_requirements(root / "requirements.txt")
|
||||
toml_main = parse_toml_section(toml_data, "main")
|
||||
assert txt_main == toml_main, (
|
||||
f"Production version mismatch!\n"
|
||||
f"Only in TXT: {txt_main - toml_main}\n"
|
||||
f"Only in TOML: {toml_main - txt_main}"
|
||||
)
|
||||
|
||||
# Validate Development Sync
|
||||
txt_dev = parse_txt_requirements(root / "requirements-dev.txt")
|
||||
toml_dev = parse_toml_section(toml_data, "dev")
|
||||
assert txt_dev == toml_dev, (
|
||||
f"Development version mismatch!\n"
|
||||
f"Only in TXT: {txt_dev - toml_dev}\n"
|
||||
f"Only in TOML: {toml_dev - txt_dev}"
|
||||
)
|
||||
|
||||
def test_environment_vs_toml():
|
||||
"""2. Verifies that installed packages satisfy TOML requirements."""
|
||||
root = get_root_path()
|
||||
with open(root / "pyproject.toml", "rb") as f:
|
||||
data = tomllib.load(f)
|
||||
|
||||
all_declared = parse_toml_section(data, "main") | parse_toml_section(data, "dev")
|
||||
_verify_installation(all_declared, "TOML")
|
||||
|
||||
def test_environment_vs_requirements():
|
||||
"""3. Verifies that installed packages satisfy .txt requirements."""
|
||||
root = get_root_path()
|
||||
all_txt_deps = (
|
||||
parse_txt_requirements(root / "requirements.txt") |
|
||||
parse_txt_requirements(root / "requirements-dev.txt")
|
||||
)
|
||||
_verify_installation(all_txt_deps, "requirements.txt")
|
||||
|
||||
def _verify_installation(package_set, source_name):
|
||||
"""Helper to check if declared versions match installed versions."""
|
||||
missing_or_wrong = []
|
||||
|
||||
for req in package_set:
|
||||
# Split name from version to check installation status
|
||||
# handles ==, >=, ~=, <=, > , <
|
||||
import re
|
||||
parts = re.split(r'==|>=|~=|<=|>|<', req)
|
||||
name = parts[0].strip()
|
||||
|
||||
try:
|
||||
installed_ver = importlib.metadata.version(name)
|
||||
# If the config uses exact versioning '==', we can do a strict check
|
||||
if "==" in req:
|
||||
expected_ver = req.split("==")[1].strip()
|
||||
if installed_ver != expected_ver:
|
||||
missing_or_wrong.append(f"{name} (Installed: {installed_ver}, Expected: {expected_ver})")
|
||||
except importlib.metadata.PackageNotFoundError:
|
||||
missing_or_wrong.append(f"{name} (Not installed)")
|
||||
|
||||
if missing_or_wrong:
|
||||
pytest.fail(f"Environment out of sync with {source_name}:\n" + "\n".join(missing_or_wrong))
|
||||
Reference in New Issue
Block a user