diff --git a/tests/test_cookbook_cli_state.py b/tests/test_cookbook_cli_state.py index 5673d5d..9abeacf 100644 --- a/tests/test_cookbook_cli_state.py +++ b/tests/test_cookbook_cli_state.py @@ -1,25 +1,12 @@ -import importlib.machinery -import importlib.util import io -from pathlib import Path import pytest - -ROOT = Path(__file__).resolve().parents[1] - - -def _load_cli(): - path = ROOT / "scripts" / "odysseus-cookbook" - loader = importlib.machinery.SourceFileLoader("odysseus_cookbook_cli", str(path)) - spec = importlib.util.spec_from_loader(loader.name, loader) - module = importlib.util.module_from_spec(spec) - loader.exec_module(module) - return module +from tests.helpers.cli_loader import load_script def test_state_set_rejects_non_object_json(tmp_path, monkeypatch, capsys): - cli = _load_cli() + cli = load_script("odysseus-cookbook") cli._STATE_PATH = tmp_path / "cookbook_state.json" monkeypatch.setattr(cli.sys, "stdin", io.StringIO("[]")) diff --git a/tests/test_logs_cli_resolve_nonstring.py b/tests/test_logs_cli_resolve_nonstring.py index 5c7d87c..6f3f64b 100644 --- a/tests/test_logs_cli_resolve_nonstring.py +++ b/tests/test_logs_cli_resolve_nonstring.py @@ -4,22 +4,10 @@ (e.g. None) raised TypeError once any *.log file existed. Non-strings now return None (no match). """ -import importlib.machinery -import importlib.util -from pathlib import Path - -ROOT = Path(__file__).resolve().parents[1] - - -def _load(): - loader = importlib.machinery.SourceFileLoader("odysseus_logs_cli", str(ROOT / "scripts" / "odysseus-logs")) - spec = importlib.util.spec_from_loader(loader.name, loader) - m = importlib.util.module_from_spec(spec) - loader.exec_module(m) - return m +from tests.helpers.cli_loader import load_script def test_non_string_name_returns_none(): - cli = _load() + cli = load_script("odysseus-logs") assert cli._resolve(None) is None assert cli._resolve(123) is None diff --git a/tests/test_memory_cli_rows.py b/tests/test_memory_cli_rows.py index fe63d24..e656cc6 100644 --- a/tests/test_memory_cli_rows.py +++ b/tests/test_memory_cli_rows.py @@ -1,24 +1,15 @@ -import importlib.machinery -import importlib.util import sys import types -from pathlib import Path from unittest.mock import MagicMock - -ROOT = Path(__file__).resolve().parents[1] +from tests.helpers.cli_loader import load_script def _load_cli(monkeypatch): svc = types.ModuleType("services.memory.memory") svc.MemoryManager = MagicMock() monkeypatch.setitem(sys.modules, "services.memory.memory", svc) - path = ROOT / "scripts" / "odysseus-memory" - loader = importlib.machinery.SourceFileLoader("odysseus_memory_cli", str(path)) - spec = importlib.util.spec_from_loader(loader.name, loader) - module = importlib.util.module_from_spec(spec) - loader.exec_module(module) - return module + return load_script("odysseus-memory") def test_memory_entries_skips_invalid_rows(monkeypatch): diff --git a/tests/test_odysseus_dispatcher.py b/tests/test_odysseus_dispatcher.py index 96637e7..199ae76 100644 --- a/tests/test_odysseus_dispatcher.py +++ b/tests/test_odysseus_dispatcher.py @@ -1,19 +1,8 @@ -import importlib.machinery -import importlib.util -from pathlib import Path - - -def _load_dispatcher(): - path = Path(__file__).resolve().parent.parent / "scripts" / "odysseus" - loader = importlib.machinery.SourceFileLoader("odysseus_dispatcher_under_test", str(path)) - spec = importlib.util.spec_from_loader(loader.name, loader) - module = importlib.util.module_from_spec(spec) - loader.exec_module(module) - return module +from tests.helpers.cli_loader import load_script def test_is_runnable_subcommand_requires_executable_file(tmp_path): - cli = _load_dispatcher() + cli = load_script("odysseus") sub = tmp_path / "odysseus-demo" sub.write_text("#!/bin/sh\n") sub.chmod(0o644) diff --git a/tests/test_personal_cli_rows.py b/tests/test_personal_cli_rows.py index b9fa861..0b7ed41 100644 --- a/tests/test_personal_cli_rows.py +++ b/tests/test_personal_cli_rows.py @@ -1,24 +1,15 @@ -import importlib.machinery -import importlib.util import sys import types -from pathlib import Path from unittest.mock import MagicMock - -ROOT = Path(__file__).resolve().parents[1] +from tests.helpers.cli_loader import load_script def _load_cli(monkeypatch): personal_docs = types.ModuleType("src.personal_docs") personal_docs.PersonalDocsManager = MagicMock() monkeypatch.setitem(sys.modules, "src.personal_docs", personal_docs) - path = ROOT / "scripts" / "odysseus-personal" - loader = importlib.machinery.SourceFileLoader("odysseus_personal_cli", str(path)) - spec = importlib.util.spec_from_loader(loader.name, loader) - module = importlib.util.module_from_spec(spec) - loader.exec_module(module) - return module + return load_script("odysseus-personal") def test_file_rows_skips_invalid_rows(monkeypatch): diff --git a/tests/test_preset_cli_invalid_entries.py b/tests/test_preset_cli_invalid_entries.py index 11110e1..3bf192d 100644 --- a/tests/test_preset_cli_invalid_entries.py +++ b/tests/test_preset_cli_invalid_entries.py @@ -1,19 +1,8 @@ -import importlib.machinery -import importlib.util -from pathlib import Path - - -def _load_preset_cli(): - path = Path(__file__).resolve().parent.parent / "scripts" / "odysseus-preset" - loader = importlib.machinery.SourceFileLoader("odysseus_preset_invalid_entries", str(path)) - spec = importlib.util.spec_from_loader(loader.name, loader) - module = importlib.util.module_from_spec(spec) - loader.exec_module(module) - return module +from tests.helpers.cli_loader import load_script def test_entry_or_fail_rejects_non_object_entries(): - cli = _load_preset_cli() + cli = load_script("odysseus-preset") try: cli._entry_or_fail({"broken": "raw prompt"}, "broken") @@ -24,6 +13,6 @@ def test_entry_or_fail_rejects_non_object_entries(): def test_entry_or_fail_returns_valid_entry(): - cli = _load_preset_cli() + cli = load_script("odysseus-preset") assert cli._entry_or_fail({"ok": {"name": "ok"}}, "ok") == {"name": "ok"} diff --git a/tests/test_preset_cli_store.py b/tests/test_preset_cli_store.py index c9cc0bb..dd42ee5 100644 --- a/tests/test_preset_cli_store.py +++ b/tests/test_preset_cli_store.py @@ -1,24 +1,10 @@ -import importlib.machinery -import importlib.util -from pathlib import Path - import pytest - -ROOT = Path(__file__).resolve().parents[1] - - -def _load_cli(): - path = ROOT / "scripts" / "odysseus-preset" - loader = importlib.machinery.SourceFileLoader("odysseus_preset_cli", str(path)) - spec = importlib.util.spec_from_loader(loader.name, loader) - module = importlib.util.module_from_spec(spec) - loader.exec_module(module) - return module +from tests.helpers.cli_loader import load_script def test_load_rejects_non_object_preset_store(tmp_path, capsys): - cli = _load_cli() + cli = load_script("odysseus-preset") cli._PATH = tmp_path / "presets.json" cli._PATH.write_text("[]") diff --git a/tests/test_skills_cli_rows.py b/tests/test_skills_cli_rows.py index 5438b46..da8e0b1 100644 --- a/tests/test_skills_cli_rows.py +++ b/tests/test_skills_cli_rows.py @@ -1,24 +1,15 @@ -import importlib.machinery -import importlib.util import sys import types -from pathlib import Path from unittest.mock import MagicMock - -ROOT = Path(__file__).resolve().parents[1] +from tests.helpers.cli_loader import load_script def _load_cli(monkeypatch): svc = types.ModuleType("services.memory.skills") svc.SkillsManager = MagicMock() monkeypatch.setitem(sys.modules, "services.memory.skills", svc) - path = ROOT / "scripts" / "odysseus-skills" - loader = importlib.machinery.SourceFileLoader("odysseus_skills_cli", str(path)) - spec = importlib.util.spec_from_loader(loader.name, loader) - module = importlib.util.module_from_spec(spec) - loader.exec_module(module) - return module + return load_script("odysseus-skills") def test_skill_entries_skips_invalid_rows(monkeypatch): diff --git a/tests/test_theme_cli_store.py b/tests/test_theme_cli_store.py index 3e0a2d8..f38985c 100644 --- a/tests/test_theme_cli_store.py +++ b/tests/test_theme_cli_store.py @@ -1,25 +1,11 @@ -import importlib.machinery -import importlib.util -from pathlib import Path - import pytest - -ROOT = Path(__file__).resolve().parents[1] - - -def _load_cli(): - path = ROOT / "scripts" / "odysseus-theme" - loader = importlib.machinery.SourceFileLoader("odysseus_theme_cli", str(path)) - spec = importlib.util.spec_from_loader(loader.name, loader) - module = importlib.util.module_from_spec(spec) - loader.exec_module(module) - return module +from tests.helpers.cli_loader import load_script @pytest.mark.parametrize("payload", ["[]", '{"_users": []}']) def test_load_prefs_rejects_non_object_user_store(tmp_path, capsys, payload): - cli = _load_cli() + cli = load_script("odysseus-theme") cli._USER_PREFS_PATH = tmp_path / "user_prefs.json" cli._USER_PREFS_PATH.write_text(payload)