Files
Aislo/resources/tester/test_m02_structure_def_screen.py
T
eomsangdonandClaude Opus 5.5 81f7d98e6f feat(구조물표): 323-7 새 종류 · 정리 — M02 종류 더하기(본보기 복사 · 일곱 갈래 본보기 그대로) · 손코딩 동작 · 명세 = 본보기 키 · 특수 동작 = 동작 이름 · 정본 목록 = 표 · drawing_views 걷음 · 옛 이름 되짚기 걷음(자리로 가름) · 허용 거리 파이썬 한 곳 · 벽 툴팁 = 종류 이름
- M02 종류별 탭 [종류 더하기] = 본보기(구조물 정본 원본) 복사 — 키 자동 · 이름 「본보기 2」 · 옵션 · 표시 · 그룹 · 배치 · 규칙 · 종류 덧칸 · 반영 그대로 · 종류.{새}.본보기 · 관 지점 종류 · 복사본은 본보기 밖
- 구조물 표 = 본보기 처음값 이어받음(resolveCatalog · resolve_catalog 짝 · 줄 칸 base) · baseType/base_type · specFor(명세) · 덧단 · 길이 전후 풀기 · 옹벽 추가 단 콘크리트
- 검사(화면 = 서버 짝) — 본보기 = 원본 · 같은 군 · 자리꼴 · 정본 · 만든 뒤 고정 · 복사본은 본보기가 숨긴 칸 이어받음 · 서버 덧칸 본보기 받음
- 특수 동작 = 동작 이름 — 바로 안 놓기 · 포장 나누기 = 포장_물넘이_겹침 · 월류 높이 기다림 = 월류단면
- 정본 목록 = 표 — 파이썬 관 지점 종류 = catalog owner · B05 시설 서브폼 = 표 형상 · 안 쓰는 손 목록 걷음
- drawing_views — 스키마에서 빼고 읽을 때 버림 · M02 [저장] 때 빠짐(코드는 마스터 안 고침)
- 이관 = 지난 판 이름 대신 측점 계획 자리(planted)로 가름 · all_type_names 걷음
- 허용 거리 = common_util_structure_station.py 한 곳(SAME_STATION_M · EDGE_TOLERANCE_M · PIPE_MATCH_M) · TS 표는 station.ts 머리
- 시험: test_323_7_new_type(템플릿 · 일곱 갈래 · 그림 · 검사 짝 · 서버 읽기) · 322-0 유령 시험 = 자리 · 옛 도움 파일 동작 · 표 길 · 기대 글 고침

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
2026-10-14 18:59:13 +09:00

128 lines
5.2 KiB
Python

