Files
Aislo/resources/tester/test_m02_empty_master.py
T
eomsangdonandClaude Opus 5.5 2a3051fbca feat(M02): 마스터 구조물집계표 초기화 · 시험 견본화(PLAN 26-5a)
- 마스터 층 구조물 항목 51개 지움 — 나무 지우기(tree.apply delete) → 집계표 저장(store.write) 한 줄기 · 집계표 구조물 열 · SS 장부 줄 · structure/area/material 파일 153개 · 남김 = no · sta · 비고 열 · 변수 · 쪽줄 · 합계줄 · 바인딩규칙 · 자재조합 · 구조물옵션표시 · drawing · M01 · 회사 · 개인 층 · 프로젝트 복사본 · 지운 열의 열너비만 뺌
- 키 · 번호 다시 안 씀 — 장부 다음 52(새 항목 SS000052) · 지운번호 51개 기록(새 번호는 SD-000001 모양이라 옛 8자리와 안 겹침)
- 지우기 전 사본 tmp/마스터_집계표_초기화전_0930/(git 밖 · 156 파일 = 지우기 전과 같음)
- 시험 안 견본 fixtures/m02_master_sample(옛 집계표 · 장부 · 자재조합 · rv · c4 · pp_len · ms 세 파일 · 도면 줄임) + helper_m02_master_sample — 실제 마스터를 읽던 시험 일곱(table_fill · template_layers · structures_summary_snapshot · item_copy_complete · m02_tree · m02_item_inputs · spreadsheet_saved_values)을 견본으로 · M01 쓰는 곳 찾기(users_of) 시험은 이미 임시 표(combo_inputs)라 그대로
- 새 시험 test_m02_empty_master — 빈 마스터에서 항목 0 · 빈 나무 · 첫 화면 길 · 새 폴더 · 새 항목(SS000052 · SD-000001) · 지우기 · 고르기 모달 마스터 0 · 프로젝트 복사본 calc 그대로 · 원본없음

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

127 lines
6.4 KiB
Python

