"""라이브러리 공유 — 같은 회사 동료에게 내 항목을 복사해 보냄 (PLAN 4장 · 2026-09-14 브레인 판정 ①). ⚠ 받는 쪽이 모르게 들어가지 않음 — 받은 항목은 그 사람 개인 단을 덮지 않고 **「받음」 단**에 따로 섬 (개인 단은 종류당 하나라 그대로 넣으면 동료가 고친 내 것이 조용히 덮임). 받은 뒤 가져오기·복제는 받는 사람 몫. ⚠ 같은 회사 안만 · 출처 공사명은 그대로(같은 회사라 그 공사를 앎 · 판정 ③). """ from __future__ import annotations import json import sys from pathlib import Path 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 B08_Quantity.B08_Quantity_Engine_StructureTemplate import load_template # noqa: E402 from common_util.common_util_auth import verify_session # noqa: E402 LIB = "/api/projects/33333333-3333-3333-3333-333333333333/quantity/structure-sheets/library" MINE = "AX-ST-0000aaaa" @pytest.fixture() def client(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> TestClient: monkeypatch.setattr(library_module, "STORAGE_BASE_DIR", str(tmp_path / "storage")) item = { **load_template("masonry_wet"), "code": MINE, "library_tier": "personal", "name": "내 돌쌓기", "origin": {"project": "봉화 임도"}, } folder = tmp_path / "storage" / "7" / "42" / "library" folder.mkdir(parents=True) (folder / f"{MINE}.json").write_text(json.dumps(item), encoding="utf-8") # 받는 사람(43)도 같은 종류 내 것이 있음 — 덮이면 안 됨 theirs = tmp_path / "storage" / "7" / "43" / "library" theirs.mkdir(parents=True) (theirs / "AX-ST-0000bbbb.json").write_text( json.dumps({**item, "code": "AX-ST-0000bbbb", "name": "동료 것"}), encoding="utf-8" ) async def members(company_id: int) -> list[dict]: assert company_id == 7 return [ {"id": 42, "name": "나", "email": "me@x"}, {"id": 43, "name": "동료", "email": "you@x"}, ] monkeypatch.setattr(router_module, "_company_members", members) app = FastAPI() app.include_router(router_module.router) app.dependency_overrides[verify_session] = lambda: {"company_id": 7, "user_id": 42} return TestClient(app) def test_동료_목록은_같은_회사에서_나를_뺀다(client: TestClient) -> None: body = client.get(f"{LIB}/colleagues").json() assert body["colleagues"] == [{"id": 43, "name": "동료"}] def test_보내면_받는_쪽_받음_단에_서고_그_사람_개인_단은_안_덮인다( client: TestClient, tmp_path: Path ) -> None: sent = client.put( f"{LIB}/share", json={"type_id": "masonry_wet", "code": MINE, "to_user_id": 43} ) assert sent.status_code == 200, sent.text received = tmp_path / "storage" / "7" / "43" / "library_received" / f"{MINE}.json" saved = json.loads(received.read_text(encoding="utf-8")) assert saved["library_tier"] == "received" assert saved["received_from"]["name"] == "나" and saved["origin"]["project"] == "봉화 임도" theirs = tmp_path / "storage" / "7" / "43" / "library" / "AX-ST-0000bbbb.json" assert json.loads(theirs.read_text(encoding="utf-8"))["name"] == "동료 것" dirs = library_module.tier_dirs(7, 43) listed = library_module.list_items(dirs, "masonry_wet") assert [i["tier"] for i in listed][:2] == ["personal", "received"] def test_회사_밖이나_내_것_아닌_항목은_못_보낸다(client: TestClient) -> None: stranger = client.put( f"{LIB}/share", json={"type_id": "masonry_wet", "code": MINE, "to_user_id": 99} ) assert stranger.status_code == 404 missing = client.put( f"{LIB}/share", json={"type_id": "masonry_wet", "code": "AX-ST-0000cccc", "to_user_id": 43} ) assert missing.status_code == 404 myself = client.put( f"{LIB}/share", json={"type_id": "masonry_wet", "code": MINE, "to_user_id": 42} ) assert myself.status_code == 400 def test_화면에_보내기_단추와_받음_표시() -> None: ui = (ROOT / "B08_Quantity" / "B08_Quantity_UI_StructureSheet_Library.ts").read_text( encoding="utf-8" ) assert "/share" in ui and "/colleagues" in ui and "동료에게 보내기" in ui assert 'received: "받음"' in ui