"""조합 갈라 내기 은퇴 · 분류 더하기 복사 (PLAN 15장 · 39-1d). M02 견본 표(`write_sample_table`) + M01 마스터 사본(조합 줄은 비워 시작)으로만 봄. · 갈라 내기 · 키 적기 길은 은퇴(39-1d) — 404 · 분류 더하기로 복사한 열(`본뜬열`) — [저장] 때 원본 키 · 세 파일 내용을 새 번호로 받음 """ import json import shutil import pytest from fastapi import FastAPI from fastapi.testclient import TestClient from M01_MasterData import M01_MasterData_Store as m01 from M01_MasterData import M01_MasterData_Store_Combo as combo_store from M02_MasterTemplete import M02_MasterTemplete_Store as store from M02_MasterTemplete.M02_MasterTemplete_Router import router from resources.tester.test_m02_structure import write_sample_table REAL = m01.FOLDER A, B, C = "GF000219", "GF000220", "GF000211" # 돌쌓기 메쌓기(인력 · 장비) · 채집(인력) TABLE = "/api/m02/templates/table/구조물집계표" @pytest.fixture() def client(tmp_path, monkeypatch): master = tmp_path / "master" master.mkdir() for path in REAL.glob("*.json"): if not path.name.startswith("_") or path.name == m01.mk.BOOK.name: shutil.copy(path, master / path.name) own = master / combo_store.FILE data = json.loads(own.read_text(encoding="utf-8")) data["줄"] = [] data.pop("폴더", None) # 정본 머리의 빈 폴더 목록은 안 물려받음 own.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8") monkeypatch.setattr(m01, "FOLDER", master) template = tmp_path / "template" template.mkdir() write_sample_table(template) monkeypatch.setattr(store, "FOLDER", template) app = FastAPI() app.include_router(router) return TestClient(app) def _source(client) -> str: """원래 조합(A · B) — rv · c1 두 열이 같이 가리킴.""" got = combo_store.combo_new( { "이름": "기슭막이", "구분": "실무 일위대가", "상세구분": "13장 구조물", "단위": "m", "담은로직": [{"로직": A, "메모": None}, {"로직": B, "메모": None}], "출처": "자체", }, "현장", ) table = client.get(TABLE).json() for col in table["문서"]["열"]: if col["id"] in ("rv", "c1"): col["일위대가"] = got["key"] assert client.put(TABLE, json={"판": table["판"], "문서": table["문서"]}).status_code == 200 return got["key"] def test_갈라_내기_키_적기_길은_은퇴(client): """39-1d — 일위대가 정본 = 열마다 labor 문서 · 갈라 내기 · 키 적기 길 없음.""" ua = _source(client) body = {"본뜬키": ua, "담은로직": [{"로직": A}], "이름": "", "판": ""} assert client.post("/api/m02/structures/rv/combo", json=body).status_code == 404 use = {"종류": "일위대가", "키": ua, "판": ""} assert client.post("/api/m02/structures/c1/use-combo", json=use).status_code == 404 def test_분류_더하기로_복사한_열은_원본_키_세_파일_내용을_받음(client): _source(client) drawing = client.get("/api/m02/templates/structure/rv").json() marked = {**drawing["문서"], "도면": {"format": 6, "entities": [{"type": "line"}]}} put = client.put("/api/m02/templates/structure/rv", json={"판": drawing["판"], "문서": marked}) assert put.status_code == 200 table = client.get(TABLE).json() doc = table["문서"] at = next(i for i, c in enumerate(doc["열"]) if c["id"] == "rv") head = ["돌기슭막이", "(형태마다)", "H=(높이마다) 2", None] doc["열"].insert(at + 1, {"id": "c9", "머리": head, "단위": None, "꼴": "수", "본뜬열": "rv"}) assert client.put(TABLE, json={"판": table["판"], "문서": doc}).status_code == 200 saved = next(c for c in client.get(TABLE).json()["문서"]["열"] if c["id"] == "c9") assert "본뜬열" not in saved # 뗌 assert not saved.get("일위대가") # 열 키는 안 받음 — 일위대가는 labor 문서로 복사(39-1b) copy = client.get("/api/m02/templates/structure/c9").json()["문서"] assert copy["도면"]["entities"] == [{"type": "line"}] and copy["열"] == "c9" numbers = client.get("/api/m02/structures/numbers").json() assert numbers["c9"]["도번"] != numbers["rv"]["도번"] # 새 번호 assert numbers["c9"]["면적번"][2:] == numbers["c9"]["도번"][2:] for kind in ("area",): assert client.get(f"/api/m02/templates/{kind}/c9").json()["문서"]["열"] == "c9" # 그 뒤로는 열마다 따로 — 원본을 고쳐도 복사본은 그대로 drawing = client.get("/api/m02/templates/structure/rv").json() client.put( "/api/m02/templates/structure/rv", json={ "판": drawing["판"], "문서": {**drawing["문서"], "도면": marked["도면"] | {"entities": []}}, }, ) again = client.get("/api/m02/templates/structure/c9").json()["문서"] assert again["도면"]["entities"] == [{"type": "line"}]