import math
import pytest
from dataloader_rs import PyDataloader as DataLoader
from tests.py_dataloader_test_utils import ListDataset, all_items
def test_seq_all_items_covered():
n = 20
loader = DataLoader(ListDataset(range(n)), batch_size=3)
assert all_items(loader) == list(range(n))
def test_seq_empty_dataset():
loader = DataLoader(ListDataset([]), batch_size=4)
batches = list(loader)
assert batches == [], "empty dataset must produce no batches"
def test_seq_single_item():
loader = DataLoader(ListDataset([42]), batch_size=1)
batches = list(loader)
assert len(batches) == 1
assert batches[0] == [42]
def test_seq_bs_equals_n():
loader = DataLoader(ListDataset(range(5)), batch_size=5)
batches = list(loader)
assert len(batches) == 1
assert batches[0] == [0, 1, 2, 3, 4]
def test_seq_bs_larger_than_n_no_drop():
loader = DataLoader(ListDataset(range(3)), batch_size=10, drop_last=False)
batches = list(loader)
assert len(batches) == 1, "should get exactly one (partial) batch"
assert batches[0] == [0, 1, 2]
def test_seq_bs_larger_than_n_drop_last():
loader = DataLoader(ListDataset(range(3)), batch_size=10, drop_last=True)
batches = list(loader)
assert batches == [], "drop_last=True with bs>N must yield no batches"
def test_seq_batch_size_one():
loader = DataLoader(ListDataset(range(5)), batch_size=1)
batches = list(loader)
assert len(batches) == 5
for i, batch in enumerate(batches):
assert len(batch) == 1
assert batch[0] == i
def test_seq_prime_batch_size():
n, bs = 100, 7
loader = DataLoader(ListDataset(range(n)), batch_size=bs)
batches = list(loader)
expected = math.ceil(n / bs)
assert len(batches) == expected
items = sorted(x for b in batches for x in b)
assert items == list(range(n))
def test_seq_multi_epoch_consistent():
loader = DataLoader(ListDataset(range(12)), batch_size=4)
first_epoch = list(loader)
for _ in range(4):
assert list(loader) == first_epoch, "every epoch must be identical"
def test_seq_items_are_integers():
loader = DataLoader(ListDataset(range(6)), batch_size=3)
for batch in loader:
for item in batch:
assert isinstance(item, int), f"expected int, got {type(item)}"
def test_seq_order_preserved():
n = 9
loader = DataLoader(ListDataset(range(n)), batch_size=3)
batches = list(loader)
flat = [x for b in batches for x in b]
assert flat == list(range(n)), "sequential sampler must preserve item order"
def test_seq_drop_last_exact_divisor():
loader = DataLoader(ListDataset(range(9)), batch_size=3, drop_last=True)
batches = list(loader)
assert len(batches) == 3
for b in batches:
assert len(b) == 3
def test_seq_drop_last_partial():
loader = DataLoader(ListDataset(range(10)), batch_size=3, drop_last=True)
batches = list(loader)
assert len(batches) == 3
for b in batches:
assert len(b) == 3, "every remaining batch must be full"
def test_shuffle_covers_all_items():
n = 20
loader = DataLoader(ListDataset(range(n)), batch_size=4, shuffle=True)
def flat(ldr):
return [x for batch in ldr for x in batch]
epoch1 = flat(loader)
epoch2 = flat(loader)
assert sorted(epoch1) == list(range(n)), "epoch 1: all items must be present"
assert sorted(epoch2) == list(range(n)), "epoch 2: all items must be present"
assert epoch1 != epoch2, "shuffled epochs must differ"
def _epochs(loader, n):
return [list(loader) for _ in range(n)]
@pytest.mark.parametrize("num_workers", [0, 2])
def test_seeded_shuffle_is_reproducible(num_workers):
def make():
return DataLoader(
ListDataset(range(50)), batch_size=4, shuffle=True, seed=123, num_workers=num_workers
)
first, second = _epochs(make(), 3), _epochs(make(), 3)
assert first == second
assert first[0] != first[1], "epochs must still differ from each other"
for epoch in first:
assert sorted(x for batch in epoch for x in batch) == list(range(50))
def test_different_seeds_give_different_orders():
a = DataLoader(ListDataset(range(50)), shuffle=True, seed=1)
b = DataLoader(ListDataset(range(50)), shuffle=True, seed=2)
assert list(a) != list(b)
def test_seed_without_shuffle_is_rejected():
with pytest.raises(ValueError, match="seed only applies when shuffle=True"):
DataLoader(ListDataset(range(4)), seed=0)
def test_negative_seed_is_rejected():
with pytest.raises(OverflowError):
DataLoader(ListDataset(range(4)), shuffle=True, seed=-1)