tests/test_rgbd_train_ext_data.py
"""TRAIN-EXT candidate rule: splits, exclusions, DEV-volume fence, asset uniqueness, order."""
import importlib.util
from pathlib import Path
SCRIPT = Path(__file__).resolve().parents[1] / "scripts" / "prepare_rgbd_train_ext_data.py"
spec = importlib.util.spec_from_file_location("prepare_rgbd_train_ext_data", SCRIPT)
ext = importlib.util.module_from_spec(spec)
spec.loader.exec_module(ext)
def row(sid, split="train", partition=None):
return {"scene_name": sid, "official_split": split, "protocol_partition": partition or split}
def assets_for(ids, shared=()):
"""One unique asset per scene; scenes in `shared` reuse the asset of the first one."""
out = {sid: {"archive_file": f"AI_{sid}.rar", "asset_file": "01"} for sid in ids}
for sid in shared[1:]:
out[sid] = out[shared[0]]
return out
def run(rows, **kw):
ids = [r["scene_name"] for r in rows]
options = {
"assets": assets_for(ids),
"allowed": {sid: list(range(16)) for sid in ids},
"trajectories": {f"{sid}_cam_00": {"Scene type": "OK"} for sid in ids},
"excluded_sets": [],
"blocked_assets": set(),
"fence": set(),
}
options.update(kw)
return ext.select_candidates(rows, **options)
def test_train_and_val_are_kept_but_test_and_mismatched_partitions_are_not():
rows = [
row("ai_001_001"),
row("ai_002_001", "val"),
row("ai_003_001", "test", "final_holdout"),
row("ai_004_001", "train", "val"),
]
assert sorted(run(rows)) == ["ai_001_001", "ai_002_001"]
def test_exclusions_fence_short_and_bad_trajectories_are_dropped():
rows = [row(f"ai_00{i}_001") for i in range(1, 7)]
ids = [r["scene_name"] for r in rows]
allowed = {sid: list(range(16)) for sid in ids} | {"ai_004_001": list(range(15))}
trajectories = {f"{sid}_cam_00": {"Scene type": "OK"} for sid in ids}
trajectories["ai_005_001_cam_00"] = {"Scene type": "BAD"}
kept = run(
rows,
excluded_sets=[{"ai_001_001"}, {"ai_002_001"}],
fence={"003"},
allowed=allowed,
trajectories=trajectories,
)
assert kept == ["ai_006_001"]
def test_source_assets_are_unique_against_blocked_and_within_the_set():
rows = [row(f"ai_00{i}_001") for i in range(1, 5)]
ids = [r["scene_name"] for r in rows]
assets = assets_for(ids, shared=("ai_001_001", "ai_002_001"))
blocked = {ext.asset_identity(assets["ai_003_001"])}
kept = run(rows, assets=assets, blocked_assets=blocked)
assert "ai_003_001" not in kept and "ai_004_001" in kept
assert len({"ai_001_001", "ai_002_001"} & set(kept)) == 1
def test_order_is_the_seeded_hash_order():
rows = [row(f"ai_0{i:02d}_001") for i in range(1, 20)]
kept = run(rows)
assert kept == sorted(kept, key=ext.selection_key)
assert ext.SELECTION_SEED == "TRAIN-EXT-20260930" and ext.TRAIN_EXT_MIN == 40