Coverage for tests/io/test_evt3_edge_cases.py: 100%
35 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"""EVT3 parser coverage gaps — recorded as skipped stubs to fill in later.
3The normal recordings exercise the common EVT3 packets, but a few real branches
4in ``EVT3_parse_chunk_soa`` (csrc/evt3.c) are never hit by them, and the
5target-clone build makes branch coverage look worse than it is. Each test below
6documents one gap: what input triggers the branch and what to assert. Drop the
7``skip`` and implement the body when writing the real test.
9These are correctness gaps, not known bugs.
10"""
11import pytest
14def test_incomplete_vector_continuation() -> None:
15 import numpy as np
16 from evutils.io._native_evt import Evt3Parser, Evt3Input
17 from evutils.io._native_core import EventSoABuffers, TriggerSoABuffers, parse_step
19 # VECT_BASE_X (type 3) followed by the FIRST VECT_12 (type 4).
20 # Normally a second VECT_12 follows. Here, we interrupt with EVT_ADDR_X (type 2).
21 words = np.array([
22 (0x3 << 12) | 0x0,
23 (0x4 << 12) | 0xFFF,
24 (0x2 << 12) | 200,
25 ], dtype=np.uint16)
27 parser = Evt3Parser()
28 ev = EventSoABuffers(100)
29 ev.c.capacity = 100
30 tr = TriggerSoABuffers(100)
32 parse_step(words, 0, Evt3Input, parser, ev, tr, tail_pad=4, word_dtype=np.uint16)
34 # 12 events from the first vector word + 1 from the EVT_ADDR_X word = 13 events.
35 # The interruption aborts the continuation gracefully.
36 assert ev.size == 13
38def test_output_buffer_full_stops_mid_chunk() -> None:
39 import numpy as np
40 from evutils.io._native_evt import Evt3Parser, Evt3Input
41 from evutils.io._native_core import EventSoABuffers, TriggerSoABuffers, parse_step
43 # VECT_BASE_X + 6 full blocks of (VECT_12, VECT_12, VECT_8).
44 # Each full block emits 32 events. 6 blocks = 192 events.
45 words = [(0x3 << 12) | 0x0]
46 block = [
47 (0x4 << 12) | 0xFFF,
48 (0x4 << 12) | 0xFFF,
49 (0x5 << 12) | 0xFF,
50 ]
51 words.extend(block * 6)
52 words = np.array(words, dtype=np.uint16)
54 parser = Evt3Parser()
55 # Create an event buffer with a capacity of 100.
56 # events_capacity_offset is 100 - 64 = 36.
57 ev = EventSoABuffers(100)
58 ev.c.capacity = 100
59 tr = TriggerSoABuffers(100)
61 # First parse: should stop after 2 blocks (64 events) because 64 >= 36.
62 appended, off = parse_step(words, 0, Evt3Input, parser, ev, tr, tail_pad=4, word_dtype=np.uint16)
63 assert appended == 64
64 assert off == 7 # 1 VECT_BASE_X + 2 blocks * 3 words = 7 words consumed
65 assert ev.size == 64
67 # "Drain" the buffer and resume from `off`
68 ev.reset()
69 appended2, off2 = parse_step(words, off, Evt3Input, parser, ev, tr, tail_pad=4, word_dtype=np.uint16)
70 assert appended2 == 64 # 2 more blocks
71 assert off2 == 13 # 7 + 2 * 3 = 13
72 assert ev.size == 64
75@pytest.mark.skip(reason="Measurement note, not a runtime test — see docstring")
76def test_note_target_clone_branch_coverage() -> None:
77 """gcovr under-reports EVT3 branch coverage because of function multi-versioning.
79 ``EVUTILS_TARGET_CLONES`` (csrc/include/evutils/compat.h) tags the hot chunk
80 parsers with ``__attribute__((target_clones("avx2","default")))`` on
81 GCC/x86-64, so the compiler emits TWO instantiations of each function. The
82 coverage host runs only one clone (whichever its CPU dispatches to); gcovr
83 still counts the branches of BOTH, so the unrun clone shows every branch as
84 "not taken" and halves the reported branch-rate.
86 Fix for a later PR (not code to run here): build the coverage target with the
87 clones disabled so branches attribute to a single instantiation. E.g. give
88 ``EVUTILS_COVERAGE`` in CMakeLists.txt a ``-DEVUTILS_NO_TARGET_CLONES``
89 define and make ``EVUTILS_TARGET_CLONES`` expand to nothing when it is set.
90 Then re-run scripts/coverage.sh and confirm evt3.c branch-rate jumps.
91 """