# -*- coding: utf-8 -*- """계획노선 편집의 **곡선 하한(R·L)** 회귀검증 — 2026-09-12. 사용자 확정: 「반경과 길이가 트레이드오프기는 하지만 **둘 다 지켜야** 한다」. L = R·Δ 라 한 자리의 하한은 반지름 하나로 모이고, 그 값을 `radiusFloorM` 이 낸다. ⚠ 예외 하나 — **내각 155° 이상은 곡선을 설치하지 않을 수 있다**(별표2 Ⅰ.2.다.(1)). 거기서 L 을 채우라고 하면 교각이 0 에 가까워 R 이 수십 배로 부풀고, 아무것도 안 고쳤는데 노선이 휜다(실측: 내각 174.8° 자리가 R 12m → 55m). 그래서 그 자리는 R 하한만 본다. Node 헬퍼(`helper_b05_curve_radius_floor.cjs`)가 TS 를 그 자리에서 트랜스파일해 돌리고, 여기서 값을 판정한다. """ import json import os import subprocess import pytest HERE = os.path.dirname(os.path.abspath(__file__)) @pytest.fixture(scope="module") def results(): proc = subprocess.run( ["node", os.path.join(HERE, "helper_b05_curve_radius_floor.cjs")], capture_output=True, text=True, timeout=60, ) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) def test_R_하한이_이기는_자리는_R_하한_그대로(results): """내각 140° 면 R 12m 만 지켜도 L 이 8.4m 라 L 하한(5m)이 안 건다.""" assert results["floors"]["bend140"] == pytest.approx(12.0) def test_L_하한이_이기면_R_을_끌어올린다(results): """내각 150°(교각 30°)에 L 하한 20m 면 R 은 38.2m 이어야 한다 — 여기가 「둘 다」의 핵심.""" assert results["floors"]["bend150LongArc"] == pytest.approx(20 / (30 * 3.141592653589793 / 180)) assert results["floors"]["bend150LongArc"] > 12.0 def test_내각_155도_이상은_L_하한을_안_건다(results): """곡선 생략이 되는 자리다 — 걸었다면 R 이 28.6m 로 부풀어 노선이 조용히 휜다.""" assert results["floors"]["bend170"] == pytest.approx(12.0) assert results["floors"]["bend170NoExempt"] > 28.0 # 예외가 없을 때의 값(참고) assert results["floors"]["bend155"] == pytest.approx(12.0) def test_155도_바로_아래는_L_하한을_건다(results): """경계는 「155° 이상」이라 154° 는 지켜야 하는 쪽이다.""" assert results["floors"]["bend154"] > 12.0 def test_내각을_모르면_R_하한만_본다(results): assert results["floors"]["unknown"] == pytest.approx(12.0) def test_지정한_반지름만_끌어올린다(results): """비워 둔(자동) 자리는 안 건드린다 — 건드리면 안 고쳤는데 「R 지정」이 늘어난다.""" applied = results["applied"] assert applied["specified"] == pytest.approx(20 / (30 * 3.141592653589793 / 180)) assert applied["auto"] is None assert applied["curveOff"] == 12 # 곡선을 지운 자리는 그대로 def test_모자란_양도_R과_L을_함께_잰다(results): """내각 150°(하한 38.2m)에서 R 12m 는 26.2m 모자라고, 170° 는 곡선 생략 자리라 0 이다.""" short = results["shortfalls"] assert short[0] == pytest.approx(20 / (30 * 3.141592653589793 / 180) - 12) assert short[1] == 0 assert short[2] == 0 # R 40m 는 하한을 넘겼다