Skip to content

Commit 7891c2a

Browse files
test: cover dev symlink fallback without privileges
1 parent 6ca27db commit 7891c2a

2 files changed

Lines changed: 81 additions & 0 deletions

File tree

tests/test_extension_skills.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,40 @@ def test_dev_skill_symlink_refreshes_existing_cache(
369369
assert "speckit-test-ext-hello" in written
370370
assert "Run this updated hello." in skill_file.read_text(encoding="utf-8")
371371

372+
def test_dev_skill_registration_falls_back_to_copy_when_symlink_fails(
373+
self, skills_project, extension_dir, monkeypatch
374+
):
375+
"""Dev-mode skill registration works when Windows cannot create symlinks."""
376+
project_dir, skills_dir = skills_project
377+
manager = ExtensionManager(project_dir)
378+
manifest = ExtensionManifest(extension_dir / "extension.yml")
379+
380+
def raise_windows_symlink_error(target, link):
381+
raise OSError("A required privilege is not held by the client")
382+
383+
monkeypatch.setattr(
384+
"specify_cli.extensions.os.symlink", raise_windows_symlink_error
385+
)
386+
387+
written = manager._register_extension_skills(
388+
manifest,
389+
extension_dir,
390+
link_outputs=True,
391+
)
392+
393+
skill_file = skills_dir / "speckit-test-ext-hello" / "SKILL.md"
394+
assert "speckit-test-ext-hello" in written
395+
assert skill_file.exists()
396+
assert not skill_file.is_symlink()
397+
assert "Run this to say hello." in skill_file.read_text(encoding="utf-8")
398+
assert (
399+
extension_dir
400+
/ ".specify-dev"
401+
/ "extension-skills"
402+
/ "speckit-test-ext-hello"
403+
/ "SKILL.md"
404+
).exists()
405+
372406
def test_dev_skill_registration_falls_back_to_copy_when_relpath_fails(
373407
self, skills_project, extension_dir, monkeypatch
374408
):

tests/test_extensions.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3561,6 +3561,53 @@ def test_add_dev_links_copilot_agent_when_supported(
35613561
else:
35623562
assert not agent_file.is_symlink()
35633563

3564+
def test_add_dev_falls_back_to_copy_when_windows_symlinks_unavailable(
3565+
self, extension_dir, project_dir, monkeypatch
3566+
):
3567+
"""extension add --dev should work when Windows cannot create symlinks."""
3568+
from typer.testing import CliRunner
3569+
from unittest.mock import patch
3570+
from specify_cli import app
3571+
3572+
(project_dir / ".github" / "agents").mkdir(parents=True)
3573+
3574+
def raise_windows_symlink_error(target, link):
3575+
raise OSError("A required privilege is not held by the client")
3576+
3577+
monkeypatch.setattr(
3578+
"specify_cli.agents.os.symlink", raise_windows_symlink_error
3579+
)
3580+
3581+
runner = CliRunner()
3582+
with patch.object(Path, "cwd", return_value=project_dir):
3583+
result = runner.invoke(
3584+
app,
3585+
["extension", "add", str(extension_dir), "--dev"],
3586+
catch_exceptions=True,
3587+
)
3588+
3589+
assert result.exit_code == 0, result.output
3590+
3591+
agent_file = (
3592+
project_dir
3593+
/ ".github"
3594+
/ "agents"
3595+
/ "speckit.test-ext.hello.agent.md"
3596+
)
3597+
assert agent_file.exists()
3598+
assert not agent_file.is_symlink()
3599+
assert "Extension: test-ext" in agent_file.read_text(encoding="utf-8")
3600+
assert (
3601+
project_dir
3602+
/ ".specify"
3603+
/ "extensions"
3604+
/ "test-ext"
3605+
/ ".specify-dev"
3606+
/ "agent-commands"
3607+
/ "copilot"
3608+
/ "speckit.test-ext.hello.agent.md"
3609+
).exists()
3610+
35643611
def test_add_by_display_name_uses_resolved_id_for_download(self, tmp_path):
35653612
"""extension add by display name should use resolved ID for download_extension()."""
35663613
from typer.testing import CliRunner

0 commit comments

Comments
 (0)