- 원본처럼 이름·항목 명칭·규격에서 빈칸·|·괄호를 빼고 찾아 목록을 좁힘 - 고르기 줄을 산출서 모듈로 옮겨 700줄 제한 유지 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
157 lines
6.7 KiB
Python
157 lines
6.7 KiB
Python
"""EST 테스트 앱 수량산출서 복사·순서 이동과 ESTX 저장 거부."""
|
||
|
||
import json
|
||
import subprocess
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
MAIN = Path("C:/Dasansoft/Est Plus 2/Data/ProjectData/main.estx")
|
||
LOAD = """
|
||
const fs = require('fs'), vm = require('vm');
|
||
const ctx = vm.createContext({ structuredClone, console });
|
||
vm.runInContext(fs.readFileSync('tools/est-test/native-quantity-sheets.js', 'utf8'), ctx);
|
||
const run = (code) => vm.runInContext(code, ctx);
|
||
"""
|
||
|
||
|
||
def node(script: str, *args: str):
|
||
out = subprocess.check_output(["node", "-e", LOAD + script, *args], cwd=ROOT)
|
||
return json.loads(out.decode("utf-8"))
|
||
|
||
|
||
def test_copy_inserts_below_with_new_code_and_cleared_links():
|
||
result = node("""
|
||
ctx.project = { quantitySheets: [
|
||
{ Code: 'A', Name: '토공', items: [{ Code: 'r000000', TargetCode: 'D1', TargetKey: 'id:3', LinkCode: 'D1' }], rows: [{ LineData: 'x', markers: ['r000000'] }] },
|
||
{ Code: 'B', Name: '포장', items: [], rows: [] },
|
||
] };
|
||
const first = run("EstQuantitySheets.copy(project, 'A', 'u1')");
|
||
const second = run("EstQuantitySheets.copy(project, 'A', 'u1')");
|
||
const p = ctx.project;
|
||
process.stdout.write(JSON.stringify({
|
||
first, second, order: p.quantitySheets.map((s) => s.Code), name: p.quantitySheets[1].Name,
|
||
link: p.quantitySheets[1].items[0], original: p.quantitySheets[0].items[0].TargetCode,
|
||
rows: p.quantitySheets[1].rows[0].markers,
|
||
}));
|
||
""")
|
||
assert result == {
|
||
"first": "Qu1",
|
||
"second": "Qu1_2",
|
||
"order": ["A", "Qu1_2", "Qu1", "B"],
|
||
"name": "토공 복사본",
|
||
"link": {"Code": "r000000", "TargetCode": "", "TargetKey": ""},
|
||
"original": "D1",
|
||
"rows": ["r000000"],
|
||
}
|
||
|
||
|
||
def test_move_swaps_and_stops_at_edges():
|
||
result = node("""
|
||
ctx.project = { quantitySheets: [{ Code: 'A' }, { Code: 'B' }, { Code: 'C' }] };
|
||
const out = [run("EstQuantitySheets.move(project, 'B', -1)"), run("EstQuantitySheets.move(project, 'B', -1)"),
|
||
run("EstQuantitySheets.move(project, 'C', 1)")];
|
||
process.stdout.write(JSON.stringify({ out, order: ctx.project.quantitySheets.map((s) => s.Code) }));
|
||
""")
|
||
assert result == {"out": [True, False, False], "order": ["B", "A", "C"]}
|
||
|
||
|
||
def test_estx_export_refuses_reordered_sheets():
|
||
if not MAIN.exists():
|
||
pytest.skip("installed EST main sample unavailable")
|
||
result = node(
|
||
"""
|
||
const imp = require('./tools/est-test/import-estx.cjs'), ex = require('./tools/est-test/export-estx.cjs');
|
||
ctx.project = imp.importEstx(fs.readFileSync(process.argv[1]));
|
||
run("EstQuantitySheets.move(project, project.quantitySheets[0].Code, 1)");
|
||
let message = '';
|
||
try { ex.exportEstx(ctx.project); } catch (e) { message = e.message; }
|
||
process.stdout.write(JSON.stringify(message));
|
||
""",
|
||
str(MAIN),
|
||
)
|
||
assert result.startswith("수량산출서 순서 변경은 ESTX")
|
||
|
||
|
||
MARK = r"""(()=>{
|
||
const sheet={Code:'N1',options:{digits:2,roundMode:2},items:[{Code:'r000000',Name:'가'}],
|
||
rows:[{LineData:' \x0e잔토\x0e \x130.15\x13 2×3 = 6 \x15㎥\x15 그리고 \x125\x12',markers:['r000000']}]};
|
||
const shown=EstText.display(sheet.rows[0].LineData);
|
||
const at=shown.indexOf('6 ');
|
||
const out=[];
|
||
const t=(fn)=>{try{fn();out.push('ok');}catch(e){out.push(e.message.slice(0,6));}};
|
||
t(()=>EstQuantitySheets.mark(sheet,0,at,at+1,'r000001'));
|
||
const item=sheet.items.find(i=>i.Code==='r000001');
|
||
const markers=[...sheet.rows[0].markers];
|
||
const calc=EstQuantity.calculate(sheet).items.map(i=>[i.Code,i.GN]);
|
||
t(()=>EstQuantitySheets.mark(sheet,0,at+4,at+5,'r000002'));
|
||
t(()=>EstQuantitySheets.mark(sheet,0,0,3,'r000002'));
|
||
const inside=EstText.display(sheet.rows[0].LineData).indexOf('⟦결과⟧6')+5;
|
||
t(()=>EstQuantitySheets.free(sheet,0,inside));
|
||
const after=EstText.display(sheet.rows[0].LineData);
|
||
sheet.items[0].TargetCode='D1';
|
||
const last=after.lastIndexOf('⟦결과⟧')-1;
|
||
t(()=>EstQuantitySheets.free(sheet,0,last));
|
||
return {out,markers,item:[item.Name,item.Size,item.Unite],calc,
|
||
back:after===shown,items:sheet.items.map(i=>i.Code)};
|
||
})()"""
|
||
|
||
|
||
def test_mark_and_free_quantity_in_existing_line():
|
||
files = ["native-math.js", "native-formula.js", "native-text.js", "native-quantity.cjs"]
|
||
result = node(
|
||
f"""
|
||
for (const f of {json.dumps(files)})
|
||
vm.runInContext(fs.readFileSync('tools/est-test/' + f, 'utf8'), ctx, {{ filename: f }});
|
||
process.stdout.write(JSON.stringify(run({json.dumps(MARK)})));
|
||
"""
|
||
)
|
||
assert result["markers"] == ["r000001", "r000000"]
|
||
assert result["item"] == ["잔토", "0.15", "㎥"]
|
||
assert ["r000001", 6] in result["calc"]
|
||
assert result["back"] is True
|
||
assert result["items"] == ["r000000"]
|
||
assert [m[:2] for m in result["out"]] == ["ok", "이미", "산출", "ok", "내역"]
|
||
|
||
|
||
def test_estx_export_refuses_marker_edit():
|
||
if not MAIN.exists():
|
||
pytest.skip("installed EST main sample unavailable")
|
||
files = ["native-math.js", "native-formula.js", "native-text.js", "native-quantity.cjs"]
|
||
result = node(
|
||
f"""
|
||
for (const f of {json.dumps(files)})
|
||
vm.runInContext(fs.readFileSync('tools/est-test/' + f, 'utf8'), ctx, {{ filename: f }});
|
||
const imp = require('./tools/est-test/import-estx.cjs'), ex = require('./tools/est-test/export-estx.cjs');
|
||
ctx.project = imp.importEstx(fs.readFileSync(process.argv[1]));
|
||
run(`(() => {{
|
||
for (const s of project.quantitySheets)
|
||
for (let i = 0; i < s.rows.length; i++) {{
|
||
const code = s.rows[i].markers[0], item = s.items.find((x) => x.Code === code);
|
||
if (!code || !item || item.TargetCode || item.TargetKey) continue;
|
||
const t = EstText.display(s.rows[i].LineData);
|
||
return EstQuantitySheets.free(s, i, t.indexOf('⟦결과⟧') + 4);
|
||
}}
|
||
}})()`);
|
||
let message = '';
|
||
try {{ ex.exportEstx(ctx.project); }} catch (e) {{ message = e.message; }}
|
||
process.stdout.write(JSON.stringify(message));
|
||
""",
|
||
str(MAIN),
|
||
)
|
||
assert result.startswith("산출 줄의 수량 지정·해제는 ESTX")
|
||
|
||
|
||
def test_sheet_search_ignores_spaces_bars_and_brackets():
|
||
result = node("""
|
||
const sheet = { Code: 'N1', Name: '토 공(터파기)', items: [{ Name: '잔토|처리', Size: '0.7㎥' }] };
|
||
process.stdout.write(JSON.stringify([
|
||
run("EstQuantitySheets.matches(" + JSON.stringify(sheet) + ", '토공터파기')"),
|
||
run("EstQuantitySheets.matches(" + JSON.stringify(sheet) + ", '잔토 처리')"),
|
||
run("EstQuantitySheets.matches(" + JSON.stringify(sheet) + ", '포장')"),
|
||
run("EstQuantitySheets.matches(" + JSON.stringify(sheet) + ", '')"),
|
||
]));
|
||
""")
|
||
assert result == [True, True, False, True]
|