Files
Aislo/resources/tester/test_m02_structure_combo.py
T
eomsangdonandClaude Opus 5.5 b5114ec17f feat(M02): 집계 항목 폴더 구조 서버 — 경로 · 일련번호 · 나무 고침 길(PLAN 26-2a)
- 항목 경로 = 폴더 이름 배열(깊이 자유) · 집계표 열 머리(빈 칸 건너뜀)가 곧 경로 · 열에 경로를 같이 적음 · 머리 줄 수(층)는 가장 깊은 경로에 맞춤(넷 밑으로는 안 줄임) · 빈 폴더는 집계표 폴더 칸(M02_MasterTemplete_Tree)
- 표 저장과 나무 고침 한 줄기 — 나무 고침은 집계표 문서를 고쳐 같은 집계표 저장(store.write)을 탐(번호 · SS 장부 · 세 파일 · 입력 연결 파일 지우기가 함께)
- 나무 고침 길 POST /api/m02/layers/{layer}/tree(add-folder · add-item · rename · move · delete · 판 409 · 422 · 404 · 층 권한) · 읽기 GET 같은 길 {판, 폴더, items}
- 번호 = 새 항목은 자리 뜻 없는 일련번호(있던 번호 · 지운 번호 가장 큰 수 + 1) · 있던 번호 그대로
- SS 장부 = M02_MasterTemplete_Book 로 떼어 냄(Store 543 → 478) · 줄에 경로 · 이름 · 옛 종류 · 분류1~3 = 경로 앞 넷 · 경로 없는 옛 줄은 읽을 때 채움 · 옮기는 함수 migrate_paths
- 목록 길 /api/m02/items 줄에 경로 · 이름(경로 이음) · 자재 조합 · 갈라 내기 이름도 경로 이음
- 마스터 집계표 · 장부를 경로 모양으로 옮김(51 항목 · 키 · 번호 그대로 · 빈 글 머리는 null)
- 시험 test_m02_tree 5(옛 51 항목 · 옮기기 두 번 같음 · 깊이 1 · 2 · 5 · 이름 · 옮기기 · 지우기 · 마지막 항목 · 409 · 403 · 표 저장 한 줄기) · 번호 시험을 일련번호 규칙으로

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KmELpdXFDRZHhfbGuRhSmL
2026-09-30 07:50:20 +09:00

111 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""구조물집계표조합 — 서버가 집계표 [저장] 때 맞추는 장부(키 SS · 열마다 한 줄).
견본 표(`write_sample_table`)로만 봄 — 실제 마스터 양식은 안 읽음.
"""
import json
from pathlib import Path
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from M02_MasterTemplete import M02_MasterTemplete_Book as book
from M02_MasterTemplete import M02_MasterTemplete_Store as store
from M02_MasterTemplete import M02_Template_Layers as layers
from M02_MasterTemplete.M02_MasterTemplete_Router import router
from resources.tester.test_m02_structure import write_sample_table
ROOT = Path(__file__).resolve().parents[2]
TABLE = "/api/m02/templates/table/구조물집계표"
@pytest.fixture()
def client(tmp_path, monkeypatch):
write_sample_table(tmp_path)
monkeypatch.setattr(store, "FOLDER", tmp_path)
app = FastAPI()
app.include_router(router)
return TestClient(app)
def _save_table(client, change) -> None:
got = client.get(TABLE).json()
change(got["문서"])
assert client.put(TABLE, json={"판": got["판"], "문서": got["문서"]}).status_code == 200
def _keys(client) -> dict[str, str]:
return {row["열"]: row["키"] for row in client.get("/api/m02/structure-combos").json()["줄"]}
def test_처음_한_번_만듦_글_열_빼고_칸은_집계표_그대로(client, tmp_path):
assert not (tmp_path / store.COMBO_FILE).exists()
doc = client.get("/api/m02/structure-combos").json()
assert (doc["그룹"], doc["다음"]) == ("구조물집계표조합", 14)
rows = doc["줄"]
assert [r["열"] for r in rows][:3] == ["rv", "c1", "pv_b"]
assert {"no", "sta", "memo"}.isdisjoint(r["열"] for r in rows) # 글 열 빼기
assert (rows[0]["키"], rows[-1]["키"]) == ("SS000001", "SS000013")
assert rows[-1]["열"] == "h_rip_m"
fb = next(r for r in rows if r["열"] == "fb")
assert (fb["종류"], fb["분류1"], fb["분류2"], fb["분류3"]) == (
"세월교",
"(관경 × 련수마다)",
None,
None,
)
assert (tmp_path / store.COMBO_FILE).is_file()
def test_집계표_저장_때_새_열_지운_열_고친_열을_맞춤_키_유지(client):
before = _keys(client)
def change(table):
cols = table["열"]
cols[:] = [c for c in cols if c["id"] != "h_rip_m"] # 맨 끝 키 SS000013 열 지움
rv = next(c for c in cols if c["id"] == "rv")
rv["머리"] = ["돌기슭막이", "메쌓기", "1.2m", "기초유"]
rv.update(단위="m", 일위대가="UA000004", 펼침=True, 바인딩={"종류": "revetment"})
cols.insert(3, {"id": "new1", "머리": ["옹벽", None, None, None], "단위": "m", "꼴": "수"})
_save_table(client, change)
doc = client.get("/api/m02/structure-combos").json()
rows = {r["열"]: r for r in doc["줄"]}
assert "h_rip_m" not in rows
assert rows["new1"]["키"] == "SS000014" # 지운 열의 SS000013 은 다시 안 씀
assert [r["열"] for r in doc["줄"]][:4] == ["rv", "new1", "c1", "pv_b"] # 집계표 차례
assert all(rows[c]["키"] == k for c, k in before.items() if c != "h_rip_m")
rv = rows["rv"]
assert (rv["분류1"], rv["분류3"], rv["단위"], rv["일위대가"]) == (
"메쌓기",
"기초유",
"m",
"UA000004",
)
assert (rv["바인딩"], rv["펼침"]) == ({"종류": "revetment"}, True)
# 번호는 세 파일과 같음 — 새 열도 [저장] 한 번에 SD · SA · SM 이 섬
numbers = client.get("/api/m02/structures/numbers").json()
assert {k: rows["new1"][k] for k in ("도번", "면적번", "재료번")} == numbers["new1"]
assert rows["new1"]["도번"].startswith("SD")
# 또 저장해도(바뀐 것 없음) 키 · 다음 그대로
_save_table(client, lambda table: None)
again = client.get("/api/m02/structure-combos").json()
assert (again["다음"], again["줄"]) == (15, doc["줄"])
def test_SS_머리글은_키대장과_안_겹침():
ledger = json.loads((ROOT / "resources/master_data/_키대장.json").read_text("utf-8"))
assert "SS" not in ledger["다음"]
assert book.HEAD == "SS" # 장부는 `M02_MasterTemplete_Book`(26-2a 나눔)
def test_새_프로젝트_복사에_실림(client, tmp_path, monkeypatch):
client.get("/api/m02/structure-combos")
monkeypatch.setattr(layers, "SYSTEM_ROOT", tmp_path)
copied = layers.seed_project(tmp_path / "project")
assert "구조물집계표조합" in copied["작업본"] and "구조물집계표조합" in copied["초기"]
target = layers.project_dir(tmp_path / "project") / store.COMBO_FILE
assert json.loads(target.read_bytes())["줄"][0]["키"] == "SS000001"