aboutsummaryrefslogtreecommitdiffziptar.gz
diff options
context:
space:
mode:
-rw-r--r--tests/test_readme_links.py40
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('![i](nope/none.png)'),
+ [('nope/none.png', 'missing')])
+
+
+if __name__ == '__main__':
+ unittest.main()