LCOV - code coverage report
Current view: top level - daqdataformats/unittest - Fragment_test.cxx (source / functions) Coverage Total Hit
Test: code.result Lines: 100.0 % 167 167
Test Date: 2025-12-21 13:07:08 Functions: 100.0 % 20 20

            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            4 :   BOOST_REQUIRE_EXCEPTION(fragment_ptr.reset(new Fragment(nullptr, size_t(100))),
      70              :                           std::invalid_argument,
      71              :                           [&](std::invalid_argument) { return true; });
      72            4 :   BOOST_REQUIRE_EXCEPTION(
      73              :     fragment_ptr.reset(new Fragment(nullptr, size_t(-1))), std::length_error, [&](std::length_error) { return true; });
      74              : 
      75            4 :   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            4 :   BOOST_REQUIRE_EXCEPTION(fragment_ptr.reset(new Fragment(frag, Fragment::BufferAdoptionMode::kCopyFromBuffer)),
     173              :                           std::bad_alloc,
     174              :                           [&](std::bad_alloc) { return true; });
     175            1 :   free(frag);
     176              : 
     177              :   // Use fragment_ptr
     178            1 :   auto bufsize = 10;
     179            1 :   auto buf1 = malloc(bufsize);
     180            1 :   fragment_ptr.reset(new Fragment(buf1, size_t(bufsize)));
     181            1 :   BOOST_REQUIRE_EQUAL(fragment_ptr->get_size(), sizeof(FragmentHeader) + bufsize);
     182            1 : }
     183              : 
     184            2 : BOOST_AUTO_TEST_CASE(MoveConstructor)
     185              : {
     186            1 :   auto buf1 = malloc(10);
     187            1 :   auto single_frag = new Fragment(buf1, size_t(10));
     188            1 :   BOOST_REQUIRE_EQUAL(single_frag->get_size(), sizeof(FragmentHeader) + 10);
     189              : 
     190            1 :   Fragment another_frag(std::move(*single_frag));
     191              : 
     192            1 :   delete single_frag; // NOLINT We are specifically testing what happens when the original frag is deleted
     193              : 
     194            1 :   BOOST_REQUIRE_EQUAL(another_frag.get_size(), sizeof(FragmentHeader) + 10);
     195            1 : }
     196              : 
     197            2 : BOOST_AUTO_TEST_CASE(MoveAssignment)
     198              : {
     199            1 :   auto buf1 = malloc(10);
     200            1 :   auto single_frag = new Fragment(buf1, size_t(10));
     201            1 :   BOOST_REQUIRE_EQUAL(single_frag->get_size(), sizeof(FragmentHeader) + 10);
     202              : 
     203            1 :   auto another_frag = std::move(*single_frag);
     204              : 
     205            1 :   delete single_frag; // NOLINT We are specifically testing what happens when the original frag is deleted
     206              : 
     207            1 :   BOOST_REQUIRE_EQUAL(another_frag.get_size(), sizeof(FragmentHeader) + 10);
     208            1 : }
     209              : 
     210              : /**
     211              :  * @brief Test header field manipulation methods
     212              :  */
     213            2 : BOOST_AUTO_TEST_CASE(HeaderFields)
     214              : {
     215              : 
     216            1 :   FragmentHeader header;
     217            1 :   header.size = sizeof(FragmentHeader) + 4;
     218            1 :   header.trigger_number = 1;
     219            1 :   header.trigger_timestamp = 2;
     220            1 :   header.run_number = 3;
     221            1 :   header.window_begin = 4;
     222            1 :   header.window_end = 5;
     223              : 
     224            1 :   SourceID component{ SourceID::Subsystem::kDetectorReadout, 123456789 };
     225            1 :   header.element_id = component;
     226              : 
     227            1 :   header.error_bits = 0x12345678;
     228            1 :   header.fragment_type = 8;
     229            1 :   header.sequence_number = 9;
     230              : 
     231            1 :   auto buf1 = malloc(10);
     232            1 :   Fragment frag(buf1, size_t(10));
     233            1 :   BOOST_REQUIRE_EQUAL(frag.get_size(), sizeof(FragmentHeader) + 10);
     234              : 
     235            1 :   frag.set_header_fields(header);
     236            1 :   BOOST_REQUIRE_EQUAL(frag.get_size(), sizeof(FragmentHeader) + 10);
     237            1 :   BOOST_REQUIRE_EQUAL(frag.get_header().run_number, header.run_number);
     238            1 :   BOOST_REQUIRE_EQUAL(frag.get_trigger_number(), header.trigger_number);
     239            1 :   BOOST_REQUIRE_EQUAL(frag.get_run_number(), header.run_number);
     240            1 :   BOOST_REQUIRE_EQUAL(frag.get_trigger_timestamp(), header.trigger_timestamp);
     241            1 :   BOOST_REQUIRE_EQUAL(frag.get_window_begin(), header.window_begin);
     242            1 :   BOOST_REQUIRE_EQUAL(frag.get_window_end(), header.window_end);
     243            1 :   BOOST_REQUIRE_EQUAL(frag.get_element_id(), header.element_id);
     244              : 
     245            1 :   BOOST_REQUIRE_EQUAL(frag.get_error_bits().to_ulong(), header.error_bits);
     246            1 :   BOOST_REQUIRE_EQUAL(frag.get_error_bit(static_cast<FragmentErrorBits>(3)), true);
     247              : 
     248            1 :   BOOST_REQUIRE_EQUAL(frag.get_fragment_type_code(), header.fragment_type);
     249            1 :   BOOST_REQUIRE_EQUAL(static_cast<fragment_type_t>(frag.get_fragment_type()), header.fragment_type);
     250              : 
     251            1 :   BOOST_REQUIRE_EQUAL(frag.get_sequence_number(), header.sequence_number);
     252              : 
     253            1 :   auto theHeader = static_cast<const FragmentHeader*>(frag.get_storage_location());
     254            1 :   frag.set_trigger_number(0x11);
     255            1 :   BOOST_REQUIRE_EQUAL(theHeader->trigger_number, 0x11);
     256            1 :   frag.set_run_number(0x33);
     257            1 :   BOOST_REQUIRE_EQUAL(theHeader->run_number, 0x33);
     258            1 :   frag.set_trigger_timestamp(0x22);
     259            1 :   BOOST_REQUIRE_EQUAL(theHeader->trigger_timestamp, 0x22);
     260            1 :   frag.set_window_begin(0x44);
     261            1 :   BOOST_REQUIRE_EQUAL(theHeader->window_begin, 0x44);
     262            1 :   frag.set_window_end(0x55);
     263            1 :   BOOST_REQUIRE_EQUAL(theHeader->window_end, 0x55);
     264            1 :   frag.set_type(static_cast<FragmentType>(0x88));
     265            1 :   BOOST_REQUIRE_EQUAL(theHeader->fragment_type, 0x88);
     266            1 :   frag.set_sequence_number(0x99);
     267            1 :   BOOST_REQUIRE_EQUAL(theHeader->sequence_number, 0x99);
     268              : 
     269            1 :   SourceID new_component{ SourceID::Subsystem::kDetectorReadout, 0x6677 };
     270            1 :   frag.set_element_id(new_component);
     271            1 :   BOOST_REQUIRE_EQUAL(theHeader->element_id.subsystem, SourceID::Subsystem::kDetectorReadout);
     272            1 :   BOOST_REQUIRE_EQUAL(theHeader->element_id.id, 0x6677);
     273              : 
     274            1 :   std::bitset<32> no_errors(0);
     275            1 :   frag.set_error_bits(no_errors);
     276            1 :   BOOST_REQUIRE_EQUAL(theHeader->error_bits, 0);
     277            1 :   frag.set_error_bit(static_cast<FragmentErrorBits>(1), true);
     278            1 :   BOOST_REQUIRE_EQUAL(theHeader->error_bits, 2);
     279            1 :   frag.set_error_bit(static_cast<FragmentErrorBits>(1), false);
     280            1 :   BOOST_REQUIRE_EQUAL(theHeader->error_bits, 0);
     281            1 : }
     282              : 
     283              : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1