Files
Aislo/resources/tester/test_m02_hopyo_grid.py
eomsangdonandClaude Opus 5.5 48848bb287 refactor(785-7): 옛 맞춤 층 Python 지움 · 서버 새 길로 정리 · 낡은 시험 정리
- 지움(git rm) 10 파일 3,374 줄: M02_Hopyo_Finger · Ours · Option · Fit · Combine · Verdict · Line · SkLink · SkPatch · Basis
- Match: 흐름 몫(candidates · name_cands · fix_typo · clause · b_order · _logic_specs · _line_mod · units_of · _state · view · guess · picks · chain) 지움 · 이름 도구 몫 · line_key 남김
- Words: conds · cond_score · close · cosine · jacc 지움 / Shares: sections 지움(trade · eq_key 남김)
- 옮김: Finger.kind_of → Fixed.kind_of · SkLink(sk_line · kept · left · LEFT · WHY) → Sangeun · SkPatch 기계 몫(MACH_IN · MACHINE · SOLO · _mach_logics) → Units.mach_logics
- Sangeun: 옛 /sangeun 몸(build · _sure · Maker.basis · judge · plan · make) 지움 · Kids: first · proposal · order 지움 · Build: build() · unlinked() 지움(모두 고정 Builder · build_all · _order · _origins 남김)
- Router: 옛 길 지움(GET hopyo/{키}/{번} · guess · hopyo-picks · hopyo-build · hopyo-unlinked · hopyo/{키}/sangeun) · GET hopyo/{키} = Judge.view(1차 줄 판정 줄상태 · 만든 · 블록 풀이 셈)
- Marks: 칠 = Judge.judged 만 · Forget: 맞춤 캐시 지움 줄 걷음 · Ledger: Ours.version 판 칸 걷음 · Item: Kids.first 걷음
- Row(덧): 단산 줄 = 장부 짝이 있어도 늘 「2차 필요」(장부 = 1차 후보 힌트만)

시험 정리(까닭 = 지운 길 · 모듈만 시험함):
- 지움 11 파일: test_m02_hopyo_finger · fit · golden · option · ours · basis · seam · flow · draft_calc · test_635 · test_628(지문 · 순위 · 옵션 거꾸로 · 맡은 절 · 옛 확인 흐름)
- 함수 지움: /sangeun · /hopyo-build · /hopyo-unlinked · hopyo-picks · 옛 줄 맞춤 보기를 부르던 것(572 · 718_1 · 729 · 739_1 · 777_1 · 778_5 · 780_1 · labor_national · 705_3 · m02_hopyo_match · 746_1)
- test_621 S2(지문 해시) 지움 · S1 남김 · test_m02_hopyo_build = 장부 길 시험만(PUT 으로 심음)
- 새 길로: 779_2(줄상태 = 1차 판정 · 칠 셈 전 None) · grid · stmate(hopyo-judge 줄 판) · 778_1 · 778_2(Units.mach_logics) · 642_6(Marks 원문) · 642_3 장부 짝 단산 줄 2차 지킴

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 01:15:20 +09:00

160 lines
6.9 KiB
Python

