Skip to main content

#!/usr/bin/env python3 """ CODITECT Command Validation Test Suite

Comprehensive tests to verify all 141 commands have correct configuration, valid frontmatter, proper invocation patterns, and consistent documentation.

Run: python3 scripts/tests/test_commands.py python3 scripts/tests/test_commands.py -v # Verbose python3 scripts/tests/test_commands.py --command git-sync # Single command

Author: CODITECT Team Version: 1.0.0 Created: 2025-12-22 """

import os import re import sys import json import argparse from pathlib import Path from typing import Dict, List, Tuple, Optional from dataclasses import dataclass

Shared Colors module (consolidates 36 duplicate definitions)

_script_dir = Path(file).parent.parent # tests/ -> scripts/ sys.path.insert(0, str(_script_dir / "core")) from colors import Colors

class TestResult: passed: bool message: str command: str test_name: str

@dataclass class CommandValidation: name: str path: str passed: bool tests: List[TestResult] errors: List[str] warnings: List[str]

class CommandTestSuite: """Comprehensive test suite for CODITECT commands"""

REQUIRED_FRONTMATTER = ['title', 'component_type', 'version', 'status']
RECOMMENDED_FRONTMATTER = ['summary', 'keywords', 'invocation', 'audience', 'created']

VALID_STATUSES = ['stable', 'beta', 'experimental', 'deprecated', 'draft']
VALID_COMPONENT_TYPES = ['command', 'skill', 'workflow']
VALID_AUDIENCES = ['user', 'developer', 'admin', 'internal']

def __init__(self, framework_root: Path, verbose: bool = False):
self.framework_root = framework_root
self.commands_dir = framework_root / "commands"
self.verbose = verbose
self.results: List[CommandValidation] = []

def get_all_commands(self) -> List[Path]:
"""Get all command markdown files"""
commands = []
for f in sorted(self.commands_dir.glob("*.md")):
if f.name not in ['README.md', 'COMMAND-GUIDE.md', 'INDEX.md']:
commands.append(f)
return commands

def parse_frontmatter(self, content: str) -> Tuple[Optional[Dict], str]:
"""Parse YAML frontmatter from markdown content"""
match = re.match(r'^---\n(.*?)\n---\n(.*)$', content, re.DOTALL)
if not match:
return None, content

frontmatter_text = match.group(1)
body = match.group(2)

frontmatter = {}
current_key = None
current_value = []

for line in frontmatter_text.split('\n'):
if ':' in line and not line.startswith(' ') and not line.startswith('\t'):
if current_key:
frontmatter[current_key] = '\n'.join(current_value).strip()
key, value = line.split(':', 1)
current_key = key.strip()
current_value = [value.strip()]
elif current_key:
current_value.append(line)

if current_key:
frontmatter[current_key] = '\n'.join(current_value).strip()

# Parse arrays
for key, value in frontmatter.items():
if value.startswith('[') and value.endswith(']'):
try:
frontmatter[key] = eval(value)
except:
pass

return frontmatter, body

def test_has_frontmatter(self, content: str, command_name: str) -> TestResult:
"""Test that command has YAML frontmatter"""
has_frontmatter = content.startswith('---\n') and '\n---\n' in content[4:]
return TestResult(
passed=has_frontmatter,
message="Has YAML frontmatter" if has_frontmatter else "Missing YAML frontmatter",
command=command_name,
test_name="has_frontmatter"
)

def test_required_frontmatter(self, frontmatter: Dict, command_name: str) -> TestResult:
"""Test that all required frontmatter fields are present"""
if not frontmatter:
return TestResult(False, "No frontmatter to validate", command_name, "required_frontmatter")

missing = [f for f in self.REQUIRED_FRONTMATTER if f not in frontmatter]
if missing:
return TestResult(
passed=False,
message=f"Missing required fields: {', '.join(missing)}",
command=command_name,
test_name="required_frontmatter"
)
return TestResult(True, "All required fields present", command_name, "required_frontmatter")

def test_recommended_frontmatter(self, frontmatter: Dict, command_name: str) -> TestResult:
"""Test that recommended frontmatter fields are present (warning only)"""
if not frontmatter:
return TestResult(True, "Skipped - no frontmatter", command_name, "recommended_frontmatter")

missing = [f for f in self.RECOMMENDED_FRONTMATTER if f not in frontmatter]
if missing:
return TestResult(
passed=True, # Warning, not failure
message=f"Missing recommended fields: {', '.join(missing)}",
command=command_name,
test_name="recommended_frontmatter"
)
return TestResult(True, "All recommended fields present", command_name, "recommended_frontmatter")

def test_component_type(self, frontmatter: Dict, command_name: str) -> TestResult:
"""Test that component_type is valid"""
if not frontmatter:
return TestResult(False, "No frontmatter", command_name, "component_type")

comp_type = frontmatter.get('component_type', '')
if comp_type not in self.VALID_COMPONENT_TYPES:
return TestResult(
passed=False,
message=f"Invalid component_type: '{comp_type}' (expected: {self.VALID_COMPONENT_TYPES})",
command=command_name,
test_name="component_type"
)
return TestResult(True, f"Valid component_type: {comp_type}", command_name, "component_type")

def test_status(self, frontmatter: Dict, command_name: str) -> TestResult:
"""Test that status is valid"""
if not frontmatter:
return TestResult(False, "No frontmatter", command_name, "status")

status = frontmatter.get('status', '')
if status not in self.VALID_STATUSES:
return TestResult(
passed=False,
message=f"Invalid status: '{status}' (expected: {self.VALID_STATUSES})",
command=command_name,
test_name="status"
)
return TestResult(True, f"Valid status: {status}", command_name, "status")

def test_invocation_pattern(self, frontmatter: Dict, command_name: str) -> TestResult:
"""Test that invocation pattern is present and valid"""
if not frontmatter:
return TestResult(False, "No frontmatter", command_name, "invocation_pattern")

invocation = frontmatter.get('invocation', '')
# Strip quotes that may wrap the value in YAML
if isinstance(invocation, str):
invocation = invocation.strip('"\'')
if not invocation:
return TestResult(
passed=False,
message="Missing invocation pattern",
command=command_name,
test_name="invocation_pattern"
)

# Should start with /
if not invocation.startswith('/'):
return TestResult(
passed=False,
message=f"Invocation should start with '/': {invocation}",
command=command_name,
test_name="invocation_pattern"
)

return TestResult(True, f"Valid invocation: {invocation}", command_name, "invocation_pattern")

def test_has_usage_section(self, body: str, command_name: str) -> TestResult:
"""Test that command has a Usage section"""
has_usage = bool(re.search(r'^##\s+Usage', body, re.MULTILINE | re.IGNORECASE))
return TestResult(
passed=has_usage,
message="Has Usage section" if has_usage else "Missing Usage section",
command=command_name,
test_name="has_usage_section"
)

def test_has_examples(self, body: str, command_name: str) -> TestResult:
"""Test that command has examples"""
has_examples = bool(re.search(r'^##\s+Example', body, re.MULTILINE | re.IGNORECASE)) or \
bool(re.search(r'```\s*(bash|shell)?', body))
return TestResult(
passed=has_examples,
message="Has examples" if has_examples else "Missing examples or code blocks",
command=command_name,
test_name="has_examples"
)

def test_no_placeholders(self, content: str, command_name: str) -> TestResult:
"""Test that command has no placeholder text outside code blocks"""
# Remove code blocks before checking for placeholders
# This allows TODO/XXX in example code
content_no_code = re.sub(r'```[\s\S]*?```', '', content)
content_no_code = re.sub(r'`[^`]+`', '', content_no_code)

placeholders = [
'[INSERT ', '[INSERT]', '[INSERT:',
'[ADD HERE', '[ADD YOUR', '[ADD THE',
'[PLACEHOLDER', '[TBD]', '[TBD ',
'lorem ipsum', '<!-- TODO', '<!-- FIXME'
]

found = []
for p in placeholders:
if p.lower() in content_no_code.lower():
found.append(p)

if found:
return TestResult(
passed=False,
message=f"Contains placeholders: {', '.join(found)}",
command=command_name,
test_name="no_placeholders"
)
return TestResult(True, "No placeholders found", command_name, "no_placeholders")

def test_version_format(self, frontmatter: Dict, command_name: str) -> TestResult:
"""Test that version follows semver format"""
if not frontmatter:
return TestResult(False, "No frontmatter", command_name, "version_format")

version = frontmatter.get('version', '')
if not version:
return TestResult(False, "Missing version", command_name, "version_format")

# Clean up version string
version = version.strip('"\'')

# Semver pattern
if not re.match(r'^\d+\.\d+\.\d+(-[\w.]+)?$', version):
return TestResult(
passed=False,
message=f"Invalid version format: '{version}' (expected: X.Y.Z)",
command=command_name,
test_name="version_format"
)
return TestResult(True, f"Valid version: {version}", command_name, "version_format")

def validate_command(self, command_path: Path) -> CommandValidation:
"""Run all validation tests on a command"""
command_name = command_path.stem
content = command_path.read_text(encoding='utf-8')
frontmatter, body = self.parse_frontmatter(content)

tests = []
errors = []
warnings = []

# Run all tests
tests.append(self.test_has_frontmatter(content, command_name))
tests.append(self.test_required_frontmatter(frontmatter, command_name))

rec_test = self.test_recommended_frontmatter(frontmatter, command_name)
tests.append(rec_test)
if 'Missing recommended' in rec_test.message:
warnings.append(rec_test.message)

tests.append(self.test_component_type(frontmatter, command_name))
tests.append(self.test_status(frontmatter, command_name))
tests.append(self.test_invocation_pattern(frontmatter, command_name))
tests.append(self.test_has_usage_section(body, command_name))
tests.append(self.test_has_examples(body, command_name))
tests.append(self.test_no_placeholders(content, command_name))
tests.append(self.test_version_format(frontmatter, command_name))

# Collect errors
for test in tests:
if not test.passed:
errors.append(f"{test.test_name}: {test.message}")

passed = all(t.passed for t in tests)

return CommandValidation(
name=command_name,
path=str(command_path),
passed=passed,
tests=tests,
errors=errors,
warnings=warnings
)

def run_all(self, specific_command: Optional[str] = None) -> bool:
"""Run validation on all commands"""
commands = self.get_all_commands()

if specific_command:
commands = [c for c in commands if c.stem == specific_command]
if not commands:
print(f"{Colors.RED}Command not found: {specific_command}{Colors.RESET}")
return False

print(f"{Colors.BOLD}CODITECT Command Validation Test Suite{Colors.RESET}")
print("=" * 50)
print(f"\nValidating {len(commands)} commands...\n")

passed_count = 0
failed_count = 0
total_tests = 0

for command_path in commands:
validation = self.validate_command(command_path)
self.results.append(validation)

total_tests += len(validation.tests)
passed_tests = sum(1 for t in validation.tests if t.passed)

if validation.passed:
passed_count += 1
if self.verbose:
print(f"{validation.name}: {Colors.GREEN}PASS{Colors.RESET} ({passed_tests}/{len(validation.tests)} tests)")
else:
print(f"{validation.name}: {Colors.GREEN}PASS{Colors.RESET}")
else:
failed_count += 1
print(f"{validation.name}: {Colors.RED}FAIL{Colors.RESET}")
for error in validation.errors:
print(f" {Colors.RED}✗{Colors.RESET} {error}")

if self.verbose and validation.warnings:
for warning in validation.warnings:
print(f" {Colors.YELLOW}⚠{Colors.RESET} {warning}")

# Summary
print("\n" + "=" * 50)
print(f"{Colors.BOLD}Test Summary{Colors.RESET}")
print("=" * 50)
print(f"\nCommands: {passed_count}/{len(commands)} passed")
print(f"Tests: {sum(1 for r in self.results for t in r.tests if t.passed)}/{total_tests} passed")

if failed_count == 0:
print(f"\n{Colors.GREEN}{Colors.BOLD}All commands passed validation!{Colors.RESET}")
return True
else:
print(f"\n{Colors.RED}{Colors.BOLD}{failed_count} command(s) failed validation{Colors.RESET}")
return False

def get_framework_root() -> Path: """Get framework root directory""" script_path = Path(file).resolve() return script_path.parent.parent.parent

def main(): parser = argparse.ArgumentParser(description='CODITECT Command Validation Test Suite') parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output') parser.add_argument('--command', type=str, help='Test specific command') parser.add_argument('--json', action='store_true', help='Output results as JSON') args = parser.parse_args()

framework_root = get_framework_root()
suite = CommandTestSuite(framework_root, verbose=args.verbose)

success = suite.run_all(specific_command=args.command)

if args.json:
results = {
'total_commands': len(suite.results),
'passed': sum(1 for r in suite.results if r.passed),
'failed': sum(1 for r in suite.results if not r.passed),
'commands': [
{
'name': r.name,
'passed': r.passed,
'errors': r.errors,
'warnings': r.warnings
}
for r in suite.results
]
}
print(json.dumps(results, indent=2))

sys.exit(0 if success else 1)

if name == 'main': main()