"""일위대가 다이어그램 값 만들기(`Labor_Diagram.ts` 의 `buildLaborDiagram` · 39-3) — calc 줄 → 카드 출력. 화면 TS 를 그 자리에서 트랜스파일해 node 로 돌림 — 상대 경로 TS 는 이어 트랜스파일 · 화면 부품(@ui)은 빈 흉내 · 금액 모양(Logic_Money)도 빈 흉내(이 시험은 값 만들기만 봄). 견본 줄은 이 시험 안에 둠. """ import json import shutil import subprocess from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] SOURCE = ROOT / "M02_MasterTemplete" / "M02_MasterTemplete_Labor_Diagram.ts" RUNNER = r""" const fs = require("fs"); const path = require("path"); const [root, file] = process.argv.slice(1); const ts = require(path.join(root, "config", "node_modules", "typescript")); const stub = new Proxy({}, { get: (_t, k) => (k === "currentLanguageIndex" ? 0 : () => undefined) }); const cache = {}; function load(f) { if (cache[f]) return cache[f].exports; const js = ts.transpileModule(fs.readFileSync(f, "utf8"), { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 }, }).outputText; const box = (cache[f] = { exports: {} }); const req = (id) => { if (id.startsWith(".") && !id.includes("M01_MasterData")) { const p = path.resolve(path.dirname(f), id); return fs.existsSync(p + ".ts") ? load(p + ".ts") : stub; } return stub; }; new Function("exports", "module", "require", js)(box.exports, box, req); return box.exports; } const m = load(file); const jobs = JSON.parse(fs.readFileSync(0, "utf8")); process.stdout.write(JSON.stringify(jobs.map((j) => m.buildLaborDiagram(j)))); """ def run(jobs: list[dict]) -> list: if shutil.which("node") is None: pytest.skip("node 가 없음") done = subprocess.run( ["node", "-e", RUNNER, str(ROOT), str(SOURCE)], input=json.dumps(jobs, ensure_ascii=False), capture_output=True, text=True, encoding="utf-8", check=True, ) return json.loads(done.stdout) LOGICS = [ { "로직": "GC000001", "이름": "돌쌓기", "결과단위": "원/㎡", "입력": [{"이름": "높이", "단위": "m"}, {"이름": "지역", "자동값": "서울"}], }, {"로직": "GF000002", "이름": "작업량", "결과단위": "㎥/시간", "입력": [{"이름": "지역"}]}, {"로직": "GC000003", "이름": "막힌 로직", "결과단위": "원/m", "입력": []}, ] ROWS = [ {"로직": "GC000001", "입력값": {"높이": 4}}, {"로직": "GF000002", "입력값": {"지역": "부산"}}, {"로직": "GC000003", "입력값": {}}, ] MONEY = {"노무비": 100, "재료비": 50, "경비": 0, "계": 150} APPLIED = {"노무비": 300, "재료비": 150, "경비": 0, "계": 450} def _line(key: str, **more) -> dict: return {"로직": key, "기준": None, "반영": None, "까닭": None, **more} def test_돈_값_멈춤_세_갈래_반영이_있으면_반영(): calc = { "줄": [ _line("GC000001", 기준=MONEY, 반영=APPLIED), _line("GF000002", 결과=8.946), _line("GC000003", 까닭="표에 맞는 줄이 없음"), ], "자재": [], } (got,) = run([{"rows": ROWS, "logics": LOGICS, "calc": calc, "mats": 0}]) outs = [x["out"] for x in got["logics"]] assert outs[0] == APPLIED and got["logics"][0]["basis"] == "반영" assert outs[1] == {"값": 8.946} assert outs[2] == {"멈춤": "표에 맞는 줄이 없음"} def test_수량_없으면_기준(): calc = {"줄": [_line("GC000001", 기준=MONEY)], "자재": []} (got,) = run([{"rows": ROWS[:1], "logics": LOGICS, "calc": calc, "mats": 0}]) assert got["logics"][0]["out"] == MONEY and got["logics"][0]["basis"] == "기준" def test_넣은_값은_로직별_빈_값은_자동값_또는_빈_글(): (got,) = run([{"rows": ROWS, "logics": LOGICS, "calc": None, "mats": 0}]) first, second, third = got["logics"] assert [(i["name"], i["value"]) for i in first["inputs"]] == [("높이", "4"), ("지역", "서울")] assert first["inputs"][1].get("auto") is True and "auto" not in first["inputs"][0] assert first["inputs"][0]["unit"] == "m" assert [(i["name"], i["value"]) for i in second["inputs"]] == [("지역", "부산")] assert third["inputs"] == [] def test_아직_안_셌으면_출력_없음(): (got,) = run([{"rows": ROWS, "logics": LOGICS, "calc": None, "mats": 0}]) assert [x["out"] for x in got["logics"]] == [None, None, None] assert [x["key"] for x in got["logics"]] == ["GC000001", "GF000002", "GC000003"] def test_자재목록은_카드_하나_재료비로(): calc = { "줄": [_line("GC000001", 기준=MONEY)], "자재": [{"기준단가": 1000, "반영": 5000}, {"기준단가": 200, "반영": None}], } (got,) = run([{"rows": ROWS[:1], "logics": LOGICS, "calc": calc, "mats": 2}]) card = got["logics"][-1] assert card["material"] is True and card["inputs"] == [] assert card["out"] == {"노무비": 0, "재료비": 5200, "경비": 0, "계": 5200} assert card["basis"] == "기준" # 반영 없는 자재가 있음 (none,) = run([{"rows": ROWS[:1], "logics": LOGICS, "calc": calc, "mats": 0}]) assert not any(x.get("material") for x in none["logics"])