Files
Aislo/resources/tester/test_722_ho_detail.py
T
eomsangdonandClaude Opus 5.5 2e7328d3a5 feat(794-1): M01 관리자 줄 식 시트 — 로직 상세 첫 보기 「시트」 · 식 칸 칠 때마다 검사 · 기존 [저장] 길
- 로직 상세 보기 첫 칸 「시트」(기본) — 이름 | 식 | 값 | 비목 · 근거 · 옵션(시험 값) · 변수 · 계산 · 자원 · 율 · 덧줄 · 단계 · 끝수 · 소계 · 합계 · 상태줄 지금 · 고치기 전
- 식 글 = 이름 꼴(M02 단가산출 시트와 같은 번역 · 새 서버 M01_MasterData_Sheet.py · POST /api/m01/logic/sheet · /logic/sheet/check · 저장 때와 같은 엔진 검사 · 쓰기 없음)
- 식 고침 = 시스템 관리자만 · 되는 식만 줄 사본에 · 캐시 → 기존 [저장](개정 확인 · 서버 검사 422) · [원래로]
- 식 칸 몸 = 공용 A00_Common/sheet_formula_cell.ts — M02 단가산출 시트도 같은 것을 씀(동작 그대로)
- 자체 로직(GX) 편집기 식 날 입력칸 → 읽기만(시트 식 칸으로 갈음)
- 시험: test_794_1_m01_sheet 새로 · test_790_1 식 칸 문구 자리를 공용 파일로 옮김(식 칸 몸이 공용으로 감) · test_717_2b · test_722 LogicLab.ts 줄 상한 627 → 637(시트 이음 10 줄 · 셈 · 고침은 시트 파일로 뺌 · 700 아래)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 18:45:48 +09:00

114 lines
5.1 KiB
Python

