diff --git a/resources/tester/helper_est_native.cjs b/resources/tester/helper_est_native.cjs index 23ea0e740..b0a2350e5 100644 --- a/resources/tester/helper_est_native.cjs +++ b/resources/tester/helper_est_native.cjs @@ -64,7 +64,16 @@ else if (command === "repeat") ); else if (command === "import") result = require(path.join(base, "import-estx.cjs")).importEstx(fs.readFileSync(process.argv[3])); -else if (command === "blob-tail") { +else if (command === "baseline-size") { + context.input = require(path.join(base, "import-estx.cjs")).importEstx( + fs.readFileSync(process.argv[3]), + ); + const baseline = vm.runInContext("EstBusiness.baseline(input)", context); + result = { + bytes: Buffer.byteLength(JSON.stringify(baseline), "utf8"), + archivePreserved: baseline.originalArchive === context.input.originalArchive, + }; +} else if (command === "blob-tail") { const { blob } = require(path.join(base, "import-estx.cjs")), bytes = Buffer.alloc(1536); bytes.writeUInt32LE(2, 516); diff --git a/resources/tester/test_est_business.py b/resources/tester/test_est_business.py index 92211aead..4b8b3fc7a 100644 --- a/resources/tester/test_est_business.py +++ b/resources/tester/test_est_business.py @@ -208,3 +208,40 @@ def test_original_numeric_fields_reject_invalid_saved_values(): })()""", ) assert "GN_" in result + + +def test_baseline_keeps_current_inputs_once_and_preserves_working_binaries(): + result = run( + "math", + """(()=>{ + const p=EstNative.empty(); + p.tables.CostMainDat=[{Index:1,Code:'C',LineData:'current',LineData_:'previous'}]; + p.tables.CadMainDat=[{Code:'D',Data:{binary:'QUJD'}}]; + p.tables.StuffcDat=[{Code:'M',InputTC:100}];p.originalArchive='original bytes'; + const q=EstBusiness.baseline(p),again=EstBusiness.baseline(q); + return {p,q,again}; + })()""", + ) + for item in [result["q"], result["again"]]: + assert item["originalArchive"] == "original bytes" + assert item["tables"]["CadMainDat"][0]["Data"]["binary"] == "QUJD" + assert "CadMainDat" not in item["baseline"]["tables"] + assert "StuffcDat" not in item["baseline"]["tables"] + assert item["baseline"]["tables"]["CostMainDat"][0]["LineData"] == "current" + assert "LineData_" not in item["baseline"]["tables"]["CostMainDat"][0] + assert result["p"]["tables"]["CostMainDat"][0]["LineData_"] == "previous" + + +def test_large_original_baseline_stays_within_the_save_request_limit(): + import os + from pathlib import Path + import pytest + + archive = Path( + os.environ.get("EST_REA_MAIN", "C:/Dasansoft/Est Plus 2/Data/ProjectData/main.estx") + ) + if not archive.is_file(): + pytest.skip("Original main.estx is not installed") + result = run("baseline-size", str(archive)) + assert result["archivePreserved"] + assert result["bytes"] < 256 * 1024 * 1024 diff --git a/tools/est-test/README.md b/tools/est-test/README.md index c47499ae0..df7b3fbbd 100644 --- a/tools/est-test/README.md +++ b/tools/est-test/README.md @@ -10,6 +10,8 @@ Ctrl+S는 입력 중인 셀도 확정한 뒤 저장합니다. 연속 저장 요청은 순서대로 처리하며, 저장 대기 중의 추가 입력이나 새로 연 문서를 이전 저장 응답으로 덮어쓰지 않습니다. 실행 취소는 현재 작업 파일의 연결을 유지합니다. +당초 확정 사본에는 재계산 입력을 한 번만 보관하며, 작업본의 도면·원본 압축 자료는 보존합니다. 설치된 `main.estx`의 당초 확정 후 실제 저장 API를 통과했고, 산근 77,395행과 원본 압축 해시 보존·계산 오류 0을 확인했습니다(요청 약 215MB, 저장 약 221MB). + 초기 자료는 기술정보 DB의 실제 REA 저장 샘플입니다. `REA 샘플 대조`에서 원본 저장값과 275개 계산 결과를 비교합니다. 테스트용 임의 요율을 원본 기본값으로 넣지 않습니다. 새 원가 서식의 요율은 사용자가 입력합니다. ## 검증과 남은 범위 diff --git a/tools/est-test/native-business.js b/tools/est-test/native-business.js index cec72656b..aa743b86c 100644 --- a/tools/est-test/native-business.js +++ b/tools/est-test/native-business.js @@ -5,8 +5,29 @@ const EstBusiness = (() => { const rowKey = (row, index) => String(row.PkID ?? row.Code ?? index); const special = (row) => [57, 58, 62, 67].includes(num(row.LinkIndex)); function baseline(project) { - const next = copy(project); - next.baseline = { tables: copy(project.tables), name: project.name }; + const working = { ...project }; + delete working.baseline; + const next = copy(working); + // Original recalculation replaces source catalogs from the working project. + // Keep its contract inputs once; drawings and pre-existing '_' copies stay in the working file. + const tables = {}; + for (const table of [ + "EstMainDat", + "HeadMainDat", + "HeadTitleDat", + "CostMainDat", + "CostTitleDat", + "MachTitleDat", + "Wonga", + ]) { + tables[table] = (project.tables[table] || []).map((row) => { + const values = Object.fromEntries( + Object.entries(row).filter(([key]) => !key.endsWith("_")), + ); + return copy(values); + }); + } + next.baseline = { tables, name: project.name }; for (const rows of Object.values(next.baseline.tables)) for (const row of rows) row.NewItem = false; for (const rows of Object.values(next.tables))