Skip to content

Commit d45b95d

Browse files
Add joint dataset coverage tests
1 parent 9697f25 commit d45b95d

2 files changed

Lines changed: 157 additions & 0 deletions

File tree

test/test_io/test_dataset.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,6 +1585,57 @@ def __getitem__(self, idx):
15851585
)
15861586

15871587

1588+
def test_joint_dataset_rejects_overlay_metadata_mismatch():
1589+
"""JointDataset should reject matching keys with conflicting metadata."""
1590+
1591+
class DummyDataset:
1592+
data_types = {"index": "scalar"}
1593+
1594+
def __init__(self, overlay_methods):
1595+
self.overlay_methods = overlay_methods
1596+
1597+
def __len__(self):
1598+
return 1
1599+
1600+
def __getitem__(self, idx):
1601+
return {"index": idx}
1602+
1603+
with pytest.raises(ValueError, match="overlay mismatch"):
1604+
joint_dataset_module.JointDataset(
1605+
primary=DummyDataset({"index": "cat"}),
1606+
secondary=DummyDataset({"index": "first"}),
1607+
)
1608+
1609+
1610+
def test_joint_dataset_rejects_empty_sources():
1611+
"""JointDataset should require both primary and secondary samples."""
1612+
1613+
class DummyDataset:
1614+
data_types = {"index": "scalar"}
1615+
overlay_methods = {"index": "cat"}
1616+
1617+
def __init__(self, size):
1618+
self.size = size
1619+
1620+
def __len__(self):
1621+
return self.size
1622+
1623+
def __getitem__(self, idx):
1624+
return {"index": idx}
1625+
1626+
with pytest.raises(ValueError, match="primary dataset must expose"):
1627+
joint_dataset_module.JointDataset(
1628+
primary=DummyDataset(0),
1629+
secondary=DummyDataset(1),
1630+
)
1631+
1632+
with pytest.raises(ValueError, match="secondary dataset must expose"):
1633+
joint_dataset_module.JointDataset(
1634+
primary=DummyDataset(1),
1635+
secondary=DummyDataset(0),
1636+
)
1637+
1638+
15881639
def test_joint_dataset_accepts_explicit_pair_index():
15891640
"""Pair indexes should let an external sampler own secondary pairing."""
15901641

@@ -1611,6 +1662,34 @@ def __getitem__(self, idx):
16111662
assert dataset[(1, None)]["index"] == 1
16121663

16131664

1665+
def test_joint_dataset_rejects_bad_pair_indexes():
1666+
"""JointDataset should validate tuple shape and secondary bounds."""
1667+
1668+
class DummyDataset:
1669+
data_types = {"index": "scalar"}
1670+
overlay_methods = {"index": "cat"}
1671+
1672+
def __init__(self, indexes):
1673+
self.indexes = indexes
1674+
1675+
def __len__(self):
1676+
return len(self.indexes)
1677+
1678+
def __getitem__(self, idx):
1679+
return {"index": self.indexes[idx]}
1680+
1681+
dataset = joint_dataset_module.JointDataset(
1682+
primary=DummyDataset([0, 1]),
1683+
secondary=DummyDataset([10]),
1684+
)
1685+
1686+
with pytest.raises(ValueError, match="length 2"):
1687+
dataset[(0, 1, 2)]
1688+
1689+
with pytest.raises(ValueError, match="outside of bounds"):
1690+
dataset[(0, 4)]
1691+
1692+
16141693
def test_joint_dataset_merges_shared_dataset_config(monkeypatch):
16151694
"""Shared dataset config should let source blocks override only paths."""
16161695

@@ -1675,6 +1754,48 @@ def build_dataset(source, dtype):
16751754
]
16761755

16771756

1757+
def test_joint_dataset_resolve_source_config_rejects_string_base():
1758+
"""A string base cannot be merged into mapping source overrides."""
1759+
with pytest.raises(ValueError, match="shared `base`"):
1760+
joint_dataset_module.JointDataset.resolve_source_config(
1761+
"hdf5", {"file_keys": "input.h5"}
1762+
)
1763+
1764+
1765+
def test_joint_dataset_build_dataset_uses_factory(monkeypatch):
1766+
"""Mapping-based source configs should instantiate through dataset_factory."""
1767+
1768+
class DummyDataset:
1769+
data_types = {"index": "scalar"}
1770+
overlay_methods = {"index": "cat"}
1771+
1772+
def __len__(self):
1773+
return 1
1774+
1775+
def __getitem__(self, idx):
1776+
return {"index": idx}
1777+
1778+
calls = []
1779+
1780+
def fake_dataset_factory(source, entry_list=None, dtype=None):
1781+
calls.append((source, entry_list, dtype))
1782+
return DummyDataset()
1783+
1784+
monkeypatch.setattr("spine.io.factories.dataset_factory", fake_dataset_factory)
1785+
1786+
dataset = joint_dataset_module.JointDataset(
1787+
primary={"name": "hdf5", "file_keys": "a.h5"},
1788+
secondary={"name": "hdf5", "file_keys": "b.h5"},
1789+
dtype="float32",
1790+
)
1791+
1792+
assert len(dataset) == 1
1793+
assert calls == [
1794+
({"name": "hdf5", "file_keys": "a.h5"}, None, "float32"),
1795+
({"name": "hdf5", "file_keys": "b.h5"}, None, "float32"),
1796+
]
1797+
1798+
16781799
def test_larcv_dataset_uses_augmenter_and_length(monkeypatch):
16791800
"""The LArCV dataset should initialize and apply the configured augmenter."""
16801801
seen = {}

test/test_io/test_factories.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,42 @@ def __init__(self, dataset, **kwargs):
279279
assert captured["pin_memory"] is True
280280

281281

282+
def test_loader_factory_requires_sampler_for_joint_dataset(monkeypatch):
283+
"""Joint datasets should fail early when no joint sampler is configured."""
284+
285+
class DummyDataset:
286+
joint = True
287+
data_types = {"value": "scalar"}
288+
overlay_methods = {"value": "cat"}
289+
290+
class DummyDataLoader:
291+
def __init__(self, dataset, **kwargs):
292+
self.dataset = dataset
293+
self.kwargs = kwargs
294+
295+
fake_torch = types.ModuleType("torch")
296+
fake_utils = types.ModuleType("torch.utils")
297+
fake_data = types.ModuleType("torch.utils.data")
298+
fake_data.DataLoader = DummyDataLoader
299+
fake_utils.data = fake_data
300+
fake_torch.utils = fake_utils
301+
302+
monkeypatch.setattr(factories_module, "TORCH_AVAILABLE", True)
303+
monkeypatch.setattr(
304+
factories_module, "dataset_factory", lambda *args, **kwargs: DummyDataset()
305+
)
306+
monkeypatch.setitem(sys.modules, "torch", fake_torch)
307+
monkeypatch.setitem(sys.modules, "torch.utils", fake_utils)
308+
monkeypatch.setitem(sys.modules, "torch.utils.data", fake_data)
309+
310+
with pytest.raises(ValueError, match="explicit joint sampler"):
311+
factories_module.loader_factory(
312+
dataset={"name": "joint"},
313+
dtype="float32",
314+
minibatch_size=2,
315+
)
316+
317+
282318
def test_loader_factory_distributed_requires_explicit_rank(monkeypatch):
283319
"""Distributed loader setup should reject an unspecified process rank."""
284320

0 commit comments

Comments
 (0)