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); // NOLINT(build/unsigned)
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); // NOLINT(build/unsigned)
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 :
73 2 : BOOST_REQUIRE_EXCEPTION(
74 : fragment_ptr.reset(new Fragment({ nullptr, size_t(-1) - sizeof(dunedaq::daqdataformats::FragmentHeader) })),
75 : std::bad_alloc,
76 : [&](std::bad_alloc) { return true; });
77 :
78 1 : auto bufsize = 10;
79 1 : std::vector<uint8_t> buf1(bufsize); // NOLINT(build/unsigned)
80 1 : fragment_ptr = std::make_unique<Fragment>(buf1.data(), buf1.size());
81 1 : BOOST_REQUIRE_EQUAL(fragment_ptr->get_size(), sizeof(FragmentHeader) + bufsize);
82 1 : }
83 :
84 : /**
85 : * @brief Check that Fragment constructors function correctly
86 : */
87 2 : BOOST_AUTO_TEST_CASE(ExistingFragmentConstructor)
88 : {
89 1 : FragmentHeader header;
90 1 : header.size = sizeof(FragmentHeader) + 4;
91 1 : header.trigger_number = 1;
92 1 : header.trigger_timestamp = 2;
93 1 : header.run_number = 3;
94 :
95 1 : auto frag = malloc(sizeof(FragmentHeader) + 4); // NOLINT
96 1 : memcpy(frag, &header, sizeof(FragmentHeader));
97 :
98 1 : uint8_t one = 1, two = 2, three = 3, four = 4; // NOLINT
99 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader), &one, 1); // NOLINT
100 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader) + 1, &two, 1); // NOLINT
101 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader) + 2, &three, 1); // NOLINT
102 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader) + 3, &four, 1); // NOLINT
103 :
104 1 : free(frag); // Should not cause errors // NOLINT
105 :
106 1 : frag = malloc(sizeof(FragmentHeader) + 4); // NOLINT
107 1 : memcpy(frag, &header, sizeof(FragmentHeader)); // NOLINT
108 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader), &four, 1); // NOLINT
109 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader) + 1, &three, 1); // NOLINT
110 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader) + 2, &two, 1); // NOLINT
111 1 : memcpy(static_cast<uint8_t*>(frag) + sizeof(FragmentHeader) + 3, &one, 1); // NOLINT
112 :
113 1 : {
114 1 : Fragment test_frag(frag, Fragment::BufferAdoptionMode::kCopyFromBuffer);
115 :
116 1 : BOOST_REQUIRE(test_frag.get_storage_location() != frag);
117 1 : BOOST_REQUIRE_EQUAL(test_frag.get_trigger_number(), 1);
118 1 : BOOST_REQUIRE_EQUAL(test_frag.get_trigger_timestamp(), 2);
119 1 : BOOST_REQUIRE_EQUAL(test_frag.get_run_number(), 3);
120 :
121 1 : BOOST_REQUIRE_EQUAL(*static_cast<uint8_t*>(test_frag.get_data()), four); // NOLINT(build/unsigned)
122 1 : BOOST_REQUIRE_EQUAL(*(static_cast<uint8_t*>(test_frag.get_data()) + 1), three); // NOLINT(build/unsigned)
123 1 : BOOST_REQUIRE_EQUAL(*(static_cast<uint8_t*>(test_frag.get_data()) + 2), two); // NOLINT(build/unsigned)
124 1 : BOOST_REQUIRE_EQUAL(*(static_cast<uint8_t*>(test_frag.get_data()) + 3), one); // NOLINT(build/unsigned)
125 1 : }
126 :
127 1 : {
128 1 : using blobtype_t = uint8_t; // NOLINT(build/unsigned)
129 :
130 1 : constexpr int blob1_num_elements = 123;
131 1 : constexpr int blob2_num_elements = 456;
132 1 : std::array<blobtype_t, blob1_num_elements> blob1;
133 1 : std::array<blobtype_t, blob2_num_elements> blob2;
134 :
135 1 : Fragment test_frag(
136 1 : std::vector<std::pair<void*, size_t>>({ { &blob1[0], blob1_num_elements }, { &blob2[0], blob2_num_elements } }));
137 :
138 1 : BOOST_REQUIRE_EQUAL(sizeof(FragmentHeader) + blob1_num_elements + blob2_num_elements, test_frag.get_size());
139 1 : }
140 :
141 1 : free(frag); // Should not cause errors // NOLINT
142 1 : }
143 :
144 2 : BOOST_AUTO_TEST_CASE(BadExistingFragmentConstructor)
145 : {
146 1 : FragmentHeader header;
147 1 : header.size = -1;
148 1 : header.trigger_number = 1;
149 1 : header.trigger_timestamp = 2;
150 1 : header.run_number = 3;
151 :
152 1 : auto frag = malloc(sizeof(FragmentHeader) + 4); // NOLINT
153 1 : memcpy(frag, &header, sizeof(FragmentHeader));
154 :
155 1 : std::unique_ptr<Fragment> fragment_ptr{};
156 1 : #pragma GCC diagnostic push
157 1 : #pragma GCC diagnostic ignored "-Wrestrict"
158 2 : BOOST_REQUIRE_EXCEPTION(fragment_ptr.reset(new Fragment(frag, Fragment::BufferAdoptionMode::kCopyFromBuffer)),
159 : std::bad_alloc,
160 : [&](std::bad_alloc) { return true; });
161 1 : #pragma GCC diagnostic pop
162 :
163 1 : free(frag); // NOLINT
164 :
165 : // Use fragment_ptr
166 1 : size_t bufsize = 10;
167 1 : auto buf1 = malloc(bufsize); // NOLINT
168 1 : fragment_ptr = std::make_unique<Fragment>(buf1, bufsize);
169 1 : BOOST_REQUIRE_EQUAL(fragment_ptr->get_size(), sizeof(FragmentHeader) + bufsize);
170 1 : }
171 :
172 2 : BOOST_AUTO_TEST_CASE(MoveConstructor)
173 : {
174 1 : size_t bufsize{ 10 };
175 1 : auto buf1 = malloc(bufsize); // NOLINT
176 1 : auto single_frag = new Fragment(buf1, bufsize);
177 1 : BOOST_REQUIRE_EQUAL(single_frag->get_size(), sizeof(FragmentHeader) + bufsize);
178 :
179 1 : Fragment another_frag(std::move(*single_frag));
180 :
181 1 : delete single_frag; // NOLINT We are specifically testing what happens when the original frag is deleted
182 :
183 1 : BOOST_REQUIRE_EQUAL(another_frag.get_size(), sizeof(FragmentHeader) + bufsize);
184 1 : }
185 :
186 2 : BOOST_AUTO_TEST_CASE(MoveAssignment)
187 : {
188 1 : size_t bufsize{ 10 };
189 1 : auto buf1 = malloc(bufsize); // NOLINT
190 1 : auto single_frag = new Fragment(buf1, bufsize);
191 1 : BOOST_REQUIRE_EQUAL(single_frag->get_size(), sizeof(FragmentHeader) + bufsize);
192 :
193 1 : auto another_frag = std::move(*single_frag);
194 :
195 1 : delete single_frag; // NOLINT We are specifically testing what happens when the original frag is deleted
196 :
197 1 : BOOST_REQUIRE_EQUAL(another_frag.get_size(), sizeof(FragmentHeader) + bufsize);
198 1 : }
199 :
200 : /**
201 : * @brief Test header field manipulation methods
202 : */
203 2 : BOOST_AUTO_TEST_CASE(HeaderFields)
204 : {
205 :
206 1 : FragmentHeader header;
207 1 : header.size = sizeof(FragmentHeader) + 4;
208 1 : header.trigger_number = 1;
209 1 : header.trigger_timestamp = 2;
210 1 : header.run_number = 3;
211 1 : header.window_begin = 4;
212 1 : header.window_end = 5;
213 :
214 1 : SourceID component{ SourceID::Subsystem::kDetectorReadout, 123456789 };
215 1 : header.element_id = component;
216 :
217 1 : header.status_bits = 0x12345678;
218 1 : header.fragment_type = 8;
219 1 : header.sequence_number = 9;
220 :
221 1 : auto buf1 = malloc(10); // NOLINT
222 1 : Fragment frag(buf1, static_cast<size_t>(10));
223 1 : BOOST_REQUIRE_EQUAL(frag.get_size(), sizeof(FragmentHeader) + 10);
224 :
225 1 : frag.set_header_fields(header);
226 1 : BOOST_REQUIRE_EQUAL(frag.get_size(), sizeof(FragmentHeader) + 10);
227 1 : BOOST_REQUIRE_EQUAL(frag.get_header().run_number, header.run_number);
228 1 : BOOST_REQUIRE_EQUAL(frag.get_trigger_number(), header.trigger_number);
229 1 : BOOST_REQUIRE_EQUAL(frag.get_run_number(), header.run_number);
230 1 : BOOST_REQUIRE_EQUAL(frag.get_trigger_timestamp(), header.trigger_timestamp);
231 1 : BOOST_REQUIRE_EQUAL(frag.get_window_begin(), header.window_begin);
232 1 : BOOST_REQUIRE_EQUAL(frag.get_window_end(), header.window_end);
233 1 : BOOST_REQUIRE_EQUAL(frag.get_element_id(), header.element_id);
234 :
235 1 : BOOST_REQUIRE_EQUAL(frag.get_status_bits().to_ulong(), header.status_bits);
236 1 : BOOST_REQUIRE_EQUAL(frag.get_status_bit(static_cast<FragmentStatusBits>(3)), true);
237 :
238 1 : BOOST_REQUIRE_EQUAL(frag.get_fragment_type_code(), header.fragment_type);
239 1 : BOOST_REQUIRE_EQUAL(static_cast<fragment_type_t>(frag.get_fragment_type()), header.fragment_type);
240 :
241 1 : BOOST_REQUIRE_EQUAL(frag.get_sequence_number(), header.sequence_number);
242 :
243 1 : auto theHeader = static_cast<const FragmentHeader*>(frag.get_storage_location());
244 1 : frag.set_trigger_number(0x11);
245 1 : BOOST_REQUIRE_EQUAL(theHeader->trigger_number, 0x11);
246 1 : frag.set_run_number(0x33);
247 1 : BOOST_REQUIRE_EQUAL(theHeader->run_number, 0x33);
248 1 : frag.set_trigger_timestamp(0x22);
249 1 : BOOST_REQUIRE_EQUAL(theHeader->trigger_timestamp, 0x22);
250 1 : frag.set_window_begin(0x44);
251 1 : BOOST_REQUIRE_EQUAL(theHeader->window_begin, 0x44);
252 1 : frag.set_window_end(0x55);
253 1 : BOOST_REQUIRE_EQUAL(theHeader->window_end, 0x55);
254 1 : frag.set_type(static_cast<FragmentType>(0x88)); // NOLINT
255 1 : BOOST_REQUIRE_EQUAL(theHeader->fragment_type, 0x88);
256 1 : frag.set_sequence_number(0x99);
257 1 : BOOST_REQUIRE_EQUAL(theHeader->sequence_number, 0x99);
258 :
259 1 : SourceID new_component{ SourceID::Subsystem::kDetectorReadout, 0x6677 };
260 1 : frag.set_element_id(new_component);
261 1 : BOOST_REQUIRE_EQUAL(theHeader->element_id.subsystem, SourceID::Subsystem::kDetectorReadout);
262 1 : BOOST_REQUIRE_EQUAL(theHeader->element_id.id, 0x6677);
263 :
264 1 : std::bitset<32> no_status(0);
265 1 : frag.set_status_bits(no_status);
266 1 : BOOST_REQUIRE_EQUAL(theHeader->status_bits, 0);
267 1 : frag.set_status_bit(static_cast<FragmentStatusBits>(1), true);
268 1 : BOOST_REQUIRE_EQUAL(theHeader->status_bits, 2);
269 1 : frag.set_status_bit(static_cast<FragmentStatusBits>(1), false);
270 1 : BOOST_REQUIRE_EQUAL(theHeader->status_bits, 0);
271 1 : }
272 :
273 : BOOST_AUTO_TEST_SUITE_END()
|