helpers.py
Language Python2.4 KB74 lines
"""Shared test helpers: load a gate module fresh with its env, and copy thesample vaults into a temp dir so tests can edit, delete and symlink freely."""import contextlibimport importlib.utilimport ioimport itertoolsimport osimport shutilimport tempfilefrom pathlib import PathREPO = Path(__file__).resolve().parent.parentSAMPLE = REPO / "sample-vaults"_counter = itertools.count()def load(script: str, env: dict):"""Import REPO/<script> as a fresh module with `env` applied. The gates readtheir configuration from the environment at import time."""old = {k: os.environ.get(k) for k in env}os.environ.update(env)try:spec = importlib.util.spec_from_file_location(f"_bm_{Path(script).stem}_{next(_counter)}", REPO / script)mod = importlib.util.module_from_spec(spec)spec.loader.exec_module(mod)return modfinally:for k, v in old.items():if v is None:os.environ.pop(k, None)else:os.environ[k] = vdef run(mod) -> tuple[int, str]:"""Run mod.main(), capturing stdout."""buf = io.StringIO()with contextlib.redirect_stdout(buf):code = mod.main()return code, buf.getvalue()class TempVaults:"""A throwaway copy of the sample vaults plus a staging root."""def __init__(self):self.dir = Path(tempfile.mkdtemp(prefix="bm-test-"))self.vaults = self.dir / "vaults"shutil.copytree(SAMPLE, self.vaults)# A .git folder inside a nested vault cannot be committed to this repo,# so the fixture creates it here.git = self.vaults / "workbench" / "Efforts" / "garden-studio" / ".git"git.mkdir(parents=True)(git / "notes.md").write_text("# git internals\n\nWALLED at any depth.\n")self.workbench = self.vaults / "workbench"self.identity = self.vaults / "identity"self.staging_root = self.dir / "cowork-staging"@propertydef env(self) -> dict:return {"VAULT_ROOTS": f"{self.workbench}:{self.identity}","STAGING_DIR": str(self.staging_root), "EXTRA_DENY": ""}@propertydef staged(self) -> list[str]:d = self.staging_root / "staging"return sorted(p.name for p in d.iterdir()) if d.exists() else []def gate(self):return load("gate.py", self.env)def cleanup(self):shutil.rmtree(self.dir, ignore_errors=True)