"""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.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('과장'), 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")