Merges setup_mcp.sh fix for v2.0.0 src/ layout + test updates. Original fix by @501981732 in PR #197. Test updates to make CI pass. Closes #192
298 lines
9.2 KiB
Python
298 lines
9.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Tests for cli/quality_checker.py functionality
|
|
"""
|
|
|
|
import unittest
|
|
import tempfile
|
|
from pathlib import Path
|
|
import os
|
|
|
|
from skill_seekers.cli.quality_checker import SkillQualityChecker, QualityReport
|
|
|
|
|
|
class TestQualityChecker(unittest.TestCase):
|
|
"""Test quality checker functionality"""
|
|
|
|
def create_test_skill(self, tmpdir, skill_md_content, create_references=True):
|
|
"""Helper to create a test skill directory"""
|
|
skill_dir = Path(tmpdir) / "test-skill"
|
|
skill_dir.mkdir()
|
|
|
|
# Create SKILL.md
|
|
skill_md = skill_dir / "SKILL.md"
|
|
skill_md.write_text(skill_md_content, encoding='utf-8')
|
|
|
|
# Create references directory
|
|
if create_references:
|
|
refs_dir = skill_dir / "references"
|
|
refs_dir.mkdir()
|
|
(refs_dir / "index.md").write_text("# Index\n\nTest reference.", encoding='utf-8')
|
|
(refs_dir / "getting_started.md").write_text("# Getting Started\n\nHow to start.", encoding='utf-8')
|
|
|
|
return skill_dir
|
|
|
|
def test_checker_detects_missing_skill_md(self):
|
|
"""Test that checker detects missing SKILL.md"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
skill_dir = Path(tmpdir) / "test-skill"
|
|
skill_dir.mkdir()
|
|
|
|
checker = SkillQualityChecker(skill_dir)
|
|
report = checker.check_all()
|
|
|
|
# Should have error about missing SKILL.md
|
|
self.assertTrue(report.has_errors)
|
|
self.assertTrue(any('SKILL.md' in issue.message for issue in report.errors))
|
|
|
|
def test_checker_detects_missing_references(self):
|
|
"""Test that checker warns about missing references"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
skill_md = """---
|
|
name: test
|
|
---
|
|
|
|
# Test Skill
|
|
|
|
This is a test.
|
|
"""
|
|
skill_dir = self.create_test_skill(tmpdir, skill_md, create_references=False)
|
|
|
|
checker = SkillQualityChecker(skill_dir)
|
|
report = checker.check_all()
|
|
|
|
# Should have warning about missing references
|
|
self.assertTrue(report.has_warnings)
|
|
self.assertTrue(any('references' in issue.message.lower() for issue in report.warnings))
|
|
|
|
def test_checker_detects_invalid_frontmatter(self):
|
|
"""Test that checker detects invalid YAML frontmatter"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
skill_md = """# Test Skill
|
|
|
|
No frontmatter here!
|
|
"""
|
|
skill_dir = self.create_test_skill(tmpdir, skill_md)
|
|
|
|
checker = SkillQualityChecker(skill_dir)
|
|
report = checker.check_all()
|
|
|
|
# Should have error about missing frontmatter
|
|
self.assertTrue(report.has_errors)
|
|
self.assertTrue(any('frontmatter' in issue.message.lower() for issue in report.errors))
|
|
|
|
def test_checker_detects_missing_name_field(self):
|
|
"""Test that checker detects missing name field in frontmatter"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
skill_md = """---
|
|
description: test
|
|
---
|
|
|
|
# Test Skill
|
|
"""
|
|
skill_dir = self.create_test_skill(tmpdir, skill_md)
|
|
|
|
checker = SkillQualityChecker(skill_dir)
|
|
report = checker.check_all()
|
|
|
|
# Should have error about missing name field
|
|
self.assertTrue(report.has_errors)
|
|
self.assertTrue(any('name' in issue.message.lower() for issue in report.errors))
|
|
|
|
def test_checker_detects_code_without_language(self):
|
|
"""Test that checker warns about code blocks without language tags"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
skill_md = """---
|
|
name: test
|
|
---
|
|
|
|
# Test Skill
|
|
|
|
Here's some code:
|
|
|
|
```
|
|
print("hello")
|
|
```
|
|
"""
|
|
skill_dir = self.create_test_skill(tmpdir, skill_md)
|
|
|
|
checker = SkillQualityChecker(skill_dir)
|
|
report = checker.check_all()
|
|
|
|
# Should have warning about code without language
|
|
self.assertTrue(report.has_warnings)
|
|
self.assertTrue(any('language' in issue.message.lower() for issue in report.warnings))
|
|
|
|
def test_checker_approves_good_skill(self):
|
|
"""Test that checker gives high score to well-formed skill"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
skill_md = """---
|
|
name: test
|
|
description: A test skill
|
|
---
|
|
|
|
# Test Skill
|
|
|
|
## When to Use This Skill
|
|
|
|
Use this when you need to test.
|
|
|
|
## Quick Reference
|
|
|
|
Here are some examples:
|
|
|
|
```python
|
|
def hello():
|
|
print("hello")
|
|
```
|
|
|
|
```javascript
|
|
console.log("hello");
|
|
```
|
|
|
|
## Example: Basic Usage
|
|
|
|
This shows how to use it.
|
|
|
|
## Reference Files
|
|
|
|
See the references directory for more:
|
|
- [Getting Started](references/getting_started.md)
|
|
- [Index](references/index.md)
|
|
"""
|
|
skill_dir = self.create_test_skill(tmpdir, skill_md)
|
|
|
|
checker = SkillQualityChecker(skill_dir)
|
|
report = checker.check_all()
|
|
|
|
# Should have no errors
|
|
self.assertFalse(report.has_errors)
|
|
|
|
# Quality score should be high
|
|
self.assertGreaterEqual(report.quality_score, 80.0)
|
|
|
|
def test_checker_detects_broken_links(self):
|
|
"""Test that checker detects broken internal links"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
skill_md = """---
|
|
name: test
|
|
---
|
|
|
|
# Test Skill
|
|
|
|
See [this file](nonexistent.md) for more info.
|
|
"""
|
|
skill_dir = self.create_test_skill(tmpdir, skill_md)
|
|
|
|
checker = SkillQualityChecker(skill_dir)
|
|
report = checker.check_all()
|
|
|
|
# Should have warning about broken link
|
|
self.assertTrue(report.has_warnings)
|
|
self.assertTrue(any('broken link' in issue.message.lower() for issue in report.warnings))
|
|
|
|
def test_quality_score_calculation(self):
|
|
"""Test that quality score is calculated correctly"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
report = QualityReport("test", Path(tmpdir))
|
|
|
|
# Perfect score to start
|
|
self.assertEqual(report.quality_score, 100.0)
|
|
|
|
# Add an error (should deduct 15 points)
|
|
report.add_error('test', 'Test error')
|
|
self.assertEqual(report.quality_score, 85.0)
|
|
|
|
# Add a warning (should deduct 5 points)
|
|
report.add_warning('test', 'Test warning')
|
|
self.assertEqual(report.quality_score, 80.0)
|
|
|
|
# Add more errors
|
|
report.add_error('test', 'Another error')
|
|
report.add_error('test', 'Yet another error')
|
|
self.assertEqual(report.quality_score, 50.0)
|
|
|
|
def test_quality_grade_calculation(self):
|
|
"""Test that quality grades are assigned correctly"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
report = QualityReport("test", Path(tmpdir))
|
|
|
|
# Grade A (90-100)
|
|
self.assertEqual(report.quality_grade, 'A')
|
|
|
|
# Grade B (80-89)
|
|
report.add_error('test', 'Error 1')
|
|
self.assertEqual(report.quality_grade, 'B')
|
|
|
|
# Grade C (70-79)
|
|
report.add_warning('test', 'Warning 1')
|
|
report.add_warning('test', 'Warning 2')
|
|
self.assertEqual(report.quality_grade, 'C')
|
|
|
|
# Grade D (60-69)
|
|
report.add_warning('test', 'Warning 3')
|
|
report.add_warning('test', 'Warning 4')
|
|
self.assertEqual(report.quality_grade, 'D')
|
|
|
|
# Grade F (below 60)
|
|
report.add_error('test', 'Error 2')
|
|
report.add_error('test', 'Error 3')
|
|
self.assertEqual(report.quality_grade, 'F')
|
|
|
|
def test_is_excellent_property(self):
|
|
"""Test is_excellent property"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
report = QualityReport("test", Path(tmpdir))
|
|
|
|
# Should be excellent with no issues
|
|
self.assertTrue(report.is_excellent)
|
|
|
|
# Adding an error should make it not excellent
|
|
report.add_error('test', 'Test error')
|
|
self.assertFalse(report.is_excellent)
|
|
|
|
# Clean report
|
|
report2 = QualityReport("test", Path(tmpdir))
|
|
# Adding a warning should also make it not excellent
|
|
report2.add_warning('test', 'Test warning')
|
|
self.assertFalse(report2.is_excellent)
|
|
|
|
|
|
class TestQualityCheckerCLI(unittest.TestCase):
|
|
"""Test quality checker CLI"""
|
|
|
|
def test_cli_help_output(self):
|
|
"""Test that CLI help works"""
|
|
import subprocess
|
|
|
|
try:
|
|
result = subprocess.run(
|
|
['python3', '-m', 'skill_seekers.cli.quality_checker', '--help'],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=5
|
|
)
|
|
|
|
# Should include usage info
|
|
output = result.stdout + result.stderr
|
|
self.assertTrue('usage:' in output.lower() or 'quality' in output.lower())
|
|
except FileNotFoundError:
|
|
self.skipTest("Module not installed")
|
|
|
|
def test_cli_with_nonexistent_directory(self):
|
|
"""Test CLI behavior with nonexistent directory"""
|
|
import subprocess
|
|
|
|
result = subprocess.run(
|
|
['python3', '-m', 'skill_seekers.cli.quality_checker', '/nonexistent/path'],
|
|
capture_output=True,
|
|
text=True
|
|
)
|
|
|
|
# Should fail
|
|
self.assertNotEqual(result.returncode, 0)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|