generated from coulomb/repo-seed
Initial schemas and validation with extension workplan
This commit is contained in:
164
tests/test_schema_contract.py
Normal file
164
tests/test_schema_contract.py
Normal file
@@ -0,0 +1,164 @@
|
||||
from pathlib import Path
|
||||
|
||||
from click.testing import CliRunner
|
||||
|
||||
from markitect_tool.cli import main
|
||||
from markitect_tool.schema import (
|
||||
InvalidSchemaFormatError,
|
||||
SchemaNotFoundError,
|
||||
load_schema_file,
|
||||
validate_markdown_file,
|
||||
validate_schema,
|
||||
)
|
||||
|
||||
|
||||
SCHEMA_TEXT = """---
|
||||
schema-id: "https://example.test/schemas/document/v1"
|
||||
version: "1.0.0"
|
||||
status: "stable"
|
||||
---
|
||||
|
||||
# Document Schema
|
||||
|
||||
## Schema Definition
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "Document Schema",
|
||||
"type": "object",
|
||||
"required": ["frontmatter", "headings"],
|
||||
"properties": {
|
||||
"frontmatter": {
|
||||
"type": "object",
|
||||
"required": ["title"],
|
||||
"properties": {
|
||||
"title": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"headings": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["level", "text"],
|
||||
"properties": {
|
||||
"level": {"type": "integer"},
|
||||
"text": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
def test_load_schema_file_extracts_metadata_and_json_schema(tmp_path: Path):
|
||||
schema_file = tmp_path / "document-schema.md"
|
||||
schema_file.write_text(SCHEMA_TEXT, encoding="utf-8")
|
||||
|
||||
loaded = load_schema_file(schema_file)
|
||||
|
||||
assert loaded.metadata["schema-id"] == "https://example.test/schemas/document/v1"
|
||||
assert loaded.metadata["status"] == "stable"
|
||||
assert loaded.schema["title"] == "Document Schema"
|
||||
assert loaded.schema["x-markitect-source"]["format"] == "markdown"
|
||||
assert loaded.source_path == str(schema_file)
|
||||
|
||||
|
||||
def test_load_schema_file_requires_json_block(tmp_path: Path):
|
||||
schema_file = tmp_path / "missing.md"
|
||||
schema_file.write_text("# Missing\n\nNo schema.", encoding="utf-8")
|
||||
|
||||
try:
|
||||
load_schema_file(schema_file)
|
||||
except SchemaNotFoundError as exc:
|
||||
assert "No JSON schema found" in str(exc)
|
||||
else:
|
||||
raise AssertionError("expected SchemaNotFoundError")
|
||||
|
||||
|
||||
def test_load_schema_file_rejects_invalid_json(tmp_path: Path):
|
||||
schema_file = tmp_path / "invalid.md"
|
||||
schema_file.write_text("```json\n{invalid json}\n```", encoding="utf-8")
|
||||
|
||||
try:
|
||||
load_schema_file(schema_file)
|
||||
except InvalidSchemaFormatError as exc:
|
||||
assert "Invalid JSON schema block" in str(exc)
|
||||
else:
|
||||
raise AssertionError("expected InvalidSchemaFormatError")
|
||||
|
||||
|
||||
def test_validate_markdown_file_returns_valid_result(tmp_path: Path):
|
||||
schema_file = tmp_path / "document-schema.md"
|
||||
schema_file.write_text(SCHEMA_TEXT, encoding="utf-8")
|
||||
markdown_file = tmp_path / "document.md"
|
||||
markdown_file.write_text("---\ntitle: Example\n---\n\n# Example\n\nBody.", encoding="utf-8")
|
||||
|
||||
result = validate_markdown_file(markdown_file, schema_file)
|
||||
|
||||
assert result.valid is True
|
||||
assert result.violations == []
|
||||
assert result.document_path == str(markdown_file)
|
||||
assert result.schema_path == str(schema_file)
|
||||
|
||||
|
||||
def test_validate_markdown_file_reports_violations(tmp_path: Path):
|
||||
schema_file = tmp_path / "document-schema.md"
|
||||
schema_file.write_text(SCHEMA_TEXT, encoding="utf-8")
|
||||
markdown_file = tmp_path / "document.md"
|
||||
markdown_file.write_text("# Missing Title\n\nBody.", encoding="utf-8")
|
||||
|
||||
result = validate_markdown_file(markdown_file, schema_file)
|
||||
|
||||
assert result.valid is False
|
||||
assert result.violations
|
||||
assert result.violations[0].path == "$.frontmatter"
|
||||
assert "title" in result.violations[0].message
|
||||
|
||||
|
||||
def test_validate_schema_reports_invalid_schema():
|
||||
result = validate_schema({"type": 7})
|
||||
|
||||
assert result.valid is False
|
||||
assert result.violations
|
||||
|
||||
|
||||
def test_mkt_validate_exits_zero_for_valid_document(tmp_path: Path):
|
||||
schema_file = tmp_path / "document-schema.md"
|
||||
schema_file.write_text(SCHEMA_TEXT, encoding="utf-8")
|
||||
markdown_file = tmp_path / "document.md"
|
||||
markdown_file.write_text("---\ntitle: Example\n---\n\n# Example\n", encoding="utf-8")
|
||||
|
||||
result = CliRunner().invoke(
|
||||
main, ["validate", str(markdown_file), "--schema", str(schema_file)]
|
||||
)
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "valid" in result.output
|
||||
|
||||
|
||||
def test_mkt_validate_exits_nonzero_for_invalid_document(tmp_path: Path):
|
||||
schema_file = tmp_path / "document-schema.md"
|
||||
schema_file.write_text(SCHEMA_TEXT, encoding="utf-8")
|
||||
markdown_file = tmp_path / "document.md"
|
||||
markdown_file.write_text("# Missing Title\n", encoding="utf-8")
|
||||
|
||||
result = CliRunner().invoke(
|
||||
main, ["validate", str(markdown_file), "--schema", str(schema_file)]
|
||||
)
|
||||
|
||||
assert result.exit_code == 1
|
||||
assert "invalid" in result.output
|
||||
|
||||
|
||||
def test_mkt_schema_validate(tmp_path: Path):
|
||||
schema_file = tmp_path / "document-schema.md"
|
||||
schema_file.write_text(SCHEMA_TEXT, encoding="utf-8")
|
||||
|
||||
result = CliRunner().invoke(main, ["schema", "validate", str(schema_file)])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "valid" in result.output
|
||||
Reference in New Issue
Block a user