Files
Aislo/resources/tester/test_est_cleanup.py
T
eomsangdonandClaude Opus 5.5 27869d7b81 feat(est-test): 무관자료 삭제와 내역서순 정리
- 원본 처리 근거대로 내역서가 쓰는 자료만 하위까지 따라가 남기고 나머지 삭제
- 내역서 첫 등장 순서 재배열, 묶음 앞 빈 줄 정리, 미연결 수량산출서 삭제

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 19:32:05 +09:00

103 lines
4.3 KiB
Python

"""EST 테스트 앱 무관자료 삭제(원본 mnuNotLinkDelete·DelSort·MulDelete)."""
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-cleanup.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_unused_rows_removed_and_totals_unchanged():
result = run_js(
"""(() => {
const calc = (p) => EstNative.calculate(EstModel.validate(p));
const p = calc(structuredClone(source));
p.tables.StuffcDat.push({ Code: 'MZZZ', Name: '안 쓰는 자재', Index: 999, Cost1: 1, ValueIndex: 0 });
p.tables.HeadMainDat.push({ Index: 900, Code: 'UZZZ', Name: '안 쓰는 일위', TitleCode: 'UZZZ' },
{ Code: 'MZZZ', LinkIndex: 5, GN: 1 });
const before = calc(p), total = before.calculation.total, direct = before.calculation.direct.TC;
const counts = Object.fromEntries(['StuffcDat','LaborcDat','HeadMainDat','CostMainDat','MachMainDat'].map((t) => [t, p.tables[t].length]));
const removed = EstCleanup.clean(p, false);
const after = calc(p);
return { total: after.calculation.total === total, direct: after.calculation.direct.TC === direct,
errors: after.calculation.errors.length,
gone: !p.tables.StuffcDat.some((r) => r.Code === 'MZZZ') && !EstNative.groups(p.tables.HeadMainDat).has('UZZZ'),
removedStuff: removed.StuffcDat >= 1, removedHead: removed.HeadMainDat >= 1,
estimate: p.tables.EstMainDat.length === before.tables.EstMainDat.length };
})()"""
)
assert result == {
"total": True,
"direct": True,
"errors": 0,
"gone": True,
"removedStuff": True,
"removedHead": True,
"estimate": True,
}
def test_sorted_mode_follows_first_use_and_keeps_codes():
result = run_js(
"""(() => {
const calc = (p) => EstNative.calculate(EstModel.validate(p));
const p = calc(structuredClone(source));
const order = EstCleanup.used(p);
const total = p.calculation.total;
const codes = new Set(p.tables.HeadTitleDat.map((r) => r.Code));
EstCleanup.clean(p, true);
const after = calc(p);
return { heads: [...EstNative.groups(p.tables.HeadMainDat).keys()].join() === order.get('HeadMainDat').join(),
stuff: p.tables.StuffcDat.map((r) => r.Code).join() === order.get('StuffcDat').join(),
codes: p.tables.HeadTitleDat.every((r) => codes.has(r.Code)),
total: after.calculation.total === total, errors: after.calculation.errors.length };
})()"""
)
assert result == {"heads": True, "stuff": True, "codes": True, "total": True, "errors": 0}
def test_blank_rows_before_heads_and_quantity_sheets():
result = run_js(
"""(() => {
const rows = [{ Index: 1, Code: 'A' }, { Name: 'x', GN: 1 }, {}, {}, { Index: 2, Code: 'B' }, {}];
const trimmed = EstCleanup.trimBeforeHeads(rows, 'HeadMainDat').map((r) => r.Code || r.Name || '-');
const p = { tables: { EstMainDat: [{ PkID: 7, Code: 'D1' }] }, quantitySheets: [
{ Code: 'Q1', items: [{ TargetKey: 'id:7' }] }, { Code: 'Q2', items: [{ TargetCode: 'NONE' }] }, { Code: 'Q3', items: [] }] };
const gone = EstCleanup.cleanQuantity(p);
return { trimmed, gone, left: p.quantitySheets.map((s) => s.Code) };
})()"""
)
assert result == {"trimmed": ["A", "x", "B", "-"], "gone": 2, "left": ["Q1"]}