diff --git a/resources/tester/test_b06_b08_wall_thickness_match.py b/resources/tester/test_b06_b08_wall_thickness_match.py new file mode 100644 index 00000000..ff670cd5 --- /dev/null +++ b/resources/tester/test_b06_b08_wall_thickness_match.py @@ -0,0 +1,102 @@ +"""횡단도(B06)가 그리는 돌쌓기 벽 폭과 수량(B08)이 세는 벽 두께가 **같은 값인가** — 대조 시험. + +왜 (2026-09-14 브레인 차례 「두께 차이」) — 같은 다단 벽을 두 곳이 다른 두께로 봄: + B06 `REVET_THICKNESS_M` 0.45(울진 뒷길이 관측 · 표시용) → 윗폭 1.5×0.45 · 밑폭 윗폭 + 기울기×H + B08 `wall_thickness` 실무 구조물도 식 → 상부 뒷길이 + 0.30 · 하부 상부 + 0.30×(H−1) +어느 쪽으로 맞출지는 아직 안 정함 — 그래서 `xfail(strict)`: 지금은 빨강이 **나야** 하고, +두 값이 맞춰지면 통과로 뒤집혀 이 표시를 걷으라고 알림. +실제 화면 코드를 컴파일해 Node 로 돌림(`test_b06_extra_shift_floor` 와 같은 방식). +""" + +import json +import subprocess +import sys +from pathlib import Path + +import pytest + +PROJECT_ROOT = Path(__file__).resolve().parents[2] +if str(PROJECT_ROOT) not in sys.path: + sys.path.insert(0, str(PROJECT_ROOT)) + +from B08_Quantity.B08_Quantity_Engine_UnitQuantity_StoneSpec import ( # noqa: E402 + _back_length, + wall_thickness, +) + +TSC = PROJECT_ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc" +MODULE = PROJECT_ROOT / "B06_Section" / "B06_Section_UI_Cross_Culvert_Extra.ts" +FORM = "돌쌓기(메)" +LEAN = 0.35 # 품셈 13-4-4 [주]⑪ 메쌓기 성토 ~3m + +_RUNNER = """ +const { buildOutletExtras } = require(process.argv[3]); +const { writeFileSync } = require("node:fs"); +const groundAt = (offset) => 95 - offset / 2; +const result = buildOutletExtras({ + start: { offset: 0, elevation: 100 }, + startBottomElevation: 100, + outward: 1, + groundAt, + limitOffset: 60, + adjusts: [{ x: 0, d: null, h: 2.0, m: "%(form)s" }], + leanFor: () => %(lean)s, +}); +const wall = result.walls[0]; +const [bottomBack, topBack, topFront, bottomFront] = wall.points; +writeFileSync(process.argv[2], JSON.stringify({ + pureHeight: wall.height + 0.5, + top: Math.abs(topFront.offset - topBack.offset), + bottom: Math.abs(bottomFront.offset - bottomBack.offset), +})); +""" + + +def _drawn(tmp_path: Path) -> dict: + out = tmp_path / "out" + subprocess.run( # noqa: S603 — 고정 실행 파일 + [ + "node", + str(TSC), + "--ignoreConfig", + "--target", + "es2022", + "--module", + "commonjs", + "--skipLibCheck", + "--outDir", + str(out), + str(MODULE), + ], + cwd=str(PROJECT_ROOT), + check=False, + capture_output=True, + ) + compiled = next(out.rglob("B06_Section_UI_Cross_Culvert_Extra.js"), None) + assert compiled is not None, "화면 코드가 JS 로 안 나옴 — tsc 실패" + (out / "runner.cjs").write_text(_RUNNER % {"form": FORM, "lean": LEAN}, encoding="utf-8") + result = tmp_path / "result.json" + subprocess.run( # noqa: S603 — 고정 실행 파일 + ["node", str(out / "runner.cjs"), str(result), str(compiled)], + 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="프론트엔드 의존성 미설치") +@pytest.mark.xfail(strict=True, reason="B06 0.45 표시값 ↔ B08 구조물도 식 — 맞출 쪽 판정 대기") +def test_횡단도_벽_폭과_수량_벽_두께가_같다(tmp_path: Path) -> None: + drawn = _drawn(tmp_path) + height = drawn["pureHeight"] + options = {"form": FORM} + back_cm = _back_length(options, wet=False, height_m=height) + top, bottom, basis = wall_thickness(options, back_cm=back_cm, height_m=height) + assert (round(drawn["top"], 2), round(drawn["bottom"], 2)) == ( + round(top, 2), + round(bottom, 2), + ), ( + f"H {height:.2f} — 횡단도 윗폭 {drawn['top']:.3f} · 밑폭 {drawn['bottom']:.3f}" + f" ↔ 수량 {basis}" + )