Files
Aislo/resources/tester/test_794_1_m01_sheet.py
eomsangdonandClaude Sonnet 5.5 c9bdf6d891 feat(799-2): M01 로직 상세 · M02 단가산출 상세 옛 탭 넷(시트 · 인력/재료/경비 · 시험 계산 · 텍스트 수식) 걷음 — 보기는 수식 · 단가산출 상세 · 셈 구동 따로
- 셈 구동 떼기: 새 M01_MasterData_UI_Logic_Drive.ts(driveRun · previewText · autoFill · createDrive) — M01 상세는 숨은 시험 계산 칸 단추 대신 구동 함수 · 시험 계산 칸(Logic_Calc)은 로직 복사 화면이 쓰므로 남기고 같은 구동을 부름 · 재료 고름은 rerun 고리
- M02: 새 _Sangeun_Tabs.ts(수식 · 단가산출 상세 보기 고르기) · Detail 의 시험 계산 · 인력/재료/경비 걷음
- 걷은 파일(git rm): M01 LogicLab_Sheet · Logic_Sheet_Model · LogicLab_Formula(.ts .css) · FormulaTokens · LogicLab_Est / M02 Sangeun_Sheet(.ts .css) · SheetEdit · SheetFormula · logic Sheet_Model · Const_Model · Formula_Model · 부품 시트 줄(createCalcSheetRow) · Cover_Model.sheetGroups · Calc 의 M02 고리(answer · shown · held) · 죽은 CSS · 글
- 서버 길 · 문서 칸(변수줄 · 글줄 · 덮개)은 남김 — 금액 그대로
- 낡은 시험: test_790_1(시트 화면 전부) · test_714_3 · test_748_2(+ helper)는 화면이 없어져 지움 · test_794_1 · test_790_2 는 화면 · TS 거울만 덜고 서버 시험 남김 · test_714_2 · 717_2b · 721 · 722(원래 틀린 한 줄 고침) · 734 · 737 · 750_2 · 793_3b · 796_2 · 796_2b 는 보기 둘 · 새 파일에 맞춤 · 새 test_799_2_old_tabs_gone

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-07 12:57:30 +09:00