"""722 M01 단가산출 상세 개편 지킴 시험 — 글 · 순수 함수(화면 · 서버 없음).
- 722-1 공용 단가산출 상세(`M01_MasterData_UI_LogicLab_Ho.ts`) — 하위 박스(서버 묶음) · 장비 한 줄 + 펼침 · 계산식 열 · 박스 옵션
- 722-2 그 자리 고침(`M01_MasterData_UI_LogicLab_Cover.ts`) — M01 = 시험 값(줄 사본) · 정본 · 캐시 안 바뀜
"""
import json
import shutil
import subprocess
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
M01 = ROOT / "M01_MasterData"
HO = M01 / "M01_MasterData_UI_LogicLab_Ho.ts"
COVER = M01 / "M01_MasterData_UI_LogicLab_Cover.ts"
def _text(p: Path) -> str:
return p.read_text(encoding="utf-8")
def _pure(p: Path) -> str:
s = _text(p)
return s[s.index("/* ── 순수 셈 ── */") : s.index("/* ── 순수 셈 끝 ── */")]
def _node(code: str):
out = subprocess.run(
["node", "--experimental-strip-types", "--no-warnings",
"--input-type=module-typescript", "-e", code],
capture_output=True, text=True, encoding="utf-8", timeout=60,
) # fmt: skip
assert out.returncode == 0, out.stderr
return json.loads(out.stdout)
def test_상세가_공용_부품을_씀():
detail = _text(M01 / "M01_MasterData_UI_LogicLab_Detail.ts")
assert "buildHo({ ...ctx, edit: trialEdit(ctx) })" in detail
ho = _text(HO)
# 부품 상자만 — 표 · 카드 · 계산 줄 · 변수 칸(calc_sheet) · 입력 칩(텍스트 수식)
for part in (
"tableShell(",
"tableRow(",
"createCard(",
"varRow(",
"sheetFormula(",
):
assert part in ho, part
assert "inputChip(" not in ho # 748-3 줄마다 붙던 옵션 값 칩 걷음(위 옵션 칸이 대신)
for s in (ho, _text(COVER)):
assert 'el("table"' not in s and 'el("button"' not in s and 'el("input"' not in s
assert "document.createElement" not in s and "sessionStorage" not in s
assert "export function varRow(" in _text(ROOT / "A00_Common" / "calc_sheet.ts")
for p in (HO, COVER, M01 / "M01_MasterData_UI_LogicLab.ts"):
assert len(_text(p).splitlines()) <= (
637 if p.name == "M01_MasterData_UI_LogicLab.ts" else 700 # 794-1 시트 이음 10 줄
)
def test_시험_고침은_캐시_밖():
lab = _text(M01 / "M01_MasterData_UI_LogicLab.ts")
# 시험 계산에만 덮은 사본 · 고침이 있으면 줄을 보냄 · drafts(캐시)에는 원본 줄
assert ": trial.apply(row);" in lab
assert "dirty: () => current.id in drafts || trial.has(current.row)," in lab
assert "onTrial: drawCalc," in lab
cover = _text(COVER)
assert "drafts" not in cover and "touch" not in cover and "/save" not in cover
modal = _text(M01 / "M01_MasterData_UI_LogicLab_Modal.ts")
assert "...(target.edit ? [target.edit(close, head)] : [])" in modal
@pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음")
def test_박스_묶기():
body = """
const e = (idx, bundle, merge, amount) => ({ idx, bundle, merge, amount });
const got = boxesOf([
e(0, "인력", false, 10), e(1, "경비", true, 100), e(1, "경비", true, 20), e(1, "경비", true, 30),
e(2, "하위", true, 5), e(2, "하위", true, null), e(3, "재료", false, null),
], ["인력", "재료", "경비"]).map((b) => ({ 묶음: b.묶음, 소계: b.소계,
줄: b.줄.map((r) => "몫" in r ? [r.idx, r.금액, r.몫.length] : r.idx) }));
console.log(JSON.stringify(got));
"""
got = _node(_pure(HO) + "\n" + body)
assert [b["묶음"] for b in got] == ["인력", "재료", "경비", "하위"]
assert got[0] == {"묶음": "인력", "소계": 10, "줄": [0]}
assert got[1] == {"묶음": "재료", "소계": 0, "줄": [3]}
assert got[2] == {"묶음": "경비", "소계": 150, "줄": [[1, 150, 3]]} # 장비 한 줄 = 몫 셋 합
assert got[3]["줄"] == [[2, 5, 2]]
empty = _node(_pure(HO) + '\nconsole.log(JSON.stringify(boxesOf([], ["인력"])))')
assert empty == [{"묶음": "인력", "줄": [], "소계": 0}]
@pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음")
def test_고침_덮기():
body = """
const row = { 키: "GF1", 호표: [
{ 종류: "인력", 요소: "LB1", 수량: "찾기(Q).수량" },
{ 종류: "로직", 요소: "로직(GC1)", 수량: "1 / 작업량", 값묶음: { 경비: 3 } },
{ 종류: "재료", 요소: "MT1", 수량: "2" } ], 덧줄: [{ 이름: "공구", 식: "노무비 * 3 / 100" }] };
const out = applyCovers(row, { 0: { qty: 0.0000001, labor: 100000 }, 1: { labor: 50000 }, 9: { qty: 1 } });
console.log(JSON.stringify({ out, same: row.호표[0].수량, keep: out.호표[2] === row.호표[2] }));
"""
got = _node(_pure(COVER) + "\n" + body)
out = got["out"]
assert (
out["호표"][0]["수량"] == "0.0000001" and out["호표"][0]["단가"] == 100000
) # 지수 꼴 없음 · 손 단가
assert out["호표"][1]["값묶음"] == {"경비": 3, "노무비": 50000} and "단가" not in out["호표"][1]
assert got["keep"] and got["same"] == "찾기(Q).수량" # 원본 안 바뀜 · 안 고친 줄 그대로
assert out["덧줄"] == [{"이름": "공구", "식": "노무비 * 3 / 100"}]