diff --git a/resources/tester/test_b05_revetment_sabang_basis.py b/resources/tester/test_b05_revetment_sabang_basis.py index 8b22c4a3..c0071504 100644 --- a/resources/tester/test_b05_revetment_sabang_basis.py +++ b/resources/tester/test_b05_revetment_sabang_basis.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- -"""독립 기슭막이 치수 한 벌 — B05 칸 밑 근거와 B08 사유가 **같은 파일**을 읽음 (2026-09-14 브레인 판정). +"""독립 기슭막이 치수 — B05 칸 밑 근거가 표(`resources/data_masonry/revetment_sabang_*.json`)를 읽음. -한 자리 = `resources/data_masonry/수량_사방기슭막이치수_*.json`. TS 는 판 이름을 import 로 박으므로 판이 -바뀌면 import 도 옮겨야 함 — 여기서 최신 판과 대조. 쪽·줄 번호가 사유에 그대로 실리는지도 봄. +2026-09-22 sub1: B08 쪽 사유 대조(`B08_Quantity_Engine_Pipe.own_revetment_basis` 등)는 B08 이 +`old_code/` 로 끊기며 같이 죽었음 — 그 대조 시험은 빼고, **B05 몫**(TS 가 최신판을 읽는지 · +그 판이 쓰는 칸이 실제로 있는지 · 높이 칸이 제안 없이 설계자 입력인지)만 되살림. """ from __future__ import annotations @@ -16,12 +17,7 @@ ROOT = Path(__file__).resolve().parents[2] if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) -from B08_Quantity.B08_Quantity_Engine_Pipe import ( # noqa: E402 - own_height_unconfirmed, - own_revetment_basis, -) - -DATA_DIR = ROOT / "resources" / "master_data" / "ref" +DATA_DIR = ROOT / "resources" / "data_masonry" FIELDS = (ROOT / "B05_Profile" / "B05_Profile_UI_Drainage_Facility_Fields.ts").read_text( encoding="utf-8" ) @@ -29,13 +25,13 @@ CHROME = (ROOT / "B06_Section" / "B06_Section_UI_Cross_Card_Chrome.ts").read_tex def test_TS_가_최신_판을_읽는다() -> None: - latest = sorted(DATA_DIR.glob("수량_사방기슭막이치수_*.json"))[-1].name - imported = re.search(r'from "\.\./resources/master_data/ref/(수량_사방기슭막이치수_[^"]+)"', FIELDS) + latest = sorted(DATA_DIR.glob("revetment_sabang_*.json"))[-1].name + imported = re.search(r'from "\.\./resources/data_masonry/(revetment_sabang_[^"]+)"', FIELDS) assert imported and imported.group(1) == latest def test_TS_가_쓰는_칸이_파일에_있다() -> None: - latest = sorted(DATA_DIR.glob("수량_사방기슭막이치수_*.json"))[-1] + latest = sorted(DATA_DIR.glob("revetment_sabang_*.json"))[-1] data = json.loads(latest.read_text(encoding="utf-8")) items = data["items"] assert data["scope"] and "사방(계류) 교본 기준" in data["scope"] @@ -45,13 +41,6 @@ def test_TS_가_쓰는_칸이_파일에_있다() -> None: assert "L7164" in items["backfill_pebble"]["source"] -def test_B08_사유가_같은_근거를_쪽_줄_번호로() -> None: - basis = own_revetment_basis() - for ref in ("2-나:141", "3-가:181", "2-나:129", "3-가:151", "2-나:143", "L7164~7171"): - assert ref in basis, ref - assert "2-나:141" in own_height_unconfirmed() - - def test_B05_높이_칸은_제안_없이_설계자_입력() -> None: assert 'height: "",' in FIELDS and '"설계자 입력"' in FIELDS assert "기슭막이 높이 없음 — 근입만 그림" in CHROME diff --git a/resources/tester/test_b06_wall_lean_table.py b/resources/tester/test_b06_wall_lean_table.py index f914278e..49e018f9 100644 --- a/resources/tester/test_b06_wall_lean_table.py +++ b/resources/tester/test_b06_wall_lean_table.py @@ -1,124 +1,22 @@ # -*- coding: utf-8 -*- """B06 벽 전면 기울기도 **품셈 표준경사 표**를 읽음 — B5 (2026-09-14 브레인 판정 「양쪽 다 이 표를」). -앞서 B06 횡단도는 벽(관 유입·유출 · 독립 기슭막이 · 다단 추가 · C군 벽)을 **1:0.3 붙박이**로 그렸고 -B08 은 품셈 13-4-4 [주]⑪ 표(원문 L7185~7191)로 셈 — 메쌓기 성토 H2.5 에서 1:0.3 ↔ 1:0.35 로 갈림. - -재는 것(브레인: 고치기 전 코드에서 빨강부터) - ① 네 갈래 — 직고 구간 × 성토/절토 × 메/찰 (+ 사용자 칸 `face_slope_ratio`·`face_role`, 못 가르면 종전 0.3) - TS 짝 `common_util_masonry_slope.ts` 을 실제로 돌려 파이썬 `face_slope_ratio` 와 한 칸씩 대조. - ② 기하가 그 값을 씀 — 벽 모양 파일에서 붙박이 `REVET_LEAN_RATIO` 곱이 사라지고 벽마다 기울기를 받음. +2026-09-22 sub1: B08 쪽 파이썬 대조(`B08_Quantity_Engine_UnitQuantity_StoneSpec`)는 B08 이 +`old_code/` 로 끊기며 같이 죽었음 — 그 대조 시험은 빼고, **B06 몫**(표 경로가 최신판인지 · +벽 모양이 붙박이 기울기를 더는 안 곱하는지)만 되살림. """ from __future__ import annotations -import itertools -import json import re -import shutil -import subprocess import sys from pathlib import Path -import pytest - ROOT = Path(__file__).resolve().parents[2] if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) -from B08_Quantity.B08_Quantity_Engine_UnitQuantity_StoneSpec import ( # noqa: E402 - face_slope_ratio, - load_slope_table, -) -from common_util.common_util_structure_face_role import structure_face_role_of # noqa: E402 - -TSC = ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc" -TS_FILE = ROOT / "common_util" / "common_util_masonry_slope.ts" - -FORMS = ("돌쌓기(찰)", "돌쌓기(메)", "콘크리트") -HEIGHTS = (1.0, 1.5, 2.5, 3.0, 4.0, 6.0, 7.5) -MODES = ("left_cut", "right_cut", "both_cut", "both_fill", None) -SIDES = (None, "자동(성토 쪽)", "좌", "우", "양쪽") -OVERRIDES = ({}, {"face_role": "절토"}, {"face_slope_ratio": 0.5}) - -_RUNNER = """ -const { readFileSync, writeFileSync } = require("node:fs"); -const { wallLeanRatio } = require("./common_util_masonry_slope.js"); -const input = JSON.parse(readFileSync(process.argv[2], "utf8")); -const out = input.cases.map((c) => wallLeanRatio(input.table, c)); -writeFileSync(process.argv[3], JSON.stringify(out)); -""" - - -def _cases() -> list[dict]: - cases = [] - for form, height, mode, side, extra in itertools.product( - FORMS, HEIGHTS, MODES, SIDES, OVERRIDES - ): - cases.append( - {"form": form, "height_m": height, "section_mode": mode, "side": side, **extra} - ) - return cases - - -def _python(case: dict) -> float: - """B08 이 그 벽을 셀 때의 기울기 — 돌쌓기 형태만 표, 나머지는 종전 0.3.""" - wet = {"돌쌓기(찰)": True, "돌쌓기(메)": False}.get(case["form"]) - if wet is None: - return 0.3 - options = {k: case[k] for k in ("side", "face_role", "face_slope_ratio") if k in case} - face, reason = structure_face_role_of(case["section_mode"], options) - ratio, _basis = face_slope_ratio( - options, wet=wet, height_m=case["height_m"], face=face, face_reason=reason - ) - return ratio - - -@pytest.mark.skipif(shutil.which("node") is None or not TSC.is_file(), reason="node·tsc 없음") -def test_네_갈래_표를_TS_가_파이썬과_같게_읽는다(tmp_path: Path) -> None: - assert TS_FILE.is_file(), "TS 짝이 아직 없음 — B06 이 표를 안 읽는다" - out = tmp_path / "js" - subprocess.run( # noqa: S603 — 고정 실행 파일 - [ - "node", - str(TSC), - str(TS_FILE), - "--outDir", - str(out), - "--module", - "commonjs", - "--target", - "es2022", - "--ignoreConfig", - ], - cwd=str(ROOT), - check=True, - capture_output=True, - ) - (out / "runner.cjs").write_text(_RUNNER, encoding="utf-8") - cases = _cases() - payload = tmp_path / "in.json" - result = tmp_path / "out.json" - payload.write_text( - json.dumps({"table": load_slope_table(), "cases": cases}, ensure_ascii=False), - encoding="utf-8", - ) - subprocess.run( # noqa: S603 - ["node", str(out / "runner.cjs"), str(payload), str(result)], - cwd=str(ROOT), - check=True, - capture_output=True, - ) - got = json.loads(result.read_text(encoding="utf-8")) - wrong = [ - (case, ts, _python(case)) - for case, ts in zip(cases, got, strict=True) - if abs(ts - _python(case)) > 1e-9 - ] - assert not wrong, wrong[:5] - # 갈래가 실제로 갈렸는지 — 한 값만 나와 같아지는 것을 막음(메 성토 H2.5 0.35 · 찰 절토 H1.0 0.2) - assert {round(v, 2) for v in got} >= {0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5} - +DATA_DIR = ROOT / "resources" / "data_masonry" GEOMETRY = [ "B06_Section_UI_Cross_Culvert_Geom.ts", @@ -130,8 +28,8 @@ GEOMETRY = [ def test_횡단도가_최신_표준경사_판을_읽는다() -> None: const = (ROOT / "B06_Section" / "B06_Section_UI_Cross_Lean.ts").read_text(encoding="utf-8") - latest = sorted((ROOT / "resources" / "master_data" / "old").glob("3_품셈_산림_돌쌓기경사_*.json"))[-1].name - imported = re.search(r'from "\.\./resources/master_data/old/(3_품셈_산림_돌쌓기경사_[^"]+)"', const) + latest = sorted(DATA_DIR.glob("masonry_slope_*.json"))[-1].name + imported = re.search(r'from "\.\./resources/data_masonry/(masonry_slope_[^"]+)"', const) assert imported and imported.group(1) == latest