"""テスト共通の fixture(ダミーデータのみ.臨床データは使わない)."""
import sqlite3
from collections.abc import Iterator
from dataclasses import dataclass
from pathlib import Path
import pytest
from PIL import Image
from tiasdata import catalog
# 舌色データセットの 9 フォルダ(フォルダ名 → label・severity).
# TIASJudgeModel の TEST_01「フォルダ構成とラベル対応」と同じ.フォルダの直下に <番号>.png を置く
TONGUE_COLOR_FOLDERS: dict[str, tuple[str, str]] = {
"淡紅(正常)": ("light_red", "normal"),
"暗赤紅_あり": ("dark_red", "strong"),
"暗赤紅_ややあり": ("dark_red", "mild"),
"紫_ややあり": ("purple", "mild"),
"紅_あり": ("red", "strong"),
"紅_ややあり": ("red", "mild"),
"紫_あり": ("purple", "strong"),
"淡白_あり": ("pale", "strong"),
"淡白_ややあり": ("pale", "mild"),
}
def write_dummy_png(path: Path, seed: int, size: tuple[int, int] = (8, 6)) -> Path:
"""`seed` ごとに中身の違う小さい PNG を書く(同じ `seed` なら同じバイト列)."""
path.parent.mkdir(parents=True, exist_ok=True)
color = (seed * 37 % 256, seed * 59 % 256, seed * 83 % 256)
image = Image.new("RGB", size, color)
# 色だけだと seed が 256 周期で重なるため,1 画素に seed を埋めて中身を一意にする
image.putpixel((0, 0), (seed % 256, seed // 256 % 256, seed // 65536 % 256))
image.save(path, format="PNG")
return path
@dataclass(frozen=True)
class DummyImage:
"""ダミーの取り込み元の画像 1 枚."""
number: int
folder: str
label: str
severity: str
path: Path
@dataclass(frozen=True)
class DummyTongueColorSource:
"""ダミーの舌色データセット(9 フォルダ × 数枚)."""
root: Path
images: list[DummyImage]
@pytest.fixture
def make_png():
"""小さい PNG を書く関数(`make_png(path, seed)`)."""
return write_dummy_png
@pytest.fixture
def store_dir(tmp_path: Path) -> Path:
"""空のストアのフォルダ(`tiasdata init` 後と同じ状態)."""
directory = tmp_path / "tiasdata" / "store"
directory.mkdir(parents=True)
return directory
@pytest.fixture
def tongue_color_source(tmp_path: Path) -> DummyTongueColorSource:
"""舌色データセットと同じ構成のダミーの取り込み元(各フォルダ 2 枚・番号は 1 から連番).
対応表(xlsx)は含まない(Step 3 で足す).
"""
root = tmp_path / "source" / "TIASJudgeModel"
images: list[DummyImage] = []
number = 1
for folder, (label, severity) in TONGUE_COLOR_FOLDERS.items():
for _ in range(2):
path = write_dummy_png(root / folder / f"{number}.png", seed=number)
images.append(DummyImage(number, folder, label, severity, path))
number += 1
return DummyTongueColorSource(root=root, images=images)
@pytest.fixture(autouse=True)
def _isolate_config_env(monkeypatch: pytest.MonkeyPatch) -> None:
# 開発者の環境変数が混ざらないようにする(テストごとに必要なら設定する)
monkeypatch.delenv("TIASDATA_CONFIG", raising=False)
@pytest.fixture
def catalog_conn(tmp_path: Path) -> Iterator[sqlite3.Connection]:
"""マイグレーション適用済みの目録(tmp_path に作る)."""
conn = catalog.connect(tmp_path / "catalog.sqlite", create=True)
catalog.apply_migrations(conn, "catalog")
try:
yield conn
finally:
conn.close()
@pytest.fixture
def identity_conn(tmp_path: Path) -> Iterator[sqlite3.Connection]:
"""マイグレーション適用済みの対応表(tmp_path に作る)."""
conn = catalog.connect(tmp_path / "identity.sqlite", create=True)
catalog.apply_migrations(conn, "identity")
try:
yield conn
finally:
conn.close()