Files
Aislo/resources/tester/test_156_1_b08_unlink.py
T
eomsangdonandClaude Opus 5.5 9e53b866e2 feat(b08): 구조물도 모달 공용 큰 창 · 카드 셋 한 줄 세 칸(156-4)
- 모달 = 공용 wide(96vw × 94vh) · 자기 폭 규칙 지움
- 도면 · 일위대가 · 면적산출 카드 = 한 줄 세 칸(3:2:2) · 카드 높이 큰 창에 맞춤 · 칸 사이 넓힘
- 조합끼리 가름줄
- 시험 test_156_1 덧붙임 · test_61_2 옛 폭 판정을 wide 로

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01STqEqztUthVFBmEP18wBSz
2026-10-09 20:40:17 +09:00

113 lines
5.5 KiB
Python

# -*- coding: utf-8 -*-
"""B08 조합 [연결 끊기](PLAN 156-1 · 156-3) — 임시 저장소(154-2 시험 바탕 그대로).
- 링크 길에 null = 그 시설 칸만 비움 · 다른 시설 · 칸 · 관 지점 노선 지문 그대로 · 구조물 판 +1
- 끊기는 사본 맞춤을 안 부름 — 사본 폴더 그대로(고아 정리 안 함)
- 집계 응답 `facilities` = 모든 시설 칸(연결된 칸 포함) · 끊은 시설은 `unlinked` 로
- 화면 = 연결된 칸만 [연결 끊기] · 확인 창 · 초안이면 막음 · 단추 = 모달 [닫기] 양식
"""
from __future__ import annotations
import asyncio
from pathlib import Path
from B08_Quantity import B08_Quantity_Router_Summary as summary
from M02_MasterTemplete import M02_Item_Snapshot as snap
from M02_MasterTemplete import M02_Project_Items_Router as items_router
from M02_MasterTemplete.StructOptions import M02_SO_Definition as definition
from resources.tester.test_154_2_b08_direct_link import ( # noqa: F401 — 시험 저장소
MS,
PIPE,
ROOT,
_points,
_structures,
root,
)
def _folders(root: Path) -> set[str]:
return {p.name for p in snap.structures_dir(root).iterdir() if p.is_dir()}
def _unlink(monkeypatch, root: Path, copy: str, facility: str | None) -> dict:
async def fake_root(session, project_id):
return root
def no_sync(*args):
raise AssertionError("끊기는 사본 맞춤을 부르지 않음")
monkeypatch.setattr(items_router, "_root", fake_root)
monkeypatch.setattr(items_router, "safe_sync", no_sync)
body = items_router.LinkBody(summary_item=None, facility=facility)
return asyncio.run(items_router.link_item("proj", copy, body, session={}))
def test_구조물_끊기_그_칸만_사본_그대로(root, monkeypatch):
folders, points = _folders(root), _points(root)
assert snap.folder_name("st1") in folders
reply = _unlink(monkeypatch, root, "st1", None)
assert reply == {"폴더": snap.folder_name("st1"), "snapshot_failed": []}
got = _structures(root)
assert got["revision"] == 5
st0, st1 = got["structures"]
assert st1.get("summary_item") is None and st1["chainage_m"] == 400
assert st0.get("summary_item") is None and st0["chainage_m"] == 300
assert _points(root) == points # 관 지점 · 노선 지문 그대로
assert _folders(root) == folders # 사본 폴더 그대로
assert "st1" not in snap.linked_snapshots(root)
def test_관_그룹_끊기_다른_시설_그대로(root, monkeypatch):
folders, before = _folders(root), _points(root)
_unlink(monkeypatch, root, "pipe@100.0__grv6lny", "pipe")
after = _points(root)
assert after["route_signature"] == "sig-1"
assert "group_items" not in after["points"][0]
assert after["points"][1:] == before["points"][1:] # 같은 측점 박스 · 다른 관 그대로
assert _structures(root)["structures"][1]["summary_item"] == MS
assert _folders(root) == folders
def test_집계_모든_시설_칸_끊으면_미연결(root, monkeypatch):
names = definition.read()["종류"]["pipe"]["이름"]
designs = [{"chainage_m": 100.0, "design": {"pipe_length_m": 12}}]
first = summary.pipe_summary(root, designs, names, 6.0)
assert not any(u["id"] == "st1" for u in first["unlinked"])
st1 = next(f for f in first["facilities"] if f["id"] == "st1")
assert st1["slots"][0] == {"copy": "st1", "group": None, "item": MS, "linked": True}
pipe = next(
f for f in first["facilities"] if f["id"] == "pipe@100.0" and f["type_id"] == "pipe"
)
assert any(s["copy"] == "pipe@100.0__grv6lny" and s["linked"] for s in pipe["slots"])
assert {u["id"] for u in first["unlinked"]} <= {f["id"] for f in first["facilities"]}
_unlink(monkeypatch, root, "st1", None)
after = summary.pipe_summary(root, designs, names, 6.0)
st1 = next(u for u in after["unlinked"] if u["id"] == "st1")
assert st1["slots"][0]["linked"] is False and st1["chainage_m"] == 400
assert PIPE == _points(root)["points"][0]["group_items"]["grv6lny"] # 다른 칸 그대로
def test_화면_연결된_칸만_끊기_닫기_양식():
ui = (ROOT / "B08_Quantity/B08_Quantity_UI_Link.ts").read_text(encoding="utf-8")
assert 'if (slot.linked) buttons.append(act(L("B08_Quantity_Link_Unlink"), unlink))' in ui
assert ".link(slot.copy, facility.facility, null)" in ui
assert 'showConfirmDialog(L("B08_Quantity_Link_UnlinkAsk")' in ui
assert ui.count("hasPendingDesign(projectId)") == 2 # 선택 · 끊기 둘 다 막음
assert 'size: "sm"' not in ui # 모달 [닫기] = ghost · 기본 크기
modal = (ROOT / "ui_template/ui_template_modal.ts").read_text(encoding="utf-8")
assert 'label: opts.closeLabel,\n variant: "ghost",\n onClick' in modal
page = (ROOT / "B08_Quantity/B08_Quantity_UI_Summary.ts").read_text(encoding="utf-8")
assert "facilities: unlinkedAt(saved?.facilities ?? [], station)" in page
sheets = (ROOT / "B08_Quantity/B08_Quantity_UI_Drawing.ts").read_text(encoding="utf-8")
assert "linkSection(request.projectId, request.facilities" in sheets
def test_156_4_구조물도_모달_큰_창_세_칸():
sheets = (ROOT / "B08_Quantity/B08_Quantity_UI_Drawing.ts").read_text(encoding="utf-8")
assert "wide: true" in sheets
css = (ROOT / "B08_Quantity/B08_Quantity_UI_Drawing.css").read_text(encoding="utf-8")
assert "min(1320px" not in css # 자기 폭 없음 — 공용 wide 그대로
assert "minmax(0, 3fr) minmax(0, 2fr) minmax(0, 2fr)" in css # 도면 · 일위대가 · 면적산출
assert ".b08-sheets__combo + .b08-sheets__combo" in css