mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-29 18:40:38 +00:00
214 lines
7.1 KiB
Python
214 lines
7.1 KiB
Python
"""Tests for the SkillParser strict + tolerant passes."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from openjarvis.skills.parser import SkillParseError, SkillParser
|
|
|
|
|
|
class TestStrictRequiredFields:
|
|
def test_missing_name_raises(self):
|
|
parser = SkillParser()
|
|
frontmatter = {"description": "x"}
|
|
with pytest.raises(SkillParseError, match="name"):
|
|
parser.parse_frontmatter(frontmatter)
|
|
|
|
def test_missing_description_raises(self):
|
|
parser = SkillParser()
|
|
frontmatter = {"name": "test-skill"}
|
|
with pytest.raises(SkillParseError, match="description"):
|
|
parser.parse_frontmatter(frontmatter)
|
|
|
|
def test_minimal_valid_frontmatter(self):
|
|
parser = SkillParser()
|
|
manifest = parser.parse_frontmatter(
|
|
{"name": "minimal", "description": "Does something useful"}
|
|
)
|
|
assert manifest.name == "minimal"
|
|
assert manifest.description == "Does something useful"
|
|
|
|
|
|
class TestStrictNamingRules:
|
|
def test_uppercase_rejected(self):
|
|
parser = SkillParser()
|
|
with pytest.raises(SkillParseError, match="lowercase"):
|
|
parser.parse_frontmatter({"name": "MySkill", "description": "x"})
|
|
|
|
def test_underscore_rejected(self):
|
|
parser = SkillParser()
|
|
with pytest.raises(SkillParseError, match="hyphen"):
|
|
parser.parse_frontmatter({"name": "my_skill", "description": "x"})
|
|
|
|
def test_leading_hyphen_rejected(self):
|
|
parser = SkillParser()
|
|
with pytest.raises(SkillParseError, match="hyphen"):
|
|
parser.parse_frontmatter({"name": "-skill", "description": "x"})
|
|
|
|
def test_trailing_hyphen_rejected(self):
|
|
parser = SkillParser()
|
|
with pytest.raises(SkillParseError, match="hyphen"):
|
|
parser.parse_frontmatter({"name": "skill-", "description": "x"})
|
|
|
|
def test_consecutive_hyphens_rejected(self):
|
|
parser = SkillParser()
|
|
with pytest.raises(SkillParseError, match="consecutive"):
|
|
parser.parse_frontmatter({"name": "my--skill", "description": "x"})
|
|
|
|
def test_valid_kebab_name_accepted(self):
|
|
parser = SkillParser()
|
|
manifest = parser.parse_frontmatter(
|
|
{"name": "my-skill-123", "description": "x"}
|
|
)
|
|
assert manifest.name == "my-skill-123"
|
|
|
|
|
|
class TestStrictLengthLimits:
|
|
def test_name_over_64_chars_rejected(self):
|
|
parser = SkillParser()
|
|
too_long = "a" * 65
|
|
with pytest.raises(SkillParseError, match="64"):
|
|
parser.parse_frontmatter({"name": too_long, "description": "x"})
|
|
|
|
def test_description_over_1024_chars_rejected(self):
|
|
parser = SkillParser()
|
|
too_long = "a" * 1025
|
|
with pytest.raises(SkillParseError, match="1024"):
|
|
parser.parse_frontmatter({"name": "test", "description": too_long})
|
|
|
|
|
|
class TestTolerantFieldMapping:
|
|
def test_top_level_version_mapped_to_metadata(self):
|
|
parser = SkillParser()
|
|
manifest = parser.parse_frontmatter(
|
|
{
|
|
"name": "test",
|
|
"description": "x",
|
|
"version": "1.2.3",
|
|
}
|
|
)
|
|
assert manifest.version == "1.2.3"
|
|
|
|
def test_top_level_author_mapped_to_metadata(self):
|
|
parser = SkillParser()
|
|
manifest = parser.parse_frontmatter(
|
|
{
|
|
"name": "test",
|
|
"description": "x",
|
|
"author": "alice",
|
|
}
|
|
)
|
|
assert manifest.author == "alice"
|
|
|
|
def test_top_level_tags_mapped_to_metadata(self):
|
|
parser = SkillParser()
|
|
manifest = parser.parse_frontmatter(
|
|
{
|
|
"name": "test",
|
|
"description": "x",
|
|
"tags": ["research", "nlp"],
|
|
}
|
|
)
|
|
assert manifest.tags == ["research", "nlp"]
|
|
|
|
def test_top_level_required_capabilities_mapped(self):
|
|
parser = SkillParser()
|
|
manifest = parser.parse_frontmatter(
|
|
{
|
|
"name": "test",
|
|
"description": "x",
|
|
"required_capabilities": ["network:fetch"],
|
|
}
|
|
)
|
|
assert manifest.required_capabilities == ["network:fetch"]
|
|
|
|
def test_top_level_depends_mapped(self):
|
|
parser = SkillParser()
|
|
manifest = parser.parse_frontmatter(
|
|
{
|
|
"name": "test",
|
|
"description": "x",
|
|
"depends": ["summarize"],
|
|
}
|
|
)
|
|
assert manifest.depends == ["summarize"]
|
|
|
|
def test_top_level_user_invocable_mapped(self):
|
|
parser = SkillParser()
|
|
manifest = parser.parse_frontmatter(
|
|
{
|
|
"name": "test",
|
|
"description": "x",
|
|
"user_invocable": False,
|
|
}
|
|
)
|
|
assert manifest.user_invocable is False
|
|
|
|
def test_top_level_disable_model_invocation_mapped(self):
|
|
parser = SkillParser()
|
|
manifest = parser.parse_frontmatter(
|
|
{
|
|
"name": "test",
|
|
"description": "x",
|
|
"disable_model_invocation": True,
|
|
}
|
|
)
|
|
assert manifest.disable_model_invocation is True
|
|
|
|
def test_metadata_openjarvis_namespace_used(self):
|
|
parser = SkillParser()
|
|
manifest = parser.parse_frontmatter(
|
|
{
|
|
"name": "test",
|
|
"description": "x",
|
|
"metadata": {
|
|
"openjarvis": {
|
|
"version": "9.9.9",
|
|
"tags": ["already", "mapped"],
|
|
},
|
|
},
|
|
}
|
|
)
|
|
assert manifest.version == "9.9.9"
|
|
assert manifest.tags == ["already", "mapped"]
|
|
|
|
def test_unmapped_field_logs_warning(self, caplog):
|
|
import logging
|
|
|
|
parser = SkillParser()
|
|
with caplog.at_level(logging.WARNING):
|
|
parser.parse_frontmatter(
|
|
{
|
|
"name": "test",
|
|
"description": "x",
|
|
"weird_vendor_field": "something",
|
|
}
|
|
)
|
|
assert any("weird_vendor_field" in record.message for record in caplog.records)
|
|
|
|
def test_original_frontmatter_preserved(self):
|
|
parser = SkillParser()
|
|
original = {
|
|
"name": "test",
|
|
"description": "x",
|
|
"weird_field": "preserved",
|
|
}
|
|
manifest = parser.parse_frontmatter(original)
|
|
# Stored under metadata.openjarvis.original_frontmatter
|
|
oj = manifest.metadata.get("openjarvis", {})
|
|
assert "original_frontmatter" in oj
|
|
assert oj["original_frontmatter"]["weird_field"] == "preserved"
|
|
|
|
def test_platforms_list_mapped_to_compatibility_string(self):
|
|
parser = SkillParser()
|
|
manifest = parser.parse_frontmatter(
|
|
{
|
|
"name": "test",
|
|
"description": "x",
|
|
"platforms": ["macos", "linux"],
|
|
}
|
|
)
|
|
# Platforms get rendered into a compatibility string under metadata
|
|
oj = manifest.metadata.get("openjarvis", {})
|
|
assert "platforms" in oj or "compatibility" in oj
|