Files
Aislo/resources/tester/test_m02_empty_master.py
T
eomsangdonandClaude Opus 5.5 c704f18982 refactor(M02): 선택 입력 지움(39-7b G3) — 카드 · 자리 고르기 · inputs/ 연결 · 입력 목록 · 연결 · 알약 길 · 프로젝트 복사본 「입력연결」 · 시스템 층 inputs · 시험
- 넣을 값 카드(M02_Labor_Values)는 담은 로직 입력 전부를 보임(자리 「선택」 감싸기 없앰) · 이름 「넣을 값」
- 고르기 모달 면적산출 알약 = 복사본 일위대가 알약(가져온 때 그대로)
- 입력값.json · 고른자재.json · /calc 는 그대로 · storage 층 inputs/ 파일은 안 건드림(읽기만 끊음)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NPJGtfXo6GMbcpiboQC4uK
2026-10-04 19:36:46 +09:00

126 lines
6.3 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"):
assert not list((system / kind).glob("*.json")), kind
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