Files
Aislo/resources/tester/test_b08_stmate_library_router.py
T

109 lines
4.3 KiB
Python

"""라이브러리 — STmate 출력 엑셀에서 고정형 항목 뽑아 넣기 창구(PLAN 4장 · 2026-09-14 브레인 판정).
두 걸음: [읽기]는 호표 수·구성 줄 수·못 읽은 사유만 돌려주고 아무것도 안 씀 → [넣기]는 같은 파일을
서버가 **다시 읽어** 고른 호표를 개인 단에 씀(브라우저가 보낸 줄을 받아 적지 않음 · 개인 단만 · 판정 Ⓗ).
"""
from __future__ import annotations
import io
import json
import sys
from pathlib import Path
import openpyxl
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
import B08_Quantity.B08_Quantity_Engine_StructureLibrary as library_module # noqa: E402
import B08_Quantity.B08_Quantity_Router_StmateLibrary as router_module # noqa: E402
from common_util.common_util_auth import verify_session # noqa: E402
PROJECT_ID = "33333333-3333-3333-3333-333333333333"
BASE = f"/api/projects/{PROJECT_ID}/quantity/structure-sheets/library/stmate"
def _xlsx() -> bytes:
book = openpyxl.Workbook()
ws = book.active
ws.title = "일위대가표"
for row in [
["일 위 대 가 표"],
["공사명 : 시험 공사"],
["명 칭", "규 격", "수 량", "단위"],
[None],
[" 제 1 호표"],
["돌기슭막이(메쌓기)", "H=2.0", None, "m"],
["메쌓기", "L3=55cm이하", 2.09, "m2"],
["고임돌채집", "기계", 0.31, "m3"],
["합 계"],
[" 제 2 호표"],
["규준틀설치", "종단", None, "개소"],
["각재", "외송", "약간", "M3"],
["합 계"],
]:
ws.append(row)
buffer = io.BytesIO()
book.save(buffer)
return buffer.getvalue()
@pytest.fixture()
def client(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> TestClient:
monkeypatch.setattr(library_module, "STORAGE_BASE_DIR", str(tmp_path / "storage"))
app = FastAPI()
app.include_router(router_module.router)
app.dependency_overrides[verify_session] = lambda: {"company_id": 7, "user_id": 42}
return TestClient(app)
def _files() -> dict:
return {"file": ("견본.xlsx", _xlsx(), "application/octet-stream")}
def test_읽기는_수와_사유만_주고_안_쓴다(client: TestClient, tmp_path: Path) -> None:
body = client.post(f"{BASE}/read", files=_files()).json()
assert body["counts"] == {"hopyo": 1, "rows": 2}
assert body["hopyo"][0]["name"] == "돌기슭막이(메쌓기)" and body["hopyo"][0]["rows"] == 2
assert any("C12" in p for p in body["problems"]) # 수량이 수가 아닌 2호표는 사유로
assert not (tmp_path / "storage").exists()
def test_넣기는_서버가_다시_읽어_개인_단에_고정형으로(client: TestClient, tmp_path: Path) -> None:
response = client.post(
f"{BASE}/save", files=_files(), data={"hopyo_no": "1", "type_id": "masonry_dry"}
)
assert response.status_code == 200, response.text
code = response.json()["code"]
saved = json.loads(
(tmp_path / "storage" / "7" / "42" / "library" / f"{code}.json").read_text(encoding="utf-8")
)
assert saved["library_tier"] == "personal" and saved["origin"]["project"] == "시험 공사"
assert [r["amount"] for r in saved["rows"]] == ["2.09", "0.31"]
dirs = library_module.tier_dirs(7, 42)
assert [i["kind"] for i in library_module.list_items(dirs, "masonry_dry")] == ["fixed"]
def test_회사_없으면_403_없는_호표는_404_모르는_종류는_400(client: TestClient) -> None:
bad = client.post(
f"{BASE}/save", files=_files(), data={"hopyo_no": "2", "type_id": "masonry_dry"}
)
assert bad.status_code == 404 # 못 읽은 호표는 넣을 수 없음
unknown = client.post(f"{BASE}/save", files=_files(), data={"hopyo_no": "1", "type_id": "없음"})
assert unknown.status_code == 400
client.app.dependency_overrides[verify_session] = lambda: {"company_id": None, "user_id": 1}
denied = client.post(
f"{BASE}/save", files=_files(), data={"hopyo_no": "1", "type_id": "masonry_dry"}
)
assert denied.status_code == 403
def test_앱에_창구가_걸린다() -> None:
main = (ROOT / "main.py").read_text(encoding="utf-8")
assert "B08_Quantity_Router_StmateLibrary" in main and "b08_stmate_library_router" in main