Line data Source code
1 : /**
2 : * @file TriggerRecordHeader_test.cxx TriggerRecordHeader class Unit Tests
3 : *
4 : * This is part of the DUNE DAQ Application Framework, copyright 2020.
5 : * Licensing/copyright details are in the COPYING file that you should have
6 : * received with this code.
7 : */
8 :
9 : // Disable warnings in light of the use of intentially bad constructors during testing
10 :
11 : #pragma GCC diagnostic ignored "-Walloc-size-larger-than="
12 : #pragma GCC diagnostic ignored "-Warray-bounds"
13 : #pragma GCC diagnostic ignored "-Wstringop-overflow="
14 :
15 : #include "daqdataformats/TriggerRecordHeader.hpp"
16 : #include "daqdataformats/TriggerRecordHeaderData.hpp"
17 :
18 : #pragma GCC diagnostic pop
19 : #pragma GCC diagnostic pop
20 : #pragma GCC diagnostic pop
21 :
22 : /**
23 : * @brief Name of this test module
24 : */
25 : #define BOOST_TEST_MODULE TriggerRecordHeader_test // NOLINT
26 :
27 : #include "boost/test/unit_test.hpp"
28 :
29 : #include <cstring>
30 : #include <limits>
31 : #include <memory>
32 : #include <sstream>
33 : #include <string>
34 : #include <utility>
35 : #include <vector>
36 :
37 : using namespace dunedaq::daqdataformats;
38 :
39 : BOOST_AUTO_TEST_SUITE(TriggerRecordHeader_test)
40 :
41 : /**
42 : * @brief Check that TriggerRecords have appropriate Copy/Move semantics
43 : */
44 2 : BOOST_AUTO_TEST_CASE(CopyAndMoveSemantics)
45 : {
46 1 : BOOST_REQUIRE(std::is_copy_constructible_v<TriggerRecordHeader>);
47 1 : BOOST_REQUIRE(std::is_copy_assignable_v<TriggerRecordHeader>);
48 1 : BOOST_REQUIRE(std::is_move_constructible_v<TriggerRecordHeader>);
49 1 : BOOST_REQUIRE(std::is_move_assignable_v<TriggerRecordHeader>);
50 1 : }
51 :
52 : /**
53 : * @brief Check that TriggerRecordHeader constructors function correctly
54 : */
55 2 : BOOST_AUTO_TEST_CASE(ExistingHeader)
56 : {
57 1 : std::vector<ComponentRequest> components;
58 1 : components.emplace_back();
59 1 : components.back().component = { SourceID::Subsystem::kDetectorReadout, 12 };
60 1 : components.back().window_begin = 3;
61 1 : components.back().window_end = 4;
62 1 : components.emplace_back();
63 1 : components.back().component = { SourceID::Subsystem::kDetectorReadout, 56 };
64 1 : components.back().window_begin = 7;
65 1 : components.back().window_end = 8;
66 :
67 1 : auto header = new TriggerRecordHeader(components);
68 1 : header->set_run_number(9);
69 1 : header->set_trigger_number(10);
70 1 : header->set_trigger_timestamp(11);
71 1 : header->set_trigger_type(12);
72 1 : header->set_sequence_number(13);
73 1 : header->set_max_sequence_number(14);
74 1 : header->set_error_bit(TriggerRecordErrorBits::kMismatch, true);
75 1 : header->set_error_bit(TriggerRecordErrorBits::kUnassigned3, true);
76 :
77 2 : BOOST_REQUIRE_THROW(header->at(header->get_header().num_requested_components), std::range_error);
78 2 : BOOST_REQUIRE_THROW((*header)[header->get_header().num_requested_components], std::range_error);
79 :
80 1 : void* buff = malloc(header->get_total_size_bytes());
81 1 : std::memcpy(buff, header->get_storage_location(), header->get_total_size_bytes());
82 :
83 : // Constructor should copy header
84 1 : TriggerRecordHeader copy_header(const_cast<void*>(header->get_storage_location()), true);
85 1 : delete header; // NOLINT(build/raw_ownership)
86 :
87 1 : BOOST_REQUIRE_EQUAL(copy_header.get_run_number(), 9);
88 1 : BOOST_REQUIRE_EQUAL(copy_header.get_sequence_number(), 13);
89 1 : BOOST_REQUIRE_EQUAL(copy_header.get_max_sequence_number(), 14);
90 1 : BOOST_REQUIRE_EQUAL(copy_header.get_error_bit(static_cast<TriggerRecordErrorBits>(0)), false);
91 1 : BOOST_REQUIRE_EQUAL(copy_header.get_error_bit(static_cast<TriggerRecordErrorBits>(1)), true);
92 1 : BOOST_REQUIRE_EQUAL(copy_header.get_header().error_bits, 10);
93 1 : BOOST_REQUIRE_EQUAL(copy_header.at(0).window_begin, 3);
94 1 : BOOST_REQUIRE_EQUAL(copy_header[1].window_begin, 7);
95 :
96 1 : {
97 : // Test copy constructor
98 1 : TriggerRecordHeader copy_copy_header(copy_header);
99 1 : BOOST_REQUIRE_EQUAL(copy_copy_header.get_run_number(), 9);
100 1 : BOOST_REQUIRE_EQUAL(copy_copy_header.get_sequence_number(), 13);
101 1 : BOOST_REQUIRE_EQUAL(copy_copy_header.get_max_sequence_number(), 14);
102 1 : BOOST_REQUIRE_EQUAL(copy_copy_header.get_error_bit(static_cast<TriggerRecordErrorBits>(0)), false);
103 1 : BOOST_REQUIRE_EQUAL(copy_copy_header.get_error_bit(static_cast<TriggerRecordErrorBits>(1)), true);
104 1 : BOOST_REQUIRE_EQUAL(copy_copy_header.get_header().error_bits, 10);
105 1 : BOOST_REQUIRE_EQUAL(copy_copy_header.at(0).window_begin, 3);
106 1 : BOOST_REQUIRE_EQUAL(copy_copy_header[1].window_begin, 7);
107 1 : }
108 1 : {
109 : // Test copy assignment
110 1 : TriggerRecordHeader copy_assign_header = copy_header;
111 1 : BOOST_REQUIRE_EQUAL(copy_assign_header.get_run_number(), 9);
112 1 : BOOST_REQUIRE_EQUAL(copy_assign_header.get_sequence_number(), 13);
113 1 : BOOST_REQUIRE_EQUAL(copy_assign_header.get_max_sequence_number(), 14);
114 1 : BOOST_REQUIRE_EQUAL(copy_assign_header.get_error_bit(static_cast<TriggerRecordErrorBits>(0)), false);
115 1 : BOOST_REQUIRE_EQUAL(copy_assign_header.get_error_bit(static_cast<TriggerRecordErrorBits>(1)), true);
116 1 : BOOST_REQUIRE_EQUAL(copy_assign_header.get_header().error_bits, 10);
117 1 : BOOST_REQUIRE_EQUAL(copy_assign_header.at(0).window_begin, 3);
118 1 : BOOST_REQUIRE_EQUAL(copy_assign_header[1].window_begin, 7);
119 1 : }
120 :
121 1 : {
122 : // Test Buffer adoption constructor
123 1 : TriggerRecordHeader buffer_header(buff, false);
124 :
125 1 : BOOST_REQUIRE_EQUAL(buffer_header.get_run_number(), 9);
126 1 : BOOST_REQUIRE_EQUAL(buffer_header.get_sequence_number(), 13);
127 1 : BOOST_REQUIRE_EQUAL(buffer_header.get_max_sequence_number(), 14);
128 1 : BOOST_REQUIRE_EQUAL(buffer_header.get_error_bit(static_cast<TriggerRecordErrorBits>(0)), false);
129 1 : BOOST_REQUIRE_EQUAL(buffer_header.get_error_bit(static_cast<TriggerRecordErrorBits>(1)), true);
130 1 : BOOST_REQUIRE_EQUAL(buffer_header.get_header().error_bits, 10);
131 1 : BOOST_REQUIRE_EQUAL(buffer_header.at(0).window_begin, 3);
132 1 : BOOST_REQUIRE_EQUAL(buffer_header[1].window_begin, 7);
133 1 : }
134 :
135 1 : BOOST_REQUIRE_EQUAL(*reinterpret_cast<uint32_t*>(buff), // NOLINT
136 : TriggerRecordHeaderData::s_trigger_record_header_magic);
137 :
138 1 : free(buff);
139 1 : }
140 :
141 2 : BOOST_AUTO_TEST_CASE(MoveConstructor)
142 : {
143 1 : std::vector<ComponentRequest> components;
144 1 : components.emplace_back();
145 1 : components.back().component = { SourceID::Subsystem::kDetectorReadout, 12 };
146 1 : components.back().window_begin = 3;
147 1 : components.back().window_end = 4;
148 1 : components.emplace_back();
149 1 : components.back().component = { SourceID::Subsystem::kDetectorReadout, 56 };
150 1 : components.back().window_begin = 7;
151 1 : components.back().window_end = 8;
152 :
153 1 : auto header = new TriggerRecordHeader(components);
154 :
155 1 : TriggerRecordHeader another_header(std::move(*header));
156 :
157 1 : delete header; // NOLINT We are specifically testing what happens when the original trh is deleted
158 :
159 1 : BOOST_REQUIRE_EQUAL(another_header.get_num_requested_components(), 2);
160 1 : }
161 :
162 2 : BOOST_AUTO_TEST_CASE(MoveAssignment)
163 : {
164 1 : std::vector<ComponentRequest> components;
165 1 : components.emplace_back();
166 1 : components.back().component = { SourceID::Subsystem::kDetectorReadout, 12 };
167 1 : components.back().window_begin = 3;
168 1 : components.back().window_end = 4;
169 1 : components.emplace_back();
170 1 : components.back().component = { SourceID::Subsystem::kDetectorReadout, 56 };
171 1 : components.back().window_begin = 7;
172 1 : components.back().window_end = 8;
173 :
174 1 : auto header = new TriggerRecordHeader(components);
175 :
176 1 : auto another_header = std::move(*header);
177 :
178 1 : delete header; // NOLINT We are specifically testing what happens when the original trh is deleted
179 :
180 1 : BOOST_REQUIRE_EQUAL(another_header.get_num_requested_components(), 2);
181 1 : }
182 :
183 2 : BOOST_AUTO_TEST_CASE(BadConstructors)
184 : {
185 1 : TriggerRecordHeaderData header_data;
186 1 : header_data.num_requested_components = std::numeric_limits<uint64_t>::max() - 10; // NOLINT(build/unsigned)
187 1 : header_data.run_number = 9;
188 1 : header_data.trigger_number = 10;
189 1 : header_data.trigger_timestamp = 11;
190 1 : header_data.trigger_type = 12;
191 :
192 1 : auto hdr = malloc(sizeof(TriggerRecordHeaderData) + sizeof(ComponentRequest));
193 1 : std::memcpy(hdr, &header_data, sizeof(TriggerRecordHeaderData));
194 :
195 3 : BOOST_REQUIRE_EXCEPTION(
196 : TriggerRecordHeader oversize_header(hdr, true), std::bad_alloc, [&](std::bad_alloc) { return true; });
197 :
198 1 : header_data.num_requested_components = 1;
199 1 : std::memcpy(hdr, &header_data, sizeof(TriggerRecordHeaderData));
200 1 : TriggerRecordHeader bad_header(hdr, false);
201 1 : BOOST_REQUIRE_EQUAL(bad_header.get_num_requested_components(), 1);
202 :
203 1 : reinterpret_cast<TriggerRecordHeaderData*>(hdr)->num_requested_components = // NOLINT
204 1 : std::numeric_limits<uint64_t>::max() - 10; // NOLINT(build/unsigned)
205 1 : BOOST_REQUIRE_EQUAL(bad_header.get_num_requested_components(),
206 : std::numeric_limits<uint64_t>::max() - 10); // NOLINT(build/unsigned)
207 :
208 3 : BOOST_REQUIRE_EXCEPTION(
209 : TriggerRecordHeader header_inst = bad_header, std::bad_alloc, [&](std::bad_alloc) { return true; });
210 :
211 1 : free(hdr);
212 1 : }
213 :
214 : /**
215 : * @brief Test header field manipulation methods
216 : */
217 2 : BOOST_AUTO_TEST_CASE(HeaderFields)
218 : {
219 1 : std::vector<ComponentRequest> components;
220 1 : components.emplace_back();
221 1 : components.back().component = { SourceID::Subsystem::kDetectorReadout, 12 };
222 1 : components.back().window_begin = 3;
223 1 : components.back().window_end = 4;
224 1 : components.emplace_back();
225 1 : components.back().component = { SourceID::Subsystem::kDetectorReadout, 34 };
226 1 : components.back().window_begin = 5;
227 1 : components.back().window_end = 6;
228 1 : components.emplace_back();
229 1 : components.back().component = { SourceID::Subsystem::kDetectorReadout, 56 };
230 1 : components.back().window_begin = 7;
231 1 : components.back().window_end = 8;
232 1 : components.emplace_back();
233 1 : components.back().component = { SourceID::Subsystem::kDetectorReadout, 78 };
234 1 : components.back().window_begin = 9;
235 1 : components.back().window_end = 10;
236 1 : components.emplace_back();
237 1 : components.back().component = { SourceID::Subsystem::kDetectorReadout, 90 };
238 1 : components.back().window_begin = 11;
239 1 : components.back().window_end = 12;
240 :
241 1 : auto header = new TriggerRecordHeader(components);
242 1 : header->set_run_number(9);
243 1 : header->set_trigger_number(10);
244 1 : header->set_trigger_timestamp(11);
245 1 : header->set_trigger_type(12);
246 1 : header->set_sequence_number(13);
247 1 : header->set_max_sequence_number(14);
248 1 : header->set_error_bit(TriggerRecordErrorBits::kMismatch, true);
249 1 : header->set_error_bit(TriggerRecordErrorBits::kUnassigned31, true);
250 :
251 1 : auto header_data = header->get_header();
252 1 : BOOST_REQUIRE_EQUAL(header->get_run_number(), header_data.run_number);
253 1 : BOOST_REQUIRE_EQUAL(header->get_trigger_number(), header_data.trigger_number);
254 1 : BOOST_REQUIRE_EQUAL(header->get_trigger_timestamp(), header_data.trigger_timestamp);
255 1 : BOOST_REQUIRE_EQUAL(header->get_trigger_type(), header_data.trigger_type);
256 1 : BOOST_REQUIRE_EQUAL(header->get_sequence_number(), header_data.sequence_number);
257 1 : BOOST_REQUIRE_EQUAL(header->get_max_sequence_number(), header_data.max_sequence_number);
258 1 : BOOST_REQUIRE_EQUAL(header->get_num_requested_components(), 5);
259 1 : BOOST_REQUIRE_EQUAL(header->get_num_requested_components(), header_data.num_requested_components);
260 1 : BOOST_REQUIRE_EQUAL(header->get_error_bits().to_ulong(), 0x80000002);
261 :
262 1 : auto comp_ref = header->get_component_for_source_id({ SourceID::Subsystem::kDetectorReadout, 78 });
263 1 : BOOST_REQUIRE_EQUAL(comp_ref.window_begin, 9);
264 1 : BOOST_REQUIRE_EQUAL(comp_ref.window_end, 10);
265 1 : comp_ref = header->get_component_for_source_id({ SourceID::Subsystem::kDetectorReadout, 56 });
266 1 : BOOST_REQUIRE_EQUAL(comp_ref.window_begin, 7);
267 1 : BOOST_REQUIRE_EQUAL(comp_ref.window_end, 8);
268 1 : comp_ref = header->get_component_for_source_id({ SourceID::Subsystem::kDetectorReadout, 12 });
269 1 : BOOST_REQUIRE_EQUAL(comp_ref.window_begin, 3);
270 1 : BOOST_REQUIRE_EQUAL(comp_ref.window_end, 4);
271 1 : comp_ref = header->get_component_for_source_id({ SourceID::Subsystem::kDetectorReadout, 90 });
272 1 : BOOST_REQUIRE_EQUAL(comp_ref.window_begin, 11);
273 1 : BOOST_REQUIRE_EQUAL(comp_ref.window_end, 12);
274 3 : BOOST_REQUIRE_EXCEPTION(header->get_component_for_source_id({ SourceID::Subsystem::kDetectorReadout, 43 }),
275 : std::invalid_argument,
276 : [&](std::invalid_argument) { return true; });
277 :
278 1 : auto header_ptr = static_cast<const TriggerRecordHeaderData*>(header->get_storage_location());
279 1 : BOOST_REQUIRE_EQUAL(header_ptr->run_number, header_data.run_number);
280 1 : header->set_run_number(10);
281 1 : BOOST_REQUIRE(header_ptr->run_number != header_data.run_number);
282 1 : BOOST_REQUIRE_EQUAL(header_ptr->run_number, 10);
283 1 : header->set_error_bits(std::bitset<32>(0x11111111));
284 1 : BOOST_REQUIRE_EQUAL(header_ptr->error_bits, 0x11111111);
285 1 : }
286 :
287 2 : BOOST_AUTO_TEST_CASE(StreamOperator)
288 : {
289 1 : std::vector<ComponentRequest> components;
290 1 : components.emplace_back();
291 1 : components.back().component = { SourceID::Subsystem::kDetectorReadout, 12 };
292 1 : components.back().window_begin = 3;
293 1 : components.back().window_end = 4;
294 1 : components.emplace_back();
295 1 : components.back().component = { SourceID::Subsystem::kDetectorReadout, 56 };
296 1 : components.back().window_begin = 7;
297 1 : components.back().window_end = 8;
298 :
299 1 : auto header = std::make_unique<TriggerRecordHeader>(components);
300 1 : header->set_run_number(9);
301 1 : header->set_trigger_number(10);
302 1 : header->set_trigger_timestamp(11);
303 1 : header->set_trigger_type(12);
304 1 : header->set_sequence_number(13);
305 1 : header->set_max_sequence_number(14);
306 1 : header->set_error_bit(TriggerRecordErrorBits::kMismatch, true);
307 1 : header->set_error_bit(TriggerRecordErrorBits::kUnassigned3, true);
308 :
309 1 : auto header_data = header->get_header();
310 1 : std::ostringstream oss;
311 1 : oss << header_data;
312 1 : std::istringstream iss(oss.str());
313 1 : TriggerRecordHeaderData trhd;
314 1 : iss >> trhd;
315 1 : BOOST_REQUIRE_EQUAL(trhd.run_number, header_data.run_number);
316 1 : BOOST_REQUIRE_EQUAL(trhd.trigger_number, header_data.trigger_number);
317 1 : BOOST_REQUIRE_EQUAL(trhd.trigger_timestamp, header_data.trigger_timestamp);
318 1 : BOOST_REQUIRE_EQUAL(trhd.trigger_type, header_data.trigger_type);
319 1 : BOOST_REQUIRE_EQUAL(trhd.sequence_number, header_data.sequence_number);
320 1 : BOOST_REQUIRE_EQUAL(trhd.max_sequence_number, header_data.max_sequence_number);
321 1 : BOOST_REQUIRE_EQUAL(trhd.num_requested_components, header_data.num_requested_components);
322 1 : }
323 :
324 : BOOST_AUTO_TEST_SUITE_END()
|