- 셈 구동 떼기: 새 M01_MasterData_UI_Logic_Drive.ts(driveRun · previewText · autoFill · createDrive) — M01 상세는 숨은 시험 계산 칸 단추 대신 구동 함수 · 시험 계산 칸(Logic_Calc)은 로직 복사 화면이 쓰므로 남기고 같은 구동을 부름 · 재료 고름은 rerun 고리 - M02: 새 _Sangeun_Tabs.ts(수식 · 단가산출 상세 보기 고르기) · Detail 의 시험 계산 · 인력/재료/경비 걷음 - 걷은 파일(git rm): M01 LogicLab_Sheet · Logic_Sheet_Model · LogicLab_Formula(.ts .css) · FormulaTokens · LogicLab_Est / M02 Sangeun_Sheet(.ts .css) · SheetEdit · SheetFormula · logic Sheet_Model · Const_Model · Formula_Model · 부품 시트 줄(createCalcSheetRow) · Cover_Model.sheetGroups · Calc 의 M02 고리(answer · shown · held) · 죽은 CSS · 글 - 서버 길 · 문서 칸(변수줄 · 글줄 · 덮개)은 남김 — 금액 그대로 - 낡은 시험: test_790_1(시트 화면 전부) · test_714_3 · test_748_2(+ helper)는 화면이 없어져 지움 · test_794_1 · test_790_2 는 화면 · TS 거울만 덜고 서버 시험 남김 · test_714_2 · 717_2b · 721 · 722(원래 틀린 한 줄 고침) · 734 · 737 · 750_2 · 793_3b · 796_2 · 796_2b 는 보기 둘 · 새 파일에 맞춤 · 새 test_799_2_old_tabs_gone Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
114 lines
5.2 KiB
Python
114 lines
5.2 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 and "rerun: () => void drive.run()," in lab # 799-2 셈 구동
|
|
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"}]
|