LCOV - code coverage report
Current view: top level - daqdataformats/unittest - Fragment_test.cxx (source / functions) Coverage Total Hit
Test: code.result Lines: 100.0 % 160 160
Test Date: 2026-05-24 15:29:04 Functions: 100.0 % 16 16

            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()
        

Generated by: LCOV version 2.0-1