import io
import pytest
from mrrc import MARCReader, MARCWriter
class TestQueueStateMachine:
def test_first_call_reads_batch(self, fixture_1k):
reader = MARCReader(io.BytesIO(fixture_1k))
rec1 = next(reader)
assert rec1 is not None
assert rec1.leader is not None
def test_subsequent_calls_use_queue(self, fixture_1k):
reader = MARCReader(io.BytesIO(fixture_1k))
rec1 = next(reader)
assert rec1 is not None
for i in range(99):
rec = next(reader)
assert rec is not None
if i > 0:
assert rec.leader is not None
def test_eof_idempotence(self, fixture_1k):
reader = MARCReader(io.BytesIO(fixture_1k))
records = list(reader)
assert len(records) > 0
for _ in range(5):
with pytest.raises(StopIteration):
next(reader)
def test_iteration_semantic_unchanged(self, fixture_1k):
reader = MARCReader(io.BytesIO(fixture_1k))
records = list(reader)
assert len(records) == 1000
for rec in records:
assert rec.leader is not None
def test_queue_reduces_gil_pressure(self, fixture_10k):
reader = MARCReader(io.BytesIO(fixture_10k))
records = []
for i, rec in enumerate(reader):
records.append(rec)
if i >= 99: break
assert len(records) == 100
for i, rec in enumerate(reader):
records.append(rec)
if i >= 99: break
assert len(records) == 200
def test_first_batch_boundary(self, fixture_1k):
reader = MARCReader(io.BytesIO(fixture_1k))
records = []
for i, rec in enumerate(reader):
records.append(rec)
if i >= 99: break
assert len(records) == 100
next_rec = next(reader)
assert next_rec is not None
def test_queue_ordering_preserved(self, fixture_1k):
reader = MARCReader(io.BytesIO(fixture_1k))
records = []
for i, rec in enumerate(reader):
records.append(rec)
if i >= 99:
break
assert len(records) == 100
for rec in records:
leader = rec.leader
assert leader is not None
assert len(str(leader)) > 0
def test_read_record_legacy_api_uses_queue(self, fixture_1k):
reader = MARCReader(io.BytesIO(fixture_1k))
rec1 = reader.read_record()
assert rec1 is not None
rec2 = reader.read_record()
assert rec2 is not None
def test_mixed_iteration_and_read_record(self, fixture_1k):
reader = MARCReader(io.BytesIO(fixture_1k))
rec1 = next(reader)
assert rec1 is not None
rec2 = reader.read_record()
assert rec2 is not None
rec3 = next(reader)
assert rec3 is not None
def test_reader_repr_reflects_state(self, fixture_1k):
reader = MARCReader(io.BytesIO(fixture_1k))
repr_str = repr(reader)
assert repr_str is not None
assert "MARCReader" in repr_str
list(reader)
repr_str2 = repr(reader)
assert repr_str2 is not None
class TestQueueEdgeCases:
def test_batch_boundary_1000_records(self, fixture_1k):
reader = MARCReader(io.BytesIO(fixture_1k))
records = list(reader)
assert len(records) == 1000
with pytest.raises(StopIteration):
next(reader)
def test_batch_boundary_10000_records(self, fixture_10k):
reader = MARCReader(io.BytesIO(fixture_10k))
records = list(reader)
assert len(records) == 10000
def test_batch_boundary_10000_records_alt(self, fixture_10k):
reader = MARCReader(io.BytesIO(fixture_10k))
records = list(reader)
assert len(records) == 10000
def test_queue_empty_check(self, fixture_1k):
reader = MARCReader(io.BytesIO(fixture_1k))
count = 0
for rec in reader:
count += 1
assert rec is not None
assert count == 1000
def test_empty_input_yields_no_records(self):
reader = MARCReader(io.BytesIO(b""))
records = list(reader)
assert len(records) == 0
def test_single_record_file(self, fixture_small):
source = MARCReader(io.BytesIO(fixture_small))
rec = next(source)
output = io.BytesIO()
writer = MARCWriter(output)
writer.write_record(rec)
writer.close()
reader = MARCReader(io.BytesIO(output.getvalue()))
records = list(reader)
assert len(records) == 1
with pytest.raises(StopIteration):
next(reader)
def test_batch_boundary_201_crosses_hard_cap(self, fixture_1k):
reader = MARCReader(io.BytesIO(fixture_1k))
records = []
for i, rec in enumerate(reader):
records.append(rec)
if i >= 200:
break
assert len(records) == 201
assert all(rec is not None for rec in records)