Files
Aislo/resources/tester/test_stmate_img_code.py
T

105 lines
4.3 KiB
Python

"""STMATE 재현 앱 — 그림 코드(I · COSTN IFORM · SIZE 꼴) 지킴 시험 · 쓰기는 임시 폴더.
근거: 지식DB REA 분석/37 §4 — STmate.Cpm TwM_Boxa 0x514df0(넣기) · 0x514bc0~0x514d30(저장: NAME 빈칸이면 파일 이름 ·
SIZE = UpperCase(그림.ClassName) · IFORM = 그림 스트림) · 0x4dac10(새 코드 이름 「새로운 그림코드」)
"""
import base64
import io
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT / "tools/stmate-test"))
import api_img as A # noqa: E402
import server # noqa: E402
from dbf_memo import SixMemo # noqa: E402
from dbf_rw import DbfTable, find_rows # noqa: E402
from img_code import NEW_NAME, get_image, kind_of_file, list_images, put_image # noqa: E402
from stc_read import Source # noqa: E402
STC = next((ROOT / "tools/stmate-test/work_dbf").glob("*.STC"), None)
def _bmp(w=3, h=2) -> bytes:
from PIL import Image
out = io.BytesIO()
Image.new("RGB", (w, h), (200, 30, 40)).save(out, "BMP")
return out.getvalue()
@pytest.fixture(scope="module")
def files():
if STC is None:
pytest.skip("표본 STC 없음")
return Source(str(STC)).files
def test_kind_by_extension():
assert [kind_of_file(n) for n in ("a.JPG", "b.jpeg", "c.bmp", "d.ico", "e.emf", "f.WMF")] == [
"TJPEGIMAGE",
"TJPEGIMAGE",
"TBITMAP",
"TICON",
"TMETAFILE",
"TMETAFILE",
]
with pytest.raises(ValueError):
kind_of_file("x.png")
def test_new_code_put_and_read_back(files):
data = _bmp()
out, rep = put_image(files, "i00009", data, "다리 사진.bmp")
assert rep == {"code": "I00009", "new": True, "kind": "TBITMAP", "bytes": len(data), "name": NEW_NAME}
f2 = dict(files) | out
got, kind, mime = get_image(f2, "I00009")
assert got == data and kind == "TBITMAP" and mime == "image/bmp"
assert any(r["CODE"] == "I00009" and r["bytes"] == len(data) for r in list_images(f2))
# 다른 레코드·옛 메모 바이트는 그대로(무손실)
a, b = DbfTable(files["COSTN.DBF"]), DbfTable(out["COSTN.DBF"])
assert b.recs[: len(a.recs)] == a.recs and len(b.recs) == len(a.recs) + 1
old = files.get("COSTN.SMT", b"")
assert out["COSTN.SMT"][16 : len(old)] == old[16:]
def test_existing_code_bitmap_to_jpeg_and_name_rule(files):
f1 = dict(files) | put_image(files, "I00009", _bmp(), "x.bmp")[0]
t = DbfTable(f1["COSTN.DBF"])
i = find_rows(t, "CODE")["I00009"]
t.set(i, "NAME", "") # 이름이 비면 파일 이름(확장자 뺌)
f1["COSTN.DBF"] = t.to_bytes()
out, rep = put_image(f1, "I00009", _bmp(8, 8), "교량 정면.BMP", to_jpeg=True)
assert rep["kind"] == "TJPEGIMAGE" and rep["name"] == "교량 정면" and not rep["new"]
data, kind, _ = get_image(dict(f1) | out, "I00009")
assert data[:3] == b"\xff\xd8\xff" and kind == "TJPEGIMAGE"
with pytest.raises(ValueError):
put_image(files, "M00001", data, "a.jpg") # I 코드만
with pytest.raises(ValueError):
put_image(files, "I00010", data, "a.jpg", to_jpeg=True) # 변환은 비트맵만
def test_sniff_when_size_blank(files):
out, _ = put_image(files, "I00011", _bmp(), "a.bmp")
t = DbfTable(out["COSTN.DBF"])
t.set(find_rows(t, "CODE")["I00011"], "SIZE", "")
f2 = dict(files) | out | {"COSTN.DBF": t.to_bytes()}
assert get_image(f2, "I00011")[1] == "TBITMAP"
assert SixMemo(out["COSTN.SMT"]).read(t.raw(find_rows(t, "CODE")["I00011"], "IFORM"))[:2] == b"BM"
def test_api_put_writes_only_costn(files, tmp_path, monkeypatch):
monkeypatch.setattr(server, "WORK_DBF_ROOT", tmp_path)
b64 = "data:image/bmp;base64," + base64.b64encode(_bmp()).decode()
r = A.img_put(A.ImgPutReq(source_path=str(STC), code="I00012", data_b64=b64, filename="p.bmp"))
assert Path(r["saved_dir"]).parent == tmp_path and r["report"]["kind"] == "TBITMAP"
new = Source(r["saved_stc"]).files
changed = sorted(k for k in files if new.get(k) != files[k])
assert set(changed) <= {"COSTN.DBF", "COSTN.SMT"}
res = A.img_get(A.ImgReq(source_path=r["saved_stc"], code="I00012"))
assert res.headers["X-Img-Kind"] == "TBITMAP" and res.body[:2] == b"BM"
assert any(x["CODE"] == "I00012" for x in A.img_list(A.ImgReq(source_path=r["saved_dir"]))["rows"])