| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- #!/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()
|