test: add comprehensive coverage for cli, chat, renderer, dirs, install, paths
56 new tests covering previously untested modules: - test_cli.py: memory write/read/append/list + plugin enable/disable + daemon stubs (via CliRunner) - test_chat_history.py: ConversationHistory build_for_api, add_*/clear, _trim_to_budget - test_chat_renderer.py: render_text_response return values, void render_* functions - test_config_dirs.py: bootstrap idempotency, directory/template/vault/db creation - test_plugin_install.py: list_bundled_plugins, read_manifest, install_bundled_plugin - test_utils_paths.py: ensure_dir (nested, idempotent), safe_chmod Total: 171 → 227 passing tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
import json
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from pyra.plugins.install import (
|
||||
get_bundled_plugins_dir,
|
||||
install_bundled_plugin,
|
||||
list_bundled_plugins,
|
||||
read_manifest,
|
||||
)
|
||||
|
||||
|
||||
def test_get_bundled_plugins_dir_name():
|
||||
d = get_bundled_plugins_dir()
|
||||
assert d.name == "bundled_plugins"
|
||||
assert d.parent.name == "pyra"
|
||||
|
||||
|
||||
def test_list_bundled_plugins_empty_dir(tmp_path):
|
||||
bundled = tmp_path / "bundled"
|
||||
bundled.mkdir()
|
||||
assert list_bundled_plugins(bundled) == []
|
||||
|
||||
|
||||
def test_list_bundled_plugins_missing_dir(tmp_path):
|
||||
assert list_bundled_plugins(tmp_path / "nonexistent") == []
|
||||
|
||||
|
||||
def test_list_bundled_plugins_with_manifest(tmp_path):
|
||||
bundled = tmp_path / "bundled"
|
||||
plugin = bundled / "myplugin"
|
||||
plugin.mkdir(parents=True)
|
||||
(plugin / "manifest.json").write_text('{"name": "myplugin", "version": "1.0"}')
|
||||
assert list_bundled_plugins(bundled) == ["myplugin"]
|
||||
|
||||
|
||||
def test_list_bundled_plugins_without_manifest(tmp_path):
|
||||
bundled = tmp_path / "bundled"
|
||||
(bundled / "myplugin").mkdir(parents=True)
|
||||
assert list_bundled_plugins(bundled) == []
|
||||
|
||||
|
||||
def test_list_bundled_plugins_sorted(tmp_path):
|
||||
bundled = tmp_path / "bundled"
|
||||
for name in ["zebra", "alpha", "mango"]:
|
||||
p = bundled / name
|
||||
p.mkdir(parents=True)
|
||||
(p / "manifest.json").write_text("{}")
|
||||
result = list_bundled_plugins(bundled)
|
||||
assert result == sorted(result)
|
||||
|
||||
|
||||
def test_read_manifest_valid(tmp_path):
|
||||
plugin_dir = tmp_path / "myplugin"
|
||||
plugin_dir.mkdir()
|
||||
(plugin_dir / "manifest.json").write_text(
|
||||
json.dumps({"name": "myplugin", "version": "1.0.0", "description": "Test plugin"})
|
||||
)
|
||||
manifest = read_manifest(plugin_dir)
|
||||
assert manifest["name"] == "myplugin"
|
||||
assert manifest["version"] == "1.0.0"
|
||||
assert manifest["description"] == "Test plugin"
|
||||
|
||||
|
||||
def test_read_manifest_missing(tmp_path):
|
||||
plugin_dir = tmp_path / "myplugin"
|
||||
plugin_dir.mkdir()
|
||||
assert read_manifest(plugin_dir) == {}
|
||||
|
||||
|
||||
def test_install_bundled_plugin_not_found(tmp_path):
|
||||
bundled = tmp_path / "bundled"
|
||||
bundled.mkdir()
|
||||
plugins = tmp_path / "plugins"
|
||||
plugins.mkdir()
|
||||
with pytest.raises(FileNotFoundError):
|
||||
install_bundled_plugin("nonexistent", bundled, plugins)
|
||||
|
||||
|
||||
def test_install_bundled_plugin_missing_manifest(tmp_path):
|
||||
bundled = tmp_path / "bundled"
|
||||
(bundled / "myplugin").mkdir(parents=True)
|
||||
(bundled / "myplugin" / "plugin.py").write_text("# stub")
|
||||
plugins = tmp_path / "plugins"
|
||||
plugins.mkdir()
|
||||
with pytest.raises(FileNotFoundError):
|
||||
install_bundled_plugin("myplugin", bundled, plugins)
|
||||
|
||||
|
||||
def test_install_bundled_plugin_success(tmp_path):
|
||||
bundled = tmp_path / "bundled"
|
||||
src = bundled / "myplugin"
|
||||
src.mkdir(parents=True)
|
||||
(src / "manifest.json").write_text('{"name": "myplugin", "version": "1.0"}')
|
||||
(src / "plugin.py").write_text("# stub plugin")
|
||||
|
||||
plugins = tmp_path / "plugins"
|
||||
plugins.mkdir()
|
||||
|
||||
install_bundled_plugin("myplugin", bundled, plugins)
|
||||
|
||||
dest = plugins / "myplugin"
|
||||
assert dest.is_dir()
|
||||
assert (dest / "manifest.json").exists()
|
||||
assert (dest / "plugin.py").exists()
|
||||
if os.name != "nt":
|
||||
assert oct((dest / "plugin.py").stat().st_mode)[-3:] == "600"
|
||||
|
||||
|
||||
def test_install_bundled_plugin_overwrites(tmp_path):
|
||||
bundled = tmp_path / "bundled"
|
||||
src = bundled / "myplugin"
|
||||
src.mkdir(parents=True)
|
||||
(src / "manifest.json").write_text('{"name": "myplugin", "version": "1.0"}')
|
||||
|
||||
plugins = tmp_path / "plugins"
|
||||
plugins.mkdir()
|
||||
|
||||
install_bundled_plugin("myplugin", bundled, plugins)
|
||||
install_bundled_plugin("myplugin", bundled, plugins) # second install should not raise
|
||||
assert (plugins / "myplugin").is_dir()
|
||||
Reference in New Issue
Block a user