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

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

Generated by: LCOV version 2.0-1