migration
This commit is contained in:
@@ -1,78 +1,21 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import PurePosixPath
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
from pydantic import ValidationError
|
||||
|
||||
from personal_mcp.registry.ingest.document import MarkdownDocument
|
||||
from personal_mcp.registry.models.common import parse_docs_path
|
||||
from personal_mcp.registry.models.registry import DocsRegistry
|
||||
|
||||
pytestmark = pytest.mark.unit
|
||||
|
||||
|
||||
def make_markdown_document(
|
||||
relpath: str,
|
||||
*,
|
||||
content: str = "# body\n",
|
||||
frontmatter: str | None = None,
|
||||
) -> MarkdownDocument:
|
||||
"""Builds a markdown ingest document with deterministic defaults."""
|
||||
return MarkdownDocument(
|
||||
relpath=PurePosixPath(relpath),
|
||||
content=content,
|
||||
frontmatter=frontmatter,
|
||||
)
|
||||
|
||||
|
||||
def make_prompt_frontmatter_payload(
|
||||
*,
|
||||
prompt_id: str,
|
||||
name: str | None = None,
|
||||
version: str = "1.0.0",
|
||||
description: str = "demo prompt",
|
||||
tags: tuple[str, ...] = ("testing",),
|
||||
capabilities: tuple[str, ...] | None = None,
|
||||
arguments: dict[str, dict[str, Any]] | None = None,
|
||||
) -> str:
|
||||
"""Builds frontmatter payload YAML for prompt conversion tests."""
|
||||
canonical_name = name or prompt_id
|
||||
payload: dict[str, Any] = {
|
||||
"name": canonical_name,
|
||||
"description": description,
|
||||
"x-personal-mcp": {
|
||||
"id": prompt_id,
|
||||
"version": version,
|
||||
"tags": list(tags),
|
||||
"capabilities": list(capabilities or (f"resource://prompts/{canonical_name}/document",)),
|
||||
"arguments": arguments or {},
|
||||
},
|
||||
}
|
||||
return yaml.safe_dump(payload, sort_keys=False)
|
||||
|
||||
|
||||
def as_markdown(frontmatter_yaml: str, *, body: str = "# body\n") -> str:
|
||||
"""Wraps frontmatter YAML in markdown fence delimiters."""
|
||||
return f"---\n{frontmatter_yaml.strip()}\n---\n{body}"
|
||||
|
||||
|
||||
def assert_model_is_frozen(instance: Any, *, attr: str, value: Any) -> None:
|
||||
"""Asserts pydantic frozen model semantics."""
|
||||
with pytest.raises(ValidationError, match="Instance is frozen"):
|
||||
setattr(instance, attr, value)
|
||||
|
||||
|
||||
class TestGate5ContractValidation:
|
||||
"""Gate 5: canonical resource-path contracts."""
|
||||
class TestDocsPathValidation:
|
||||
"""Covers canonical resource-path contracts."""
|
||||
|
||||
def test_parse_docs_path_returns_pure_posix_path(self) -> None:
|
||||
"""Ensures boundary strings become path objects before publication."""
|
||||
path = parse_docs_path("skills/demo/SKILL.md")
|
||||
path = parse_docs_path("guides/demo.md")
|
||||
|
||||
assert path == PurePosixPath("skills/demo/SKILL.md")
|
||||
assert path == PurePosixPath("guides/demo.md")
|
||||
assert isinstance(path, PurePosixPath)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -80,51 +23,11 @@ class TestGate5ContractValidation:
|
||||
(
|
||||
"/absolute.md",
|
||||
"../outside.md",
|
||||
"skills\\demo\\SKILL.md",
|
||||
"skills//demo/SKILL.md",
|
||||
"skills/demo/README.txt",
|
||||
"guides\\demo.md",
|
||||
"guides//demo.md",
|
||||
"guides/demo.txt",
|
||||
),
|
||||
)
|
||||
def test_parse_docs_path_rejects_invalid_paths(self, value: str) -> None:
|
||||
"""Ensures non-canonical docs paths fail contract validation."""
|
||||
with pytest.raises(ValueError):
|
||||
parse_docs_path(value)
|
||||
|
||||
|
||||
class TestGate6FreezeValidation:
|
||||
"""Gate 6: immutable in-memory registry snapshot semantics."""
|
||||
|
||||
def test_docs_registry_copies_mapping_inputs(self) -> None:
|
||||
"""Ensures registry snapshots are isolated from caller-owned mapping mutations."""
|
||||
index_path = PurePosixPath("index.md")
|
||||
source_docs = {index_path: "# index\n"}
|
||||
registry = DocsRegistry(
|
||||
docs_markdown_by_path=source_docs,
|
||||
docs_markdown_path_index=(index_path,),
|
||||
prompts_by_id={},
|
||||
prompts_in_load_order=(),
|
||||
prompts_summary_in_load_order=(),
|
||||
tag_to_prompt_ids={},
|
||||
)
|
||||
|
||||
source_docs[PurePosixPath("other.md")] = "# other\n"
|
||||
|
||||
assert PurePosixPath("other.md") not in registry.docs_markdown_by_path
|
||||
assert registry.docs_markdown_path_index == (index_path,)
|
||||
|
||||
def test_docs_registry_instance_is_frozen(self) -> None:
|
||||
"""Ensures frozen model prevents attribute reassignment."""
|
||||
registry = DocsRegistry(
|
||||
docs_markdown_by_path={},
|
||||
docs_markdown_path_index=(),
|
||||
prompts_by_id={},
|
||||
prompts_in_load_order=(),
|
||||
prompts_summary_in_load_order=(),
|
||||
tag_to_prompt_ids={},
|
||||
)
|
||||
|
||||
assert_model_is_frozen(
|
||||
registry,
|
||||
attr="docs_markdown_path_index",
|
||||
value=(PurePosixPath("index.md"),),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user