Coverage for tests/test_sensor_size_metadata.py: 100%
66 statements
« prev ^ index » next coverage.py v7.15.1, created at 2026-07-18 05:24 +0000
« prev ^ index » next coverage.py v7.15.1, created at 2026-07-18 05:24 +0000
1"""Tests for lightweight EventArray metadata (sensor_size) and its io wiring."""
2import numpy as np
3import pytest
5from evutils.io import EventReader, EventWriter
6from evutils.types import Event_dtype, EventArray
9def _events(n=3000, w=320, h=240):
10 return EventArray(
11 t=np.arange(n, dtype=np.int64) * 10,
12 x=(np.arange(n) % w).astype(np.uint16),
13 y=(np.arange(n) % h).astype(np.uint16),
14 p=(np.arange(n) % 2).astype(np.uint8),
15 )
18# --------------------------------------------------------------------------- #
19# Core type behaviour
20# --------------------------------------------------------------------------- #
22def test_metadata_defaults_none_and_roundtrips():
23 e = EventArray(t=[1], x=[2], y=[3], p=[1])
24 assert e.metadata is None
25 assert e.sensor_size is None
27 e.sensor_size = (64, 48)
28 assert e.metadata == {"sensor_size": (64, 48)}
29 assert e.sensor_size == (64, 48)
32def test_metadata_survives_slice_and_subset():
33 e = EventArray(t=[1, 2, 3], x=[1, 2, 3], y=[1, 2, 3], p=[1, 0, 1],
34 metadata={"sensor_size": (64, 48)})
35 assert e[:2].sensor_size == (64, 48)
36 assert e[["t", "x"]].sensor_size == (64, 48)
39def test_copy_isolates_metadata():
40 e = EventArray(t=[1], x=[2], y=[3], p=[1], metadata={"sensor_size": (64, 48)})
41 c = e.copy()
42 c.metadata["sensor_size"] = (1, 1)
43 assert e.sensor_size == (64, 48) # original untouched
44 assert c.sensor_size == (1, 1)
47def test_from_aos_accepts_metadata():
48 aos = np.zeros(3, dtype=Event_dtype)
49 e = EventArray.from_aos(aos, metadata={"sensor_size": (10, 20)})
50 assert e.sensor_size == (10, 20)
53# --------------------------------------------------------------------------- #
54# Reader populates / Writer consumes
55# --------------------------------------------------------------------------- #
57def test_reader_populates_sensor_size(tmp_path):
58 p = tmp_path / "geom.raw"
59 with EventWriter(p, format="evt3", width=640, height=480) as w:
60 w.write(_events())
62 assert EventReader(p).read_all().sensor_size == (640, 480)
64 r = EventReader(p, n_events=500)
65 assert r.read().sensor_size == (640, 480)
67 for chunk in EventReader(p, n_events=500):
68 assert chunk.sensor_size == (640, 480)
69 break
72def test_writer_infers_dims_from_metadata(tmp_path):
73 ev = _events(w=320, h=240)
74 ev.sensor_size = (320, 240)
75 p = tmp_path / "infer.raw"
76 with EventWriter(p, format="evt3") as w: # no width/height given
77 w.write(ev)
78 assert EventReader(p).shape() == (320, 240)
81def test_writer_explicit_dims_override_metadata(tmp_path):
82 ev = _events()
83 ev.sensor_size = (320, 240)
84 p = tmp_path / "explicit.raw"
85 with EventWriter(p, format="evt3", width=100, height=50) as w:
86 w.write(ev)
87 assert EventReader(p).shape() == (100, 50)
90def test_writer_falls_back_without_metadata(tmp_path):
91 p = tmp_path / "fallback.raw"
92 with EventWriter(p, format="evt3") as w:
93 w.write(_events()) # no sensor_size metadata
94 assert EventReader(p).shape() == (1280, 720)
97def test_read_write_read_roundtrip_preserves_geometry(tmp_path):
98 """Geometry read off one file flows into the next via metadata alone."""
99 src = tmp_path / "src.raw"
100 with EventWriter(src, format="evt3", width=346, height=260) as w:
101 w.write(_events(w=346, h=260))
103 events = EventReader(src).read_all()
104 assert events.sensor_size == (346, 260)
106 dst = tmp_path / "dst.raw"
107 with EventWriter(dst, format="evt3") as w: # dims inferred from events
108 w.write(events)
109 assert EventReader(dst).shape() == (346, 260)