2026-07-23 16:05:54 -07:00
|
|
|
from pathlib import Path
|
|
|
|
|
|
2026-07-23 12:18:13 -07:00
|
|
|
import pytest
|
|
|
|
|
from unittest.mock import MagicMock
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
|
def mock_ctx():
|
|
|
|
|
ctx = MagicMock()
|
|
|
|
|
ctx._hooks = {}
|
2026-07-23 16:05:54 -07:00
|
|
|
ctx._skills = {}
|
2026-07-23 12:18:13 -07:00
|
|
|
|
|
|
|
|
def register_hook(event, fn):
|
|
|
|
|
ctx._hooks[event] = fn
|
|
|
|
|
|
2026-07-23 16:05:54 -07:00
|
|
|
def register_skill(name, path):
|
|
|
|
|
# Mimic hermes' real register_skill, which calls path.exists() and
|
|
|
|
|
# therefore breaks on a str (the bug that silently disabled the whole
|
|
|
|
|
# plugin, found 2026-07-23). Keeping that fidelity here means a
|
|
|
|
|
# regression to str paths fails these tests instead of failing
|
|
|
|
|
# silently inside hermes.
|
|
|
|
|
if not isinstance(path, Path):
|
|
|
|
|
raise AttributeError(
|
|
|
|
|
f"register_skill requires a pathlib.Path, got {type(path).__name__}"
|
|
|
|
|
)
|
|
|
|
|
ctx._skills[name] = path
|
2026-07-23 12:18:13 -07:00
|
|
|
|
|
|
|
|
ctx.register_hook.side_effect = register_hook
|
2026-07-23 16:05:54 -07:00
|
|
|
ctx.register_skill.side_effect = register_skill
|
2026-07-23 12:18:13 -07:00
|
|
|
return ctx
|