From 29130c3a0c88504eebd1486f283130410522c7b0 Mon Sep 17 00:00:00 2001 From: John Lancaster <32917998+jsl12@users.noreply.github.com> Date: Sun, 21 Jun 2026 12:55:06 -0500 Subject: [PATCH] registry ingest test scaffolding --- .../registry/ingest/{skills.py => skill.py} | 0 tests/conftest.py | 3 + tests/registry/ingest/conftest.py | 3 + tests/registry/ingest/test_document.py | 70 +++++++++++++++++++ tests/registry/ingest/test_skill.py | 51 ++++++++++++++ 5 files changed, 127 insertions(+) rename src/personal_mcp/registry/ingest/{skills.py => skill.py} (100%) create mode 100644 tests/conftest.py create mode 100644 tests/registry/ingest/conftest.py create mode 100644 tests/registry/ingest/test_document.py create mode 100644 tests/registry/ingest/test_skill.py diff --git a/src/personal_mcp/registry/ingest/skills.py b/src/personal_mcp/registry/ingest/skill.py similarity index 100% rename from src/personal_mcp/registry/ingest/skills.py rename to src/personal_mcp/registry/ingest/skill.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..1d9929c --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,3 @@ +from __future__ import annotations + +# Global lightweight fixtures can be added here as the suite grows. diff --git a/tests/registry/ingest/conftest.py b/tests/registry/ingest/conftest.py new file mode 100644 index 0000000..6e6b06d --- /dev/null +++ b/tests/registry/ingest/conftest.py @@ -0,0 +1,3 @@ +from __future__ import annotations + +# Ingest-specific fixtures and factories belong in this subtree conftest. diff --git a/tests/registry/ingest/test_document.py b/tests/registry/ingest/test_document.py new file mode 100644 index 0000000..16188c5 --- /dev/null +++ b/tests/registry/ingest/test_document.py @@ -0,0 +1,70 @@ +from __future__ import annotations + + +class TestMarkdownDocument: + """Covers MarkdownDocument construction and derived properties.""" + + class TestFromRoot: + """Covers loading markdown documents from a resource root.""" + + def test_keys_by_relpath(self) -> None: + """Ensures from_root returns a mapping keyed by relative path.""" + + def test_loads_markdown_only(self) -> None: + """Ensures from_root includes only markdown resources.""" + + def test_preserves_relpaths(self) -> None: + """Ensures from_root preserves PurePosixPath-style relative paths.""" + + class TestFromResource: + """Covers loading a single markdown document from a resource.""" + + def test_reads_utf8(self) -> None: + """Ensures from_resource reads text using UTF-8.""" + + def test_sets_frontmatter(self) -> None: + """Ensures from_resource stores frontmatter when delimiters exist.""" + + def test_none_frontmatter(self) -> None: + """Ensures from_resource sets frontmatter to None when absent.""" + + class TestSkillSlugProperty: + """Covers skill_slug derivation from document relative paths.""" + + def test_returns_slug(self) -> None: + """Ensures skill_slug returns the slug for valid skills paths.""" + + def test_none_for_non_skill(self) -> None: + """Ensures skill_slug is None for non-skills paths.""" + + def test_none_for_incomplete_skill(self) -> None: + """Ensures skill_slug is None for incomplete skills paths.""" + + +class TestWalkResources: + """Covers recursive resource walking and markdown filtering behavior.""" + + def test_yields_markdown(self) -> None: + """Ensures walk_resources yields markdown files from nested directories.""" + + def test_ignores_other_suffixes(self) -> None: + """Ensures walk_resources excludes files with non-matching suffixes.""" + + def test_sorted_output(self) -> None: + """Ensures walk_resources yields entries in sorted child-name order.""" + + def test_applies_prefix(self) -> None: + """Ensures walk_resources prepends the provided prefix to relpaths.""" + + +class TestFrontmatterParsing: + """Covers frontmatter delimiter discovery and raw block extraction.""" + + def test_extracts_between_delimiters(self) -> None: + """Ensures get_raw_frontmatter returns lines between first delimiters.""" + + def test_none_without_two_delimiters(self) -> None: + """Ensures get_raw_frontmatter returns None without two delimiters.""" + + def test_allows_leading_whitespace(self) -> None: + """Ensures delimiter detection accepts lines with leading whitespace.""" diff --git a/tests/registry/ingest/test_skill.py b/tests/registry/ingest/test_skill.py new file mode 100644 index 0000000..9ddc4f2 --- /dev/null +++ b/tests/registry/ingest/test_skill.py @@ -0,0 +1,51 @@ +from __future__ import annotations + + +class TestSkillFilesBundle: + """Covers SkillFilesBundle construction and path-based categorization.""" + + class TestFromRoot: + """Covers bundle creation from resource roots.""" + + def test_builds_bundles(self) -> None: + """Ensures from_root builds bundles from discovered markdown docs.""" + + def test_delegates_to_from_docs(self) -> None: + """Ensures from_root delegates bundle assembly to from_docs.""" + + class TestFromDocs: + """Covers bundle creation from preloaded markdown documents.""" + + def test_groups_by_slug(self) -> None: + """Ensures from_docs groups documents by skill slug.""" + + def test_one_bundle_per_slug(self) -> None: + """Ensures from_docs produces one SkillFilesBundle per slug.""" + + class TestFromPaths: + """Covers classification of skill, reference, and other documents.""" + + def test_selects_skill_md(self) -> None: + """Ensures from_paths selects SKILL.md as the primary document.""" + + def test_collects_references(self) -> None: + """Ensures from_paths captures reference docs under references/.""" + + def test_collects_other_docs(self) -> None: + """Ensures from_paths classifies non-reference docs as other docs.""" + + +class TestGroupSkillPaths: + """Covers grouping markdown documents by derived skill slug.""" + + def test_groups_slugged_docs(self) -> None: + """Ensures group_skill_paths groups only documents with a slug.""" + + def test_excludes_unslugged_docs(self) -> None: + """Ensures group_skill_paths excludes documents without skill slugs.""" + + def test_returns_sets(self) -> None: + """Ensures group_skill_paths returns sets of docs per slug.""" + + def test_stable_grouping(self) -> None: + """Ensures group_skill_paths behaves consistently after internal sorting."""