tmp/ 가 창끼리 안 건너가는 것이 확정돼(랩탑이 시간 두고 두 번 확인) 시험·예외가 저절로 건너가도록 git 안으로 옮김. 사용자 확정. - 내용은 하나도 안 고침 — 자리만 옮김. tmp/tests 는 남겨 둠. - 같은 이름이 이미 있던 64 개는 랩탑 것을 그대로 두고 건너뜀. - helper_b05_*.js 둘은 랩탑이 .cjs 로 이미 올린 것과 **줄바꿈만 다른 같은 내용**이라 복사본을 도로 뺌(시험이 .cjs 를 부름). - resources/tester/ 에서 전체 1176 통과 · 29 건너뜀 · 실패 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
185 lines
6.8 KiB
Python
185 lines
6.8 KiB
Python
"""토적표 엔진 검사 — PLAN 8-4b·8-16.
|
||
|
||
정답지는 거창 실무 토적표(오솔길 `1.BOM` 과 1:1)다. 평균단면적법이 실물과 같은 값을
|
||
내는지, 첫 측점에 체적이 없는지, 값을 자르지 않는지를 못 박는다.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
sys.path.insert(0, str(ROOT))
|
||
|
||
from B08_Quantity.B08_Quantity_Engine_EarthworkTable import ( # noqa: E402
|
||
StationArea,
|
||
build_rows,
|
||
build_table,
|
||
totals,
|
||
)
|
||
from config.config_system_design import EARTHWORK_CONVERSION_FACTORS # noqa: E402
|
||
|
||
SOIL_C = EARTHWORK_CONVERSION_FACTORS["soil"]["compacted"]
|
||
|
||
|
||
def 거창_앞_네_측점() -> list[StationArea]:
|
||
"""거창 `1.BOM` 앞부분 — 절토 토사만 있고 측구는 단면 0.18㎡ 고정인 구간.
|
||
|
||
BOM 값: 0(0.00) · 0+10(1.89) · 1(1.73) · 1+10(1.45), 거리 10m 등간.
|
||
"""
|
||
return [
|
||
StationArea(chainage_m=0.0, cut_soil_area_m2=0.00, ditch_area_m2=0.0),
|
||
StationArea(chainage_m=10.0, cut_soil_area_m2=1.89, ditch_area_m2=0.18),
|
||
StationArea(chainage_m=20.0, cut_soil_area_m2=1.73, ditch_area_m2=0.18),
|
||
StationArea(chainage_m=30.0, cut_soil_area_m2=1.45, ditch_area_m2=0.18),
|
||
]
|
||
|
||
|
||
def test_첫_측점은_체적이_없음() -> None:
|
||
"""앞 측점이 없으면 평균을 낼 수 없다 — 실무 토적표도 첫 행 체적이 비어 있다."""
|
||
rows = build_rows(거창_앞_네_측점())
|
||
assert rows[0].distance_m == 0.0
|
||
assert rows[0].cut_soil_volume_m3 == 0.0
|
||
assert rows[0].adjusted_total_m3 == 0.0
|
||
|
||
|
||
def test_평균단면적법_실무값_재현() -> None:
|
||
"""BOM 0+10 행: 단면적 1.89 → 체적 9.45 → 보정 8.50 (거리 10m)."""
|
||
rows = build_rows(거창_앞_네_측점())
|
||
row = rows[1]
|
||
assert row.distance_m == pytest.approx(10.0)
|
||
assert row.cut_soil_volume_m3 == pytest.approx(9.45) # (0.00+1.89)/2 × 10
|
||
assert row.cut_soil_adjusted_m3 == pytest.approx(9.45 * SOIL_C)
|
||
assert row.cut_soil_adjusted_m3 == pytest.approx(8.505) # BOM 표기 8.50
|
||
|
||
|
||
def test_평균단면적법_다음_측점() -> None:
|
||
"""BOM 1 행: (1.89+1.73)/2 × 10 = 18.10 → 보정 16.29."""
|
||
row = build_rows(거창_앞_네_측점())[2]
|
||
assert row.cut_soil_volume_m3 == pytest.approx(18.10)
|
||
assert row.cut_soil_adjusted_m3 == pytest.approx(16.29)
|
||
|
||
|
||
def test_측구_단면_0_18이_체적으로() -> None:
|
||
"""측구 0.18㎡ 가 이어지면 10m 당 1.80㎥ — BOM 10열과 같다."""
|
||
rows = build_rows(거창_앞_네_측점())
|
||
assert rows[2].ditch_soil_volume_m3 == pytest.approx(1.80)
|
||
assert rows[2].ditch_soil_adjusted_m3 == pytest.approx(1.62)
|
||
|
||
|
||
def test_보정량계는_네_갈래_합() -> None:
|
||
row = build_rows(거창_앞_네_측점())[2]
|
||
assert row.adjusted_total_m3 == pytest.approx(
|
||
row.cut_soil_adjusted_m3
|
||
+ row.cut_rock_adjusted_m3
|
||
+ row.ditch_soil_adjusted_m3
|
||
+ row.ditch_rock_adjusted_m3
|
||
)
|
||
assert row.adjusted_total_m3 == pytest.approx(16.29 + 1.62) # BOM 15열 17.91
|
||
|
||
|
||
def test_누가토량은_차인토량의_누계() -> None:
|
||
"""유토곡선의 원본이 이 열이다 — 누계가 어긋나면 곡선이 통째로 틀린다."""
|
||
rows = build_rows(거창_앞_네_측점())
|
||
running = 0.0
|
||
for row in rows:
|
||
running += row.balance_m3
|
||
assert row.cumulative_m3 == pytest.approx(running)
|
||
|
||
|
||
def test_성토가_있으면_유용토는_작은_쪽() -> None:
|
||
stations = [
|
||
StationArea(chainage_m=0.0),
|
||
StationArea(chainage_m=10.0, cut_soil_area_m2=2.0, fill_area_m2=8.0),
|
||
]
|
||
row = build_rows(stations)[1]
|
||
assert row.adjusted_total_m3 == pytest.approx(10.0 * SOIL_C) # 절취 10㎥ → 보정 9㎥
|
||
assert row.fill_volume_m3 == pytest.approx(40.0)
|
||
assert row.diverted_m3 == pytest.approx(9.0) # 둘 중 작은 쪽
|
||
assert row.balance_m3 == pytest.approx(9.0 - 40.0)
|
||
|
||
|
||
def test_암은_토사와_다른_계수() -> None:
|
||
"""토사 0.90 · 리핑암 1.15 — 한 계수로 뭉치면 암 물량이 틀린다."""
|
||
stations = [
|
||
StationArea(chainage_m=0.0),
|
||
StationArea(chainage_m=10.0, cut_rock_area_m2=2.0, cut_rock_kind="ripping_rock"),
|
||
]
|
||
row = build_rows(stations)[1]
|
||
assert row.cut_rock_volume_m3 == pytest.approx(10.0)
|
||
assert row.cut_rock_adjusted_m3 == pytest.approx(
|
||
10.0 * EARTHWORK_CONVERSION_FACTORS["ripping_rock"]["compacted"]
|
||
)
|
||
|
||
|
||
def test_측구_안분은_절토_토사암_비율() -> None:
|
||
"""측구 지반이 따로 안 오므로 그 측점 절토 비율로 가른다(엔진 주석의 TODO 자리)."""
|
||
stations = [
|
||
StationArea(chainage_m=0.0),
|
||
StationArea(
|
||
chainage_m=10.0,
|
||
cut_soil_area_m2=3.0,
|
||
cut_rock_area_m2=1.0,
|
||
ditch_area_m2=0.4,
|
||
cut_rock_kind="ripping_rock",
|
||
),
|
||
]
|
||
row = build_rows(stations)[1]
|
||
assert row.ditch_soil_area_m2 == pytest.approx(0.3)
|
||
assert row.ditch_rock_area_m2 == pytest.approx(0.1)
|
||
|
||
|
||
def test_값을_자르지_않을것() -> None:
|
||
"""품셈 1-2-2 는 표기 규칙이다 — 엔진은 전정밀로 둔다(PLAN 8-16)."""
|
||
stations = [StationArea(chainage_m=0.0), StationArea(chainage_m=7.0, cut_soil_area_m2=1.0)]
|
||
row = build_rows(stations)[1]
|
||
assert row.cut_soil_volume_m3 == pytest.approx(3.5)
|
||
assert row.cut_soil_adjusted_m3 == pytest.approx(3.15)
|
||
assert repr(row.cut_soil_adjusted_m3) != "3.2"
|
||
|
||
|
||
def test_합계행() -> None:
|
||
rows = build_rows(거창_앞_네_측점())
|
||
total = totals(rows)
|
||
assert total["distance_m"] == pytest.approx(30.0)
|
||
assert total["cut_soil_volume_m3"] == pytest.approx(
|
||
sum(r.cut_soil_volume_m3 for r in rows)
|
||
)
|
||
|
||
|
||
def test_표_모양() -> None:
|
||
table = build_table(거창_앞_네_측점())
|
||
assert table["method"] == "average_end_area"
|
||
assert table["station_count"] == 4
|
||
assert table["conversion_factors"] is EARTHWORK_CONVERSION_FACTORS
|
||
assert len(table["rows"]) == 4
|
||
assert "cut_soil_adjusted_m3" in table["rows"][1]
|
||
|
||
|
||
def test_설계결과에서_담기() -> None:
|
||
"""B06 설계 결과의 키 이름을 그대로 받는다 — 이름이 어긋나면 0 이 조용히 들어간다."""
|
||
design = {
|
||
"cut_soil_area_m2": 1.5,
|
||
"cut_rock_area_m2": 0.5,
|
||
"fill_area_m2": 2.0,
|
||
"ditch_area_m2": 0.18,
|
||
"cut_rock_kind": "blasting_rock",
|
||
}
|
||
area = StationArea.from_design(20.0, design)
|
||
assert area.chainage_m == 20.0
|
||
assert area.cut_soil_area_m2 == 1.5
|
||
assert area.cut_rock_kind == "blasting_rock"
|
||
|
||
|
||
def test_측점_순서가_뒤죽박죽이어도_이정순으로() -> None:
|
||
stations = [
|
||
StationArea(chainage_m=20.0, cut_soil_area_m2=1.0),
|
||
StationArea(chainage_m=0.0),
|
||
StationArea(chainage_m=10.0, cut_soil_area_m2=2.0),
|
||
]
|
||
rows = build_rows(stations)
|
||
assert [r.chainage_m for r in rows] == [0.0, 10.0, 20.0]
|