Files
Aislo/resources/tester/test_b06_wall_shape_unified.py
T
eomsangdonandClaude Opus 5.5 d3315da993 refactor(472-3 B06 벽 · 기슭막이 · 배치): 구조물 기하 logic 분리 · 그림 파일은 그리기만
- logic 새 파일 다섯 — Cross_Wall_Geom(벽 1매) · Cross_Wall_Hatch_Geom(무늬 띠 · 물빼기 · 도수로 띠 · 원지반선) · Cross_Excavation_Geom(벽 터파기) · Cross_Design_Surface_Geom(암선 · 포장층) · Cross_Revetment_Geom(독립 기슭막이 배치)
- logic 으로 옮김 — Body_Guard → Cross_Body_Guard · Structure_Layouts · Route_Carry_Patch(내용 그대로 · import 경로만)
- inferStationInterval → common_util_station(글자표 없는 자리 · common_util_svg 는 다시 내보냄) — Node 묶음 ui_template_locale 끌림 끊음
- 부르는 쪽 import 줄 · 등록부 ts 경로 · 시험 · 도우미 경로
- test_472_3 GEOMETRY_PULLS 다섯 줄 걷음 · Wall_Hatch · Excavation · Design_Surface 세 줄은 Culvert · Box · Ford 그림 파일(518-2)이 그리기 함수로 부르는 동안 남김

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 19:22:27 +09:00

112 lines
5.5 KiB
Python

