Line data Source code
1 : /**
2 : * @file HSIFrame_test.cxx HSIFrame class Unit Tests
3 : *
4 : * This is part of the DUNE DAQ Application Framework, copyright 2022.
5 : * Licensing/copyright details are in the COPYING file that you should have
6 : * received with this code.
7 : */
8 :
9 : #include "detdataformats/HSIFrame.hpp"
10 :
11 : #define BOOST_TEST_MODULE HSIFrame_test // NOLINT
12 :
13 : #include "boost/test/unit_test.hpp"
14 :
15 : #include <cstring>
16 : #include <limits>
17 : #include <vector>
18 :
19 : using namespace dunedaq::detdataformats;
20 :
21 : // Unit tests for a data formats library can expect to work with a lot of unsigned integers
22 : // NOLINTBEGIN(build/unsigned)
23 :
24 : namespace {
25 : // Helper to create HSIFrame from individual components
26 : HSIFrame
27 4 : make_frame(uint32_t version,
28 : uint32_t detector_id,
29 : uint32_t crate,
30 : uint32_t slot,
31 : uint32_t link,
32 : uint64_t timestamp,
33 : uint32_t input_low,
34 : uint32_t input_high,
35 : uint32_t trigger,
36 : uint32_t sequence)
37 : {
38 4 : HSIFrame frame;
39 4 : frame.version = version;
40 4 : frame.detector_id = detector_id;
41 4 : frame.crate = crate;
42 4 : frame.slot = slot;
43 4 : frame.link = link;
44 4 : frame.set_timestamp(timestamp);
45 4 : frame.input_low = input_low;
46 4 : frame.input_high = input_high;
47 4 : frame.trigger = trigger;
48 4 : frame.sequence = sequence;
49 4 : return frame;
50 : }
51 : } // namespace ""
52 :
53 : BOOST_AUTO_TEST_SUITE(HSIFrame_test)
54 :
55 2 : BOOST_AUTO_TEST_CASE(DefaultConstruction)
56 : {
57 1 : HSIFrame frame;
58 :
59 : // Note: bitfield members are uninitialized by default, so we don't test them here
60 1 : BOOST_REQUIRE_EQUAL(frame.get_timestamp(), std::numeric_limits<uint64_t>::max());
61 1 : BOOST_REQUIRE_EQUAL(frame.input_low, std::numeric_limits<uint32_t>::max());
62 1 : BOOST_REQUIRE_EQUAL(frame.input_high, std::numeric_limits<uint32_t>::max());
63 1 : BOOST_REQUIRE_EQUAL(frame.trigger, std::numeric_limits<uint32_t>::max());
64 1 : BOOST_REQUIRE_EQUAL(frame.sequence, std::numeric_limits<uint32_t>::max());
65 1 : }
66 :
67 2 : BOOST_AUTO_TEST_CASE(GetTimestamp)
68 : {
69 1 : HSIFrame frame;
70 :
71 1 : uint64_t ts = frame.get_timestamp();
72 1 : BOOST_REQUIRE_EQUAL(ts, std::numeric_limits<uint64_t>::max());
73 1 : }
74 :
75 2 : BOOST_AUTO_TEST_CASE(SetTimestampMax)
76 : {
77 1 : HSIFrame frame;
78 :
79 1 : uint64_t max_ts = std::numeric_limits<uint64_t>::max();
80 1 : frame.set_timestamp(max_ts);
81 1 : BOOST_REQUIRE_EQUAL(frame.get_timestamp(), max_ts);
82 1 : BOOST_REQUIRE_EQUAL(frame.timestamp_low, std::numeric_limits<uint32_t>::max());
83 1 : BOOST_REQUIRE_EQUAL(frame.timestamp_high, std::numeric_limits<uint32_t>::max());
84 1 : }
85 :
86 2 : BOOST_AUTO_TEST_CASE(SetTimestampSplit)
87 : {
88 1 : HSIFrame frame;
89 :
90 : // Test a 64-bit value that crosses the 32-bit boundary
91 1 : uint64_t ts = 0x0123456789ABCDEF;
92 1 : frame.set_timestamp(ts);
93 :
94 1 : BOOST_REQUIRE_EQUAL(frame.get_timestamp(), ts);
95 1 : BOOST_REQUIRE_EQUAL(frame.timestamp_low, 0x89ABCDEF); // lower 32 bits
96 1 : BOOST_REQUIRE_EQUAL(frame.timestamp_high, 0x01234567); // upper 32 bits
97 1 : }
98 :
99 2 : BOOST_AUTO_TEST_CASE(TimestampRoundTrip)
100 : {
101 : // Test a range of timestamp values
102 1 : const std::vector<uint64_t> test_timestamps = { 0,
103 : 1,
104 : 0xFF,
105 : 0xFFFFFFFF, // max 32-bit
106 : 0x100000000, // just above 32-bit
107 : 0x123456789ABCDEF0,
108 1 : std::numeric_limits<uint64_t>::max() };
109 :
110 8 : for (const auto& ts : test_timestamps) {
111 7 : HSIFrame frame;
112 7 : frame.set_timestamp(ts);
113 7 : BOOST_REQUIRE_EQUAL(frame.get_timestamp(), ts);
114 : }
115 1 : }
116 :
117 2 : BOOST_AUTO_TEST_CASE(BitfieldMembers)
118 : {
119 1 : HSIFrame frame;
120 :
121 1 : frame.version = 5;
122 1 : frame.detector_id = 3;
123 1 : frame.crate = 7;
124 1 : frame.slot = 2;
125 1 : frame.link = 42;
126 :
127 1 : BOOST_REQUIRE_EQUAL(frame.version, 5);
128 1 : BOOST_REQUIRE_EQUAL(frame.detector_id, 3);
129 1 : BOOST_REQUIRE_EQUAL(frame.crate, 7);
130 1 : BOOST_REQUIRE_EQUAL(frame.slot, 2);
131 1 : BOOST_REQUIRE_EQUAL(frame.link, 42);
132 1 : }
133 :
134 2 : BOOST_AUTO_TEST_CASE(BitfieldMask)
135 : {
136 1 : HSIFrame frame;
137 :
138 : // version is 6 bits: max value 63
139 1 : frame.version = 63;
140 1 : BOOST_REQUIRE_EQUAL(frame.version, 63);
141 :
142 : // detector_id is 6 bits: max value 63
143 1 : frame.detector_id = 63;
144 1 : BOOST_REQUIRE_EQUAL(frame.detector_id, 63);
145 :
146 : // crate is 10 bits: max value 1023
147 1 : frame.crate = 1023;
148 1 : BOOST_REQUIRE_EQUAL(frame.crate, 1023);
149 :
150 : // slot is 4 bits: max value 15
151 1 : frame.slot = 15;
152 1 : BOOST_REQUIRE_EQUAL(frame.slot, 15);
153 :
154 : // link is 6 bits: max value 63
155 1 : frame.link = 63;
156 1 : BOOST_REQUIRE_EQUAL(frame.link, 63);
157 1 : }
158 :
159 2 : BOOST_AUTO_TEST_CASE(RegularMembers)
160 : {
161 1 : HSIFrame frame;
162 :
163 1 : frame.input_low = 0x11223344;
164 1 : frame.input_high = 0x55667788;
165 1 : frame.trigger = 0xDEADBEEF;
166 1 : frame.sequence = 0xCAFEBABE;
167 :
168 1 : BOOST_REQUIRE_EQUAL(frame.input_low, 0x11223344);
169 1 : BOOST_REQUIRE_EQUAL(frame.input_high, 0x55667788);
170 1 : BOOST_REQUIRE_EQUAL(frame.trigger, 0xDEADBEEF);
171 1 : BOOST_REQUIRE_EQUAL(frame.sequence, 0xCAFEBABE);
172 1 : }
173 :
174 2 : BOOST_AUTO_TEST_CASE(CompleteFrameSetup)
175 : {
176 1 : HSIFrame frame = make_frame(5, // version
177 : 3, // detector_id
178 : 7, // crate
179 : 2, // slot
180 : 42, // link
181 : 0x0123456789ABCDEF, // timestamp
182 : 0x11111111, // input_low
183 : 0x22222222, // input_high
184 : 0x33333333, // trigger
185 : 0x44444444 // sequence
186 : );
187 :
188 1 : BOOST_REQUIRE_EQUAL(frame.version, 5);
189 1 : BOOST_REQUIRE_EQUAL(frame.detector_id, 3);
190 1 : BOOST_REQUIRE_EQUAL(frame.crate, 7);
191 1 : BOOST_REQUIRE_EQUAL(frame.slot, 2);
192 1 : BOOST_REQUIRE_EQUAL(frame.link, 42);
193 1 : BOOST_REQUIRE_EQUAL(frame.get_timestamp(), 0x0123456789ABCDEF);
194 1 : BOOST_REQUIRE_EQUAL(frame.input_low, 0x11111111);
195 1 : BOOST_REQUIRE_EQUAL(frame.input_high, 0x22222222);
196 1 : BOOST_REQUIRE_EQUAL(frame.trigger, 0x33333333);
197 1 : BOOST_REQUIRE_EQUAL(frame.sequence, 0x44444444);
198 1 : }
199 :
200 2 : BOOST_AUTO_TEST_CASE(ByteRoundTrip)
201 : {
202 : // Create a frame with specific values
203 1 : HSIFrame original = make_frame(5, 3, 7, 2, 42, 0x0123456789ABCDEF, 0x11111111, 0x22222222, 0x33333333, 0x44444444);
204 :
205 : // Serialize to bytes
206 1 : uint8_t buffer[sizeof(HSIFrame)]; // NOLINT(modernize-avoid-c-arrays)
207 1 : std::memcpy(buffer, &original, sizeof(HSIFrame));
208 :
209 : // Deserialize from bytes
210 1 : HSIFrame recovered;
211 1 : std::memcpy(&recovered, buffer, sizeof(HSIFrame));
212 :
213 : // Verify all fields match
214 1 : BOOST_REQUIRE_EQUAL(recovered.version, original.version);
215 1 : BOOST_REQUIRE_EQUAL(recovered.detector_id, original.detector_id);
216 1 : BOOST_REQUIRE_EQUAL(recovered.crate, original.crate);
217 1 : BOOST_REQUIRE_EQUAL(recovered.slot, original.slot);
218 1 : BOOST_REQUIRE_EQUAL(recovered.link, original.link);
219 1 : BOOST_REQUIRE_EQUAL(recovered.get_timestamp(), original.get_timestamp());
220 1 : BOOST_REQUIRE_EQUAL(recovered.input_low, original.input_low);
221 1 : BOOST_REQUIRE_EQUAL(recovered.input_high, original.input_high);
222 1 : BOOST_REQUIRE_EQUAL(recovered.trigger, original.trigger);
223 1 : BOOST_REQUIRE_EQUAL(recovered.sequence, original.sequence);
224 1 : }
225 :
226 2 : BOOST_AUTO_TEST_CASE(TimestampEndianness)
227 : {
228 1 : HSIFrame frame;
229 :
230 : // Set timestamp to a value where endianness matters
231 1 : uint64_t ts = 0x0102030405060708;
232 1 : frame.set_timestamp(ts);
233 :
234 : // On little-endian: low 32 bits should be 0x05060708, high 32 bits should be 0x01020304
235 1 : BOOST_REQUIRE_EQUAL(frame.timestamp_low, 0x05060708);
236 1 : BOOST_REQUIRE_EQUAL(frame.timestamp_high, 0x01020304);
237 :
238 : // Verify get_timestamp reconstructs it correctly
239 1 : BOOST_REQUIRE_EQUAL(frame.get_timestamp(), ts);
240 1 : }
241 :
242 2 : BOOST_AUTO_TEST_CASE(MultipleFramesIndependent)
243 : {
244 1 : HSIFrame frame1 = make_frame(1, 1, 1, 1, 1, 0x1111111111111111, 0x11, 0x11, 0x11, 0x11);
245 1 : HSIFrame frame2 = make_frame(2, 2, 2, 2, 2, 0x2222222222222222, 0x22, 0x22, 0x22, 0x22);
246 :
247 : // Verify they're independent
248 1 : BOOST_REQUIRE_EQUAL(frame1.version, 1);
249 1 : BOOST_REQUIRE_EQUAL(frame2.version, 2);
250 :
251 1 : BOOST_REQUIRE_EQUAL(frame1.get_timestamp(), 0x1111111111111111);
252 1 : BOOST_REQUIRE_EQUAL(frame2.get_timestamp(), 0x2222222222222222);
253 :
254 : // Modify frame1, verify frame2 unchanged
255 1 : frame1.version = 5; // Use a value that fits in 6 bits
256 1 : BOOST_REQUIRE_EQUAL(frame1.version, 5);
257 1 : BOOST_REQUIRE_EQUAL(frame1.version, 5);
258 1 : BOOST_REQUIRE_EQUAL(frame2.version, 2);
259 1 : }
260 :
261 2 : BOOST_AUTO_TEST_CASE(EdgeCaseHighBitfieldValues)
262 : {
263 1 : HSIFrame frame;
264 :
265 : // Set all bitfields to maximum valid values for their bit widths
266 1 : frame.version = (1u << 6) - 1; // 6 bits: 0x3F = 63
267 1 : frame.detector_id = (1u << 6) - 1; // 6 bits: 0x3F = 63
268 1 : frame.crate = (1u << 10) - 1; // 10 bits: 0x3FF = 1023
269 1 : frame.slot = (1u << 4) - 1; // 4 bits: 0xF = 15
270 1 : frame.link = (1u << 6) - 1; // 6 bits: 0x3F = 63
271 :
272 : // Verify all are at max
273 1 : BOOST_REQUIRE_EQUAL(frame.version, 63);
274 1 : BOOST_REQUIRE_EQUAL(frame.detector_id, 63);
275 1 : BOOST_REQUIRE_EQUAL(frame.crate, 1023);
276 1 : BOOST_REQUIRE_EQUAL(frame.slot, 15);
277 1 : BOOST_REQUIRE_EQUAL(frame.link, 63);
278 1 : }
279 :
280 : BOOST_AUTO_TEST_SUITE_END()
281 :
282 : // NOLINTEND(build/unsigned)
|