"""EST 테스트 앱 품명정리와 자재·견적단가 등록(원본 TfrmNameDevide·popMainStuffcReg·popMainEstimateReg).""" import json import subprocess from pathlib import Path ROOT = Path(__file__).resolve().parents[2] 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-name-reg.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_divide_splits_at_position_and_syncs_title(): result = run_js( """(() => { const p = { tables: { HeadMainDat: [{ Index: 1, Code: 'U1', Name: '거푸집 설치 합판', Size: '3회', Unite: '' }, { Code: 'L1', LinkIndex: 6 }, { Index: 2, Code: 'U2', Name: '거푸집 해체 강재', Size: '', Unite: '㎡' }], HeadTitleDat: [{ Code: 'U1', Name: '거푸집 설치 합판' }, { Code: 'U2', Name: '거푸집 해체 강재' }] } }; const n = EstNameReg.divide(p, [0, 1, 2], 4, 0, '㎡'); const c = { tables: { HeadMainDat: [{ Index: 1, Code: 'X', Name: 'AB-CD', Size: '' }] } }; EstNameReg.divide(c, [0], 2, 1, ''); let bad = ''; try { EstNameReg.divide(p, [1], 4, 0, ''); } catch (e) { bad = e.message.slice(0, 6); } const r = p.tables.HeadMainDat; return { n, a: [r[0].Name, r[0].Size, r[0].Unite], b: [r[2].Name, r[2].Size, r[2].Unite], title: p.tables.HeadTitleDat[0].Size, bad, cut: c.tables.HeadMainDat[0].Size }; })()""" ) assert result["n"] == 2 assert result["a"] == ["거푸집 ", "설치 합판3회", "㎡"] assert result["b"] == ["거푸집 ", "해체 강재", "㎡"] assert result["title"] == "설치 합판3회" assert result["bad"] == "품명을 정리" assert result["cut"] == "CD" def test_register_stuff_and_estimate_link_row_and_keep_price(): result = run_js( r"""(() => { const calc = (x) => EstNative.calculate(EstModel.validate(x)); const p = calc(structuredClone(source)); const i = p.tables.EstMainDat.findIndex((r) => Number(r.GU) > 0 && !Number(r.Level) && Number(r.LinkIndex) === 5); p.tables.EstMainDat[i].Name = '시험 자재 등록품'; const before = p.tables.EstMainDat[i].TC; const code = EstNameReg.register(p, 'EstMainDat', i, 'stuff'); const rec = p.tables.StuffcDat.find((r) => r.Code === code); const j = p.tables.EstMainDat.findIndex((r, k) => k !== i && Number(r.JU) + Number(r.NU) > 0 && !Number(r.Level) && r.Name); p.tables.EstMainDat[j].Name = '시험 견적 등록품'; const w = EstNameReg.register(p, 'EstMainDat', j, 'estimate'); const est = p.tables.EstiMateDat.find((r) => r.Code === w); const after = calc(p); const errors = []; for (const fn of [() => EstNameReg.register(p, 'EstMainDat', i, 'stuff'), () => EstNameReg.register(p, 'HeadMainDat', p.tables.HeadMainDat.findIndex((r) => Number(r.Index) > 0), 'stuff')]) try { fn(); } catch (e) { errors.push(e.message.slice(0, 6)); } return { code: /^M\d{10}$/.test(code), price: rec.Cost1 === Number(p.tables.EstMainDat[i].GU) && rec.TC === rec.Cost1, link: [p.tables.EstMainDat[i].LinkIndex, p.tables.EstMainDat[i].Code === code], same: after.tables.EstMainDat[i].TC === before, w: /^W\d{10}$/.test(w), est: est.TC === est.NC + est.GC + est.JC && est.ONC === est.NC, estLink: p.tables.EstMainDat[j].LinkIndex, errors, calcErrors: after.calculation.errors.length }; })()""" ) assert result == { "code": True, "price": True, "link": [5, True], "same": True, "w": True, "est": True, "estLink": 101, "errors": ["같은 명칭의", "호표는 자재"], "calcErrors": 0, }