import json import subprocess from pathlib import Path import pytest from test_est_native_export import ROOT HELPER = r"""const fs=require('fs'),path=require('path'),vm=require('vm'); const base=path.resolve('tools/est-test'),m=require(path.join(base,'import-estx.cjs')), e=require(path.join(base,'export-estx.cjs')),context=vm.createContext({structuredClone,console,Blob}); for(const name of ['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']) vm.runInContext(fs.readFileSync(path.join(base,name),'utf8'),context,{filename:name}); const bytes=fs.readFileSync(process.argv[1]),p=m.importEstx(bytes); if(process.argv[2]==='exclude-fee')p.options.GangubExceptJodalRatio=true; p.annual=[{name:'1차',formula:'[기준]*0.5'}];context.p=p; const q=vm.runInContext('EstBusiness.annualCopy(p,0)',context); """ def run_sample(path, script, *args): if not path.exists(): pytest.skip("EST 원본 시험 파일 없음") return json.loads( subprocess.check_output(["node", "-e", HELPER + script, str(path), *args], cwd=ROOT) ) def test_annual_copy_exports_and_reopens_native_without_index_changes(): path = next( iter( (ROOT / "resources/knowledge/original/경쟁사 프로그램/EST Plus 2/example").glob( "01*.estx" ) ), Path("missing.estx"), ) result = run_sample( path, r"""const out=e.exportEstx(q),back=m.importEstx(out);context.back=back; const recalculated=vm.runInContext('EstNative.calculate(back)',context); const old=m.unzip(bytes),updated=m.unzip(out); const fields=['GN','NC','GC','JC','SC','TC']; const equal=q.tables.EstMainDat.length===recalculated.tables.EstMainDat.length&& q.tables.EstMainDat.every((r,i)=>fields.every(k=>(r[k]||0)===(recalculated.tables.EstMainDat[i][k]||0))); const indexes=[...old].filter(([k])=>k.endsWith('.idx')).every(([k,v])=>v.equals(updated.get(k))); const costs=q.tables.Wonga.map(r=>r.Cost),costsBack=recalculated.tables.Wonga.map(r=>r.Cost); process.stdout.write(JSON.stringify({equal,indexes,costs,costsBack,errors:recalculated.calculation.errors}));""", ) assert result["equal"] and result["indexes"] assert result["costs"] == result["costsBack"] assert not result["errors"] def test_annual_procurement_previous_link_survives_native_export(): path = Path("C:/Dasansoft/Est Plus 2/Data/ProjectData/sample.estx") result = run_sample( path, r"""const out=e.exportEstx(q),back=m.importEstx(out);context.back=back; const after=vm.runInContext('EstNative.calculate(back)',context); const old=m.unzip(bytes),updated=m.unzip(out); process.stdout.write(JSON.stringify({before:q.tables.Wonga.map(r=>r.Cost), after:after.tables.Wonga.map(r=>r.Cost),errors:after.calculation.errors, fee:after.tables.EstMainDat.filter(r=>r.LinkIndex===99&&r.LinkIndex_===57).length, indexes:[...old].filter(([k])=>k.endsWith('.idx')).every(([k,v])=>v.equals(updated.get(k)))}));""", "exclude-fee", ) assert result["fee"] > 0 assert result["before"] == result["after"] assert result["indexes"] and not result["errors"] def test_annual_procurement_without_previous_link_cannot_be_silently_lost(): path = Path("C:/Dasansoft/Est Plus 2/Data/ProjectData/sample.estx") result = run_sample( path, r"""q.tables.EstMainDat.find(r=>r.AnnualSourceLink===57).LinkIndex_=null; let message='';try{e.exportEstx(q)}catch(error){message=error.message} process.stdout.write(JSON.stringify({fee:q.tables.EstMainDat.filter(r=>r.AnnualSourceLink===57).length,message}));""", "exclude-fee", ) assert result["fee"] > 0 assert "관급 수수료" in result["message"]