- 탭 셋 일위대가표 · 단가산출표 · 단가산출 상세 = 서버 역할 id(이름으로 안 찾음 · STmate 단가산출근거 뛰기 풀림) · 두 형식 같은 탭 글 · 원본 시트 이름은 막대 - 새 logic/M02_MasterTemplete_Hopyo_SheetMap.ts(순수 — 줄 칠 · 블록 칠 · 머리 행 = 가장 나쁜 칠 · 뛸 곳) · 「이어짐」 = 확인 창 체크 규칙(캐시가 이김) - 새 M02_MasterTemplete_Hopyo_SheetNav.ts — 범례 createLegend · 맥락 단추(상세 · 목록 · 하위 호표 · 부르는 줄 차례로) · 뒤로 · 두 번 누름 = 첫 단추 · 다시 칠(목록 다시 읽음 · 캐시 고침 · 만들기) · 칠은 A 열 ~ 끝 열 · 띠는 A 열 - Hopyo_Sheet.ts = 잇는 줄만(580 → 609) · 줄 행 누름 = 그 줄 그대로 · 머리 행 = 호표 영역 - 779-6 — 같은 파일 창은 새 모달 대신 그 창을 앞으로 꺼내 그 자리로 · 닫기 = 제자리로 내림 · 마지막 격자 다시 씀(확인 · 고르기 창 [엑셀 보기] 모두 openSheet 한 곳으로 지나감) - Hopyo_Check.ts saveDraft = 다시 칠 알림 한 줄(663 → 662) · Hopyo_Api.ts at 내보냄(676 그대로) - 서버 Match.view — 목록 「후보」 중 이름 후보 안 찾은 줄만 다시 셈(뒤 셈 끝 뒤) → 확인 창 「없음」과 같음(빨강) · 북부청 임도 목록 응답 2.81 → 3.49 초(다시 셈 48 줄 · 없음 11) - 시험: 새 test_779_4_sheet_map(꼴 표 · 블록 칠 · 실물 EST · STmate 칠 행 수 · 뛸 곳) · test_m02_hopyo_screen 779 지킴 더함 - 낡은 시험 고침: test_779_2 기대 「후보 ≠ 없음 허용」 → 「모두 같음」(까닭 = 이번 덧 셈) · 도우미 helper_m02_hopyo_check · helper_729_3_hopyo_left 에 document 대역(까닭 = saveDraft 알림이 document 를 씀) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
173 lines
8.3 KiB
Python
173 lines
8.3 KiB
Python
"""779-4 엑셀 보기 창 칠 · 뛸 곳(`logic/M02_MasterTemplete_Hopyo_SheetMap.ts` · Node) —
|
|
줄 칠 꼴 표(「이어짐」 = 확인 창 체크 규칙 · 캐시가 이김 · 「없음」 = 빨강) · 블록 칠(만든 SK › 판정 「예상」) ·
|
|
실물 두 형식(북부청 임도 EST · 동부청 영월 STmate): 칠 행 수 = 줄 수 · 머리 행 = 가장 나쁜 칠 ·
|
|
단산 줄 → 단가산출 상세(역할 id · STmate 「단가산출근거」) · 목록 행 · 부르는 줄 차례."""
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import warnings
|
|
|
|
import pytest
|
|
|
|
from M02_MasterTemplete import M02_Hopyo_Excel as hx
|
|
from M02_MasterTemplete import M02_Hopyo_Grid as hg
|
|
from resources.tester.helper_m02_hopyo_golden import FILES
|
|
|
|
warnings.filterwarnings("ignore", category=UserWarning, module="openpyxl")
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
STATES = ("맞음", "다른 점", "후보", "없음", "%", "노임", "별칭", "뺌")
|
|
|
|
|
|
def _node(payload: dict) -> dict:
|
|
proc = subprocess.run(
|
|
["node", os.path.join(HERE, "helper_779_4_sheet_map.cjs")],
|
|
input=json.dumps(payload, ensure_ascii=False),
|
|
capture_output=True,
|
|
text=True,
|
|
encoding="utf-8",
|
|
check=False,
|
|
)
|
|
assert proc.returncode == 0, proc.stderr
|
|
return json.loads(proc.stdout)
|
|
|
|
|
|
def _d(체크=None, 대상=None, 뺌=None) -> dict:
|
|
return {"체크": 체크 or {}, "대상": 대상 or {}, "뺌": 뺌 or {}}
|
|
|
|
|
|
def test_줄_칠_꼴표():
|
|
rows = [
|
|
(("맞음", True, None, 0), ("success", False)),
|
|
(("별칭", True, None, 0), ("success", False)),
|
|
(("호표", True, None, 0), ("success", False)),
|
|
(("다른 점", True, None, 0), ("warning", False)),
|
|
(("다른 점", False, None, 0), ("info", False)),
|
|
(("후보", False, None, 0), ("info", False)),
|
|
(("호표", False, None, 0), ("info", False)),
|
|
(("없음", False, None, 0), ("danger", False)), # 확인 창 「없음」 = 못 이음
|
|
(("노임", False, None, 0), ("danger", False)),
|
|
(("%", False, None, 0), ("muted", False)),
|
|
(("뺌", False, None, 0), ("muted", False)),
|
|
# 캐시가 이김 — 끈 맞음 = 고를 것 · 고른 대상 + 체크 = 이어짐(내가 고름 띠)
|
|
(("맞음", True, _d({"0": False}), 0), ("info", False)),
|
|
(("없음", False, _d({"0": True}, {"0": [{"배": 1}]}), 0), ("success", True)),
|
|
(("다른 점", False, _d({"0": True}, {"0": [{"배": 2}]}), 0), ("success", True)),
|
|
(("없음", False, _d({"0": True}, {"0": [{"배": None}]}), 0), ("danger", True)), # 배 없음
|
|
(("후보", False, _d({"3": True}, {"3": []}), 3), ("info", True)), # 대상 없음 = 못 체크
|
|
(("맞음", True, _d(뺌={"0": "로직없음"}), 0), ("muted", True)),
|
|
(("%", False, _d({"0": True}, {"0": [{"배": 1, "비율": "x"}]}), 0), ("success", True)),
|
|
(("%", False, _d({"0": True}, {"0": [{"배": 1}]}), 0), ("muted", True)),
|
|
(("맞음", True, _d({"5": False}), 0), ("success", False)), # 다른 줄 캐시 = 서버 제안
|
|
]
|
|
got = _node({"tones": [list(a) for a, _ in rows]})["tones"]
|
|
assert [(x["tone"], x["mine"]) for x in got] == [b for _, b in rows]
|
|
|
|
|
|
def test_블록_칠():
|
|
marks = [
|
|
None, # 안 불림
|
|
{"번": 1, "판정": None, "SK": None, "갈래": None, "못옮김": []},
|
|
{"번": 2, "판정": "맞음", "SK": None, "갈래": None, "못옮김": []},
|
|
{"번": 3, "판정": "다른 점", "SK": None, "갈래": None, "못옮김": []},
|
|
{"번": 4, "판정": "후보", "SK": None, "갈래": None, "못옮김": []},
|
|
{"번": 5, "판정": "후보", "SK": "SK-000009", "갈래": "기초", "못옮김": []},
|
|
{"번": 6, "판정": "맞음", "SK": "SK-000010", "갈래": "SK", "못옮김": []},
|
|
{"번": 7, "판정": "맞음", "SK": "SK-000011", "갈래": "SK", "못옮김": [{"이름": "x"}]},
|
|
]
|
|
got = _node({"blockTones": marks})["blocks"]
|
|
assert [x["tone"] for x in got] == [
|
|
"muted",
|
|
"muted",
|
|
"success",
|
|
"warning",
|
|
"info",
|
|
"success",
|
|
"warning",
|
|
"danger",
|
|
]
|
|
assert got[2]["글"].startswith("예상") and got[5]["글"].startswith("SK-000009")
|
|
assert "못옮김 1" in got[7]["글"]
|
|
|
|
|
|
@pytest.fixture(scope="module", params=["북부청임도", "동부청영월"])
|
|
def real(request):
|
|
path = FILES[request.param]
|
|
data = path.read_bytes()
|
|
parsed = hx.read_book(path.name, data)
|
|
grid = hg.read(path.name, data, parsed)
|
|
grid.pop("책")
|
|
return parsed, grid
|
|
|
|
|
|
def test_실물_칠_행_수_머리_행(real):
|
|
parsed, grid = real
|
|
briefs, n = [], 0
|
|
for h in parsed["호표"]:
|
|
states = []
|
|
for x in h["줄"]:
|
|
states.append([x["차례"], STATES[n % len(STATES)], n % 3 == 0])
|
|
n += 1
|
|
briefs.append({"번": h["번"], "줄상태": states})
|
|
got = _node({"grid": grid, "briefs": briefs, "blocks": []})
|
|
ilwi = grid["보기"]["일위대가표"]
|
|
paint = {int(k): v for k, v in got["paint"][ilwi].items()}
|
|
line_rows = {x["행"] for x in grid["줄"]}
|
|
assert len(line_rows) == n # 줄 행 1:1
|
|
assert line_rows <= set(paint) # 칠 칸 행 수 = 줄 상태 수
|
|
heads = {h["행"][0] for h in grid["호표"]} - line_rows
|
|
assert set(paint) == line_rows | heads
|
|
rank = ["muted", "success", "warning", "info", "danger"]
|
|
for h in grid["호표"]:
|
|
mine = [paint[x["행"]] for x in grid["줄"] if x["번"] == h["번"]]
|
|
if mine and h["행"][0] not in line_rows:
|
|
assert paint[h["행"][0]] == max(mine, key=rank.index), h["번"]
|
|
nothing = [x for b in briefs for x in b["줄상태"] if x[1] == "없음" and not x[2]]
|
|
assert nothing and all(
|
|
paint[r] == "danger"
|
|
for b in briefs
|
|
for at, s, c in b["줄상태"]
|
|
if s == "없음" and not c
|
|
for r in [next(x["행"] for x in grid["줄"] if (x["번"], x["차례"]) == (b["번"], at))]
|
|
)
|
|
# 블록 = 재료 없으면 밖(muted) · 상세 블록 행 · 목록 행 모두 칠
|
|
detail = {int(k) for k in got["paint"][grid["보기"]["단가산출상세"]]}
|
|
assert detail == {r for b in grid["단산"] for r in range(b["행"][0], b["행"][1] + 1)}
|
|
listed = {int(k) for k in got["paint"][grid["보기"]["단가산출표"]]}
|
|
assert listed == {
|
|
x["행"] for x in grid["목록"]["단산"] if x["번"] in {b["번"] for b in grid["단산"]}
|
|
}
|
|
|
|
|
|
def test_실물_뛸_곳(real):
|
|
parsed, grid = real
|
|
ids = grid["보기"]
|
|
calls = [x for x in grid["줄"] if x.get("단산")]
|
|
kids = [x for x in grid["줄"] if x.get("일위")]
|
|
listed = {x["번"]: x["행"] for x in grid["목록"]["단산"]}
|
|
block = {b["번"]: b["행"] for b in grid["단산"]}
|
|
callers: dict[int, list[int]] = {}
|
|
for x in calls:
|
|
callers.setdefault(x["단산"]["번"], []).append(x["행"])
|
|
many = next(no for no, rows in callers.items() if len(rows) > 1)
|
|
at = [[ids["일위대가표"], x["행"]] for x in calls + kids]
|
|
at += [[ids["단가산출표"], listed[many]], [ids["단가산출상세"], block[many][1]]]
|
|
at += [[ids["단가산출상세"], 1], [ids["일위대가표"], 1]] # 머리 · 블록 밖 = 없음
|
|
got = _node({"grid": grid, "at": at})["jumps"]
|
|
for x, jumps in zip(calls, got):
|
|
no = x["단산"]["번"]
|
|
first = jumps[0]
|
|
assert (first["갈래"], first["번"]) == ("상세", no)
|
|
assert first["곳"] == [{"시트": ids["단가산출상세"], "행": x["단산"]["행"]}]
|
|
assert jumps[1] == {"갈래": "목록", "번": no, "곳": [{"시트": ids["단가산출표"], "행": [listed[no]] * 2}]} # fmt: skip
|
|
assert len(jumps) == (3 if len(callers[no]) > 1 else 2)
|
|
for x, jumps in zip(kids, got[len(calls) :]):
|
|
assert jumps == [{"갈래": "호표", "번": x["일위"]["번"], "곳": [{"시트": ids["일위대가표"], "행": x["일위"]["행"]}]}] # fmt: skip
|
|
from_list, from_detail, none1, none2 = got[-4:]
|
|
assert [j["갈래"] for j in from_list] == ["상세", "부름"]
|
|
assert [j["갈래"] for j in from_detail] == ["부름", "목록"]
|
|
assert [s["행"][0] for s in from_detail[0]["곳"]] == callers[many] # 부르는 줄 차례
|
|
assert none1 == [] and none2 == []
|
|
if parsed["꼴"] == "STmate": # 역할 id = 「단가산출근거」 시트(이름으로 안 찾음)
|
|
assert grid["원본"]["단가산출상세"] == "단가산출근거"
|