37 lines
1.4 KiB
Python
37 lines
1.4 KiB
Python
from __future__ import annotations
|
|||
|
|
|
||
|
|
import ast
|
||
|
|
from pathlib import Path
|
||
|
|
import unittest
|
||
|
|
|
||
|
|
|
||
|
|
SRC = Path(__file__).resolve().parents[2] / "src" / "cmbuyer_client"
|
||
|
|
SCOPED = tuple((SRC / name) for name in ("core", "remote", "localstate"))
|
||
|
|
|
||
|
|
|
||
|
|
class StaticBoundaryTests(unittest.TestCase):
|
||
|
|
def test_scoped_modules_do_not_import_device_pdd_or_unapproved_capabilities(self) -> None:
|
||
|
|
forbidden_modules = ("cmbuyer_client.device", "cmbuyer_client.pdd")
|
||
|
|
forbidden_text = (
|
||
|
|
"ResultSink",
|
||
|
|
"/events",
|
||
|
|
"/fail",
|
||
|
|
"/submission-fence",
|
||
|
|
"/result",
|
||
|
|
"click_permitted",
|
||
|
|
)
|
||
|
|
for directory in SCOPED:
|
||
|
|
for path in directory.glob("*.py"):
|
||
|
|
text = path.read_text(encoding="utf-8")
|
||
|
|
tree = ast.parse(text)
|
||
|
|
imports = []
|
||
|
|
for node in ast.walk(tree):
|
||
|
|
if isinstance(node, ast.Import):
|
||
|
|
imports.extend(alias.name for alias in node.names)
|
||
|
|
elif isinstance(node, ast.ImportFrom) and node.module:
|
||
|
|
imports.append(node.module)
|
||
|
|
for module in forbidden_modules:
|
||
|
|
self.assertFalse(any(name.startswith(module) for name in imports), (path, module))
|
||
|
|
for value in forbidden_text:
|
||
|
|
self.assertNotIn(value, text, (path, value))
|