def test_template_crud_packs_and_unpacks_mapping_rules(client): payload = { "name": "Template", "color": "#06b6d4", "z_index": 0, "classes": [{"id": "c1", "name": "胆囊", "color": "#ff0000", "zIndex": 10}], "rules": [{"id": "r1", "name": "rule"}], } created = client.post("/api/templates", json=payload) assert created.status_code == 201 template_id = created.json()["id"] assert created.json()["classes"][0]["name"] == "胆囊" assert created.json()["rules"][0]["id"] == "r1" listing = client.get("/api/templates") assert listing.status_code == 200 assert listing.json()[0]["classes"][0]["name"] == "胆囊" detail = client.get(f"/api/templates/{template_id}") assert detail.status_code == 200 assert detail.json()["name"] == "Template" updated = client.patch(f"/api/templates/{template_id}", json={ "classes": [{"id": "c2", "name": "肝脏", "color": "#00ff00", "zIndex": 20}], "rules": [], }) assert updated.status_code == 200 assert updated.json()["classes"][0]["name"] == "肝脏" deleted = client.delete(f"/api/templates/{template_id}") assert deleted.status_code == 204 assert client.get(f"/api/templates/{template_id}").status_code == 404 def test_template_404s(client): assert client.get("/api/templates/999").status_code == 404 assert client.patch("/api/templates/999", json={"name": "x"}).status_code == 404 assert client.delete("/api/templates/999").status_code == 404 def test_default_head_neck_ct_template_is_seeded_and_visible(client, db_session): from main import ensure_default_templates from models import Template ensure_default_templates(db_session) ensure_default_templates(db_session) templates = db_session.query(Template).filter(Template.owner_user_id.is_(None)).all() names = [template.name for template in templates] assert names.count("头颈部CT分割") == 1 listing = client.get("/api/templates") assert listing.status_code == 200 head_neck = next(template for template in listing.json() if template["name"] == "头颈部CT分割") assert head_neck["description"] == "头颈部CT分割" expected_names = [ "肿瘤/结节", "下颌骨", "甲状腺", "气管", "颈椎", "颈动脉", "颈静脉", "腮腺", "下颌下腺", "舌骨", "待分类", ] expected_colors = [ "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "#00ffff", "#ff8000", "#800080", "#008080", "#808000", "#000000", ] actual_names = [item["name"] for item in head_neck["classes"]] actual_colors = [item["color"] for item in head_neck["classes"]] actual_mask_ids = [item["maskId"] for item in head_neck["classes"]] if actual_names != expected_names: raise AssertionError(f"Unexpected head-neck classes: {actual_names}") if actual_colors != expected_colors: raise AssertionError(f"Unexpected head-neck colors: {actual_colors}") if actual_mask_ids != [*list(range(1, 11)), 0]: raise AssertionError(f"Unexpected head-neck mask IDs: {actual_mask_ids}") def test_default_head_neck_ct_template_migrates_legacy_english_labels(db_session): from main import ensure_default_templates from models import Template db_session.add(Template( name="头颈部CT分割", description="legacy", color="#ef4444", z_index=10, owner_user_id=None, mapping_rules={ "classes": [ {"id": "old-1", "name": "肿瘤/结节 (Tumor/Nodule)", "color": "#ff0000", "zIndex": 10, "maskId": 1}, {"id": "reserved-unclassified", "name": "待分类", "color": "#000000", "zIndex": 0, "maskId": 0}, ], "rules": [], }, )) db_session.commit() ensure_default_templates(db_session) templates = db_session.query(Template).filter(Template.name == "头颈部CT分割").all() assert len(templates) == 1 classes = templates[0].mapping_rules["classes"] assert classes[0]["name"] == "肿瘤/结节" assert all("(" not in item["name"] for item in classes)