- Add YAML-based enhancement workflow presets shipped inside the package (default, minimal, security-focus, architecture-comprehensive, api-documentation) - Add `skill-seekers workflows` subcommand: list, show, copy, add, remove, validate - copy/add/remove all accept multiple names/files in one invocation with partial-failure behaviour - `add --name` override restricted to single-file operations - Add 5 MCP tools: list_workflows, get_workflow, create_workflow, update_workflow, delete_workflow - Fix: create command _add_common_args() now correctly forwards each --enhance-workflow as a separate flag instead of passing the whole list as a single argument - Update README: reposition as "data layer for AI systems" with AI Skills front and centre - Update CHANGELOG, QUICK_REFERENCE, CLAUDE.md with workflow preset details - 1,880+ tests passing Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
252 lines
8.5 KiB
Python
252 lines
8.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Tests for CLI Parser System
|
|
|
|
Tests the modular parser registration system.
|
|
"""
|
|
|
|
import argparse
|
|
import pytest
|
|
|
|
from skill_seekers.cli.parsers import (
|
|
PARSERS,
|
|
SubcommandParser,
|
|
get_parser_names,
|
|
register_parsers,
|
|
)
|
|
from skill_seekers.cli.parsers.scrape_parser import ScrapeParser
|
|
from skill_seekers.cli.parsers.github_parser import GitHubParser
|
|
from skill_seekers.cli.parsers.package_parser import PackageParser
|
|
|
|
|
|
class TestParserRegistry:
|
|
"""Test parser registry functionality."""
|
|
|
|
def test_all_parsers_registered(self):
|
|
"""Test that all parsers are registered."""
|
|
assert len(PARSERS) == 21, f"Expected 21 parsers, got {len(PARSERS)}"
|
|
|
|
def test_get_parser_names(self):
|
|
"""Test getting list of parser names."""
|
|
names = get_parser_names()
|
|
assert len(names) == 21
|
|
assert "scrape" in names
|
|
assert "github" in names
|
|
assert "package" in names
|
|
assert "upload" in names
|
|
assert "analyze" in names
|
|
assert "config" in names
|
|
assert "workflows" in names
|
|
|
|
def test_all_parsers_are_subcommand_parsers(self):
|
|
"""Test that all parsers inherit from SubcommandParser."""
|
|
for parser in PARSERS:
|
|
assert isinstance(parser, SubcommandParser)
|
|
|
|
def test_all_parsers_have_required_properties(self):
|
|
"""Test that all parsers have name, help, description."""
|
|
for parser in PARSERS:
|
|
assert hasattr(parser, "name")
|
|
assert hasattr(parser, "help")
|
|
assert hasattr(parser, "description")
|
|
assert isinstance(parser.name, str)
|
|
assert isinstance(parser.help, str)
|
|
assert isinstance(parser.description, str)
|
|
assert len(parser.name) > 0
|
|
assert len(parser.help) > 0
|
|
|
|
def test_all_parsers_have_add_arguments_method(self):
|
|
"""Test that all parsers implement add_arguments."""
|
|
for parser in PARSERS:
|
|
assert hasattr(parser, "add_arguments")
|
|
assert callable(parser.add_arguments)
|
|
|
|
def test_no_duplicate_parser_names(self):
|
|
"""Test that all parser names are unique."""
|
|
names = [p.name for p in PARSERS]
|
|
assert len(names) == len(set(names)), "Duplicate parser names found!"
|
|
|
|
|
|
class TestParserCreation:
|
|
"""Test parser creation functionality."""
|
|
|
|
def test_scrape_parser_creates_subparser(self):
|
|
"""Test that ScrapeParser creates valid subparser."""
|
|
main_parser = argparse.ArgumentParser()
|
|
subparsers = main_parser.add_subparsers()
|
|
|
|
scrape_parser = ScrapeParser()
|
|
subparser = scrape_parser.create_parser(subparsers)
|
|
|
|
assert subparser is not None
|
|
assert scrape_parser.name == "scrape"
|
|
assert scrape_parser.help == "Scrape documentation website"
|
|
|
|
def test_github_parser_creates_subparser(self):
|
|
"""Test that GitHubParser creates valid subparser."""
|
|
main_parser = argparse.ArgumentParser()
|
|
subparsers = main_parser.add_subparsers()
|
|
|
|
github_parser = GitHubParser()
|
|
subparser = github_parser.create_parser(subparsers)
|
|
|
|
assert subparser is not None
|
|
assert github_parser.name == "github"
|
|
|
|
def test_package_parser_creates_subparser(self):
|
|
"""Test that PackageParser creates valid subparser."""
|
|
main_parser = argparse.ArgumentParser()
|
|
subparsers = main_parser.add_subparsers()
|
|
|
|
package_parser = PackageParser()
|
|
subparser = package_parser.create_parser(subparsers)
|
|
|
|
assert subparser is not None
|
|
assert package_parser.name == "package"
|
|
|
|
def test_register_parsers_creates_all_subcommands(self):
|
|
"""Test that register_parsers creates all 19 subcommands."""
|
|
main_parser = argparse.ArgumentParser()
|
|
subparsers = main_parser.add_subparsers(dest="command")
|
|
|
|
# Register all parsers
|
|
register_parsers(subparsers)
|
|
|
|
# Test that all commands can be parsed
|
|
test_commands = [
|
|
"config --show",
|
|
"scrape --config test.json",
|
|
"github --repo owner/repo",
|
|
"package output/test/",
|
|
"upload test.zip",
|
|
"analyze --directory .",
|
|
"enhance output/test/",
|
|
"estimate test.json",
|
|
]
|
|
|
|
for cmd in test_commands:
|
|
args = main_parser.parse_args(cmd.split())
|
|
assert args.command is not None
|
|
|
|
|
|
class TestSpecificParsers:
|
|
"""Test specific parser implementations."""
|
|
|
|
def test_scrape_parser_arguments(self):
|
|
"""Test ScrapeParser has correct arguments."""
|
|
main_parser = argparse.ArgumentParser()
|
|
subparsers = main_parser.add_subparsers(dest="command")
|
|
|
|
scrape_parser = ScrapeParser()
|
|
scrape_parser.create_parser(subparsers)
|
|
|
|
# Test various argument combinations
|
|
args = main_parser.parse_args(["scrape", "--config", "test.json"])
|
|
assert args.command == "scrape"
|
|
assert args.config == "test.json"
|
|
|
|
args = main_parser.parse_args(["scrape", "--config", "test.json", "--max-pages", "100"])
|
|
assert args.max_pages == 100
|
|
|
|
args = main_parser.parse_args(["scrape", "--enhance-level", "2"])
|
|
assert args.enhance_level == 2
|
|
|
|
def test_github_parser_arguments(self):
|
|
"""Test GitHubParser has correct arguments."""
|
|
main_parser = argparse.ArgumentParser()
|
|
subparsers = main_parser.add_subparsers(dest="command")
|
|
|
|
github_parser = GitHubParser()
|
|
github_parser.create_parser(subparsers)
|
|
|
|
args = main_parser.parse_args(["github", "--repo", "owner/repo"])
|
|
assert args.command == "github"
|
|
assert args.repo == "owner/repo"
|
|
|
|
args = main_parser.parse_args(["github", "--repo", "owner/repo", "--non-interactive"])
|
|
assert args.non_interactive is True
|
|
|
|
def test_package_parser_arguments(self):
|
|
"""Test PackageParser has correct arguments."""
|
|
main_parser = argparse.ArgumentParser()
|
|
subparsers = main_parser.add_subparsers(dest="command")
|
|
|
|
package_parser = PackageParser()
|
|
package_parser.create_parser(subparsers)
|
|
|
|
args = main_parser.parse_args(["package", "output/test/"])
|
|
assert args.command == "package"
|
|
assert args.skill_directory == "output/test/"
|
|
|
|
args = main_parser.parse_args(["package", "output/test/", "--target", "gemini"])
|
|
assert args.target == "gemini"
|
|
|
|
args = main_parser.parse_args(["package", "output/test/", "--no-open"])
|
|
assert args.no_open is True
|
|
|
|
def test_analyze_parser_arguments(self):
|
|
"""Test AnalyzeParser has correct arguments."""
|
|
main_parser = argparse.ArgumentParser()
|
|
subparsers = main_parser.add_subparsers(dest="command")
|
|
|
|
from skill_seekers.cli.parsers.analyze_parser import AnalyzeParser
|
|
|
|
analyze_parser = AnalyzeParser()
|
|
analyze_parser.create_parser(subparsers)
|
|
|
|
args = main_parser.parse_args(["analyze", "--directory", "."])
|
|
assert args.command == "analyze"
|
|
assert args.directory == "."
|
|
|
|
args = main_parser.parse_args(["analyze", "--directory", ".", "--quick"])
|
|
assert args.quick is True
|
|
|
|
args = main_parser.parse_args(["analyze", "--directory", ".", "--comprehensive"])
|
|
assert args.comprehensive is True
|
|
|
|
args = main_parser.parse_args(["analyze", "--directory", ".", "--skip-patterns"])
|
|
assert args.skip_patterns is True
|
|
|
|
|
|
class TestBackwardCompatibility:
|
|
"""Test backward compatibility with old CLI."""
|
|
|
|
def test_all_original_commands_still_work(self):
|
|
"""Test that all original commands are still registered."""
|
|
names = get_parser_names()
|
|
|
|
# Original commands from old main.py
|
|
original_commands = [
|
|
"config",
|
|
"scrape",
|
|
"github",
|
|
"pdf",
|
|
"unified",
|
|
"enhance",
|
|
"enhance-status",
|
|
"package",
|
|
"upload",
|
|
"estimate",
|
|
"extract-test-examples",
|
|
"install-agent",
|
|
"analyze",
|
|
"install",
|
|
"resume",
|
|
"stream",
|
|
"update",
|
|
"multilang",
|
|
"quality",
|
|
]
|
|
|
|
for cmd in original_commands:
|
|
assert cmd in names, f"Command '{cmd}' not found in parser registry!"
|
|
|
|
def test_command_count_matches(self):
|
|
"""Test that we have exactly 21 commands (includes new create and workflows commands)."""
|
|
assert len(PARSERS) == 21
|
|
assert len(get_parser_names()) == 21
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__, "-v"])
|