"""일위대가 실무자료 엑셀꼴 격자(PLAN 329-1 · `M02_Hopyo_Grid` · `GET hopyo-grid/{키}`).
북부청 임도 xls — 병합 11 · 15열 · B20 「제3호표」 · `#,##0` · 호표 68 행 범위 안 겹침 ·
제3호표 [20, 24] · 올리면 격자도 · 200 / 옛 파일 404 · 지우면 격자도 · 역할 · xlsx 값만 ·
STmate 격자(일위대가표 · 단가산출근거 · 숨은 칸 글 뺌 · 338) ·
master_data 그대로.
"""
import pytest
from M02_MasterTemplete import M02_Hopyo_Excel as hx
from M02_MasterTemplete import M02_Hopyo_Grid as hg
from M02_MasterTemplete import M02_Hopyo_Store as hs
from M02_MasterTemplete import M02_Template_Layers as layers
from resources.tester import test_m02_hopyo_excel as base
from resources.tester.test_m02_hopyo_excel import (
NORTH,
URL,
_post,
_xlsx,
master_hash,
)
client = base.client # 공용 고정물(임시 층)
GRID = "/api/m02/layers/{}/hopyo-grid/{}"
@pytest.fixture(scope="module")
def north() -> dict:
data = NORTH.read_bytes()
return hg.read(NORTH.name, data, hx.read_book(NORTH.name, data))
def _sheet(grid: dict, name: str) -> dict:
return next(s for s in grid["책"]["시트"] if s["이름"] == name)
def test_격자_모양(north):
book = north["책"]
assert (book["종류"], book["판"], book["활성"]) == ("통합문서", 1, "s1")
assert [s["이름"] for s in book["시트"]] == ["일위대가", "단가산출총괄표", "단가산출"]
sheet = _sheet(north, "일위대가")
assert len(sheet["병합"]) == 11 and "B1:O2" in sheet["병합"]
assert len(sheet["열"]) == 15 and sheet["열"]["C"]["폭"] == round(7208 / 256, 2)
assert sheet["틀고정"] == {"행": 4}
assert sheet["칸"]["B20"]["값"] == "제3호표"
assert sheet["칸"]["H5"]["값"] == 1040052
styles = book["서식"]
assert styles[0] == {} and any(s.get("형식") == "#,##0" for s in styles)
assert any(s.get("테두리") for s in styles)
assert _sheet(north, "단가산출")["칸"]["B4"]["값"] == "1.유용토운반(무대)[㎥]"
def test_호표_단산_행_범위(north):
rows = [h["행"] for h in north["호표"]]
assert len(rows) == 68
assert all(a[1] < b[0] for a, b in zip(sorted(rows), sorted(rows)[1:], strict=False))
assert next(h for h in north["호표"] if h["번"] == 3) == {
"번": 3,
"이름": "임도표지석",
"행": [20, 24],
}
assert len(north["단산"]) == 95
assert next(b for b in north["단산"] if b["번"] == 93)["행"] == [4229, 4244]
def test_줄_행(north):
book = hx.read_book(NORTH.name, NORTH.read_bytes())
three = next(h for h in book["호표"] if h["번"] == 3)
assert three["행"] == [20, 24] and [x["행"] for x in three["줄"]] == [21, 22, 23, 24]
def test_올리기_격자_200_404_지우기(client):
before = master_hash()
assert _post(client).status_code == 200
res = client.get(GRID.format("personal", "HP-000001"))
assert res.status_code == 200, res.text
got = res.json()
assert got["책"]["열"] == "HP-000001" and len(got["호표"]) == 68
folder = layers.personal_dir(7, 42)
path = folder / hs.DIRNAME / hs.GRID / "HP-000001.json"
assert path.is_file()
assert [r["키"] for r in client.get(URL.format("personal")).json()["줄"]] == ["HP-000001"]
path.unlink() # 옛 파일(324) = 격자 없음
old = client.get(GRID.format("personal", "HP-000001"))
assert old.status_code == 404 and old.json()["detail"] == "격자 없음 — 다시 올리면 보임"
assert client.delete(URL.format("personal") + "/HP-000001").status_code == 200
assert _post(client).status_code == 200 # 718-1 — 같은 엑셀은 지운 뒤 새 번
assert client.get(GRID.format("personal", "HP-000002")).status_code == 200
assert client.delete(URL.format("personal") + "/HP-000002").status_code == 200
assert not (folder / hs.DIRNAME / hs.GRID / "HP-000002.json").exists()
assert client.get(GRID.format("personal", "HP-000002")).status_code == 404
assert client.get(GRID.format("personal", "../x")).status_code == 404
gone = client.get(URL.format("personal") + "-judge/HP-000001/3") # 718-1 지운 뒤 = 없음
assert gone.status_code == 404 and "없는 실무자료" in gone.json()["detail"]
assert master_hash() == before
@pytest.mark.parametrize(
("role", "layer", "owner", "want"),
[
({"role": "USER"}, "personal", None, 200),
({"role": "USER"}, "personal", "7/43", 403),
({"role": "USER"}, "company", None, 200),
({"role": "USER"}, "system", None, 200),
],
)
def test_역할_읽기(client, role, layer, owner, want):
client.who.update({"role": "SYSTEM_ADMIN"})
assert _post(client, layer if want == 200 else "personal").status_code == 200
client.who.update(role)
params = {"owner": owner} if owner else {}
assert client.get(GRID.format(layer, "HP-000001"), params=params).status_code == want
@pytest.mark.parametrize("layer", ["company", "system"])
def test_위_층_격자_읽기(client, layer):
"""아래 층 사용자가 위 층 목록 키로 위 층 파일 격자를 읽음."""
client.who.update({"role": "SYSTEM_ADMIN"})
assert _post(client, layer).status_code == 200
client.who.update({"role": "USER"})
rows = client.get(URL.format(layer)).json()[
"줄"
] # 위 층 목록(옛 「실무 호표」 고르기 줄 갈음 · 785-7)
res = client.get(GRID.format(layer, rows[0]["키"]))
assert res.status_code == 200 and len(res.json()["호표"]) == 68
def test_xlsx_값만():
data = _xlsx()
grid = hg.read("a.xlsx", data, hx.read_book("a.xlsx", data))
sheet = grid["책"]["시트"][0]
assert sheet["이름"] == "일위대가" and sheet["틀고정"] == {"행": 4}
assert sheet["칸"]["B5"] == {"값": "제 1 호표"} and sheet["칸"]["E6"] == {"값": 0.5}
assert "K6" not in sheet["칸"] # 머리 글(앞 4 줄) 마지막 열 J 까지
assert grid["호표"] == [{"번": 1, "이름": "표지석", "행": [5, 6]}] and grid["단산"] == []
def test_STmate_격자():
from resources.tester.test_m02_hopyo_stmate import _path
path = _path("영월")
data = path.read_bytes()
parsed = hx.read_book(path.name, data)
grid = hg.read(path.name, data, parsed)
assert [s["이름"] for s in grid["책"]["시트"]] == [
"일위대가표",
"단가산출근거목록표",
"단가산출근거",
]
cells = _sheet(grid, "일위대가표")["칸"]
one = grid["호표"][0]
assert one == {"번": 1, "이름": "녹생토(종자배합)", "행": [5, 10]}
assert cells[f"A{one['행'][0]}"]["값"].strip().startswith("제")
assert cells["A10"]["값"] == "보통인부"
calc = _sheet(grid, "단가산출근거")["칸"]
block = next(b for b in grid["단산"] if b["번"] == 2)
assert calc[f"B{block['행'][0] + 1}"]["값"].startswith("구조물터파기(인력)")
assert not any(str(c.get("값")).startswith("_x000") for c in {**cells, **calc}.values())