diff options
| -rw-r--r-- | tests/test_readme_links.py | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/tests/test_readme_links.py b/tests/test_readme_links.py new file mode 100644 index 0000000..8e997a7 --- /dev/null +++ b/tests/test_readme_links.py @@ -0,0 +1,40 @@ +"""README.md relative links must stay inside the repo and point to existing files.""" +import re +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +LINK = re.compile(r'!?\[[^\]]*\]\(([^)\s]+)(?:\s+"[^"]*")?\)') + + +def bad_links(text, root=ROOT): + bad = [] + for target in LINK.findall(text): + if re.match(r'^([a-zA-Z][a-zA-Z0-9+.-]*:|#|//)', target): + continue + path = target.split('#')[0].split('?')[0] + if not path: + continue + p = (root / path).resolve() + if root.resolve() not in (p, *p.parents): + bad.append((target, 'escapes repo')) + elif not p.exists(): + bad.append((target, 'missing')) + return bad + + +class ReadmeLinks(unittest.TestCase): + def test_current_readme(self): + self.assertEqual(bad_links((ROOT / 'README.md').read_text()), []) + + def test_detects_escape(self): + self.assertEqual(bad_links('[v](../worldmap-viewer)'), + [('../worldmap-viewer', 'escapes repo')]) + + def test_detects_missing(self): + self.assertEqual(bad_links(''), + [('nope/none.png', 'missing')]) + + +if __name__ == '__main__': + unittest.main() |
