"""표지 템플릿·엔진 검증 (2026-08-31 신설). 표지는 A1 실치수 고정이라 좌표가 어긋나면 곧바로 종이 밖으로 나간다. 그래서 ① 종이 크기 ② 플레이스홀더 치환 ③ 캐시 오염 세 가지를 못 박아 둔다. """ import json from pathlib import Path import pytest from B07_DesignDetail.B07_DesignDetail_Engine_Cad import DRAWING_FORMAT, FRAME_LAYER_ID from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Cover import build_cover_drawing TEMPLATE = Path("resources/template_2dDrawing/00_template_cover.json") # A1 도각 템플릿과 같은 재단 표식 원점 — 두 도면이 같은 종이 좌표계를 써야 한다. PAPER = (-5.05, -5.04, 834.95, 588.96) def _bbox(entities): xs, ys = [], [] for entity in entities: shape = entity.get("shapeData") or {} for key in ("basePoint", "point", "startPoint", "endPoint"): if key in shape: xs.append(shape[key]["x"]) ys.append(shape[key]["y"]) for p in shape.get("points", []): xs.append(p["x"]) ys.append(p["y"]) return min(xs), min(ys), max(xs), max(ys) def test_템플릿이_A1_종이에_맞는다(): document = json.loads(TEMPLATE.read_text(encoding="utf-8")) bbox = _bbox(document["entities"]) assert [round(v, 2) for v in bbox] == list(PAPER) assert round(bbox[2] - bbox[0], 1) == 840.0 assert round(bbox[3] - bbox[1], 1) == 594.0 def test_굵은_띠는_실치수_두께를_갖는다(): """lineWidth는 화면 픽셀이라 두께가 안 나온다 — solid Hatch로 냈는지 확인.""" document = json.loads(TEMPLATE.read_text(encoding="utf-8")) hatches = [e for e in document["entities"] if e["type"] == "Hatch"] assert len(hatches) == 3 # 상단선·하단선·제목 강조선 for hatch in hatches: assert hatch["shapeData"]["options"]["style"] == "solid" ys = [p["y"] for p in hatch["shapeData"]["points"]] assert 0.5 <= max(ys) - min(ys) <= 3.0 # mm def test_도면은_잠금_도각_레이어로_나온다(): """도각은 잠기고, 덧그릴 비잠금 층이 최소 하나 있어야 한다. 도각만 있으면 CAD에서 새 선을 놓을 자리가 없다 — 표지에 비잠금 「주기」 층을 함께 싣는다(2026-09-01 `64d944eb`). 층 순서는 규약이 아니므로 id로 찾는다. """ drawing = build_cover_drawing("cover") assert drawing["format"] == DRAWING_FORMAT assert {e["layerId"] for e in drawing["entities"]} == {FRAME_LAYER_ID} layers = {layer["id"]: layer for layer in drawing["layers"]} assert layers[FRAME_LAYER_ID]["isLocked"] is True assert any(not layer["isLocked"] for layer in drawing["layers"]), ( "덧그릴 비잠금 도면층이 없다" ) @pytest.mark.parametrize( ("fields", "expected"), [ ({}, ""), # 값이 없으면 빈칸 — 남의 값이 남지 않는다 ({"시행청": "울진국유림관리소"}, "울진국유림관리소"), ], ) def test_플레이스홀더가_치환된다(fields, expected): drawing = build_cover_drawing("cover", fields) labels = [e["shapeData"]["label"] for e in drawing["entities"] if e["type"] == "Text"] assert expected in labels def test_치환이_캐시된_템플릿을_더럽히지_않는다(): """_load_template은 lru_cache다 — 한 번 채운 값이 다음 도면에 새면 안 된다.""" build_cover_drawing("a", {"공사명": "남의 사업", "시행청": "남의 청"}) fresh = build_cover_drawing("b")["entities"] labels = [e["shapeData"]["label"] for e in fresh if e["type"] == "Text"] assert "남의 사업 설계도" not in labels assert "남의 청" not in labels