from __future__ import annotations import hashlib import json import sqlite3 import subprocess import sys import tempfile import unittest from pathlib import Path REPOSITORY = Path(__file__).resolve().parents[3] INSPECTOR = REPOSITORY / "tools" / "leafwiki-inspector" / "inspect.py" MARKDOWN_FIXTURE = REPOSITORY / "fixtures" / "markdown-import" def tree_hash(root: Path) -> str: digest = hashlib.sha256() for path in sorted(root.rglob("*"), key=lambda item: item.as_posix()): relative = path.relative_to(root).as_posix().encode("utf-8") digest.update(relative) if path.is_symlink(): digest.update(b"symlink") digest.update(path.readlink().as_posix().encode("utf-8")) elif path.is_file(): digest.update(b"file") digest.update(path.read_bytes()) else: digest.update(b"dir") return digest.hexdigest() class InspectorTests(unittest.TestCase): def run_inspector(self, source: Path, output: Path | None = None): command = [sys.executable, str(INSPECTOR), str(source)] if output is not None: command.extend(["--output", str(output)]) return subprocess.run( command, check=False, text=True, capture_output=True, ) def test_markdown_fixture_is_inventoried_without_source_changes(self): before = tree_hash(MARKDOWN_FIXTURE) result = self.run_inspector(MARKDOWN_FIXTURE) self.assertEqual(0, result.returncode, result.stderr) report = json.loads(result.stdout) self.assertGreaterEqual(report["summary"]["countsByKind"]["markdown"], 3) pages = [ entry for entry in report["entries"] if entry["kind"] == "markdown" ] self.assertTrue( any( link["target"] == "Shell-operators" for page in pages for link in page["markdown"]["wikiLinks"] ) ) self.assertEqual(before, tree_hash(MARKDOWN_FIXTURE)) def test_sqlite_is_opened_read_only_and_schema_is_reported(self): with tempfile.TemporaryDirectory() as temporary: root = Path(temporary) / "source" root.mkdir() database = root / "leafwiki.sqlite" connection = sqlite3.connect(database) connection.executescript( """ CREATE TABLE pages ( id INTEGER PRIMARY KEY, title TEXT NOT NULL, body TEXT NOT NULL ); INSERT INTO pages (title, body) VALUES ('Test', '# Test'); """ ) connection.commit() connection.close() before = tree_hash(root) result = self.run_inspector(root) after = tree_hash(root) self.assertEqual(0, result.returncode, result.stderr) report = json.loads(result.stdout) sqlite_entry = next( entry for entry in report["entries"] if entry["kind"] == "sqlite" ) pages = next( table for table in sqlite_entry["sqlite"]["tables"] if table["name"] == "pages" ) self.assertEqual(1, pages["rowCount"]) self.assertEqual(before, after) self.assertFalse((root / "leafwiki.sqlite-journal").exists()) self.assertFalse((root / "leafwiki.sqlite-wal").exists()) def test_report_cannot_be_written_inside_source(self): with tempfile.TemporaryDirectory() as temporary: root = Path(temporary) / "source" root.mkdir() (root / "page.md").write_text("# Page\n", encoding="utf-8") result = self.run_inspector(root, root / "report.json") self.assertEqual(2, result.returncode) self.assertIn("Refusing", result.stderr) self.assertFalse((root / "report.json").exists()) if __name__ == "__main__": unittest.main()