Files
Aislo/resources/tester/test_b06_berm_review_info.py
T
eomsangdonandClaude Opus 5.5 281c71b55b refactor(logic): 348-1 순수 계산 TS 49 파일 <페이지>/logic/ 로 옮김 — 이름 앞머리 그대로 · 동작 고침 없음
- 옮김: B04 2 · B05 23 · B06 11 · A00_Common/design 13 (9,299 줄) · 이미 logic/ 에 있던 16 파일 그대로
- 안 옮김: 묶음 입구(package.json build:*) · 파이썬 · 순수지만 계산 아닌 8 (보기 결선 · 콜백 · API 타입 · 갈아끼움 알림판)
- import 266 줄(142 파일) · 시험 · 주석 · 짝 표시 문자열 경로 고침 · B05 · B06 CLAUDE.md 짝 줄 logic/
- 시험 도우미 새 경로: 가짜 require 열쇠 · B05()/B06() 부름 · 형제 import 자리 · tsc 묶어 돌리는 시험 · 정규식 · rglob
- design_view_cross 줄 한도 시험 685 → 688 (긴 import 경로 줄바꿈 3줄)
- 확인: typecheck 0 · 서버 묶음 넷(corridor · server-calc · b07-extent · b07-note) 다시 지어 코드 같음(//#region 경로 주석만 다름) · 관련 시험 270 파일 — 남은 실패 19 는 옮기기 전과 같음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014utrjfoW831Vc5wJUd13kL
2026-10-16 13:44:50 +09:00

109 lines
3.9 KiB
Python

"""사면길이 3m 초과 — 소단 **검토 대상 정보 한 줄**(경고 아님 · 2026-09-15 브레인 ③).
① 법령 별표2 Ⅰ.2.차.(5) 「붕괴 또는 밀려 내려갈 **우려가 있는 지역**에는 사면길이 2~3m 마다」 —
「우려 있음」을 우리가 판정 못 함 ⇒ 경고가 아니라 정보
② 3m 를 **넘는** 쪽만(3.00 은 아님) · 절토·성토 둘 다 · 원지반을 못 만난 하한값(≥)도 넘으면 들어감
③ 벽이 선 쪽은 뺌(성토사면 5m 경고와 같은 규칙 · `wallSides`)
④ 문구는 브레인 문구 그대로
TS 를 실제로 돌린다(파이썬 짝이 없는 화면 판정 — `test_b06_fill_slope_warn` 과 같은 방식).
"""
from __future__ import annotations
import json
import re
import subprocess
from pathlib import Path
import pytest
PROJECT_ROOT = Path(__file__).resolve().parents[2]
TSC = PROJECT_ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc"
FOLDER = PROJECT_ROOT / "B06_Section"
SOURCES = [
FOLDER / "logic/B06_Section_UI_Cross_Berm_Info.ts",
FOLDER / "logic/B06_Section_UI_Cross_FillSlope_Warn.ts",
FOLDER / "logic/B06_Section_UI_Cross_Culvert_Const.ts",
]
_RUNNER = """
import { readFileSync, writeFileSync } from "node:fs";
import { BERM_INFO_TEXT, bermReviewStations } from "./B06_Section_UI_Cross_Berm_Info.js";
const [inputPath, outputPath] = process.argv.slice(2);
const cases = JSON.parse(readFileSync(inputPath, "utf8"));
const rows = bermReviewStations(cases.map((c) => c.section), (section) =>
cases.find((c) => c.section.station_id === section.station_id).lengths,
);
writeFileSync(outputPath, JSON.stringify({
text: BERM_INFO_TEXT,
rows: rows.map((w) => [w.section.station_id, w.sides.map((s) => s.side)]),
}));
"""
LONG = {"lengthM": 4.0, "open": False}
CASES = [
{"section": {"station_id": "both"}, "lengths": {"left": LONG, "right": LONG}},
{
"section": {"station_id": "edge"},
"lengths": {
"left": {"lengthM": 3.0, "open": False},
"right": {"lengthM": 2.5, "open": True},
},
},
{
"section": {"station_id": "open_long"},
"lengths": {"left": None, "right": {"lengthM": 3.4, "open": True}},
},
{"section": {"station_id": "ford", "ford": {}}, "lengths": {"left": LONG, "right": LONG}},
]
def _run(tmp_path: Path) -> dict:
out = tmp_path / "js"
subprocess.run( # noqa: S603 — 고정 실행 파일
[
"node",
str(TSC),
*map(str, SOURCES),
"--outDir",
str(out),
"--module",
"esnext",
"--target",
"es2022",
"--moduleResolution",
"bundler",
"--ignoreConfig",
"--noCheck",
"--noResolve",
],
cwd=str(PROJECT_ROOT),
check=True,
capture_output=True,
)
for emitted in out.glob("*.js"):
text = emitted.read_text(encoding="utf-8")
emitted.write_text(
re.sub(r'(from "\./[^"]+?)(")', lambda m: m.group(1) + ".js" + m.group(2), text),
encoding="utf-8",
)
(out / "runner.mjs").write_text(_RUNNER, encoding="utf-8")
payload, result = tmp_path / "input.json", tmp_path / "output.json"
payload.write_text(json.dumps(CASES, ensure_ascii=False), encoding="utf-8")
subprocess.run( # noqa: S603
["node", str(out / "runner.mjs"), str(payload), str(result)],
cwd=str(PROJECT_ROOT),
check=True,
capture_output=True,
)
return json.loads(result.read_text(encoding="utf-8"))
@pytest.mark.skipif(not TSC.is_file(), reason="프론트엔드 의존성 미설치")
def test_3m_넘는_사면만_벽_선_쪽은_뺀다(tmp_path: Path) -> None:
got = _run(tmp_path)
assert dict(got["rows"]) == {"both": ["left", "right"], "open_long": ["right"]}
assert got["text"] == "사면길이 3m 초과 — 소단 검토 대상(별표2 차.(5) · 붕괴 우려 지역 조건)"