import io
import pytest
import mrrc
try:
import pymarc
HAS_PYMARC = True
except ImportError:
HAS_PYMARC = False
requires_pymarc = pytest.mark.skipif(
not HAS_PYMARC, reason="pymarc not installed"
)
def _build_record_with_two_007s_mrrc() -> bytes:
record = mrrc.Record()
record.add_field(mrrc.Field("001", data="1118690"))
record.add_field(mrrc.Field("007", data="cr|nn ||||||aa"))
record.add_field(mrrc.Field("007", data="fb|a bnnnn"))
record.add_field(mrrc.Field("008", data="230327s2023 wau ef 000 1 eng d"))
f245 = mrrc.Field("245", "1", "0")
f245.add_subfield("a", "Test title")
record.add_field(f245)
output = io.BytesIO()
writer = mrrc.MARCWriter(output)
writer.write_record(record)
writer.close()
return output.getvalue()
def _build_record_with_repeated_006_007_mrrc() -> bytes:
record = mrrc.Record()
record.add_field(mrrc.Field("001", data="9999999"))
record.add_field(mrrc.Field("006", data="m o d "))
record.add_field(mrrc.Field("006", data="j s n "))
record.add_field(mrrc.Field("007", data="cr |||||||||||"))
record.add_field(mrrc.Field("007", data="sd fsngnnmmned"))
record.add_field(mrrc.Field("007", data="vf cbahos"))
record.add_field(mrrc.Field("008", data="230327s2023 wau ef 000 1 eng d"))
f245 = mrrc.Field("245", "1", "0")
f245.add_subfield("a", "Multi-format item")
record.add_field(f245)
output = io.BytesIO()
writer = mrrc.MARCWriter(output)
writer.write_record(record)
writer.close()
return output.getvalue()
def _build_record_with_two_007s_pymarc() -> bytes:
record = pymarc.Record()
record.add_field(pymarc.Field(tag="001", data="1118690"))
record.add_field(pymarc.Field(tag="007", data="cr|nn ||||||aa"))
record.add_field(pymarc.Field(tag="007", data="fb|a bnnnn"))
record.add_field(
pymarc.Field(
tag="008",
data="230327s2023 wau ef 000 1 eng d",
)
)
record.add_field(
pymarc.Field(
tag="245",
indicators=["1", "0"],
subfields=[pymarc.Subfield(code="a", value="Test title")],
)
)
return record.as_marc()
def _build_record_with_repeated_006_007_pymarc() -> bytes:
record = pymarc.Record()
record.add_field(pymarc.Field(tag="001", data="9999999"))
record.add_field(pymarc.Field(tag="006", data="m o d "))
record.add_field(pymarc.Field(tag="006", data="j s n "))
record.add_field(pymarc.Field(tag="007", data="cr |||||||||||"))
record.add_field(pymarc.Field(tag="007", data="sd fsngnnmmned"))
record.add_field(pymarc.Field(tag="007", data="vf cbahos"))
record.add_field(
pymarc.Field(
tag="008",
data="230327s2023 wau ef 000 1 eng d",
)
)
record.add_field(
pymarc.Field(
tag="245",
indicators=["1", "0"],
subfields=[pymarc.Subfield(code="a", value="Multi-format item")],
)
)
return record.as_marc()
class TestMrrcRepeatedControlFields:
def test_mrrc_returns_two_007s(self):
marc_bytes = _build_record_with_two_007s_mrrc()
reader = mrrc.MARCReader(io.BytesIO(marc_bytes))
record = reader.read_record()
fields_007 = record.get_fields("007")
assert len(fields_007) == 2, (
f"Expected 2 007 fields, got {len(fields_007)}: "
f"{[f.data for f in fields_007]}"
)
assert fields_007[0].data == "cr|nn ||||||aa"
assert fields_007[1].data == "fb|a bnnnn"
def test_mrrc_returns_repeated_006_and_007(self):
marc_bytes = _build_record_with_repeated_006_007_mrrc()
reader = mrrc.MARCReader(io.BytesIO(marc_bytes))
record = reader.read_record()
fields_006 = record.get_fields("006")
assert len(fields_006) == 2, (
f"Expected 2 006 fields, got {len(fields_006)}"
)
fields_007 = record.get_fields("007")
assert len(fields_007) == 3, (
f"Expected 3 007 fields, got {len(fields_007)}"
)
def test_mrrc_add_field_preserves_repeated_control_fields(self):
record = mrrc.Record()
record.add_field(mrrc.Field("007", data="cr|nn ||||||aa"))
record.add_field(mrrc.Field("007", data="fb|a bnnnn"))
fields_007 = record.get_fields("007")
assert len(fields_007) == 2
assert fields_007[0].data == "cr|nn ||||||aa"
assert fields_007[1].data == "fb|a bnnnn"
class TestMrrcRepeatedControlFieldRoundTrip:
def test_roundtrip_preserves_two_007s(self):
marc_bytes = _build_record_with_two_007s_mrrc()
reader = mrrc.MARCReader(io.BytesIO(marc_bytes))
record = reader.read_record()
output = io.BytesIO()
writer = mrrc.MARCWriter(output)
writer.write_record(record)
writer.close()
reader2 = mrrc.MARCReader(io.BytesIO(output.getvalue()))
record2 = reader2.read_record()
fields_007 = record2.get_fields("007")
assert len(fields_007) == 2
assert fields_007[0].data == "cr|nn ||||||aa"
assert fields_007[1].data == "fb|a bnnnn"
def test_roundtrip_preserves_leader_length(self):
marc_bytes = _build_record_with_two_007s_mrrc()
original_length = int(marc_bytes[:5].decode("ascii"))
reader = mrrc.MARCReader(io.BytesIO(marc_bytes))
record = reader.read_record()
output = io.BytesIO()
writer = mrrc.MARCWriter(output)
writer.write_record(record)
writer.close()
roundtrip_bytes = output.getvalue()
roundtrip_length = int(roundtrip_bytes[:5].decode("ascii"))
assert roundtrip_length == original_length, (
f"Round-trip leader length {roundtrip_length} != original "
f"{original_length} — likely a repeated control field was dropped"
)
def test_all_fields_returns_all_control_fields(self):
marc_bytes = _build_record_with_two_007s_mrrc()
reader = mrrc.MARCReader(io.BytesIO(marc_bytes))
record = reader.read_record()
all_fields = record.get_fields()
tags_007 = [f for f in all_fields if f.tag == "007"]
assert len(tags_007) == 2
@requires_pymarc
class TestPymarcBaselineRepeatedControlFields:
def test_pymarc_returns_two_007s(self):
marc_bytes = _build_record_with_two_007s_pymarc()
reader = pymarc.MARCReader(io.BytesIO(marc_bytes))
record = next(reader)
fields_007 = record.get_fields("007")
assert len(fields_007) == 2
assert fields_007[0].data == "cr|nn ||||||aa"
assert fields_007[1].data == "fb|a bnnnn"
def test_pymarc_returns_repeated_006_and_007(self):
marc_bytes = _build_record_with_repeated_006_007_pymarc()
reader = pymarc.MARCReader(io.BytesIO(marc_bytes))
record = next(reader)
fields_006 = record.get_fields("006")
assert len(fields_006) == 2
fields_007 = record.get_fields("007")
assert len(fields_007) == 3
@requires_pymarc
class TestMrrcPymarcControlFieldParity:
def test_get_fields_returns_same_count(self):
marc_bytes = _build_record_with_two_007s_pymarc()
pymarc_reader = pymarc.MARCReader(io.BytesIO(marc_bytes))
pymarc_record = next(pymarc_reader)
mrrc_reader = mrrc.MARCReader(io.BytesIO(marc_bytes))
mrrc_record = mrrc_reader.read_record()
pymarc_007s = pymarc_record.get_fields("007")
mrrc_007s = mrrc_record.get_fields("007")
assert len(mrrc_007s) == len(pymarc_007s), (
f"mrrc returned {len(mrrc_007s)} 007 fields but pymarc returned "
f"{len(pymarc_007s)}"
)
def test_get_fields_returns_same_values(self):
marc_bytes = _build_record_with_two_007s_pymarc()
pymarc_reader = pymarc.MARCReader(io.BytesIO(marc_bytes))
pymarc_record = next(pymarc_reader)
mrrc_reader = mrrc.MARCReader(io.BytesIO(marc_bytes))
mrrc_record = mrrc_reader.read_record()
pymarc_values = [f.data for f in pymarc_record.get_fields("007")]
mrrc_values = [f.data for f in mrrc_record.get_fields("007")]
assert mrrc_values == pymarc_values