- 마스터 층 구조물 항목 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
127 lines
6.4 KiB
Python
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
|