emergent-security/tests/fixture_loading.py

59 lines
1.8 KiB
Python

"""Shared fixture loading for the envelope tests.
Fixture files are data (YAML). These helpers only load and merge them; all policy
logic lives in the library under test.
"""
from __future__ import annotations
import copy
from pathlib import Path
from typing import Any
import pytest
import yaml
ROOT = Path(__file__).resolve().parent.parent
ENVELOPES = ROOT / "envelopes"
FIXTURES = Path(__file__).resolve().parent / "fixtures"
DELETE = "~delete"
def load_yaml(path: Path) -> Any:
with path.open(encoding="utf-8") as handle:
return yaml.safe_load(handle)
def deep_merge(base: Any, patch: Any) -> Any:
"""Return base with patch merged in; dicts merge recursively, '~delete' removes a key."""
if not isinstance(base, dict) or not isinstance(patch, dict):
return copy.deepcopy(patch)
merged = copy.deepcopy(base)
for key, value in patch.items():
if value == DELETE:
merged.pop(key, None)
elif key in merged:
merged[key] = deep_merge(merged[key], value)
else:
merged[key] = copy.deepcopy(value)
return merged
def decision_cases() -> list[pytest.param]:
"""All decision cases from fixtures/decisions/*.yaml, with file context merged per case."""
params = []
for path in sorted((FIXTURES / "decisions").glob("*.yaml")):
document = load_yaml(path)
file_context = document.get("context", {})
default_request = document.get("defaults", {}).get("request", {})
for case in document["cases"]:
params.append(
pytest.param(
deep_merge(default_request, case["request"]),
{**file_context, **case.get("context", {})},
case["expect"],
id=f"{path.stem}: {case['name']}",
)
)
return params