LCOV - code coverage report
Current view: top level - /opt/artdaq/srcs/artdaq-database/test/CaseStudy/OtsDaqCPPInterface/test025 - StringRoundTrip_t.cc (source / functions) Coverage Total Hit
Test: artdaq.info.cleaned Lines: 83.7 % 98 82
Test Date: 2026-10-29 00:35:58 Functions: 100.0 % 8 8

            Line data    Source code
       1              : #define BOOST_TEST_DYN_LINK
       2              : #define BOOST_TEST_MODULE (StringRoundTrip test)
       3              : 
       4              : #include <algorithm>
       5              : #include <boost/test/unit_test.hpp>
       6              : #include <fstream>
       7              : #include <numeric>
       8              : #include <random>
       9              : #include <sstream>
      10              : 
      11              : #include "../DatabaseConfigurationInterface.h"
      12              : #include "artdaq-database/JsonDocument/JSONDocument.h"
      13              : 
      14              : using namespace ots;
      15              : using artdaq::database::docrecord::JSONDocument;
      16              : 
      17              : namespace {
      18              : 
      19            4 : bool isQuickMode() {
      20            4 :   auto* quick = getenv("QUICK_TEST");
      21            4 :   return quick && (std::string(quick) == "1" || std::string(quick) == "true");
      22              : }
      23              : 
      24            2 : std::vector<std::string> loadInputsFromFile(const std::string& filename) {
      25            2 :   std::vector<std::string> inputs;
      26            2 :   std::ifstream file(filename);
      27            2 :   if (!file) return inputs;
      28              : 
      29            2 :   std::stringstream buf;
      30            2 :   buf << file.rdbuf();
      31            2 :   std::string content = buf.str();
      32              : 
      33            2 :   size_t pos = 0;
      34          178 :   while ((pos = content.find("\"input\":", pos)) != std::string::npos) {
      35          176 :     size_t start = content.find('{', pos);
      36          176 :     if (start == std::string::npos) break;
      37              : 
      38          176 :     int depth = 1;
      39          176 :     size_t end = start + 1;
      40         5904 :     while (depth > 0 && end < content.size()) {
      41         5728 :       if (content[end] == '{')
      42            8 :         depth++;
      43         5720 :       else if (content[end] == '}')
      44          184 :         depth--;
      45         5536 :       else if (content[end] == '"') {
      46         1958 :         end++;
      47        16792 :         while (end < content.size() && content[end] != '"') {
      48        14834 :           if (content[end] == '\\') end++;
      49        14834 :           end++;
      50              :         }
      51              :       }
      52         5728 :       end++;
      53              :     }
      54          176 :     inputs.push_back(content.substr(start, end - start));
      55          176 :     pos = end;
      56              :   }
      57            2 :   return inputs;
      58            2 : }
      59              : 
      60              : struct TestFixture {
      61            2 :   TestFixture() : baseVersion((srand(time(nullptr)), rand() % 99999 + 100000)) {
      62            2 :     inputs = loadInputsFromFile("test_cases.json");
      63              : 
      64            2 :     if (isQuickMode() && inputs.size() > 10) {
      65            0 :       std::vector<size_t> idx(inputs.size());
      66            0 :       std::iota(idx.begin(), idx.end(), 0);
      67            0 :       std::shuffle(idx.begin(), idx.end(), std::mt19937{std::random_device{}()});
      68            0 :       idx.resize(inputs.size() / 10);
      69            0 :       std::sort(idx.begin(), idx.end());
      70            0 :       std::vector<std::string> sampled;
      71            0 :       for (auto i : idx) sampled.push_back(inputs[i]);
      72            0 :       inputs = std::move(sampled);
      73            0 :     }
      74              : 
      75            2 :     std::cout << "Loaded " << inputs.size() << " test cases" << (isQuickMode() ? " (QUICK MODE)" : "") << "\n";
      76            2 :   }
      77              : 
      78          704 :   int nextVersion() { return baseVersion + (++versionOffset); }
      79              : 
      80              :   const int baseVersion;
      81              :   std::vector<std::string> inputs;
      82              : 
      83              :  private:
      84              :   int versionOffset = 0;
      85              : };
      86              : 
      87              : }  // namespace
      88              : 
      89              : TestFixture fixture;
      90              : 
      91              : BOOST_AUTO_TEST_SUITE(string_roundtrip_test)
      92              : 
      93            4 : BOOST_AUTO_TEST_CASE(json_roundtrip_ast_comparison) {
      94            2 :   DatabaseConfigurationInterface ifc;
      95            2 :   int passed = 0, failed = 0;
      96              : 
      97          178 :   for (const auto& inputJson : fixture.inputs) {
      98          176 :     int version = fixture.nextVersion();
      99              : 
     100          176 :     auto writer = std::make_shared<TestConfiguration001>();
     101          176 :     writer->getView().fillFromJSON(inputJson);
     102          176 :     writer->getView().version = version;
     103          176 :     if (ifc.saveActiveVersion(writer.get()) != 0) {
     104            0 :       failed++;
     105            0 :       continue;
     106              :     }
     107              : 
     108          176 :     auto reader = std::make_shared<TestConfiguration001>();
     109          176 :     if (ifc.fill(reader.get(), version) != 0) {
     110            0 :       failed++;
     111            0 :       continue;
     112              :     }
     113              : 
     114          176 :     JSONDocument inputDoc(inputJson);
     115          176 :     JSONDocument outputDoc(reader->getView()._json);
     116              : 
     117          176 :     if (inputDoc == outputDoc) {
     118          176 :       passed++;
     119              :     } else {
     120            0 :       failed++;
     121            0 :       std::cout << "FAIL: " << inputJson.substr(0, 60) << "...\n";
     122              :     }
     123          176 :   }
     124              : 
     125            2 :   std::cout << "Passed: " << passed << "/" << fixture.inputs.size() << "\n";
     126            2 :   BOOST_CHECK_EQUAL(failed, 0);
     127            2 : }
     128              : 
     129            4 : BOOST_AUTO_TEST_CASE(multiple_roundtrips_stability) {
     130            2 :   DatabaseConfigurationInterface ifc;
     131            2 :   int stable = 0, unstable = 0;
     132              : 
     133          178 :   for (const auto& inputJson : fixture.inputs) {
     134          176 :     std::vector<std::string> reads;
     135          176 :     std::string current = inputJson;
     136              : 
     137          704 :     for (int round = 0; round < 3; ++round) {
     138          528 :       int version = fixture.nextVersion();
     139          528 :       auto writer = std::make_shared<TestConfiguration001>();
     140          528 :       writer->getView().fillFromJSON(current);
     141          528 :       writer->getView().version = version;
     142          528 :       if (ifc.saveActiveVersion(writer.get()) != 0) break;
     143              : 
     144          528 :       auto reader = std::make_shared<TestConfiguration001>();
     145          528 :       if (ifc.fill(reader.get(), version) != 0) break;
     146          528 :       current = reader->getView()._json;
     147          528 :       reads.push_back(current);
     148          528 :     }
     149              : 
     150          176 :     if (reads.size() == 3) {
     151          176 :       JSONDocument d0(inputJson), d1(reads[0]), d2(reads[1]), d3(reads[2]);
     152          176 :       if (d0 == d1 && d1 == d2 && d2 == d3) {
     153          176 :         stable++;
     154              :       } else {
     155            0 :         unstable++;
     156              :       }
     157          176 :     }
     158          176 :   }
     159              : 
     160            2 :   std::cout << "Stable: " << stable << "/" << fixture.inputs.size() << "\n";
     161            2 :   BOOST_CHECK_EQUAL(unstable, 0);
     162            2 : }
     163              : 
     164              : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1