vibe/tests/skills/test_models.py
Mathias Gesbert 078693fc64 v1.3.0
Co-Authored-By: Quentin Torroba <quentin.torroba@mistral.ai>
Co-Authored-By: Michel Thomazo <michel.thomazo@mistral.ai>
Co-Authored-By: Clément Drouin <clement.drouin@mistral.ai>
Co-Authored-by: Thiago Padilha <thiago@coplane.com>
2025-12-23 19:11:27 +01:00

188 lines
6.9 KiB
Python

from __future__ import annotations
from pathlib import Path
from pydantic import ValidationError
import pytest
from vibe.core.skills.models import SkillInfo, SkillMetadata
class TestSkillMetadata:
def test_creates_with_required_fields(self) -> None:
meta = SkillMetadata(name="test-skill", description="A test skill")
assert meta.name == "test-skill"
assert meta.description == "A test skill"
assert meta.license is None
assert meta.compatibility is None
assert meta.metadata == {}
assert meta.allowed_tools == []
def test_creates_with_all_fields(self) -> None:
meta = SkillMetadata(
name="full-skill",
description="A skill with all fields",
license="MIT",
compatibility="Requires git",
metadata={"author": "Test Author", "version": "1.0"},
allowed_tools=["bash", "read_file"],
)
assert meta.name == "full-skill"
assert meta.description == "A skill with all fields"
assert meta.license == "MIT"
assert meta.compatibility == "Requires git"
assert meta.metadata == {"author": "Test Author", "version": "1.0"}
assert meta.allowed_tools == ["bash", "read_file"]
def test_raises_error_for_uppercase_name(self) -> None:
with pytest.raises(ValidationError) as exc_info:
SkillMetadata(name="Test-SKILL", description="A test skill")
assert "name" in str(exc_info.value).lower()
def test_raises_error_for_invalid_chars_in_name(self) -> None:
with pytest.raises(ValidationError) as exc_info:
SkillMetadata(name="test_skill@v1.0", description="A test skill")
assert "name" in str(exc_info.value).lower()
def test_raises_error_for_consecutive_hyphens(self) -> None:
with pytest.raises(ValidationError) as exc_info:
SkillMetadata(name="test--skill", description="A test skill")
assert "name" in str(exc_info.value).lower()
def test_raises_error_for_leading_trailing_hyphens(self) -> None:
with pytest.raises(ValidationError) as exc_info:
SkillMetadata(name="-test-skill-", description="A test skill")
assert "name" in str(exc_info.value).lower()
def test_parses_allowed_tools_from_space_delimited_string(self) -> None:
meta = SkillMetadata(
name="test",
description="A test skill",
allowed_tools="bash read_file grep", # type: ignore[arg-type]
)
assert meta.allowed_tools == ["bash", "read_file", "grep"]
def test_parses_allowed_tools_from_list(self) -> None:
meta = SkillMetadata(
name="test", description="A test skill", allowed_tools=["bash", "read_file"]
)
assert meta.allowed_tools == ["bash", "read_file"]
def test_parses_allowed_tools_handles_none(self) -> None:
meta = SkillMetadata(
name="test",
description="A test skill",
allowed_tools=None, # type: ignore[arg-type]
)
assert meta.allowed_tools == []
def test_normalizes_metadata_values_to_strings(self) -> None:
meta = SkillMetadata(
name="test",
description="A test skill",
metadata={"version": 1.0, "count": 42}, # type: ignore[dict-item]
)
assert meta.metadata == {"version": "1.0", "count": "42"}
def test_raises_error_for_missing_name(self) -> None:
with pytest.raises(ValidationError) as exc_info:
SkillMetadata(description="A test skill") # type: ignore[call-arg]
assert "name" in str(exc_info.value)
def test_raises_error_for_missing_description(self) -> None:
with pytest.raises(ValidationError) as exc_info:
SkillMetadata(name="test") # type: ignore[call-arg]
assert "description" in str(exc_info.value)
def test_raises_error_for_empty_name(self) -> None:
with pytest.raises(ValidationError) as exc_info:
SkillMetadata(name="", description="A test skill")
assert "name" in str(exc_info.value).lower()
def test_raises_error_for_empty_description(self) -> None:
with pytest.raises(ValidationError) as exc_info:
SkillMetadata(name="test", description="")
assert "description" in str(exc_info.value).lower()
class TestSkillInfo:
def test_creates_from_metadata(self, tmp_path: Path) -> None:
skill_path = tmp_path / "test-skill" / "SKILL.md"
skill_path.parent.mkdir()
skill_path.touch()
meta = SkillMetadata(
name="test-skill", description="A test skill", license="MIT"
)
info = SkillInfo.from_metadata(meta, skill_path)
assert info.name == "test-skill"
assert info.description == "A test skill"
assert info.license == "MIT"
assert info.skill_path == skill_path.resolve()
assert info.skill_dir == skill_path.parent.resolve()
def test_creates_with_all_fields(self, tmp_path: Path) -> None:
skill_path = tmp_path / "full-skill" / "SKILL.md"
skill_path.parent.mkdir()
skill_path.touch()
info = SkillInfo(
name="full-skill",
description="A skill with all fields",
license="Apache-2.0",
compatibility="git, docker",
metadata={"author": "Test"},
allowed_tools=["bash"],
skill_path=skill_path,
)
assert info.name == "full-skill"
assert info.description == "A skill with all fields"
assert info.license == "Apache-2.0"
assert info.compatibility == "git, docker"
assert info.metadata == {"author": "Test"}
assert info.allowed_tools == ["bash"]
assert info.skill_path == skill_path
assert info.skill_dir == skill_path.parent.resolve()
def test_from_metadata_resolves_paths(self, tmp_path: Path) -> None:
skill_path = tmp_path / "test-skill" / "SKILL.md"
skill_path.parent.mkdir()
skill_path.touch()
meta = SkillMetadata(name="test-skill", description="A test skill")
info = SkillInfo.from_metadata(meta, skill_path)
assert info.skill_path.is_absolute()
assert info.skill_dir.is_absolute()
def test_inherits_all_metadata_fields(self, tmp_path: Path) -> None:
skill_path = tmp_path / "test-skill" / "SKILL.md"
skill_path.parent.mkdir()
skill_path.touch()
meta = SkillMetadata(
name="test-skill",
description="A test skill",
license="MIT",
compatibility="Requires Python 3.12",
metadata={"key": "value"},
allowed_tools=["bash", "grep"],
)
info = SkillInfo.from_metadata(meta, skill_path)
assert info.license == meta.license
assert info.compatibility == meta.compatibility
assert info.metadata == meta.metadata
assert info.allowed_tools == meta.allowed_tools