127 lines
6.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ruff: noqa: E501
"""794-1 M01 관리자 줄 식 시트 — 서버 길(`/logic/sheet` · `/logic/sheet/check`) 지킴.
- 799-2 — 시트 화면 · 모델(`_LogicLab_Sheet.ts` · `logic/M01_Logic_Sheet_Model.ts`)은 걷음 · 이 서버 길은 수식 탭 검사와 같은 엔진이라 남김
- 서버(사본 폴더): 이름 꼴 식 글 · 칠 때마다 검사(없는 이름 · 아래 줄 · 괄호 · 빈 식 · 길이 · 없는 자리) ·
검사 = 쓰기 없음 · 공구손료 식 1 → 2 % 저장(개정 확인 409 → 200) 뒤 셈 51,802 · 틀린 식 저장 422 · 시스템 관리자가 아니면 403
"""
from __future__ import annotations
import copy
import hashlib
import shutil
from pathlib import Path
import pytest
from fastapi import Depends, FastAPI
from fastapi.testclient import TestClient
from common_util.common_util_auth import require_system_admin, verify_session
from M01_MasterData import M01_MasterData_Router as m01_router
from M01_MasterData import M01_MasterData_Sheet as line_sheet
from M01_MasterData import M01_MasterData_Store as store
REAL = store.FOLDER
KEY = "GC000211" # 합판거푸집 설치 및 해체
INPUTS = {"자재지역": "포항", "유형": "보통", "사용횟수": "6회", "높이감률": 0, "지붕슬래브": "아님",
"폼타이": "아님", "폼타이규격": "12.7㎜", "측압": "3t/㎡", "구멍땜": 0} # fmt: skip
TOOL_1 = "(형틀목공 × [노임 형틀목공] + 보통인부 × [노임 보통인부]) × 1 / 100"
TOOL_2 = TOOL_1.replace("× 1 / 100", "× 2 / 100")
def _text(p: Path) -> str:
return p.read_text("utf-8")
def _hashes(folder: Path) -> dict[str, str]:
return {p.name: hashlib.md5(p.read_bytes()).hexdigest() for p in sorted(folder.glob("*.json"))}
# ── 서버 ─────────────────────────────────────────────────────────────
@pytest.fixture
def folder(tmp_path: Path, monkeypatch) -> Path:
master = tmp_path / "master"
master.mkdir()
for path in REAL.glob("*.json"):
shutil.copy(path, master / path.name)
monkeypatch.setattr(store, "FOLDER", master)
return master
@pytest.fixture
def client(folder: Path) -> TestClient:
app = FastAPI()
app.include_router(m01_router.router)
return TestClient(app)
def _post(client: TestClient, url: str, body: dict, want: int = 200) -> dict:
res = client.post(url, json=body)
assert res.status_code == want, res.text
return res.json()
def test_이름_꼴_검사_쓰기_없음(client: TestClient, folder: Path) -> None:
before, real = _hashes(folder), _hashes(REAL)
one = client.get("/api/m01/logic", params={"key": KEY}).json()
row = one["logic"]
names = _post(client, "/api/m01/logic/sheet", {"row": row})
assert names["덧줄"][0] == TOOL_1
assert names["중간"][3] == "[합판거푸집설치및해체일당].형틀목공 / 시공량"
assert (
len(names["호표"]) == len(row["호표"])
and {"글": "시공량", "갈래": "중간"} in names["이름표"]
)
ask = lambda part, at, text: _post( # noqa: E731
client, "/api/m01/logic/sheet/check", {"row": row, "갈래": part, "차례": at, "식": text}
)
good = ask("덧줄", 0, TOOL_2)
assert good["되나"] and good["식"] == "(형틀목공 * LB000007 + 보통인부 * LB000002) * 2 / 100"
assert good["글"] == TOOL_2
assert ask("덧줄", 0, "형틀목공 × [노임 없음]")["까닭"] == ["없는 이름 「[노임 없음]」"]
below = ask("중간", 0, "시공량 × 2") # 시공량 = 아래 줄
assert not below["되나"] and "시공량" in below["까닭"][0]
assert not ask("중간", 2, "(1 +")["되나"]
assert ask("호표", 0, " ")["까닭"] == ["식이 빔"]
assert not ask("호표", 0, "1" + " + 1" * 200)["되나"] # 길이 상한
assert ask("덧줄", 9, "1")["까닭"] == ["없는 자리 「덧줄 9」"]
assert ask("호표", 0, "형틀목공 × 2")["되나"]
assert row == client.get("/api/m01/logic", params={"key": KEY}).json()["logic"] # 줄 안 바뀜
assert _hashes(folder) == before and _hashes(REAL) == real
def test_저장_길_개정_확인_다시_셈_틀린_식_422(client: TestClient, folder: Path) -> None:
real = _hashes(REAL)
one = client.get("/api/m01/logic", params={"key": KEY}).json()
row = copy.deepcopy(one["logic"])
got = line_sheet.check(row, "덧줄", 0, TOOL_2)
row["덧줄"][0]["식"] = got["식"]
body = {"files": [{"file": one["file"], "version": one["version"],
"changes": [{"op": "edit", "key": KEY, "row": row}]}]} # fmt: skip
assert client.post("/api/m01/save", json=body).status_code == 409 # 정본 = 개정 확인
_post(client, "/api/m01/save", {**body, "개정확인": True})
saved = client.get("/api/m01/logic", params={"key": KEY}).json()
assert saved["logic"]["덧줄"][0]["식"] == got["식"]
sums = _post(client, "/api/m01/calc", {"key": KEY, "inputs": INPUTS})["sums"]
assert sums["계"] == 51802 and sums["경비"] == 765 # _분석_650-H2 4 장 공구손료 2 %
bad = copy.deepcopy(saved["logic"])
bad["덧줄"][0]["식"] = "형틀목공 * 없는이름"
body = {"files": [{"file": saved["file"], "version": saved["version"],
"changes": [{"op": "edit", "key": KEY, "row": bad}]}], "개정확인": True} # fmt: skip
before = _hashes(folder)
assert client.post("/api/m01/save", json=body).status_code == 422
assert _hashes(folder) == before and _hashes(REAL) == real
def test_시스템_관리자가_아니면_403(folder: Path) -> None:
app = FastAPI()
app.include_router(
m01_router.router, dependencies=[Depends(verify_session), Depends(require_system_admin)]
)
app.dependency_overrides[verify_session] = lambda: {"role": "USER", "company_id": 1}
client = TestClient(app)
for url, body in (("/api/m01/logic/sheet", {"row": {}}),
("/api/m01/logic/sheet/check", {"row": {}, "갈래": "중간", "차례": 0, "식": "1"})): # fmt: skip
assert client.post(url, json=body).status_code == 403