Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D2nUMUMTsqm93PbQtipo6c
111 lines
3.9 KiB
Python
111 lines
3.9 KiB
Python
"""일위대가 조합 다이어그램 값 만들기(`M02_MasterTemplete_Labor_Diagram.ts` 의 `buildDiagramData`) — 미리 보기 줄 → 로직 카드 출력.
|
|
|
|
화면 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.buildDiagramData(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)
|
|
|
|
|
|
ROWS = [
|
|
{
|
|
"key": "GC000001",
|
|
"name": "돌쌓기",
|
|
"unit": "원/㎡",
|
|
"inputs": [{"name": "높이", "unit": "m"}, {"name": "지역", "unit": ""}],
|
|
},
|
|
{
|
|
"key": "GF000002",
|
|
"name": "작업량",
|
|
"unit": "㎥/시간",
|
|
"inputs": [{"name": "지역", "unit": ""}],
|
|
},
|
|
{"key": "GC000003", "name": "막힌 로직", "unit": "원/m", "inputs": []},
|
|
]
|
|
|
|
|
|
def test_돈_값_멈춤_세_갈래():
|
|
lines = [
|
|
{"ok": True, "갈래": "돈", "노무비": 100, "재료비": 50, "경비": 0, "계": 150},
|
|
{"ok": True, "갈래": "결과", "결과": 8.946},
|
|
{"ok": False, "까닭": "표에 맞는 줄이 없음"},
|
|
]
|
|
(got,) = run([{"rows": ROWS, "values": {"GC000001": {"높이": "4"}}, "lines": lines}])
|
|
outs = [x["out"] for x in got["logics"]]
|
|
assert outs[0] == {"노무비": 100, "재료비": 50, "경비": 0, "계": 150}
|
|
assert outs[1] == {"값": 8.946}
|
|
assert outs[2] == {"멈춤": "표에 맞는 줄이 없음"}
|
|
|
|
|
|
def test_넣은_값은_로직별_빈_값은_빈_글():
|
|
(got,) = run(
|
|
[
|
|
{
|
|
"rows": ROWS,
|
|
"values": {"GC000001": {"높이": "4"}, "GF000002": {"지역": "서울"}},
|
|
"lines": None,
|
|
}
|
|
]
|
|
)
|
|
first, second, third = got["logics"]
|
|
assert [(i["name"], i["value"]) for i in first["inputs"]] == [("높이", "4"), ("지역", "")]
|
|
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, "values": {}, "lines": None}])
|
|
assert [x["out"] for x in got["logics"]] == [None, None, None]
|
|
assert [x["key"] for x in got["logics"]] == ["GC000001", "GF000002", "GC000003"]
|