Files
SimurgArray/tests/unit/test_binutil.py
T
kemalandClaude Opus 5.5 4357d3deef
ci / test (3.12) (push) Failing after 11s
ci / test (3.13) (push) Failing after 12s
P1: file parsers, sample sheet, discovery, CLI inspect
Readers for IDAT v3, BPM (locus entries v4-v8), CSV manifest, EGT
(data blocks 5-9) and GTC v3-v5 (plus a layout-preserving GTC writer);
sample-sheet validation (IN-001..IN-014), IDAT discovery and pairing
(IN-020..IN-022), message catalogue and exit codes (CLI-014/016),
JSON Lines logging (CLI-007/008), atomic writes (CLI-011), run manifest,
and `simurg inspect`.

Validation (docs/validation/P1.md): GTC, BPM and EGT readers agree
exactly with Illumina BeadArrayFiles on GSA v4 / GDA v1 files; GTCs
round-trip byte-identically; BPM and CSV manifests are consistent.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01814GKVzZVL3FuF3DeiZXhv
2026-09-27 16:56:39 +01:00

69 lines
2.0 KiB
Python

from __future__ import annotations
import gzip
import numpy as np
import pytest
from hypothesis import given
from hypothesis import strategies as st
from simurg.core.errors import FormatError
from simurg.formats.binutil import BinaryReader, BinaryWriter, load_bytes
@given(st.text(max_size=400))
def test_string_roundtrip(s: str) -> None:
w = BinaryWriter()
w.string(s)
r = BinaryReader(w.getvalue(), "E_GTC_CORRUPT")
assert r.string() == s
assert r.remaining() == 0
@pytest.mark.parametrize("n", [0, 1, 127, 128, 16383, 16384, 300_000])
def test_varint_boundaries(n: int) -> None:
w = BinaryWriter()
w.string(b"x" * n)
r = BinaryReader(w.getvalue(), "E_GTC_CORRUPT")
assert r.varint_length() == n
def test_invalid_utf8_is_replaced_not_raised() -> None: # IN-033, EDGE-002
w = BinaryWriter()
w.string(b"ok\xff\xfe")
assert BinaryReader(w.getvalue(), "E_GTC_CORRUPT").string() == "ok��"
def test_string_past_eof_is_format_error() -> None:
buf = bytes([50]) + b"short"
with pytest.raises(FormatError) as e:
BinaryReader(buf, "E_GTC_CORRUPT", "x.gtc").string()
assert e.value.code == "E_GTC_CORRUPT"
def test_bad_varint_is_format_error() -> None:
with pytest.raises(FormatError):
BinaryReader(b"\xff\xff\xff\xff\xff\xff", "E_BPM_FORMAT").varint_length()
def test_array_bounds_and_seek() -> None:
r = BinaryReader(np.arange(4, dtype="<i4").tobytes(), "E_IDAT_FORMAT")
assert r.array("<i4", 4).tolist() == [0, 1, 2, 3]
r.seek(0)
with pytest.raises(FormatError):
r.array("<i4", 5)
with pytest.raises(FormatError):
r.seek(100)
def test_load_bytes_gzip(tmp_path) -> None: # type: ignore[no-untyped-def]
p = tmp_path / "a.bin.gz"
p.write_bytes(gzip.compress(b"hello"))
assert bytes(load_bytes(p)) == b"hello"
q = tmp_path / "b.bin"
q.write_bytes(b"world")
assert bytes(load_bytes(q)) == b"world"
e = tmp_path / "empty.bin"
e.write_bytes(b"")
assert bytes(load_bytes(e)) == b""