Real-time-isl-command-recognition / tests /test_dataset_loading.py
NAAZ1605's picture
Prepare ISL command recognition project
e2d95ed
Raw History Blame Contribute Delete
5.33 kB
"""Dataset loader / metadata parsing / split integrity."""
from __future__ import annotations
import json
from pathlib import Path
import numpy as np
import pandas as pd
import pytest
import config
from backend.preprocessing import include50
# --------------------------------------------------------------------------
# metadata
# --------------------------------------------------------------------------
def test_metadata_files_present():
for key in ("train_50", "test_50"):
p = Path(config.METADATA_DIR) / config.METADATA_FILES[key]
assert p.exists(), f"missing official metadata {p}"
assert p.stat().st_size > 0
def test_vocabulary_length_and_sortedness(vocabulary):
assert len(vocabulary) == config.NUM_CLASSES == 50
assert all(v == v.upper() for v in vocabulary), "class labels are stored upper-case"
assert len(set(vocabulary)) == len(vocabulary), "no duplicate class names"
# the official INCLUDE-50 list is sorted({Word}) - see include.py in OpenHands
assert vocabulary == sorted(vocabulary)
def test_vocabulary_matches_official_metadata():
"""Re-derive the class list from the official CSVs and compare with the frozen file."""
train = include50.load_split_metadata("train", "official")
test = include50.load_split_metadata("test", "official")
derived = sorted({str(w) for w in pd.concat([train, test])["label"].unique()})
assert len(derived) == 50
assert derived == include50.load_vocabulary()
# the raw (un-normalised) word stays available for traceability
assert pd.concat([train, test])["raw_word"].notna().all()
def test_split_metadata_columns():
df = include50.load_split_metadata("train", "official")
for col in ("raw_word", "label", "Video", "Category", "FilePath", "split"):
assert col in df.columns, f"expected column {col} in official metadata"
# labels are the normalised, upper-case glosses actually used as classes
assert (df["label"] == df["label"].str.upper()).all()
# --------------------------------------------------------------------------
# index / splits
# --------------------------------------------------------------------------
def test_index_columns_and_size(index_df):
for col in ("FilePath", "Video", "label", "split", "subset", "Category"):
assert col in index_df.columns
assert len(index_df) == 958
assert set(index_df["split"]) <= {"train", "val", "test"}
assert index_df["FilePath"].is_unique
def test_index_labels_are_from_vocabulary(index_df, vocabulary):
assert set(index_df["label"]) <= set(vocabulary)
def test_every_class_in_every_split(index_df):
for split in ("train", "val", "test"):
labels = set(index_df[index_df.split == split]["label"])
assert len(labels) == 50, f"{split} is missing classes: {set(vocabulary) - labels}"
def test_default_protocol_is_session_disjoint():
assert config.SPLIT_PROTOCOL == "session_disjoint"
# the alternative protocol is still available for the comparability table
assert (Path(config.METADATA_DIR) / "index_official.csv").exists()
def test_no_recording_cluster_spans_a_split(index_df):
"""The default protocol must not leak a recording burst across splits."""
clusters = include50.session_clusters(index_df)
df = index_df.assign(_cluster=clusters)
spanning = df.groupby("_cluster")["split"].nunique()
assert int((spanning > 1).sum()) == 0
def test_official_protocol_leaks_sessions(index_df):
"""Documented property of the official split: sessions *do* span train/test."""
p = Path(config.METADATA_DIR) / "index_official.csv"
if not p.exists():
pytest.skip("official index not built")
official = pd.read_csv(p)
clusters = include50.session_clusters(official)
df = official.assign(_cluster=clusters)
spanning = df.groupby("_cluster")["split"].nunique()
assert int((spanning > 1).sum()) > 0
# --------------------------------------------------------------------------
# session helpers
# --------------------------------------------------------------------------
@pytest.mark.parametrize("raw,expected", [
("MVI_0031.MOV", "0031"),
("MVI_0060_1.MP4", "0060"),
("MVI_4155.MOV", "4155"),
])
def test_session_id_regex(raw, expected):
assert include50.session_id(raw) == expected
def test_session_id_handles_non_numeric_names():
assert include50.session_id("clip-final.mov") == "clip-final"
def test_session_blocks_group_close_ids():
df = pd.DataFrame({"FilePath": [f"Greetings/48. Hello/MVI_{i}.MOV" for i in (100, 105, 130)]})
blocks = df["FilePath"].map(lambda p: include50.session_block(p, block=10))
assert blocks.nunique() == 2
# --------------------------------------------------------------------------
# reader
# --------------------------------------------------------------------------
def test_read_keypoints_for_real_clip():
df = include50.load_index(config.SPLIT_PROTOCOL)
row = df[df.split == "test"].iloc[0]
coords, mask, info = include50.read_keypoints_for(row["FilePath"])
assert coords.ndim == 3 and coords.shape[1:] == (75, 3)
assert mask.shape == (coords.shape[0], 75)
assert coords.shape[0] >= config.MIN_VALID_FRAMES
assert np.isfinite(coords).all()
assert "vid_shape" in info and "x_axis_scale" in info