"""빈 마스터(PLAN 26-5a) — 마스터 구조물 항목을 다 지운 뒤에도 M02 가 돎 · 프로젝트 복사본은 그대로.
마스터 초기화와 같은 줄기(나무 지우기 `tree.apply` → 집계표 저장 `store.write`)를 시험 안 견본
사본(`fixtures/m02_master_sample`)에 돌림 — 실제 마스터는 안 읽음.
① 지운 뒤 — 항목 0 · 남는 열 no · sta · 비고 · 빈 나무 · 장부 `다음` 유지 · 지운 번호 기록 ·
M02 첫 화면 길 · 새 폴더 · 새 항목(다음 키) · 지우기 · 고르기 모달의 마스터 0.
② 프로젝트 복사본 — 마스터가 비어도 계산 그대로 · 목록은 원본없음.
"""
from __future__ import annotations
from pathlib import Path
from typing import Any
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from common_util.common_util_auth import verify_session
from config import config_system
from M02_MasterTemplete import M02_Item_Copy as copies
from M02_MasterTemplete import M02_MasterTemplete_Router as main_router
from M02_MasterTemplete import M02_MasterTemplete_Router_Items as items_router
from M02_MasterTemplete import M02_MasterTemplete_Router_Layers as layers_router
from M02_MasterTemplete import M02_MasterTemplete_Store as store
from M02_MasterTemplete import M02_MasterTemplete_Tree as tree
from M02_MasterTemplete import M02_Template_Layers as layers
from resources.tester.helper_m02_master_sample import copy_master_sample
from resources.tester.test_item_copy_complete import ( # noqa: F401 — 복사본 world 고정물
FOLDER,
_fill_values,
_pipe,
_save,
master_copy,
world,
)
def empty_master(folder: Path) -> list[str]:
"""마스터 초기화 — 맨 위 폴더마다 나무 지우기 · 지운 열 너비 뺌 · 집계표 저장 한 번(세 파일 ·
장부가 따라옴)."""
with store.at(folder):
got = store.read("table", store.STRUCTURE_TABLE)
doc = tree.normalize_table(got["문서"])
tops = {tree.path_of(c)[0] for c in doc["열"] if tree.is_item(c)}
gone: list[str] = []
for top in sorted(tops | {f[0] for f in tree.folders_of(doc)}):
doc, note = tree.apply(doc, {"op": "delete", "경로": [top]})
gone += note["지운항목"]
widths = doc.get("보기", {}).get("열너비") or {}
keep = {c["id"] for c in doc["열"]}
if widths:
doc["보기"]["열너비"] = {k: v for k, v in widths.items() if k in keep}
store.write("table", store.STRUCTURE_TABLE, got["판"], doc)
return gone
@pytest.fixture()
def empty(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> dict[str, Any]:
system = copy_master_sample(tmp_path / "master")
monkeypatch.setattr(store, "FOLDER", system)
monkeypatch.setattr(layers, "SYSTEM_ROOT", system)
monkeypatch.setattr(config_system, "STORAGE_BASE_DIR", str(tmp_path / "storage"))
gone = empty_master(system)
session = {"user_id": 42, "company_id": 7, "role": "SYSTEM_ADMIN", "is_master": True}
app = FastAPI()
for module in (main_router, items_router, layers_router):
app.include_router(module.router)
app.dependency_overrides[verify_session] = lambda: session
return {"client": TestClient(app), "system": system, "gone": gone}
def test_지운_뒤_항목_0_틀은_남음(empty):
system, client = empty["system"], empty["client"]
assert len(empty["gone"]) == 51
table = client.get("/api/m02/templates/table/구조물집계표").json()["문서"]
assert [c["id"] for c in table["열"]] == ["no", "sta", "memo"] and table["폴더"] == []
assert table["변수"] and table["쪽줄"] == 50 and table["합계줄"] and table["바인딩규칙"]
assert set(table["보기"]["열너비"]) <= {"no", "sta", "memo"}
combos = client.get("/api/m02/structure-combos").json()
assert combos["줄"] == [] and combos["다음"] == 52
assert len(combos["지운번호"]) == 4 # 견본에 세 파일이 있던 넷(rv · c4 · pp_len · ms)
for kind in ("structure", "area", "material", "inputs"):
assert not list((system / kind).glob("*.json")), kind
assert (system / "자재조합.json").is_file()
def test_빈_마스터에서_첫_화면_나무_새_항목_지우기(empty):
client = empty["client"]
# M02 첫 화면 길 — 양식 목록 · 집계표 · 번호 · 장부 · 나무 · 옵션
listed = client.get("/api/m02/layers/system/templates").json()["양식"]
assert "구조물집계표" in [r["이름"] for r in listed]
assert "구조물집계표" in [r["이름"] for r in client.get("/api/m02/templates").json()]
assert client.get("/api/m02/structures/numbers").json() == {}
assert client.get("/api/m02/structure-options").status_code == 200
assert client.get("/api/m02/items").json() == []
groups = client.get("/api/m02/items?all=1").json() # 고르기 모달 — 마스터 0
assert groups[0]["layer"] == "system" and groups[0]["items"] == []
url = "/api/m02/layers/system/tree"
now = client.get(url).json()
assert now["폴더"] == [] and now["items"] == []
now = client.post(url, json={"판": now["판"], "op": "add-folder", "경로": [], "이름": "옹벽"})
assert now.status_code == 200, now.text
now = now.json()
assert now["폴더"] == [["옹벽"]]
body = {"판": now["판"], "op": "add-item", "경로": ["옹벽"], "이름": "L형", "단위": "m"}
now = client.post(url, json=body).json()
[item] = now["items"]
assert item["key"] == "SS000052" and item["경로"] == ["옹벽", "L형"] # 지운 키 다시 안 씀
assert item["도번"] == "SD-000001" # 옛 8자리 지운 번호와 안 겹치는 새 모양
now = client.post(url, json={"판": now["판"], "op": "delete", "키": item["key"]}).json()
assert now["items"] == [] and now["폴더"] == [["옹벽"]]
now = client.post(url, json={"판": now["판"], "op": "delete", "경로": ["옹벽"]}).json()
assert now["폴더"] == [] and client.get("/api/m02/structure-combos").json()["다음"] == 53
def test_마스터를_비워도_프로젝트_복사본_계산_그대로(world): # noqa: F811 — 고정물
root, system = world["root"], world["system"]
_save(root, [_pipe()])
_fill_values(root)
before = copies.calc(root, FOLDER)
assert len(empty_master(system)) == 51
assert copies.calc(root, FOLDER) == before
row = copies.list_items(root)[0]
assert row["원본없음"] is True and row["마스터바뀜"] is False