generated from coulomb/repo-seed
Add render reference asset manifest contract
This commit is contained in:
236
tests/test_render_reference_manifest.py
Normal file
236
tests/test_render_reference_manifest.py
Normal file
@@ -0,0 +1,236 @@
|
||||
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",
|
||||
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
|
||||
Reference in New Issue
Block a user