248 lines
11 KiB
Python
248 lines
11 KiB
Python
# ruff: noqa: F811 — 임시 층 fixture(world)를 test_m02_labor_ref 에서 받아 씀
|
|
"""826-3 사본 = 셈이 실제로 읽은 줄만(요구 806 · 808) · SK 저장 길 한 번씩.
|
|
|
|
지킴: 사본 줄 = 읽은 줄(닫힌 묶음 수백 줄 → 열 줄 안팎) · 금액 = 닫힌 묶음 사본과 같음 ·
|
|
M01 값 바뀌어도 그대로 · 옵션(기계) 바꿈 = 미리 셈 「사본없음 n」 + 지금 M01 값 → [저장] 때 박음
|
|
(남은 줄 = 사본 값 그대로) · [단가 갱신] · [재생성] · 층 복사 · 일위대가 · 사전조합 사본도 ·
|
|
옛 큰 사본 SK 그대로 읽힘 · 다음 [저장] 때 줄어듦 · 저장 한 번에 M01 모으기 0 · SK 파일 읽기 한 번.
|
|
M01 바꿈 = 메모리 색인 사본(정본 파일 안 고침) · 층 = 임시 storage.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import copy
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from M01_MasterData import M01_MasterData_Store as m01
|
|
from M02_MasterTemplete import M02_Doc_Sk_Path as path
|
|
from M02_MasterTemplete import M02_Item_Prices as prices
|
|
from M02_MasterTemplete import M02_Labor_Ref as refs
|
|
from M02_MasterTemplete import M02_MasterTemplete_Store as store
|
|
from M02_MasterTemplete import M02_Sangeun_Calc as calc
|
|
from M02_MasterTemplete import M02_Sangeun_Copy as skc
|
|
from resources.tester.test_795_2_sc_copy import _labor, _read, _sc, _unit
|
|
from resources.tester.test_822_1_copy_gap import (
|
|
DIG,
|
|
DIG2_NO,
|
|
MACHINE,
|
|
_at,
|
|
_fuel_and_crew,
|
|
_move,
|
|
_price,
|
|
_sk,
|
|
_stack,
|
|
_sum,
|
|
)
|
|
from resources.tester.test_m02_labor_ref import world # noqa: F401 — 같은 임시 층
|
|
|
|
DIG_BASE = "GC000088" # 터파기(기계) 보통토사 — 「기계」 고르기 후보를 닫힌 묶음이 다 담음
|
|
|
|
|
|
def _file(folder, key) -> dict:
|
|
return json.loads((folder / "sangeun" / f"{key}.json").read_bytes())
|
|
|
|
|
|
def _keys(copy_: dict) -> list[str]:
|
|
return [str(r.get("키")) for r in [*copy_["로직"], *(copy_.get("단가") or [])]]
|
|
|
|
|
|
def _closed(doc: dict) -> int:
|
|
"""옛 길(후보 전부 닫힌 묶음) 줄 수."""
|
|
got = prices.collect([str(doc["바탕"]["로직"])])
|
|
return sum(len(d[m01.items_key(d)]) for k, d in got.items() if not k.startswith("_"))
|
|
|
|
|
|
def test_base_logic_read_rows_only(world):
|
|
"""견본(터파기 기계) — 닫힌 묶음 → 읽은 줄만 · 자원 줄 한 자리 ·
|
|
금액 = 닫힌 묶음 사본."""
|
|
me = world["personal"]
|
|
key = _sk(me, 바탕={"로직": DIG_BASE}, 단위="㎥")
|
|
doc = _file(me, key)
|
|
have = doc[skc.KEY]
|
|
assert _closed(doc) >= 3 * len(_keys(have))
|
|
assert len(_keys(have)) <= 12 and len(have["단가"]) < 10
|
|
assert _keys(have) == _keys(doc["수식"]) # 두 자리 같은 줄(꼴 그대로)
|
|
full = {**doc, skc.KEY: skc.stamp(doc)} # 옛 길 사본(후보 전부)
|
|
assert len(_keys(full[skc.KEY])) >= 3 * len(_keys(have))
|
|
with store.at(me):
|
|
old = calc.calc_doc(full, None, False)["기준"]
|
|
new = calc.calc_doc(doc, None, False)["기준"]
|
|
assert new == old and new["계"] > 0
|
|
assert _sum(me, key) == new["계"]
|
|
|
|
|
|
def test_m01_change_kept_then_price(world, monkeypatch):
|
|
"""만든 뒤 M01(기계 · 유가 · 노임) 바뀜 → 금액 그대로 + 단가새값 →
|
|
[단가 갱신] → 반영 · 그래도 작음."""
|
|
me = world["personal"]
|
|
key = _sk(me, 바탕={"로직": DIG_BASE}, 단위="㎥")
|
|
was = _sum(me, key)
|
|
read = set(_keys(_file(me, key)[skc.KEY]))
|
|
moved = [k for k in read if k[:2] in ("EQ", "LB", "MO")]
|
|
assert moved
|
|
_move(monkeypatch, *moved)
|
|
assert _sum(me, key) == was
|
|
assert _at(me, path.read, key)["사본"]["단가새값"] is True
|
|
got = _price(me, key)
|
|
assert set(got["바뀐"]) == set(moved) and got["후"] > was
|
|
assert set(_keys(_file(me, key)[skc.KEY])) == read
|
|
|
|
|
|
def test_machine_swap_preview_then_save(world, monkeypatch):
|
|
"""기계 바꿈(옵션) — 미리 셈 = 새 기계 지금 M01 값 + 「사본없음 n」 · [저장] = 새 줄만 박음 ·
|
|
남은 줄(유가 · 노임) = 사본 값 그대로 · 안 읽는 옛 기계 줄은 빠짐."""
|
|
me = world["personal"]
|
|
key = _sk(me)
|
|
_stack(me, key, [("기계", MACHINE, "묶음")])
|
|
first = _file(me, key) # 줄 쌓기(수식 길) = 수식 사본 값 몫
|
|
before = set(_keys(first["수식"]))
|
|
assert DIG in before
|
|
fuel, crew = _fuel_and_crew()
|
|
w = m01.loaded()[1]
|
|
dig2 = w.numbers["EQ"][DIG2_NO]["키"]
|
|
assert dig2 not in before
|
|
files, live = m01.loaded()
|
|
_move(monkeypatch, dig2) # 바꾸는 때의 M01 = 새 기계 값 두 배
|
|
fake_dig2 = m01.loaded()[1]
|
|
_move(monkeypatch, fuel, crew) # 사본에 든 유가 · 노임도 바뀜(사본 값이 이겨야 함)
|
|
got = _at(me, path.read, key)
|
|
doc = copy.deepcopy(got["문서"])
|
|
for var in doc["변수"]:
|
|
if (var.get("연결") or {}).get("갈래") == "단가산출":
|
|
var["연결"]["입력"] = {"기계": f"'{DIG2_NO}'"}
|
|
look = _at(me, path.preview, key, {"문서": doc})
|
|
assert look["사본"]["사본없음"] > 0 # 저장하면 지금 값으로 굳음
|
|
_at(me, path.save, key, {"문서": doc, "판": got["판"]})
|
|
after = _file(me, key)
|
|
now = set(_keys(after["수식"]))
|
|
assert dig2 in now and DIG not in now and {fuel, crew} <= now
|
|
old_rows = {str(r["키"]): r for r in first["수식"]["단가"]}
|
|
new_rows = {str(r["키"]): r for r in after["수식"]["단가"]}
|
|
assert new_rows[fuel] == old_rows[fuel] and new_rows[crew] == old_rows[crew]
|
|
amount = _sum(me, key)
|
|
assert amount == look["셈"]["계"]
|
|
# 기준 = 새 기계만 두 배인 M01 로 처음 만든 같은 SK(유가 · 노임 = 처음 값)
|
|
monkeypatch.setattr(m01, "loaded", lambda: (files, fake_dig2))
|
|
ref = _sk(me)
|
|
_stack(me, ref, [("기계", {**MACHINE, "입력": {"기계": f"'{DIG2_NO}'"}}, "묶음")])
|
|
assert _sum(me, ref) == amount
|
|
monkeypatch.setattr(m01, "loaded", lambda: (files, live))
|
|
assert _sum(me, key) == amount # M01 되돌아가도 그대로
|
|
|
|
|
|
def test_regen_slim(world, monkeypatch):
|
|
"""[재생성] — 지금 M01 로 다시 찍어도 읽은 줄만 · 그 뒤 M01 바뀌어도 그대로."""
|
|
me = world["personal"]
|
|
key = _sk(me, 바탕={"로직": DIG_BASE}, 단위="㎥")
|
|
read = [k for k in _keys(_file(me, key)[skc.KEY]) if k[:2] in ("EQ", "MO")]
|
|
_move(monkeypatch, *read)
|
|
판 = _at(me, path.read, key)["판"]
|
|
_at(me, path.save, key, {"할일": skc.REGEN, "판": 판})
|
|
after = _file(me, key)[skc.KEY]
|
|
assert len(_keys(after)) <= 12
|
|
was = _sum(me, key)
|
|
_move(monkeypatch, *read)
|
|
assert _sum(me, key) == was
|
|
|
|
|
|
def test_layer_copy_slim(world, monkeypatch):
|
|
"""층 복사(개인 → 회사) — 받은 사본째 · 읽은 줄만 · 원본 M01 바뀐 뒤 복사해도 그 값."""
|
|
me, co = world["personal"], world["company"]
|
|
key = _sk(me, 바탕={"로직": DIG_BASE}, 단위="㎥")
|
|
was = _sum(me, key)
|
|
_move(monkeypatch, DIG, *[k for k in _keys(_file(me, key)[skc.KEY]) if k[:2] == "EQ"])
|
|
ref = {"층": "personal", "주인": "7/42", "키": key}
|
|
with store.at(co):
|
|
doc = refs.read_ref(ref)
|
|
new = refs.create("sangeun", refs.carry(refs.origin_mark(doc, ref), ("personal", "7/42")))
|
|
assert _sum(co, new["이름"]) == was
|
|
assert _keys(_file(co, new["이름"])[skc.KEY]) == _keys(_file(me, key)[skc.KEY])
|
|
|
|
|
|
def test_labor_and_combo_slim(world, monkeypatch):
|
|
"""일위대가 · 사전조합 사본 — 닫힌 묶음보다 작음 · 금액 그대로 · M01 바뀌어도 그대로."""
|
|
me = world["personal"]
|
|
lines = [{"로직": DIG_BASE, "수량": {"손": 1}}]
|
|
lab = _labor(me, lines)
|
|
sc = _sc(me, lines)
|
|
full = prices.collect([DIG_BASE])
|
|
closed = sum(len(d[m01.items_key(d)]) for k, d in full.items() if not k.startswith("_"))
|
|
for doc in (lab, _read(me, "precombo", sc)):
|
|
assert len(_keys(doc[skc.KEY])) * 3 <= closed
|
|
assert _keys(doc[skc.KEY]) == _keys(doc["수식"])
|
|
unit = _unit(me, sc)
|
|
assert unit > 0
|
|
_move(monkeypatch, *[k for k in _keys(lab[skc.KEY]) if k[:2] in ("EQ", "LB", "MO")])
|
|
assert _unit(me, sc) == unit
|
|
|
|
|
|
def test_old_big_copy_reads_then_slims(world):
|
|
"""옛 큰 사본(후보 전부) SK — 그대로 읽힘(같은 금액 · 열기 = 안 고쳐 씀) ·
|
|
다음 [저장] 때 줄어듦."""
|
|
me = world["personal"]
|
|
key = _sk(me, 바탕={"로직": DIG_BASE}, 단위="㎥")
|
|
was = _sum(me, key)
|
|
file = me / "sangeun" / f"{key}.json"
|
|
raw = json.loads(file.read_bytes())
|
|
big = skc.stamp(raw)
|
|
raw[skc.KEY] = big
|
|
raw["수식"] = {**raw["수식"], **{k: big[k] for k in ("판", "로직", "단가판", "단가")}}
|
|
file.write_text(json.dumps(raw, ensure_ascii=False), encoding="utf-8")
|
|
before = file.read_bytes()
|
|
assert _sum(me, key) == was
|
|
assert file.read_bytes() == before
|
|
with store.at(me):
|
|
got = store.read("sangeun", key)
|
|
store.write("sangeun", key, got["판"], got["문서"])
|
|
assert len(_keys(_file(me, key)[skc.KEY])) * 3 <= len(big["로직"]) + len(big["단가"])
|
|
assert _sum(me, key) == was
|
|
|
|
|
|
def test_save_path_once(world, monkeypatch):
|
|
"""SK 다시 저장 한 번 — M01 모으기 0 · SK 파일 읽기(셈 쪽) 한 번 · 옛 셈 한 번."""
|
|
me = world["personal"]
|
|
key = _sk(me, 바탕={"로직": DIG_BASE}, 단위="㎥")
|
|
count = {"모으기": 0, "읽기": 0, "셈": 0}
|
|
collect, run, read_bytes = prices.collect, calc.run, Path.read_bytes
|
|
|
|
def counted(name, fn):
|
|
def wrap(*a, **k):
|
|
count[name] += 1
|
|
return fn(*a, **k)
|
|
|
|
return wrap
|
|
|
|
def reading(self):
|
|
if self.name == f"{key}.json":
|
|
count["읽기"] += 1
|
|
return read_bytes(self)
|
|
|
|
with store.at(me):
|
|
got = store.read("sangeun", key)
|
|
monkeypatch.setattr(prices, "collect", counted("모으기", collect))
|
|
monkeypatch.setattr(calc, "run", counted("셈", run))
|
|
monkeypatch.setattr(Path, "read_bytes", reading)
|
|
store.write("sangeun", key, got["판"], got["문서"])
|
|
# 읽기 = 사본 정함 한 번 + 판 맞춤(쓰기 전) + 새 판(쓰기 뒤)
|
|
assert count == {"모으기": 0, "읽기": 3, "셈": 1}
|
|
|
|
|
|
def test_doc_path_save_keeps_both_slots(world):
|
|
"""수식 길 저장(옵션 Type · 지역 바꿈) — 사본 · 수식 두 칸 같은 줄 · 새로 읽은 줄 더함 ·
|
|
금액 = 미리 셈 = 같은 옵션으로 처음 만든 것."""
|
|
me = world["personal"]
|
|
key = _sk(me, 바탕={"로직": DIG_BASE}, 단위="㎥")
|
|
got = _at(me, path.read, key)
|
|
doc = copy.deepcopy(got["문서"])
|
|
for var in doc["변수"]:
|
|
if var.get("열쇠") in ("Type", "지역"):
|
|
var["연결"]["값"] = {"Type": "TypeⅢ", "지역": "경북"}[var["열쇠"]]
|
|
look = _at(me, path.preview, key, {"문서": doc})
|
|
assert look["사본"]["사본없음"] > 0
|
|
_at(me, path.save, key, {"문서": doc, "판": got["판"]})
|
|
after = _file(me, key)
|
|
assert set(_keys(after[skc.KEY])) == set(_keys(after["수식"]))
|
|
assert len(_keys(after[skc.KEY])) >= 6
|
|
assert _sum(me, key) == look["셈"]["계"] != got["셈"]["계"]
|