"""횡단 벽 형상 한 벌 — 관 유입·유출 흙막이 · 추가 흙막이 · 사면안정 흙막이 · 옹벽.
규칙(10-6 사용자):
① 네 벽 모두 공용 `buildRevetWallGeometry` 로 선다 — 형태는 안 무늬만 바꿈(외곽 같음).
② 형태별 높이 한도(메 2.0 · 찰 3.0 · 콘크리트 5.0) · 원지반 맞춤 자동 자르기 없음.
③ 벽 윗면은 노면 위로 올라오지 않음(넘으면 노면에서 멈춤).
서버 면적은 같은 TS 를 Node 로 돌리므로(`design_calc_node.ts` `structure.layouts`) 이 함수가 곧 서버 기하.
"""
import json
import re
import subprocess
from pathlib import Path
import pytest
PROJECT_ROOT = Path(__file__).resolve().parents[2]
B06 = PROJECT_ROOT / "B06_Section"
TSC = PROJECT_ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc"
_RUNNER = """
import { writeFileSync } from "node:fs";
import { buildRevetWallGeometry } from "./logic/B06_Section_Cross_Wall_Geom.js";
import { revetWallSpec, REVET_FORMS } from "./logic/B06_Section_UI_Cross_Culvert_Const.js";
const anchor = { offset: 5, elevation: 100 };
const outline = (form, role, extra = {}) =>
buildRevetWallGeometry({ anchor, outward: 1, height: 2.5, material: "dry", role, form, ...extra })
.points.map((p) => [p.offset, p.elevation]);
writeFileSync(process.argv[2], JSON.stringify({
forms: REVET_FORMS.map((form) => outline(form, "outlet")),
roles: ["inlet", "outlet", "extra"].map((role) => outline("돌쌓기(메)", role)),
capped: buildRevetWallGeometry({
anchor, outward: 1, height: 5, material: "dry", role: "outlet", roadElevation: 103,
}).topJoint.elevation,
under: buildRevetWallGeometry({
anchor, outward: 1, height: 2, material: "dry", role: "outlet", roadElevation: 103,
}).topJoint.elevation,
fill: (({ fillTop, topJoint, points }) => [fillTop.offset, fillTop.elevation, topJoint.offset, points[2].offset, points[2].elevation])(
buildRevetWallGeometry({ anchor, outward: 1, height: 2.5, material: "dry", role: "outlet" }),
),
dry: revetWallSpec({ revet_form: "돌쌓기(메)" }, { h: 3.0 }, true, 0.3).pureHeight,
concrete: revetWallSpec({ revet_form: "콘크리트" }, { h: 7.5 }, true, 0.3).pureHeight,
}));
"""
@pytest.mark.skipif(not TSC.is_file(), reason="프론트엔드 의존성 미설치")
def test_벽_외곽_한_벌_높이_입력_그대로_노면_멈춤(tmp_path: Path) -> None:
out = tmp_path / "js"
# 형(type) import 가 끌어오는 페이지 파일은 별칭을 못 풀어 오류를 내지만 산출물은 나옴.
subprocess.run( # noqa: S603 — 고정 실행 파일
[
"node",
str(TSC),
str(B06 / "B06_Section_UI_Cross_Wall.ts"),
str(B06 / "logic" / "B06_Section_Cross_Wall_Geom.ts"),
"--outDir",
str(out),
"--module",
"esnext",
"--target",
"es2022",
"--moduleResolution",
"bundler",
"--skipLibCheck",
"--ignoreConfig",
],
cwd=str(PROJECT_ROOT),
capture_output=True,
)
for emitted in out.rglob("*.js"):
emitted.write_text(
re.sub(r'(from\s+"\./[^"]+)"', r'\1.js"', emitted.read_text(encoding="utf-8")),
encoding="utf-8",
)
base = next(path.parent for path in out.rglob("B06_Section_UI_Cross_Wall.js"))
(base / "runner.mjs").write_text(_RUNNER, encoding="utf-8")
result = tmp_path / "out.json"
subprocess.run( # noqa: S603
["node", str(base / "runner.mjs"), str(result)], check=True, capture_output=True
)
got = json.loads(result.read_text(encoding="utf-8"))
assert all(outline == got["forms"][0] for outline in got["forms"]), "형태마다 외곽이 다름"
assert all(outline == got["roles"][0] for outline in got["roles"]), "벽 갈래마다 외곽이 다름"
assert got["capped"] == pytest.approx(103.0), "노면 위로 올라옴"
assert got["under"] == pytest.approx(102.0), "노면 아래 벽이 잘림"
assert got["dry"] == pytest.approx(3.0), "돌쌓기(메) 3.0 이 잘림"
assert got["concrete"] == pytest.approx(7.5), "콘크리트 7.5 가 잘림"
# 371-1 — 성토 위 이음 = 윗면 사면 쪽 끝에서 0.1 m 안 · 무늬 이음선(topJoint)은 그대로
fill_offset, fill_elevation, joint_offset, front_offset, front_elevation = got["fill"]
assert fill_offset == pytest.approx(front_offset - 0.1), "성토 위 이음이 끝에서 0.1 m 아님"
assert fill_elevation == pytest.approx(front_elevation), "성토 위 이음이 윗면 표고 아님"
assert joint_offset == pytest.approx(front_offset - 0.45), "무늬 이음선이 옮겨짐"
def test_네_벽이_공용_함수로_서고_형태_한도가_없다() -> None:
for name in (
"B06_Section_UI_Cross_Culvert_Geom",
"B06_Section_UI_Cross_Culvert_Extra",
"logic/B06_Section_Cross_Revetment_Geom",
):
source = (B06 / f"{name}.ts").read_text(encoding="utf-8")
assert "buildRevetWallGeometry(" in source, f"{name} 가 공용 벽 함수를 안 씀"
for path in B06.rglob("*.ts"): # logic/ 까지(348-1)
source = path.read_text(encoding="utf-8")
assert "revetHeightLimit" not in source, f"{path.name} 에 형태 높이 한도가 남음"
assert "materialLimit" not in source, f"{path.name} 에 재질 높이 한도가 남음"
extra = (B06 / "B06_Section_UI_Cross_Culvert_Extra.ts").read_text(encoding="utf-8")
assert "fitted" not in extra, "추가 흙막이가 원지반에 맞춰 늘어남"