mirror of
https://github.com/github/spec-kit.git
synced 2026-08-15 14:02:04 +02:00
170 lines
6.1 KiB
Python
170 lines
6.1 KiB
Python
"""Tests for IntegrationOption, IntegrationBase, MarkdownIntegration, and primitives."""
|
|||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from specify_cli.integrations.base import (
|
||
|
|
IntegrationBase,
|
||
|
|
IntegrationOption,
|
||
|
|
MarkdownIntegration,
|
||
|
|
)
|
||
|
|
from specify_cli.integrations.manifest import IntegrationManifest
|
||
|
|
from .conftest import StubIntegration
|
||
|
|
|
||
|
|
|
||
|
|
class TestIntegrationOption:
|
||
|
|
def test_defaults(self):
|
||
|
|
opt = IntegrationOption(name="--flag")
|
||
|
|
assert opt.name == "--flag"
|
||
|
|
assert opt.is_flag is False
|
||
|
|
assert opt.required is False
|
||
|
|
assert opt.default is None
|
||
|
|
assert opt.help == ""
|
||
|
|
|
||
|
|
def test_flag_option(self):
|
||
|
|
opt = IntegrationOption(name="--skills", is_flag=True, default=True, help="Enable skills")
|
||
|
|
assert opt.is_flag is True
|
||
|
|
assert opt.default is True
|
||
|
|
assert opt.help == "Enable skills"
|
||
|
|
|
||
|
|
def test_required_option(self):
|
||
|
|
opt = IntegrationOption(name="--commands-dir", required=True, help="Dir path")
|
||
|
|
assert opt.required is True
|
||
|
|
|
||
|
|
def test_frozen(self):
|
||
|
|
opt = IntegrationOption(name="--x")
|
||
|
|
with pytest.raises(AttributeError):
|
||
|
|
opt.name = "--y" # type: ignore[misc]
|
||
|
|
|
||
|
|
|
||
|
|
class TestIntegrationBase:
|
||
|
|
def test_key_and_config(self):
|
||
|
|
i = StubIntegration()
|
||
|
|
assert i.key == "stub"
|
||
|
|
assert i.config["name"] == "Stub Agent"
|
||
|
|
assert i.registrar_config["format"] == "markdown"
|
||
|
|
assert i.context_file == "STUB.md"
|
||
|
|
|
||
|
|
def test_options_default_empty(self):
|
||
|
|
assert StubIntegration.options() == []
|
||
|
|
|
||
|
|
def test_shared_commands_dir(self):
|
||
|
|
i = StubIntegration()
|
||
|
|
cmd_dir = i.shared_commands_dir()
|
||
|
|
assert cmd_dir is not None
|
||
|
|
assert cmd_dir.is_dir()
|
||
|
|
|
||
|
|
def test_setup_uses_shared_templates(self, tmp_path):
|
||
|
|
i = StubIntegration()
|
||
|
|
manifest = IntegrationManifest("stub", tmp_path)
|
||
|
|
created = i.setup(tmp_path, manifest)
|
||
|
|
assert len(created) > 0
|
||
|
|
for f in created:
|
||
|
|
assert f.parent == tmp_path / ".stub" / "commands"
|
||
|
|
assert f.name.startswith("speckit.")
|
||
|
|
assert f.name.endswith(".md")
|
||
|
|
|
||
|
|
def test_setup_copies_templates(self, tmp_path, monkeypatch):
|
||
|
|
tpl = tmp_path / "_templates"
|
||
|
|
tpl.mkdir()
|
||
|
|
(tpl / "plan.md").write_text("plan content", encoding="utf-8")
|
||
|
|
(tpl / "specify.md").write_text("spec content", encoding="utf-8")
|
||
|
|
|
||
|
|
i = StubIntegration()
|
||
|
|
monkeypatch.setattr(type(i), "list_command_templates", lambda self: sorted(tpl.glob("*.md")))
|
||
|
|
|
||
|
|
project = tmp_path / "project"
|
||
|
|
project.mkdir()
|
||
|
|
created = i.setup(project, IntegrationManifest("stub", project))
|
||
|
|
assert len(created) == 2
|
||
|
|
assert (project / ".stub" / "commands" / "speckit.plan.md").exists()
|
||
|
|
assert (project / ".stub" / "commands" / "speckit.specify.md").exists()
|
||
|
|
|
||
|
|
def test_install_delegates_to_setup(self, tmp_path):
|
||
|
|
i = StubIntegration()
|
||
|
|
manifest = IntegrationManifest("stub", tmp_path)
|
||
|
|
result = i.install(tmp_path, manifest)
|
||
|
|
assert len(result) > 0
|
||
|
|
|
||
|
|
def test_uninstall_delegates_to_teardown(self, tmp_path):
|
||
|
|
i = StubIntegration()
|
||
|
|
manifest = IntegrationManifest("stub", tmp_path)
|
||
|
|
removed, skipped = i.uninstall(tmp_path, manifest)
|
||
|
|
assert removed == []
|
||
|
|
assert skipped == []
|
||
|
|
|
||
|
|
|
||
|
|
class TestMarkdownIntegration:
|
||
|
|
def test_is_subclass_of_base(self):
|
||
|
|
assert issubclass(MarkdownIntegration, IntegrationBase)
|
||
|
|
|
||
|
|
def test_stub_is_markdown(self):
|
||
|
|
assert isinstance(StubIntegration(), MarkdownIntegration)
|
||
|
|
|
||
|
|
|
||
|
|
class TestBasePrimitives:
|
||
|
|
def test_shared_commands_dir_returns_path(self):
|
||
|
|
i = StubIntegration()
|
||
|
|
cmd_dir = i.shared_commands_dir()
|
||
|
|
assert cmd_dir is not None
|
||
|
|
assert cmd_dir.is_dir()
|
||
|
|
|
||
|
|
def test_shared_templates_dir_returns_path(self):
|
||
|
|
i = StubIntegration()
|
||
|
|
tpl_dir = i.shared_templates_dir()
|
||
|
|
assert tpl_dir is not None
|
||
|
|
assert tpl_dir.is_dir()
|
||
|
|
|
||
|
|
def test_list_command_templates_returns_md_files(self):
|
||
|
|
i = StubIntegration()
|
||
|
|
templates = i.list_command_templates()
|
||
|
|
assert len(templates) > 0
|
||
|
|
assert all(t.suffix == ".md" for t in templates)
|
||
|
|
|
||
|
|
def test_command_filename_default(self):
|
||
|
|
i = StubIntegration()
|
||
|
|
assert i.command_filename("plan") == "speckit.plan.md"
|
||
|
|
|
||
|
|
def test_commands_dest(self, tmp_path):
|
||
|
|
i = StubIntegration()
|
||
|
|
dest = i.commands_dest(tmp_path)
|
||
|
|
assert dest == tmp_path / ".stub" / "commands"
|
||
|
|
|
||
|
|
def test_commands_dest_no_config_raises(self, tmp_path):
|
||
|
|
class NoConfig(MarkdownIntegration):
|
||
|
|
key = "noconfig"
|
||
|
|
with pytest.raises(ValueError, match="config is not set"):
|
||
|
|
NoConfig().commands_dest(tmp_path)
|
||
|
|
|
||
|
|
def test_copy_command_to_directory(self, tmp_path):
|
||
|
|
src = tmp_path / "source.md"
|
||
|
|
src.write_text("content", encoding="utf-8")
|
||
|
|
dest_dir = tmp_path / "output"
|
||
|
|
result = IntegrationBase.copy_command_to_directory(src, dest_dir, "speckit.plan.md")
|
||
|
|
assert result == dest_dir / "speckit.plan.md"
|
||
|
|
assert result.read_text(encoding="utf-8") == "content"
|
||
|
|
|
||
|
|
def test_record_file_in_manifest(self, tmp_path):
|
||
|
|
f = tmp_path / "f.txt"
|
||
|
|
f.write_text("hello", encoding="utf-8")
|
||
|
|
m = IntegrationManifest("test", tmp_path)
|
||
|
|
IntegrationBase.record_file_in_manifest(f, tmp_path, m)
|
||
|
|
assert "f.txt" in m.files
|
||
|
|
|
||
|
|
def test_write_file_and_record(self, tmp_path):
|
||
|
|
m = IntegrationManifest("test", tmp_path)
|
||
|
|
dest = tmp_path / "sub" / "f.txt"
|
||
|
|
result = IntegrationBase.write_file_and_record("content", dest, tmp_path, m)
|
||
|
|
assert result == dest
|
||
|
|
assert dest.read_text(encoding="utf-8") == "content"
|
||
|
|
assert "sub/f.txt" in m.files
|
||
|
|
|
||
|
|
def test_setup_copies_shared_templates(self, tmp_path):
|
||
|
|
i = StubIntegration()
|
||
|
|
m = IntegrationManifest("stub", tmp_path)
|
||
|
|
created = i.setup(tmp_path, m)
|
||
|
|
assert len(created) > 0
|
||
|
|
for f in created:
|
||
|
|
assert f.parent.name == "commands"
|
||
|
|
assert f.name.startswith("speckit.")
|
||
|
|
assert f.name.endswith(".md")
|