chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
test_parse_knowledge_base.py — Tests for title-case infra file detection and
|
||||
article-root-prefixed wiki links in the Karpathy wiki parser (issue #342).
|
||||
|
||||
Run from the repo root:
|
||||
python -m unittest tests.skill.knowledge.test_parse_knowledge_base -v
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
# ── Module loaders ────────────────────────────────────────────────────────
|
||||
# The scripts have hyphens in their names, so we cannot `import` them
|
||||
# directly. Load them via importlib so we can call module-level helpers.
|
||||
|
||||
_HERE = Path(__file__).resolve().parent
|
||||
_REPO_ROOT = _HERE.parent.parent.parent
|
||||
_SKILL_DIR = _REPO_ROOT / "understand-anything-plugin" / "skills" / "understand-knowledge"
|
||||
|
||||
|
||||
def _load(script: str, alias: str) -> Any:
|
||||
spec = importlib.util.spec_from_file_location(alias, _SKILL_DIR / script)
|
||||
if spec is None or spec.loader is None:
|
||||
raise RuntimeError(f"Could not load {script}")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[alias] = module
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
pkb = _load("parse-knowledge-base.py", "parse_knowledge_base")
|
||||
mkg = _load("merge-knowledge-graph.py", "merge_knowledge_graph")
|
||||
|
||||
|
||||
def _fs_is_case_sensitive(tmp: Path) -> bool:
|
||||
probe = tmp / "CaseProbe.md"
|
||||
probe.write_text("x", encoding="utf-8")
|
||||
try:
|
||||
return not (tmp / "caseprobe.md").is_file()
|
||||
finally:
|
||||
probe.unlink()
|
||||
|
||||
|
||||
class TestFindMarkdownCaseInsensitive(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.tmp = Path(tempfile.mkdtemp(prefix="ua-pkb-"))
|
||||
|
||||
def tearDown(self) -> None:
|
||||
shutil.rmtree(self.tmp, ignore_errors=True)
|
||||
|
||||
def test_title_case_file_is_found(self) -> None:
|
||||
(self.tmp / "Index.md").write_text("# Wiki", encoding="utf-8")
|
||||
found = pkb.find_markdown_case_insensitive(self.tmp, "index.md")
|
||||
self.assertTrue(found.is_file())
|
||||
self.assertEqual(found.name.lower(), "index.md")
|
||||
|
||||
def test_exact_lowercase_wins_when_both_exist(self) -> None:
|
||||
if not _fs_is_case_sensitive(self.tmp):
|
||||
self.skipTest("filesystem is case-insensitive; both casings collide")
|
||||
(self.tmp / "Index.md").write_text("# Title", encoding="utf-8")
|
||||
(self.tmp / "index.md").write_text("# lower", encoding="utf-8")
|
||||
found = pkb.find_markdown_case_insensitive(self.tmp, "index.md")
|
||||
self.assertEqual(found.name, "index.md")
|
||||
|
||||
def test_missing_parent_returns_candidate(self) -> None:
|
||||
found = pkb.find_markdown_case_insensitive(self.tmp / "nope", "index.md")
|
||||
self.assertFalse(found.is_file())
|
||||
|
||||
def test_merge_script_helper_matches(self) -> None:
|
||||
(self.tmp / "Index.md").write_text("# Wiki", encoding="utf-8")
|
||||
found = mkg._find_markdown_case_insensitive(self.tmp, "index.md")
|
||||
self.assertTrue(found.is_file())
|
||||
|
||||
|
||||
class TestTitleCaseWiki(unittest.TestCase):
|
||||
"""A wiki using Index.md / Log.md must parse the same as index.md / log.md."""
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.tmp = Path(tempfile.mkdtemp(prefix="ua-pkb-wiki-"))
|
||||
wiki = self.tmp / "wiki"
|
||||
(wiki / "concepts").mkdir(parents=True)
|
||||
(wiki / "projects").mkdir(parents=True)
|
||||
(wiki / "Index.md").write_text(
|
||||
"# Hermes\n\n## Concepts\n\n- [[wiki/concepts/Index]]\n\n"
|
||||
"## Projects\n\n- [[wiki/projects/Personal Wiki Second Brain]]\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(wiki / "Log.md").write_text(
|
||||
"# Log\n\n## [2026-05-01] CREATE | Seeded wiki\n", encoding="utf-8"
|
||||
)
|
||||
(wiki / "concepts" / "Index.md").write_text(
|
||||
"# Concepts Index\n\nOverview of concepts.\n", encoding="utf-8"
|
||||
)
|
||||
(wiki / "projects" / "Personal Wiki Second Brain.md").write_text(
|
||||
"# Personal Wiki Second Brain\n\nPilot project.\n", encoding="utf-8"
|
||||
)
|
||||
|
||||
def tearDown(self) -> None:
|
||||
shutil.rmtree(self.tmp, ignore_errors=True)
|
||||
|
||||
def test_detect_format_sees_title_case_infra(self) -> None:
|
||||
signals = pkb.detect_format(self.tmp)
|
||||
self.assertTrue(signals["has_index"])
|
||||
self.assertTrue(signals["has_log"])
|
||||
self.assertTrue(signals["detected"])
|
||||
|
||||
def test_title_case_root_infra_is_not_an_article(self) -> None:
|
||||
manifest = pkb.parse_wiki(self.tmp)
|
||||
article_ids = {n["id"] for n in manifest["nodes"] if n["type"] == "article"}
|
||||
self.assertNotIn("article:Index", article_ids)
|
||||
self.assertNotIn("article:Log", article_ids)
|
||||
# Nested Index.md IS content
|
||||
self.assertIn("article:concepts/Index", article_ids)
|
||||
|
||||
def test_root_prefixed_category_links_resolve(self) -> None:
|
||||
"""[[wiki/concepts/Index]] must map to article:concepts/Index when
|
||||
wiki/ is the detected article root (the #342 pilot saw every node
|
||||
land in "Other" because this lookup missed)."""
|
||||
manifest = pkb.parse_wiki(self.tmp)
|
||||
cat_edges = {
|
||||
(e["source"], e["target"])
|
||||
for e in manifest["edges"]
|
||||
if e["type"] == "categorized_under"
|
||||
}
|
||||
self.assertIn(("article:concepts/Index", "topic:concepts"), cat_edges)
|
||||
self.assertIn(
|
||||
("article:projects/Personal Wiki Second Brain", "topic:projects"),
|
||||
cat_edges,
|
||||
)
|
||||
by_id = {n["id"]: n for n in manifest["nodes"]}
|
||||
self.assertEqual(
|
||||
by_id["article:concepts/Index"]["knowledgeMeta"].get("category"),
|
||||
"Concepts",
|
||||
)
|
||||
|
||||
def test_links_outside_article_root_stay_unresolved(self) -> None:
|
||||
"""maps/*, SCHEMA etc. must not be forced into article layers."""
|
||||
wiki = self.tmp / "wiki"
|
||||
(wiki / "concepts" / "Index.md").write_text(
|
||||
"# Concepts Index\n\nSee [[maps/overview]] and [[SCHEMA]].\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
manifest = pkb.parse_wiki(self.tmp)
|
||||
related = {
|
||||
e["target"] for e in manifest["edges"] if e["source"] == "article:concepts/Index"
|
||||
}
|
||||
self.assertNotIn("article:maps/overview", related)
|
||||
self.assertTrue(any("maps/overview" in w for w in manifest["warnings"]))
|
||||
|
||||
|
||||
class TestLowercaseWikiStillWorks(unittest.TestCase):
|
||||
"""Regression guard: the original all-lowercase layout keeps parsing."""
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.tmp = Path(tempfile.mkdtemp(prefix="ua-pkb-lower-"))
|
||||
(self.tmp / "concepts").mkdir(parents=True)
|
||||
(self.tmp / "index.md").write_text(
|
||||
"# Wiki\n\n## Concepts\n\n- [[concepts/attention]]\n", encoding="utf-8"
|
||||
)
|
||||
(self.tmp / "log.md").write_text("# Log\n", encoding="utf-8")
|
||||
(self.tmp / "concepts" / "attention.md").write_text(
|
||||
"# Attention\n\nAll you need.\n", encoding="utf-8"
|
||||
)
|
||||
(self.tmp / "concepts" / "transformer.md").write_text(
|
||||
"# Transformer\n\nSee [[attention]].\n", encoding="utf-8"
|
||||
)
|
||||
|
||||
def tearDown(self) -> None:
|
||||
shutil.rmtree(self.tmp, ignore_errors=True)
|
||||
|
||||
def test_lowercase_layout_parses_with_categories_and_edges(self) -> None:
|
||||
signals = pkb.detect_format(self.tmp)
|
||||
self.assertTrue(signals["detected"])
|
||||
manifest = pkb.parse_wiki(self.tmp)
|
||||
by_id = {n["id"]: n for n in manifest["nodes"]}
|
||||
self.assertIn("article:concepts/attention", by_id)
|
||||
self.assertEqual(
|
||||
by_id["article:concepts/attention"]["knowledgeMeta"].get("category"),
|
||||
"Concepts",
|
||||
)
|
||||
edge_keys = {(e["source"], e["target"], e["type"]) for e in manifest["edges"]}
|
||||
self.assertIn(
|
||||
("article:concepts/transformer", "article:concepts/attention", "related"),
|
||||
edge_keys,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user