import unittest from html.parser import HTMLParser from pathlib import Path from urllib.parse import urlsplit, unquote import sys import json import xml.etree.ElementTree as ET sys.path.insert(0, str(Path(__file__).resolve().parents[1])) import build class Links(HTMLParser): def __init__(self): super().__init__(); self.urls = []; self.h1 = 0 def handle_starttag(self, tag, attrs): if tag == 'h1': self.h1 += 1 for k,v in attrs: if k in ('href','src') and v.startswith('/'): self.urls.append(v) class SiteTest(unittest.TestCase): @classmethod def setUpClass(cls): build.build() def test_all_posts_preserved(self): for path in (build.ROOT/'content/posts').glob('*.md'): p = build.load_post(path) rendered = (build.OUT/f'posts/{p["slug"]}/index.html').read_text() self.assertIn(build.e(p['title']), rendered) self.assertIn(p['body'], rendered) def test_internal_links_and_headings(self): for path in build.OUT.rglob('*.html'): if '/demos/' in str(path): continue parser = Links(); parser.feed(path.read_text()) self.assertEqual(parser.h1, 1, str(path)) for url in parser.urls: target = build.OUT / unquote(urlsplit(url).path).lstrip('/') if target.is_dir(): target /= 'index.html' self.assertTrue(target.is_file(), f'{path}: {url}') def test_no_old_theme(self): self.assertNotIn('PaperMod', (build.OUT/'index.html').read_text()) self.assertNotIn('Hugo', (build.OUT/'index.html').read_text()) def test_feeds(self): count = sum(not build.load_post(p).get('draft') for p in (build.ROOT/'content/posts').glob('*.md')) self.assertEqual(len(ET.parse(build.OUT/'index.xml').findall('./channel/item')), count) self.assertEqual(len(ET.parse(build.OUT/'sitemap.xml').getroot()), count + 3) def test_app_registry(self): apps = json.loads((build.ROOT/'apps.json').read_text()) self.assertGreaterEqual(len(apps), 23) self.assertTrue(all(not urlsplit(a['url']).query and not urlsplit(a['url']).fragment for a in apps)) self.assertTrue(all(a['name'] and a['description'] and a['icon'] in build.ICONS for a in apps)) if __name__ == '__main__': unittest.main()