car-crash-fix-amount-predictor / tests /test_damage_classifier.py
theDocWho's picture
Initial commit: end-to-end car damage + repair-cost predictor
4ce7a7e
Raw
History Blame Contribute Delete
1.99 kB
"""Tests for the CarDD multi-label classifier dataset utilities and model."""
from __future__ import annotations
from pathlib import Path
import pytest
from ccdp.data import damage_dataset as dd
from ccdp.data.schema import DAMAGE_TYPES, Record
def _mk(types: list[str], path: str = "x.jpg", ds: str = "cardd") -> Record:
return Record(image_path=Path(path), dataset=ds, damage_types=types)
def test_encode_labels_canonical():
v = dd.encode_labels(["dent", "scratch"])
assert len(v) == len(DAMAGE_TYPES)
assert v[DAMAGE_TYPES.index("dent")] == 1.0
assert v[DAMAGE_TYPES.index("scratch")] == 1.0
assert sum(v) == 2.0
def test_encode_labels_unknown_dropped():
v = dd.encode_labels(["dent", "foobar"])
assert sum(v) == 1.0
def test_split_records_deterministic():
recs = [_mk(["dent"], path=f"{i}.jpg") for i in range(100)]
a = dd.split_records(recs, seed=42)
b = dd.split_records(recs, seed=42)
assert [r.image_path for r in a[0]] == [r.image_path for r in b[0]]
n_train, n_val, n_test = len(a[0]), len(a[1]), len(a[2])
assert n_train + n_val + n_test == 100
assert abs(n_train - 80) <= 1
assert abs(n_val - 10) <= 1
def test_pos_weight_inverse_frequency():
recs = []
# 90 with 'dent', 10 with 'tire_flat' — tire_flat should be weighted up
for _ in range(90):
recs.append(_mk(["dent"]))
for _ in range(10):
recs.append(_mk(["tire_flat"]))
pw = dd.pos_weight(recs)
i_dent = DAMAGE_TYPES.index("dent")
i_tf = DAMAGE_TYPES.index("tire_flat")
# rare class weight > common class weight
assert pw[i_tf] > pw[i_dent]
# neg/pos ratio: tire_flat: (100-10)/10 = 9; dent: (100-90)/90 ≈ 0.11 -> floored to 1
assert abs(pw[i_tf] - 9.0) < 0.01
assert pw[i_dent] >= 1.0
def test_pos_weight_empty_class_safe():
recs = [_mk(["dent"]) for _ in range(10)]
pw = dd.pos_weight(recs)
assert all(w >= 1.0 for w in pw)
assert len(pw) == len(DAMAGE_TYPES)