Files
Aislo/resources/tester/test_est_docs.py
T
eomsangdonandClaude Opus 5.5 892285843d feat(est-test): 워드형 수량산출서 표 보존과 편집 도구
- 가져오기가 WPT 표를 버리던 결함 고침: 표 줄(칸·수량 표지·수식·세로병합) 보존, 문서 읽기 native-quantity-wpt.cjs 로 분리
- 표 셀 합·수량 지정·병합/분리·표 만들기·표 모양, 문단·그림·쪽 삽입/삭제·품명/규격 지정·공종명칭 입력·테두리선·산출근거 양식
- 수량 불러오기·수량목록보기·선택수량복사·내역서 수량붙여넣기(연결)
- ESTX 저장은 표 줄을 건너 문단만 맞춤, 표·서식 편집은 거부

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 18:35:50 +09:00

101 lines
4.3 KiB
Python

"""EST 테스트 앱 갑지·표지·설명서(원본 TFRMGABGI·TFRMCOVER·TFRMESTEDITOR, DatGabgi/DatCover.opt)."""
import json
import subprocess
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
SAMPLE = Path("C:/Dasansoft/Est Plus 2/Data/ProjectData/sample.estx")
FILES = [
"native-math.js",
"native-formula.js",
"native-machine.js",
"native-rows.js",
"native-text.js",
"native-quantity-wpt.cjs",
"native-quantity.cjs",
"native-wonga.js",
"native-engine.js",
"native-row-match.js",
"native-escalation.js",
"native-progress.js",
"native-business.js",
"native-review.js",
"native-resources.js",
"native-schedule.js",
"native-model.js",
"native-verify.js",
"native-docs.js",
]
def run_js(code: str):
runner = f"""
const fs = require('fs'), vm = require('vm');
const ctx = vm.createContext({{ structuredClone, console }});
for (const f of {json.dumps(FILES)})
vm.runInContext(fs.readFileSync('tools/est-test/' + f, 'utf8'), ctx, {{ filename: f }});
ctx.source = JSON.parse(fs.readFileSync('tools/est-test/sample.json', 'utf8'));
process.stdout.write(JSON.stringify(vm.runInContext({json.dumps(code)}, ctx)));
"""
return json.loads(subprocess.check_output(["node", "-e", runner], cwd=ROOT).decode("utf-8"))
def test_korean_amount_and_cost_lines():
result = run_js(
"""(() => ({
k: [EstDocs.korean(15000000), EstDocs.korean(10), EstDocs.korean(100000001), EstDocs.korean(79603000), EstDocs.korean(0)],
one: EstDocs.costLine('도급액', 15000000, 1), two: EstDocs.costLine('도급액', 15000000, 2),
text: (() => { const p = EstNative.calculate(EstModel.validate(structuredClone(source)));
const i = p.tables.Wonga.findIndex((r) => Number(r.LinkIndex) === 55); return EstDocs.costText(p, [i], 1); })(),
}))()"""
)
assert result["k"] == ["일천오백만", "일십", "일억일", "칠천구백육십만삼천", "영"]
assert result["one"] == "도급액 : 금 일천오백만원(₩15,000,000)"
assert result["two"] == "도급액 : 금15,000,000원(금일천오백만원)"
assert result["text"].endswith("원(₩79,603,000)")
def test_preview_html_and_model_accepts_docs():
result = run_js(
"""(() => {
const p = structuredClone(source);
p.docs = { gabgi: { Name: 'x', Position: '경기도', Gulga: ['과장', '계장'], Cost: '도급액 : 금 일원(₩1)', CompanyPos: 2 },
cover: { Name2: '부제', Date: '2026년도', CompanyName: '시청', CompanyPos: 0 }, explan: { text: '설명 본문' } };
const g = EstDocs.html(8, p), c = EstDocs.html(9, p), e = EstDocs.html(11, p), none = EstDocs.html(10, p);
EstModel.validate(p);
return { g: [g.includes('경기도'), g.includes('<th>과장</th>'), g.includes(p.name), g.includes('text-align:right')],
c: [c.includes('2026년도'), c.includes('부제'), c.includes('text-align:left')], e: e.includes('설명 본문'), none };
})()"""
)
assert result == {
"g": [True, True, True, True],
"c": [True, True, True],
"e": True,
"none": "",
}
def test_import_reads_documents_and_export_refuses_edits():
if not SAMPLE.exists():
pytest.skip("installed EST sample unavailable")
script = """
const fs = require('fs'), imp = require(process.cwd() + '/tools/est-test/import-estx.cjs');
const ex = require(process.cwd() + '/tools/est-test/export-estx.cjs');
const p = imp.importEstx(fs.readFileSync(process.argv[1]));
const same = Buffer.compare(ex.exportEstx(p), fs.readFileSync(process.argv[1])) === 0;
p.docs.gabgi.Position = '바뀐 위치';
let message = ''; try { ex.exportEstx(p); } catch (e) { message = e.message; }
process.stdout.write(JSON.stringify({ name: p.docs.gabgi.Name, gulga: p.docs.gabgi.Gulga, cover: p.docs.cover.Date, same, message }));
"""
result = json.loads(
subprocess.check_output(["node", "-e", script, str(SAMPLE)], cwd=ROOT).decode("utf-8")
)
assert result["name"] == "연습공사"
assert result["gulga"] == ["과 장", "계 장", "심사자", "설계자"]
assert result["cover"] == "2012년도"
assert result["same"] is True
assert result["message"].startswith("갑지·표지·설명서 편집은 ESTX")