"""M02 구조물 정의 편집 화면(PLAN 48-2) — 지난 판 길 · 화면이 보내는 꼴을 서버가 받음.
못박는 것
- 지난 판 목록 `[{판, 저장일}]` 새 판부터 · 한 벌 읽기 · 없는 판 404 · 읽기는 누구나.
- 화면이 고친 정의(이름 · 순서 · 안 씀 · 기준측점 · 선택지 이름 · 배치 · 그룹 형상 · 규칙)를
그대로 PUT 하면 판 +1 · 같은 값으로 다시 읽힘.
- 시스템 관리자 아니면 PUT 403(화면은 읽기만).
- 마스터 정본은 안 씀(사본).
"""
from __future__ import annotations
import json
from pathlib import Path
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from B05_Profile import B05_Profile_Structures_Schema as schema
from common_util.common_util_auth import verify_session
from M02_MasterTemplete.StructOptions.M02_SO_Router import read_router
URL = "/api/m02/structure-definition"
ADMIN = {"role": "SYSTEM_ADMIN", "user_id": 1}
USER = {"role": "USER", "user_id": 2, "company_id": 1}
@pytest.fixture
def copy(tmp_path: Path, monkeypatch) -> Path:
path = tmp_path / "구조물정의.json"
path.write_text(Path(schema.DEFINITION_PATH).read_text("utf-8"), "utf-8")
monkeypatch.setattr(schema, "DEFINITION_PATH", str(path))
return path
def _client(session: dict) -> TestClient:
app = FastAPI()
app.include_router(read_router)
app.dependency_overrides[verify_session] = lambda: session
return TestClient(app)
def _screen_edit(doc: dict) -> dict:
"""화면이 하는 고침 한 벌 — `M02_SO_Def*.ts` 가 만드는 꼴 그대로."""
pipe = next(t for t in doc["types"] if t["type_id"] == "pipe")
pipe["name"] = "배수관(고침)"
kind = next(o for o in pipe["options"] if o["key"] == "pipe_kind")
kind["label"] = "관 종류"
# 선택지 값은 만든 뒤 고정(322-2) — 이름은 이름 표(`종류.pipe.이름`)로
doc["종류"].setdefault("pipe", {}).setdefault("이름", {})["pipe.kind=흄관"] = "흄관(고침)"
pipe["options"].append(
{
"key": "opt_ab12cd",
"label": "새 옵션 1",
"input": "select",
"choices": ["새 선택지 1", "새 선택지 2"],
"default": None,
}
)
pipe["options"][1]["enabled"] = False # 안 씀
first = list(doc["구조물군"])
doc["구조물군"] = {k: doc["구조물군"][k] for k in [first[1], first[0], *first[2:]]}
doc["종류"].setdefault("pipe", {})["기준측점"] = False
doc["배치"]["pipe"] = {"pipe_kind": {"줄": 1, "칸": 1, "너비": 2}}
doc["표시"]["pipe"] = {"wing_wall_type": False} # 부품이 안 읽는 칸(322-2 읽는 칸은 못 숨김)
doc["그룹"]["pipe"][1]["형상"] = {
"길이": {"받기": True, "뜻": "유입 보호공 연장"},
"높이": {"받기": False, "뜻": ""},
}
doc["규칙"] = [
{
"종류": "pipe",
"만약": {"옵션": "pipe_kind", "값들": ["흄관"]},
"그러면": {"옵션": "opt_ab12cd", "선택지": ["새 선택지 2"], "기본값": "새 선택지 2"},
},
{
"종류": "pipe",
"만약": {"옵션": "inlet_type", "값들": ["집수정"]},
"그러면": {"옵션": "opt_ab12cd", "보이기": False},
},
]
return doc
def test_화면_고침을_그대로_받아_판_더하기_1_지난_판_길(copy) -> None:
admin = _client(ADMIN)
doc = admin.get(URL).json()
assert admin.get(f"{URL}/history").json() == []
sent = _screen_edit(json.loads(json.dumps(doc)))
res = admin.put(URL, json={"판": doc["판"], "정의": sent})
assert res.status_code == 200, res.text
got = res.json()
assert got["판"] == doc["판"] + 1
for key in ("구조물군", "종류", "배치", "표시", "그룹", "규칙"):
assert got[key] == sent[key], key
# 옛 칸(drawing_views)은 [저장] 때 빠짐(323-7 · 아무도 안 읽음) — 나머지는 그대로
retired = schema.without_retired
assert got["types"] == [retired(t) for t in sent["types"]]
assert list(got["구조물군"]) == list(sent["구조물군"]) # 순서 그대로
rows = admin.get(f"{URL}/history").json()
assert [r["판"] for r in rows] == [doc["판"]] and len(rows[0]["저장일"]) == 16
old = admin.get(f"{URL}/history/{doc['판']}").json()
assert old == doc
assert admin.get(f"{URL}/history/999").status_code == 404
def test_지난_판은_누구나_읽고_쓰기는_시스템_관리자만(copy) -> None:
user = _client(USER)
doc = user.get(URL).json()
assert user.get(f"{URL}/history").status_code == 200
assert user.put(URL, json={"판": doc["판"], "정의": _screen_edit(doc)}).status_code == 403
assert json.loads(copy.read_text("utf-8"))["판"] == doc["판"]
def test_화면이_못_거른_틀린_규칙은_422_안_씀(copy) -> None:
admin = _client(ADMIN)
doc = admin.get(URL).json()
doc["규칙"] = [
{
"종류": "pipe",
"만약": {"옵션": "pipe_kind", "값들": ["없음"]},
"그러면": {"옵션": "inlet_type"},
}
]
assert admin.put(URL, json={"판": doc["판"], "정의": doc}).status_code == 422
assert json.loads(copy.read_text("utf-8"))["판"] == doc["판"]