import io import json import subprocess import zipfile from pathlib import Path import xml.etree.ElementTree as ET from test_est_rea_parity import run ROOT = Path(__file__).resolve().parents[2] def export_workbook(project): result = subprocess.run( [ "node", "-e", "const fs=require('fs');process.stdout.write(require('./tools/est-test/exchange.cjs').workbook(JSON.parse(fs.readFileSync(0,'utf8'))))", ], input=json.dumps(project, ensure_ascii=False).encode("utf-8"), capture_output=True, cwd=ROOT, check=True, ) return result.stdout def test_excel_is_valid_office_zip_with_numeric_text_types_and_no_executable_formulas(): data = export_workbook( { "name": "한글 공사", "tables": { "EstMainDat": [ { "PkID": 1, "Code": "001", "Name": '=HYPERLINK("bad")', "GN": 1.23456789, "TC": 99, "NewItem": False, "Editor": {"binary": "AAAA"}, } ], "CadMainDat": [{"Code": "excluded"}], }, } ) with zipfile.ZipFile(io.BytesIO(data)) as archive: assert archive.testzip() is None workbook = archive.read("xl/workbook.xml").decode("utf-8") assert "EstMainDat" in workbook and "CadMainDat" not in workbook root = ET.fromstring(archive.read("xl/worksheets/sheet2.xml")) ns = {"s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"} rows = root.findall(".//s:row", ns) assert "Editor" not in ET.tostring(rows[0], encoding="unicode") assert rows[1].find("s:c[@r='B2']", ns).get("t") == "inlineStr" assert rows[1].find("s:c[@r='D2']/s:v", ns).text == "1.23456789" assert root.findall(".//s:f", ns) == [] assert "=HYPERLINK" in ET.tostring(root, encoding="unicode") def test_print_settings_validation_blocks_css_injection_and_bad_pagination(): result = run( "math", """(()=>{ return [{paper:'A4;display:none'}, {rowsPerPage:0}, {rowsPerPage:1.5}, {font:100}, {margin:-1}, {orientation:'portrait',paper:'A4',rowsPerPage:20,font:9}].map(s=>{ const p=EstNative.empty();p.printSettings=s; try{EstModel.validate(p);return true}catch{return false} }); })()""", ) assert result == [False, False, False, False, False, True] def test_excel_price_edits_refresh_linked_values_and_keep_binary_fields(): result = run( "math", """(()=>{ const p=EstNative.empty();p.tables.StuffcDat=[{PkID:1,Code:'M',Name:'material',InputTC:100,ValueIndex:4,Editor:{binary:'AAAA'}}]; p.tables.EstMainDat=[{Code:'M',LinkIndex:5,GN:2},{LinkIndex:54}]; const q=EstNative.calculate(p),updated=EstExchange.apply(q,{StuffcDat:[{PkID:1,Code:'M',Name:'material',TC:150,InputTC:100,ValueIndex:4}]}); let rejected=false;try{EstExchange.apply(q,{StuffcDat:[{PkID:1,Code:'',TC:150}]})}catch{rejected=true} return {next:EstNative.calculate(updated),rejected}; })()""", ) assert result["rejected"] assert result["next"]["tables"]["EstMainDat"][-1]["TC"] == 300 assert result["next"]["tables"]["StuffcDat"][0]["Editor"]["binary"] == "AAAA"