Files
markitect-tool/tests/test_render_reference_manifest.py

237 lines
7.5 KiB
Python

import yaml
from markitect_tool.render import (
RENDER_REFERENCE_MANIFEST_KIND,
RENDER_REFERENCE_SCHEMA_VERSION,
RenderAsset,
RenderAssetManifest,
RenderCrossReference,
RenderExportRequest,
RenderReferenceError,
RenderReferenceManifest,
RenderSourceMap,
RenderSourceSpan,
RenderTocEntry,
RenderUnitReference,
render_asset_id,
render_manifest_id,
render_unit_id,
render_with_adapter,
)
from markitect_tool.source import SourceAsset
def test_render_unit_reference_serializes_with_stable_id_and_no_final_numbering():
span = RenderSourceSpan(
source_path="docs/report.md",
line_start=12,
line_end=16,
selector="#fig-revenue",
)
first = RenderUnitReference(
kind="figure",
label="Figure",
caption="Quarterly revenue",
source_path="docs/report.md",
anchor="fig:revenue",
source_span=span,
content_hash="sha256:figure-content",
ordinal_hint=1,
numbering={"scope": "document", "sequence": "figures"},
)
second = RenderUnitReference(
kind="figure",
label="Figure",
caption="Quarterly revenue",
source_path="docs/report.md",
anchor="fig:revenue",
source_span=span,
content_hash="sha256:figure-content",
ordinal_hint=1,
numbering={"scope": "document", "sequence": "figures"},
)
assert first.unit_id == second.unit_id
assert first.unit_id == render_unit_id(
"figure",
source_path="docs/report.md",
anchor="fig:revenue",
content_hash="sha256:figure-content",
ordinal_hint=1,
title="Quarterly revenue",
)
assert "final_number" not in first.to_dict()
assert RenderUnitReference.from_dict(first.to_dict()).to_dict() == first.to_dict()
def test_render_manifest_models_cross_references_and_toc_before_layout():
section = RenderUnitReference(
kind="section",
title="Results",
anchor="results",
source_path="docs/report.md",
ordinal_hint=1,
)
table = RenderUnitReference(
kind="table",
label="Table",
caption="Quarterly totals",
anchor="tbl:totals",
source_path="docs/report.md",
ordinal_hint=2,
numbering={"scope": "section", "sequence": "tables"},
)
cross_reference = RenderCrossReference(
source_unit_id=section.unit_id,
target_unit_id=table.unit_id,
label="Table",
requested_style="numbered",
fallback_text="Quarterly totals",
)
toc_entry = RenderTocEntry(
unit_id=section.unit_id,
title="Results",
level=1,
order=1,
)
manifest = RenderReferenceManifest(
source_path="docs/report.md",
source_digest="sha256:report",
units=[section, table],
cross_references=[cross_reference],
toc=[toc_entry],
)
data = manifest.to_dict()
assert data["schema_version"] == RENDER_REFERENCE_SCHEMA_VERSION
assert data["kind"] == RENDER_REFERENCE_MANIFEST_KIND
assert data["cross_references"][0]["target_unit_id"] == table.unit_id
assert "final_number" not in data["cross_references"][0]
assert "href" not in data["toc"][0]
assert RenderReferenceManifest.from_dict(data).to_dict() == data
assert render_manifest_id(manifest) == manifest.manifest_id
def test_render_asset_manifest_preserves_source_adapter_attachment_metadata():
source_asset = SourceAsset(
uri="attachments/chart.png",
path="attachments/chart.png",
name="chart.png",
media_type="image/png",
extension=".png",
digest="sha256:chart",
metadata={"source_adapter": "markitect-filter"},
)
render_asset = RenderAsset.from_source_asset(
source_asset,
role="figure-image",
copy_policy="copy",
output_reference="renderer://asset/chart",
)
skipped_asset = RenderAsset(
source_uri="https://example.test/logo.svg",
media_type="image/svg+xml",
extension=".svg",
digest="sha256:logo",
role="brand-logo",
copy_policy="link",
output_reference="renderer://asset/logo",
)
manifest = RenderAssetManifest(
assets=[skipped_asset, render_asset],
source_path="docs/report.md",
source_digest="sha256:report",
)
data = manifest.to_dict()
assert [asset["asset_id"] for asset in data["assets"]] == sorted(
[render_asset.asset_id, skipped_asset.asset_id]
)
assert render_asset.asset_id == render_asset_id(
"attachments/chart.png",
digest="sha256:chart",
role="figure-image",
output_reference="renderer://asset/chart",
)
chart_entry = next(asset for asset in data["assets"] if asset["asset_id"] == render_asset.asset_id)
assert chart_entry["provenance"][0]["digest"].startswith("sha256:")
assert chart_entry["copy_policy"] == "copy"
assert RenderAssetManifest.from_dict(data).to_dict() == data
def test_render_source_maps_are_echoed_by_fake_renderer_metadata():
section = RenderUnitReference(
kind="section",
title="Demo",
anchor="demo",
source_path="docs/demo.md",
)
source_map = RenderSourceMap(
source=RenderSourceSpan(source_path="docs/demo.md", line_start=1, line_end=3),
source_unit_id=section.unit_id,
generated_by="document.function.echo",
function_run_id="run:echo",
render_unit_id=section.unit_id,
artifact_ref="renderer-source",
)
asset = RenderAsset(
source_uri="images/demo.png",
source_path="images/demo.png",
media_type="image/png",
extension=".png",
digest="sha256:demo-image",
role="figure-image",
copy_policy="copy",
output_reference="renderer://asset/demo-image",
)
manifest = RenderReferenceManifest(
units=[section],
source_maps=[source_map],
asset_manifest=RenderAssetManifest(assets=[asset]),
source_path="docs/demo.md",
)
result = render_with_adapter(
RenderExportRequest(
source="# Demo\n\n![Demo](images/demo.png)",
operation="render-artifact",
profile="docs",
source_path="docs/demo.md",
render_manifest=manifest,
)
)
assert result.valid
assert result.metadata["external_renderer_invoked"] is False
assert result.metadata["render_reference_manifest_id"] == manifest.manifest_id
assert result.metadata["render_source_maps"] == 1
assert result.artifacts[0].metadata["asset_manifest_id"] == manifest.asset_manifest.manifest_id
def test_render_reference_manifest_rejects_unknown_cross_reference_targets():
unit = RenderUnitReference(kind="section", title="Known", anchor="known")
try:
RenderReferenceManifest(
units=[unit],
cross_references=[RenderCrossReference(target_unit_id="missing")],
)
except RenderReferenceError as exc:
assert "targets unknown unit" in str(exc)
else:
raise AssertionError("expected unknown cross-reference target to fail")
def test_render_reference_manifest_example_loads_and_roundtrips():
with open("examples/render/render-reference-manifest.yaml", encoding="utf-8") as handle:
data = yaml.safe_load(handle)
manifest = RenderReferenceManifest.from_dict(data)
assert manifest.schema_version == RENDER_REFERENCE_SCHEMA_VERSION
assert manifest.asset_manifest.assets
assert manifest.to_dict()["kind"] == RENDER_REFERENCE_MANIFEST_KIND