Files
matrix-screen-controller/核桃派软件源代码/tests/test_library_order.py
T

173 lines
6.1 KiB
Python

import base64
import json
import pytest
from fastapi.testclient import TestClient
from app.demo_library import DEMO_ANIMATION_ID, DEMO_STATIC_ID
from app.library_order import LibraryOrderValidationError
from app.main import create_app
def scene(color=(0, 0, 0)) -> dict:
return {
"version": 1,
"width": 64,
"height": 64,
"pixelRgb": base64.b64encode(bytes(color) * (64 * 64)).decode("ascii"),
"elements": [],
}
def create_template(client: TestClient, name: str) -> dict:
response = client.post("/api/templates", json={"name": name, "scene": scene()})
assert response.status_code == 201
return response.json()
def create_animation(client: TestClient, name: str) -> dict:
response = client.post("/api/animations", json={"name": name})
assert response.status_code == 201
return response.json()
def put_order(client: TestClient, items: list[dict], revision: str):
return client.put(
"/api/library/order",
headers={"If-Match": f'"{revision}"'},
json={"items": items},
)
def test_library_order_defaults_mixes_types_and_persists_only_after_update(tmp_path):
client = TestClient(create_app(project_root=tmp_path, driver_kind="mock"))
first_template = create_template(client, "静态一")
second_template = create_template(client, "静态二")
first_animation = create_animation(client, "动图一")
second_animation = create_animation(client, "动图二")
order_path = tmp_path / "data" / "library" / "order.json"
default = client.get("/api/library/order")
assert default.status_code == 200
assert default.json()["items"] == [
{"type": "template", "id": second_template["id"]},
{"type": "template", "id": first_template["id"]},
{"type": "animation", "id": second_animation["id"]},
{"type": "animation", "id": first_animation["id"]},
]
assert not order_path.exists()
mixed = [
{"type": "animation", "id": first_animation["id"]},
{"type": "template", "id": first_template["id"]},
{"type": "animation", "id": second_animation["id"]},
{"type": "template", "id": second_template["id"]},
]
assert client.put("/api/library/order", json={"items": mixed}).status_code == 428
updated = put_order(client, mixed, default.json()["revision"])
assert updated.status_code == 200
assert updated.json()["items"] == mixed
persisted = json.loads(order_path.read_text(encoding="utf-8"))
assert persisted == {"schema_version": 1, "items": mixed}
restarted = TestClient(create_app(project_root=tmp_path, driver_kind="mock"))
assert restarted.get("/api/library/order").json() == updated.json()
stale = put_order(restarted, list(reversed(mixed)), default.json()["revision"])
assert stale.status_code == 409
def test_library_order_rejects_invalid_demo_duplicate_and_changed_sets(tmp_path):
client = TestClient(create_app(project_root=tmp_path, driver_kind="mock"))
template = create_template(client, "静态")
animation = create_animation(client, "动图")
current = client.get("/api/library/order").json()
demo = put_order(
client,
[{"type": "template", "id": DEMO_STATIC_ID}, {"type": "animation", "id": DEMO_ANIMATION_ID}],
current["revision"],
)
assert demo.status_code == 422
duplicate = put_order(
client,
[
{"type": "template", "id": template["id"]},
{"type": "template", "id": template["id"]},
{"type": "animation", "id": animation["id"]},
],
current["revision"],
)
assert duplicate.status_code == 422
missing = put_order(
client,
[{"type": "template", "id": template["id"]}],
current["revision"],
)
assert missing.status_code == 409
extra_field = client.put(
"/api/library/order",
headers={"If-Match": f'"{current["revision"]}"'},
json={"items": [{"type": "template", "id": template["id"], "name": "bad"}]},
)
assert extra_field.status_code == 422
def test_library_order_appends_new_items_and_filters_deleted_references(tmp_path):
client = TestClient(create_app(project_root=tmp_path, driver_kind="mock"))
first = create_template(client, "静态一")
animation = create_animation(client, "动图")
initial = client.get("/api/library/order").json()
ordered = [
{"type": "animation", "id": animation["id"]},
{"type": "template", "id": first["id"]},
]
assert put_order(client, ordered, initial["revision"]).status_code == 200
appended = create_template(client, "静态二")
after_create = client.get("/api/library/order").json()
assert after_create["items"] == [
*ordered,
{"type": "template", "id": appended["id"]},
]
removed = client.delete(
f"/api/templates/{first['id']}",
headers={"If-Match": f'"{first["revision"]}"'},
)
assert removed.status_code == 200
after_delete = client.get("/api/library/order").json()
assert after_delete["items"] == [
{"type": "animation", "id": animation["id"]},
{"type": "template", "id": appended["id"]},
]
@pytest.mark.parametrize(
"content",
[
b"not json",
json.dumps({"schema_version": 2, "items": []}).encode(),
json.dumps({"schema_version": 1, "items": [], "extra": True}).encode(),
json.dumps({
"schema_version": 1,
"items": [
{"type": "template", "id": "11111111-1111-4111-8111-111111111111"},
{"type": "template", "id": "11111111-1111-4111-8111-111111111111"},
],
}).encode(),
json.dumps({
"schema_version": 1,
"items": [{"type": "template", "id": DEMO_STATIC_ID}],
}).encode(),
],
)
def test_invalid_library_order_blocks_startup_and_preserves_original(tmp_path, content):
path = tmp_path / "data" / "library" / "order.json"
path.parent.mkdir(parents=True)
path.write_bytes(content)
with pytest.raises(LibraryOrderValidationError):
create_app(project_root=tmp_path, driver_kind="mock")
assert path.read_bytes() == content