105 lines
4.3 KiB
Python
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"])
|