"""B09 [저장] 속도 — 같은 결과 범위 안 다시 셈 줄임 지킴. - 산근 두 번 셈(183-1) = 1차가 본 단가(있음 · 값)가 같을 때만 1차 풀이 그대로(`_Prices.same`) - M01 `steady()` 범위 = 파일 자국 한 번 · `stale` 뒤 다시 셈 · 범위 밖은 늘 셈 - B08 `once()` 범위 = 채집석 공제가 자재 집계표 답을 다시 씀(셈 한 번) """ from __future__ import annotations import asyncio import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(ROOT)) from B08_Quantity import B08_Quantity_Router_Material as material # noqa: E402 from B09_Estimation.B09_Estimation_Sangeun import _Prices # noqa: E402 from M01_MasterData import M01_MasterData_Store_Cache as cache # noqa: E402 SHEETS = { "labor": [{"key": "L1", "price": 100}, {"key": "L2", "price": 5}], "compare": [{"key": "M1", "applied": 3}], "machine": [{"key": "E1", "labor": 1, "material": 2, "expense": 3}], } def _seen() -> _Prices: got = _Prices(SHEETS) got.labor.get("L1") assert "M9" not in got.material got.machine.get("E1") return got def test_산근_같은_단가면_다시_씀() -> None: other = {**SHEETS, "labor": [{"key": "L1", "price": 100}, {"key": "L2", "price": 999}]} assert _seen().same(_Prices({**other, "compare": []})) # 안 본 L2 · M1 은 안 셈 def test_산근_본_단가_바뀌면_다시_셈() -> None: assert not _seen().same(_Prices({**SHEETS, "labor": [{"key": "L1", "price": 101}]})) added = {**SHEETS, "compare": [{"key": "M9", "applied": 1}]} assert not _seen().same(_Prices(added)) # 없던 자재가 생김 machine = {**SHEETS, "machine": [{"key": "E1", "labor": 1, "material": 2, "expense": 4}]} assert not _seen().same(_Prices(machine)) def test_M01_범위_안_자국_한_번(monkeypatch) -> None: calls = [] monkeypatch.setattr(cache, "_stamps", lambda folder: calls.append(folder) or {}) folder = Path("x") cache._now(folder) cache._now(folder) assert len(calls) == 2 # 범위 밖 = 늘 셈 with cache.steady(): cache._now(folder) cache._now(folder) assert len(calls) == 3 cache.stale([]) # 스스로 고친 자리 = 다시 셈 cache._now(folder) assert len(calls) == 4 cache._now(folder) assert len(calls) == 5 def test_B08_범위_안_자재_집계표_한_번(monkeypatch, tmp_path) -> None: calls = [] rows = [{"key": material.DEDUCT_KEY, "amount": 12.5}] async def sheets(_pid, _root, _over): calls.append(1) return {"sheets": {"material": {"rows": rows}}} async def root(_pid): return tmp_path monkeypatch.setattr(material, "_sheets", sheets) monkeypatch.setattr(material, "_project_root", root) monkeypatch.setattr(material, "quantity_settings", lambda _root: {}) async def run() -> list: out = [await material.picked_deduction("p", tmp_path)] with material.once(): await material.material_sheets("p") out.append(await material.picked_deduction("p", tmp_path)) out.append(await material.picked_deduction("p", tmp_path)) return out assert asyncio.run(run()) == [12.5, 12.5, 12.5] assert len(calls) == 3 # 범위 안 공제 = 셈 없음