Files
2026-07-13 13:08:41 +08:00

188 lines
6.0 KiB
Python

import asyncio
import json
from pathlib import Path
from typing import Any
from models.sql.template_v2 import TemplateV2
from templates import default_templates
def _component() -> dict[str, Any]:
return {
"id": "photo_component",
"description": "Reusable photo component for a default template.",
"position": {"x": 10, "y": 20},
"size": {"width": 320, "height": 180},
"elements": [
{
"type": "image",
"position": {"x": 0, "y": 0},
"size": {"width": 320, "height": 180},
"data": "static/image.png",
"decorative": False,
"name": "photo",
"is_icon": False,
}
],
}
def _write_template_bundle(root: Path) -> Path:
template_dir = root / "general"
static_dir = template_dir / "static"
static_dir.mkdir(parents=True)
(static_dir / "image.png").write_bytes(b"image")
(static_dir / "thumbnail.png").write_bytes(b"thumbnail")
(template_dir / "template.json").write_text(
json.dumps(
{
"id": "general",
"name": "General",
"description": "General purpose default template.",
"thumbnail": "static/thumbnail.png",
"fonts": {"Inter": "static/inter.ttf"},
"layouts": [
{
"id": "slide_1",
"description": "A valid slide layout for default import.",
"components": [_component()],
}
],
"merged_components": [
{
"id": "photo_component",
"description": "Merged reusable photo component.",
"variants": [_component()],
}
],
}
),
encoding="utf-8",
)
return template_dir
class _FakeSession:
def __init__(self, existing: TemplateV2 | None = None):
self.existing = existing
self.added: list[TemplateV2] = []
self.commit_count = 0
async def get(self, _model: Any, _key: str):
return self.existing
def add(self, template: TemplateV2) -> None:
self.added.append(template)
async def commit(self) -> None:
self.commit_count += 1
class _SessionContext:
def __init__(self, session: _FakeSession):
self.session = session
async def __aenter__(self):
return self.session
async def __aexit__(self, *_args):
return None
def test_default_template_import_normalizes_shapes_and_copies_static(
tmp_path,
monkeypatch,
):
templates_root = tmp_path / "templates"
_write_template_bundle(templates_root)
app_data_dir = tmp_path / "app_data"
session = _FakeSession()
monkeypatch.setenv("APP_DATA_DIRECTORY", str(app_data_dir))
monkeypatch.setattr(
default_templates,
"async_session_maker",
lambda: _SessionContext(session),
)
asyncio.run(default_templates.import_default_templates_on_startup(templates_root))
assert session.commit_count == 1
assert len(session.added) == 1
template = session.added[0]
assert template.id == "general"
assert template.is_default is True
assert list(template.layouts) == ["layouts"]
assert list(template.merged_components) == ["components"]
assert (
template.layouts["layouts"][0]["components"][0]["elements"][0]["data"]
== "/app_data/templates/general/static/image.png"
)
assert (
template.merged_components["components"][0]["variants"][0]["elements"][0][
"data"
]
== "/app_data/templates/general/static/image.png"
)
assert template.assets["thumbnail"] == (
"/app_data/templates/general/static/thumbnail.png"
)
assert template.assets["fonts"] == {
"Inter": "/app_data/templates/general/static/inter.ttf"
}
assert template.assets["images"] == ["/app_data/templates/general/static/image.png"]
assert (
app_data_dir / "templates/general/static/image.png"
).read_bytes() == b"image"
def test_default_template_import_updates_existing_database_row(tmp_path, monkeypatch):
templates_root = tmp_path / "templates"
_write_template_bundle(templates_root)
app_data_dir = tmp_path / "app_data"
existing = TemplateV2(
id="general",
name="Old name",
description="Old description",
layouts={"layouts": []},
merged_components={"components": []},
assets={"thumbnail": "/old.png"},
is_default=False,
)
session = _FakeSession(existing=existing)
monkeypatch.setenv("APP_DATA_DIRECTORY", str(app_data_dir))
monkeypatch.setattr(
default_templates,
"async_session_maker",
lambda: _SessionContext(session),
)
asyncio.run(default_templates.import_default_templates_on_startup(templates_root))
assert session.commit_count == 1
assert session.added == [existing]
assert existing.name == "General"
assert existing.description == "General purpose default template."
assert existing.is_default is True
assert list(existing.layouts) == ["layouts"]
assert list(existing.merged_components) == ["components"]
assert existing.assets["thumbnail"] == (
"/app_data/templates/general/static/thumbnail.png"
)
assert (app_data_dir / "templates/general/static/image.png").exists()
def test_bundled_general_template_json_matches_template_v2_shapes():
template_dir = Path(__file__).resolve().parents[4] / "templates" / "general"
template = default_templates._load_default_template(template_dir)
assert template.id == "general"
assert template.is_default is True
assert list(template.layouts) == ["layouts"]
assert len(template.layouts["layouts"]) > 0
assert list(template.merged_components) == ["components"]
assert len(template.merged_components["components"]) > 0
assert template.assets["thumbnail"] == (
"/app_data/templates/general/static/thumbnail.png"
)