# pyright: reportArgumentType=none, reportCallIssue=none
"""scene/schema.py の MetricsConfig.radial_min_max フィールド仕様ベーステスト.
仕様出典:
- docs/04_SPEC/SPEC_04_評価仕様.md(動径指標・評価パイプライン)
- docs/04_SPEC/SPEC_02_シーン定義仕様.md(evaluation/metrics セクション)
- src/sm_tias_lightsim/scene/schema.py(MetricsConfig 定義)
テスト方針:
- Pydantic モデルを直接構築して振る舞いを検証する(YAML パースは別途)
- 既存フィールド(cov/std/max_min/radial_profile)への非干渉を確認する
- YAML ロード経由の動作も確認する
"""
from __future__ import annotations
import pytest
import yaml
from pydantic import ValidationError
from sm_tias_lightsim.scene.schema import EvaluationConfig, MetricsConfig
# ---------------------------------------------------------------------------
# A1. 既定値: MetricsConfig() で radial_min_max == False
# ---------------------------------------------------------------------------
def test_metrics_radial_min_max_default_is_false():
"""MetricsConfig() のインスタンスで radial_min_max の既定値が False であること.
仕様: MetricsConfig.radial_min_max: bool = Field(default=False, ...)
(schema.py MetricsConfig)
"""
cfg = MetricsConfig()
assert cfg.radial_min_max is False
# ---------------------------------------------------------------------------
# A2. 明示 True: MetricsConfig(radial_min_max=True) で True になること
# ---------------------------------------------------------------------------
def test_metrics_radial_min_max_explicit_true():
"""MetricsConfig(radial_min_max=True) で radial_min_max が True になること.
仕様: MetricsConfig.radial_min_max: bool = Field(default=False, ...)
True を明示指定すると True が設定される(schema.py MetricsConfig)
"""
cfg = MetricsConfig(radial_min_max=True)
assert cfg.radial_min_max is True
def test_metrics_radial_min_max_explicit_false():
"""MetricsConfig(radial_min_max=False) で radial_min_max が False になること.
仕様: MetricsConfig.radial_min_max: bool = Field(default=False, ...)
"""
cfg = MetricsConfig(radial_min_max=False)
assert cfg.radial_min_max is False
# ---------------------------------------------------------------------------
# A3. 既存フィールドへの非干渉
# ---------------------------------------------------------------------------
def test_metrics_radial_min_max_does_not_affect_cov_default():
"""radial_min_max 指定有無で cov の既定値が変わらないこと.
仕様: MetricsConfig.cov: bool = Field(default=True, ...) — 非干渉
"""
cfg_default = MetricsConfig()
cfg_true = MetricsConfig(radial_min_max=True)
assert cfg_default.cov == cfg_true.cov
assert cfg_default.cov is True
def test_metrics_radial_min_max_does_not_affect_std_default():
"""radial_min_max 指定有無で std の既定値が変わらないこと.
仕様: MetricsConfig.std: bool = Field(default=True, ...) — 非干渉
"""
cfg_default = MetricsConfig()
cfg_true = MetricsConfig(radial_min_max=True)
assert cfg_default.std == cfg_true.std
assert cfg_default.std is True
def test_metrics_radial_min_max_does_not_affect_max_min_default():
"""radial_min_max 指定有無で max_min の既定値が変わらないこと.
仕様: MetricsConfig.max_min: bool = Field(default=True, ...) — 非干渉
"""
cfg_default = MetricsConfig()
cfg_true = MetricsConfig(radial_min_max=True)
assert cfg_default.max_min == cfg_true.max_min
assert cfg_default.max_min is True
def test_metrics_radial_min_max_does_not_affect_radial_profile_default():
"""radial_min_max 指定有無で radial_profile の既定値が変わらないこと.
仕様: MetricsConfig.radial_profile: bool = Field(default=True, ...) — 非干渉
radial_min_max とは独立したフィールド(schema.py MetricsConfig)
"""
cfg_default = MetricsConfig()
cfg_true = MetricsConfig(radial_min_max=True)
assert cfg_default.radial_profile == cfg_true.radial_profile
assert cfg_default.radial_profile is True
def test_metrics_config_all_fields_together():
"""radial_min_max=True を含む全フィールド指定で正常にパースされること.
仕様: MetricsConfig の全フィールドが独立して指定可能(schema.py MetricsConfig)
"""
cfg = MetricsConfig(
cov=True, std=False, max_min=True, radial_profile=False, radial_min_max=True
)
assert cfg.cov is True
assert cfg.std is False
assert cfg.max_min is True
assert cfg.radial_profile is False
assert cfg.radial_min_max is True
def test_metrics_config_is_frozen_for_radial_min_max():
"""MetricsConfig が frozen(イミュータブル)で radial_min_max も変更不可であること.
仕様: _FrozenBase → frozen=True(schema.py ConfigDict)
"""
cfg = MetricsConfig()
with pytest.raises(ValidationError):
cfg.radial_min_max = True # type: ignore[misc]
# ---------------------------------------------------------------------------
# A4. YAML ロード: YAML で metrics.radial_min_max: true を指定すると True
# ---------------------------------------------------------------------------
def test_yaml_load_metrics_radial_min_max_true():
"""YAML で metrics.radial_min_max: true を指定したとき True が反映されること.
仕様: EvaluationConfig.metrics.radial_min_max が YAML 経由で設定される
(schema.py MetricsConfig / EvaluationConfig)
"""
yaml_content = """\
roi:
type: image_pixel
x: 0
y: 0
width: 100
height: 100
metrics:
cov: true
std: true
max_min: true
radial_profile: true
radial_min_max: true
"""
data = yaml.safe_load(yaml_content)
cfg = EvaluationConfig.model_validate(data)
assert cfg.metrics is not None
assert cfg.metrics.radial_min_max is True
def test_yaml_load_metrics_radial_min_max_false():
"""YAML で metrics.radial_min_max: false を指定したとき False が反映されること.
仕様: MetricsConfig.radial_min_max: bool = Field(default=False, ...)
"""
yaml_content = """\
roi:
type: image_pixel
x: 0
y: 0
width: 100
height: 100
metrics:
cov: true
radial_min_max: false
"""
data = yaml.safe_load(yaml_content)
cfg = EvaluationConfig.model_validate(data)
assert cfg.metrics is not None
assert cfg.metrics.radial_min_max is False
def test_yaml_load_metrics_radial_min_max_omitted_defaults_false():
"""YAML で metrics.radial_min_max を省略したとき既定値 False が設定されること.
仕様: MetricsConfig.radial_min_max: bool = Field(default=False, ...)
既存 YAML(eval_baseline.yaml / eval_baseline_linear.yaml / eval_real.yaml 相当)は
radial_min_max を含まないため後方互換として False になる必要がある
"""
yaml_content = """\
roi:
type: image_pixel
x: 0
y: 0
width: 100
height: 100
metrics:
cov: true
std: true
max_min: true
radial_profile: true
"""
data = yaml.safe_load(yaml_content)
cfg = EvaluationConfig.model_validate(data)
assert cfg.metrics is not None
assert cfg.metrics.radial_min_max is False
def test_yaml_load_eval_baseline_linear_equivalent_has_radial_min_max_false():
"""eval_baseline_linear.yaml 相当の YAML では radial_min_max が False であること.
仕様: 既存 configs(eval_baseline.yaml / eval_baseline_linear.yaml)は
radial_min_max を含まず,未指定時は False(後方互換)
"""
yaml_content = """\
roi:
type: image_pixel
x: 24
y: 37
width: 464
height: 450
zones:
enabled: true
boundaries:
- 0.33
- 0.66
metrics:
cov: true
std: true
max_min: true
radial_profile: true
normalization:
enabled: true
type: mean_anchor
target_mean: 146.7146
"""
data = yaml.safe_load(yaml_content)
cfg = EvaluationConfig.model_validate(data)
assert cfg.metrics is not None
assert cfg.metrics.radial_min_max is False