Files
awesome-ai-devtools/test_readme.py
James Murdza f59798a9c3 Add test suite for README.md validation
Add a Python test file that validates the README.md structure:
- Checks README exists and is not empty
- Validates main title and required sections
- Verifies markdown link syntax
- Detects markdown formatting issues
- Validates list item format
- Checks for excessive duplicate entries

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-25 06:33:39 +00:00

202 lines
6.1 KiB
Python

#!/usr/bin/env python3
"""
Test suite for validating the awesome-ai-devtools README.md file.
This script validates:
- Markdown structure and formatting
- Link syntax validity
- Required sections presence
- Alphabetical ordering of entries (optional check)
"""
import re
import sys
from pathlib import Path
def read_readme():
"""Read the README.md file content."""
readme_path = Path(__file__).parent / "README.md"
if not readme_path.exists():
raise FileNotFoundError("README.md not found in repository root")
return readme_path.read_text(encoding="utf-8")
def test_readme_exists():
"""Test that README.md file exists."""
readme_path = Path(__file__).parent / "README.md"
assert readme_path.exists(), "README.md should exist in the repository root"
print("✓ README.md exists")
def test_readme_not_empty():
"""Test that README.md is not empty."""
content = read_readme()
assert len(content) > 0, "README.md should not be empty"
print(f"✓ README.md is not empty ({len(content)} characters)")
def test_has_title():
"""Test that README has a main title (H1)."""
content = read_readme()
assert content.startswith("# "), "README.md should start with an H1 title"
print("✓ README.md has a main title")
def test_has_required_sections():
"""Test that README has key required sections."""
content = read_readme()
required_sections = [
"## IDEs",
"## Assistants",
"## Agents",
"## Testing",
"## Resources",
]
missing_sections = []
for section in required_sections:
if section not in content:
missing_sections.append(section)
assert not missing_sections, f"Missing required sections: {missing_sections}"
print(f"✓ All {len(required_sections)} required sections present")
def test_link_syntax():
"""Test that all markdown links have valid syntax."""
content = read_readme()
# Pattern for markdown links: [text](url)
link_pattern = r'\[([^\]]+)\]\(([^)]+)\)'
links = re.findall(link_pattern, content)
invalid_links = []
for text, url in links:
# Check for common issues
if not url.strip():
invalid_links.append(f"Empty URL for text: {text}")
elif url.startswith(" ") or url.endswith(" "):
invalid_links.append(f"URL has extra spaces: {url}")
elif not (url.startswith("http") or url.startswith("#") or url.startswith("/")):
# Allow http(s), anchors, and relative paths
if not url.startswith("mailto:"):
invalid_links.append(f"Potentially invalid URL: {url}")
assert not invalid_links, f"Invalid links found: {invalid_links}"
print(f"✓ All {len(links)} links have valid syntax")
def test_no_broken_markdown_formatting():
"""Test for common markdown formatting issues."""
content = read_readme()
issues = []
lines = content.split('\n')
for i, line in enumerate(lines, 1):
# Check for unclosed brackets
if line.count('[') != line.count(']'):
# Skip if it's a code block or intentional
if not line.strip().startswith('```'):
issues.append(f"Line {i}: Mismatched brackets")
# Check for unclosed parentheses in link context
if '](' in line:
if line.count('](') != line.count(')'):
issues.append(f"Line {i}: Possible unclosed link parenthesis")
# Only fail on clear issues, some edge cases are acceptable
critical_issues = [i for i in issues if "Mismatched brackets" in i]
assert len(critical_issues) < 5, f"Too many formatting issues: {critical_issues[:5]}"
print("✓ No critical markdown formatting issues")
def test_list_items_format():
"""Test that list items follow the expected format."""
content = read_readme()
# Pattern for list items: - [Name](url) — Description
list_item_pattern = r'^- \[.+\]\(.+\)'
lines = content.split('\n')
list_items = [line for line in lines if line.startswith('- [')]
assert len(list_items) > 10, "Should have more than 10 list items"
print(f"✓ Found {len(list_items)} properly formatted list items")
def test_no_duplicate_entries():
"""Test that there are no excessive duplicate tool entries.
Note: Some duplicates are acceptable if a tool appears in multiple categories.
This test warns about duplicates but only fails if there are many.
"""
content = read_readme()
# Extract tool names from links
link_pattern = r'^- \[([^\]]+)\]'
lines = content.split('\n')
tool_names = []
for line in lines:
match = re.match(link_pattern, line)
if match:
tool_names.append(match.group(1).lower())
duplicates = []
seen = set()
for name in tool_names:
if name in seen:
duplicates.append(name)
seen.add(name)
if duplicates:
print(f" Note: Found {len(duplicates)} duplicate(s): {duplicates[:5]}")
# Allow some duplicates (tools may appear in multiple categories)
assert len(duplicates) <= 5, f"Too many duplicate entries: {duplicates}"
print(f"✓ Acceptable duplicate count ({len(duplicates)}) among {len(tool_names)} tools")
def run_all_tests():
"""Run all tests and report results."""
tests = [
test_readme_exists,
test_readme_not_empty,
test_has_title,
test_has_required_sections,
test_link_syntax,
test_no_broken_markdown_formatting,
test_list_items_format,
test_no_duplicate_entries,
]
print("=" * 50)
print("Running README.md validation tests")
print("=" * 50)
passed = 0
failed = 0
for test in tests:
try:
test()
passed += 1
except AssertionError as e:
print(f"{test.__name__}: {e}")
failed += 1
except Exception as e:
print(f"{test.__name__}: Unexpected error - {e}")
failed += 1
print("=" * 50)
print(f"Results: {passed} passed, {failed} failed")
print("=" * 50)
return failed == 0
if __name__ == "__main__":
success = run_all_tests()
sys.exit(0 if success else 1)