Line data Source code
1 : /**
2 : * @file Fragment_test.cxx Fragment 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 "-Warray-bounds"
12 : #pragma GCC diagnostic ignored "-Wstringop-overflow="
13 : #pragma GCC diagnostic ignored "-Walloc-size-larger-than="
14 :
15 : #include "daqdataformats/Fragment.hpp"
16 :
17 : #pragma GCC diagnostic pop
18 : #pragma GCC diagnostic pop
19 : #pragma GCC diagnostic pop
20 :
21 : /**
22 : * @brief Name of this test module
23 : */
24 : #define BOOST_TEST_MODULE Fragment_test // NOLINT
25 :
26 : #include "boost/test/unit_test.hpp"
27 :
28 : #include <memory>
29 : #include <string>
30 : #include <utility>
31 : #include <vector>
32 :
33 : using namespace dunedaq::daqdataformats;
34 :
35 : BOOST_AUTO_TEST_SUITE(Fragment_test)
36 :
37 : /**
38 : * @brief Check that Fragments have appropriate Copy/Move semantics
39 : */
40 2 : BOOST_AUTO_TEST_CASE(CopyAndMoveSemantics)
41 : {
42 1 : BOOST_REQUIRE(!std::is_copy_constructible_v<Fragment>);
43 1 : BOOST_REQUIRE(!std::is_copy_assignable_v<Fragment>);
44 1 : BOOST_REQUIRE(std::is_move_constructible_v<Fragment>);
45 1 : BOOST_REQUIRE(std::is_move_assignable_v<Fragment>);
46 1 : }
47 :
48 : /**
49 : * @brief Test constructors that gather existing data buffers
50 : */
51 2 : BOOST_AUTO_TEST_CASE(DataConstructors)
52 : {
53 1 : std::vector<uint8_t> buf1(10);
54 1 : Fragment single_frag(buf1.data(), buf1.size());
55 1 : BOOST_REQUIRE_EQUAL(single_frag.get_size(), sizeof(FragmentHeader) + buf1.size());
56 :
57 1 : std::vector<uint8_t> buf2(20);
58 1 : Fragment collect_frag({ { buf1.data(), buf1.size() }, { buf2.data(), buf2.size() } });
59 1 : BOOST_REQUIRE_EQUAL(collect_frag.get_size(), sizeof(FragmentHeader) + buf1.size() + buf2.size());
60 1 : }
61 :
62 : /**
63 : * @brief Test construction of invalid Fragments
64 : */
65 2 : BOOST_AUTO_TEST_CASE(BadConstructors)
66 : {
67 1 : std::unique_ptr<Fragment> fragment_ptr{};
68 :
69 2 : BOOST_REQUIRE_EXCEPTION(fragment_ptr.reset(new Fragment(nullptr, size_t(100))),
70 : std::invalid_argument,
71 : [&](std::invalid_argument) { return true; });
72 2 : BOOST_REQUIRE_EXCEPTION(
73 : fragment_ptr.reset(new Fragment(nullptr, size_t(-1))), std::length_error, [&](std::length_error) { return true; });
74 :
75 2 : BOOST_REQUIRE_EXCEPTION(
76 : fragment_ptr.reset(new Fragment({ nullptr, size_t(-1) - sizeof(dunedaq::daqdataformats::FragmentHeader) })),
77 : std::bad_alloc,
78 : [&](std::bad_alloc) { return true; });
79 :
80 1 : auto bufsize = 10;
81 1 : std::vector<uint8_t> buf1(bufsize);
82 1 : fragment_ptr.reset(new Fragment(buf1.data(), buf1.size()));
83 1 : BOOST_REQUIRE_EQUAL(fragment_ptr->get_size(), sizeof(FragmentHeader) + bufsize);
84 1 : }
85 :
86 : /**
87 : * @brief Check that Fragment constructors function correctly
88 : */
89 2 : BOOST_AUTO_TEST_CASE(ExistingFragmentConstructor)
90 : {
91 1 : FragmentHeader header;
92 1 : header.size = sizeof(FragmentHeader) + 4;
93 1 : header.trigger_number = 1;
94 1 : header.trigger_timestamp = 2;
95 1 : header.run_number = 3;
96 :
97 1 : auto frag = malloc(sizeof(FragmentHeader) + 4);
98 1 : memcpy(frag, &header, sizeof(FragmentHeader));
99 :
100 1 : uint8_t one = 1, two = 2, three = 3, four = 4; // NOLINT(build/unsigned)
101 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader), &one, 1); // NOLINT(build/unsigned)
102 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader) + 1, &two, 1); // NOLINT(build/unsigned)
103 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader) + 2, &three, 1); // NOLINT(build/unsigned)
104 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader) + 3, &four, 1); // NOLINT(build/unsigned)
105 :
106 1 : {
107 1 : Fragment test_frag(frag, Fragment::BufferAdoptionMode::kReadOnlyMode);
108 :
109 1 : BOOST_REQUIRE_EQUAL(test_frag.get_storage_location(), frag);
110 :
111 1 : BOOST_REQUIRE_EQUAL(test_frag.get_trigger_number(), 1);
112 1 : BOOST_REQUIRE_EQUAL(test_frag.get_trigger_timestamp(), 2);
113 1 : BOOST_REQUIRE_EQUAL(test_frag.get_run_number(), 3);
114 :
115 1 : BOOST_REQUIRE_EQUAL(*static_cast<uint8_t*>(test_frag.get_data()), one); // NOLINT(build/unsigned)
116 1 : BOOST_REQUIRE_EQUAL(*(static_cast<uint8_t*>(test_frag.get_data()) + 1), two); // NOLINT(build/unsigned)
117 1 : BOOST_REQUIRE_EQUAL(*(static_cast<uint8_t*>(test_frag.get_data()) + 2), three); // NOLINT(build/unsigned)
118 1 : BOOST_REQUIRE_EQUAL(*(static_cast<uint8_t*>(test_frag.get_data()) + 3), four); // NOLINT(build/unsigned)
119 1 : }
120 1 : free(frag); // Should not cause errors
121 :
122 1 : frag = malloc(sizeof(FragmentHeader) + 4);
123 1 : memcpy(frag, &header, sizeof(FragmentHeader));
124 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader), &four, 1); // NOLINT(build/unsigned)
125 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader) + 1, &three, 1); // NOLINT(build/unsigned)
126 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader) + 2, &two, 1); // NOLINT(build/unsigned)
127 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader) + 3, &one, 1); // NOLINT(build/unsigned)
128 :
129 1 : {
130 1 : Fragment test_frag(frag, Fragment::BufferAdoptionMode::kCopyFromBuffer);
131 :
132 1 : BOOST_REQUIRE(test_frag.get_storage_location() != frag);
133 1 : BOOST_REQUIRE_EQUAL(test_frag.get_trigger_number(), 1);
134 1 : BOOST_REQUIRE_EQUAL(test_frag.get_trigger_timestamp(), 2);
135 1 : BOOST_REQUIRE_EQUAL(test_frag.get_run_number(), 3);
136 :
137 1 : BOOST_REQUIRE_EQUAL(*static_cast<uint8_t*>(test_frag.get_data()), four); // NOLINT(build/unsigned)
138 1 : BOOST_REQUIRE_EQUAL(*(static_cast<uint8_t*>(test_frag.get_data()) + 1), three); // NOLINT(build/unsigned)
139 1 : BOOST_REQUIRE_EQUAL(*(static_cast<uint8_t*>(test_frag.get_data()) + 2), two); // NOLINT(build/unsigned)
140 1 : BOOST_REQUIRE_EQUAL(*(static_cast<uint8_t*>(test_frag.get_data()) + 3), one); // NOLINT(build/unsigned)
141 1 : }
142 :
143 1 : {
144 1 : using blobtype_t = uint8_t; // NOLINT(build/unsigned)
145 :
146 1 : constexpr int blob1_num_elements = 123;
147 1 : constexpr int blob2_num_elements = 456;
148 1 : std::array<blobtype_t, blob1_num_elements> blob1;
149 1 : std::array<blobtype_t, blob2_num_elements> blob2;
150 :
151 1 : Fragment test_frag(
152 1 : std::vector<std::pair<void*, size_t>>({ { &blob1[0], blob1_num_elements }, { &blob2[0], blob2_num_elements } }));
153 :
154 1 : BOOST_REQUIRE_EQUAL(sizeof(FragmentHeader) + blob1_num_elements + blob2_num_elements, test_frag.get_size());
155 1 : }
156 :
157 1 : free(frag); // Should not cause errors
158 1 : }
159 :
160 2 : BOOST_AUTO_TEST_CASE(BadExistingFragmentConstructor)
161 : {
162 1 : FragmentHeader header;
163 1 : header.size = -1;
164 1 : header.trigger_number = 1;
165 1 : header.trigger_timestamp = 2;
166 1 : header.run_number = 3;
167 :
168 1 : auto frag = malloc(sizeof(FragmentHeader) + 4);
169 1 : memcpy(frag, &header, sizeof(FragmentHeader));
170 :
171 1 : std::unique_ptr<Fragment> fragment_ptr{};
172 1 : #pragma GCC diagnostic push
173 1 : #pragma GCC diagnostic ignored "-Wrestrict"
174 2 : BOOST_REQUIRE_EXCEPTION(fragment_ptr.reset(new Fragment(frag, Fragment::BufferAdoptionMode::kCopyFromBuffer)),
175 : std::bad_alloc,
176 : [&](std::bad_alloc) { return true; });
177 1 : #pragma GCC diagnostic pop
178 :
179 1 : free(frag);
180 :
181 : // Use fragment_ptr
182 1 : auto bufsize = 10;
183 1 : auto buf1 = malloc(bufsize);
184 1 : fragment_ptr.reset(new Fragment(buf1, size_t(bufsize)));
185 1 : BOOST_REQUIRE_EQUAL(fragment_ptr->get_size(), sizeof(FragmentHeader) + bufsize);
186 1 : }
187 :
188 2 : BOOST_AUTO_TEST_CASE(MoveConstructor)
189 : {
190 1 : auto buf1 = malloc(10);
191 1 : auto single_frag = new Fragment(buf1, size_t(10));
192 1 : BOOST_REQUIRE_EQUAL(single_frag->get_size(), sizeof(FragmentHeader) + 10);
193 :
194 1 : Fragment another_frag(std::move(*single_frag));
195 :
196 1 : delete single_frag; // NOLINT We are specifically testing what happens when the original frag is deleted
197 :
198 1 : BOOST_REQUIRE_EQUAL(another_frag.get_size(), sizeof(FragmentHeader) + 10);
199 1 : }
200 :
201 2 : BOOST_AUTO_TEST_CASE(MoveAssignment)
202 : {
203 1 : auto buf1 = malloc(10);
204 1 : auto single_frag = new Fragment(buf1, size_t(10));
205 1 : BOOST_REQUIRE_EQUAL(single_frag->get_size(), sizeof(FragmentHeader) + 10);
206 :
207 1 : auto another_frag = std::move(*single_frag);
208 :
209 1 : delete single_frag; // NOLINT We are specifically testing what happens when the original frag is deleted
210 :
211 1 : BOOST_REQUIRE_EQUAL(another_frag.get_size(), sizeof(FragmentHeader) + 10);
212 1 : }
213 :
214 : /**
215 : * @brief Test header field manipulation methods
216 : */
217 2 : BOOST_AUTO_TEST_CASE(HeaderFields)
218 : {
219 :
220 1 : FragmentHeader header;
221 1 : header.size = sizeof(FragmentHeader) + 4;
222 1 : header.trigger_number = 1;
223 1 : header.trigger_timestamp = 2;
224 1 : header.run_number = 3;
225 1 : header.window_begin = 4;
226 1 : header.window_end = 5;
227 :
228 1 : SourceID component{ SourceID::Subsystem::kDetectorReadout, 123456789 };
229 1 : header.element_id = component;
230 :
231 1 : header.status_bits = 0x12345678;
232 1 : header.fragment_type = 8;
233 1 : header.sequence_number = 9;
234 :
235 1 : auto buf1 = malloc(10);
236 1 : Fragment frag(buf1, size_t(10));
237 1 : BOOST_REQUIRE_EQUAL(frag.get_size(), sizeof(FragmentHeader) + 10);
238 :
239 1 : frag.set_header_fields(header);
240 1 : BOOST_REQUIRE_EQUAL(frag.get_size(), sizeof(FragmentHeader) + 10);
241 1 : BOOST_REQUIRE_EQUAL(frag.get_header().run_number, header.run_number);
242 1 : BOOST_REQUIRE_EQUAL(frag.get_trigger_number(), header.trigger_number);
243 1 : BOOST_REQUIRE_EQUAL(frag.get_run_number(), header.run_number);
244 1 : BOOST_REQUIRE_EQUAL(frag.get_trigger_timestamp(), header.trigger_timestamp);
245 1 : BOOST_REQUIRE_EQUAL(frag.get_window_begin(), header.window_begin);
246 1 : BOOST_REQUIRE_EQUAL(frag.get_window_end(), header.window_end);
247 1 : BOOST_REQUIRE_EQUAL(frag.get_element_id(), header.element_id);
248 :
249 1 : BOOST_REQUIRE_EQUAL(frag.get_status_bits().to_ulong(), header.status_bits);
250 1 : BOOST_REQUIRE_EQUAL(frag.get_status_bit(static_cast<FragmentStatusBits>(3)), true);
251 :
252 1 : BOOST_REQUIRE_EQUAL(frag.get_fragment_type_code(), header.fragment_type);
253 1 : BOOST_REQUIRE_EQUAL(static_cast<fragment_type_t>(frag.get_fragment_type()), header.fragment_type);
254 :
255 1 : BOOST_REQUIRE_EQUAL(frag.get_sequence_number(), header.sequence_number);
256 :
257 1 : auto theHeader = static_cast<const FragmentHeader*>(frag.get_storage_location());
258 1 : frag.set_trigger_number(0x11);
259 1 : BOOST_REQUIRE_EQUAL(theHeader->trigger_number, 0x11);
260 1 : frag.set_run_number(0x33);
261 1 : BOOST_REQUIRE_EQUAL(theHeader->run_number, 0x33);
262 1 : frag.set_trigger_timestamp(0x22);
263 1 : BOOST_REQUIRE_EQUAL(theHeader->trigger_timestamp, 0x22);
264 1 : frag.set_window_begin(0x44);
265 1 : BOOST_REQUIRE_EQUAL(theHeader->window_begin, 0x44);
266 1 : frag.set_window_end(0x55);
267 1 : BOOST_REQUIRE_EQUAL(theHeader->window_end, 0x55);
268 1 : frag.set_type(static_cast<FragmentType>(0x88));
269 1 : BOOST_REQUIRE_EQUAL(theHeader->fragment_type, 0x88);
270 1 : frag.set_sequence_number(0x99);
271 1 : BOOST_REQUIRE_EQUAL(theHeader->sequence_number, 0x99);
272 :
273 1 : SourceID new_component{ SourceID::Subsystem::kDetectorReadout, 0x6677 };
274 1 : frag.set_element_id(new_component);
275 1 : BOOST_REQUIRE_EQUAL(theHeader->element_id.subsystem, SourceID::Subsystem::kDetectorReadout);
276 1 : BOOST_REQUIRE_EQUAL(theHeader->element_id.id, 0x6677);
277 :
278 1 : std::bitset<32> no_status(0);
279 1 : frag.set_status_bits(no_status);
280 1 : BOOST_REQUIRE_EQUAL(theHeader->status_bits, 0);
281 1 : frag.set_status_bit(static_cast<FragmentStatusBits>(1), true);
282 1 : BOOST_REQUIRE_EQUAL(theHeader->status_bits, 2);
283 1 : frag.set_status_bit(static_cast<FragmentStatusBits>(1), false);
284 1 : BOOST_REQUIRE_EQUAL(theHeader->status_bits, 0);
285 1 : }
286 :
287 : BOOST_AUTO_TEST_SUITE_END()
|