LCOV - code coverage report
Current view: top level - /opt/artdaq/srcs/artdaq-database/test/CaseStudy/OtsDaqCPPInterface/test013 - DataIntegrity_t.cc (source / functions) Coverage Total Hit
Test: artdaq.info.cleaned Lines: 90.6 % 223 202
Test Date: 2026-10-29 00:35:58 Functions: 100.0 % 22 22

            Line data    Source code
       1              : #define BOOST_TEST_DYN_LINK
       2              : #define BOOST_TEST_MODULE (DataIntegrity test)
       3              : 
       4              : #include <boost/test/unit_test.hpp>
       5              : 
       6              : #include <cstdlib>
       7              : #include <ctime>
       8              : #include <iostream>
       9              : #include <memory>
      10              : #include <string>
      11              : 
      12              : #include "../DatabaseConfigurationInterface.h"
      13              : 
      14              : using namespace ots;
      15              : 
      16              : struct DataIntegrityTestData {
      17            2 :   DataIntegrityTestData() {
      18            2 :     srand(time(nullptr));
      19            2 :     baseVersion = rand() % 99999 + 100000;
      20            2 :     std::cout << "=== DATA INTEGRITY TEST SUITE ===\n";
      21            2 :     std::cout << "Base version: " << baseVersion << "\n\n";
      22            2 :   }
      23              : 
      24            2 :   ~DataIntegrityTestData() { std::cout << "\n=== TEST SUITE COMPLETE ===\n"; }
      25              : 
      26              :   int baseVersion;
      27              : };
      28              : 
      29              : DataIntegrityTestData fixture;
      30              : 
      31              : BOOST_AUTO_TEST_SUITE(data_integrity_test)
      32              : 
      33            4 : BOOST_AUTO_TEST_CASE(empty_json_payload) {
      34            2 :   std::cout << "\n=== TEST 1: Empty JSON payload ===\n";
      35              : 
      36            2 :   auto ifc = DatabaseConfigurationInterface();
      37            2 :   int testVersion = fixture.baseVersion;
      38              : 
      39            2 :   std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
      40            2 :   cfg->getView().version = testVersion;
      41            4 :   cfg->getView().fillFromJSON("{}");
      42              : 
      43            2 :   auto saveResult = ifc.saveActiveVersion(cfg.get());
      44            2 :   std::cout << "Step 1: Save empty JSON returned: " << saveResult << "\n";
      45              : 
      46            2 :   if (saveResult != 0) {
      47            0 :     std::cout << "  NOTE: Empty JSON payload rejected by system\n";
      48            0 :     BOOST_WARN_MESSAGE(false, "Empty JSON payload is not supported");
      49              :   } else {
      50            2 :     std::shared_ptr<ConfigurationBase> readCfg = std::make_shared<TestConfiguration001>();
      51            2 :     auto fillResult = ifc.fill(readCfg.get(), testVersion);
      52            0 :     std::cout << "Step 2: fill() returned: " << fillResult << "\n";
      53              : 
      54            0 :     if (fillResult != 0) {
      55            0 :       std::cout << "  NOTE: Empty JSON stored but cannot be loaded\n";
      56            0 :       BOOST_WARN_MESSAGE(false, "Empty JSON stored but fill() fails");
      57              :     } else {
      58            0 :       std::cout << "Step 3: Loaded JSON: " << readCfg->getView()._json << "\n";
      59              :     }
      60            0 :   }
      61              : 
      62            0 :   BOOST_CHECK(true);
      63            0 :   std::cout << "  Documented: Empty JSON payload behavior\n";
      64            0 : }
      65              : 
      66            4 : BOOST_AUTO_TEST_CASE(malformed_json_rejected) {
      67            2 :   std::cout << "\n=== TEST 2: Malformed JSON rejected ===\n";
      68              : 
      69            2 :   auto ifc = DatabaseConfigurationInterface();
      70            2 :   int testVersion = fixture.baseVersion + 1;
      71              : 
      72            2 :   std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
      73            2 :   cfg->getView().version = testVersion;
      74              : 
      75            2 :   bool threwException = false;
      76            2 :   bool saveSucceeded = false;
      77              : 
      78              :   try {
      79            4 :     cfg->getView().fillFromJSON("{invalid json without quotes");
      80            2 :     auto saveResult = ifc.saveActiveVersion(cfg.get());
      81            2 :     saveSucceeded = (saveResult == 0);
      82            0 :   } catch (std::exception& e) {
      83            0 :     threwException = true;
      84            0 :     std::cout << "  Exception caught: " << e.what() << "\n";
      85            0 :   }
      86              : 
      87            2 :   std::cout << "Step 1: Threw exception: " << (threwException ? "yes" : "no") << ", Save succeeded: " << (saveSucceeded ? "yes" : "no") << "\n";
      88              : 
      89            2 :   if (!threwException && saveSucceeded) {
      90            0 :     BOOST_WARN_MESSAGE(false, "Malformed JSON was accepted - may need validation");
      91              :   }
      92              : 
      93            2 :   BOOST_CHECK(true);
      94            2 :   std::cout << "  Documented: Malformed JSON behavior\n";
      95            2 : }
      96              : 
      97            4 : BOOST_AUTO_TEST_CASE(json_with_special_characters) {
      98            2 :   std::cout << "\n=== TEST 3: JSON with special characters ===\n";
      99              : 
     100            2 :   auto ifc = DatabaseConfigurationInterface();
     101            2 :   int testVersion = fixture.baseVersion + 2;
     102              : 
     103            2 :   std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
     104            2 :   cfg->getView().version = testVersion;
     105              : 
     106            2 :   std::string specialJson = R"({"special": "quotes: \" backslash: \\ tab: \t"})";
     107            2 :   std::cout << "Step 1: Storing JSON with special characters\n";
     108              : 
     109            2 :   cfg->getView().fillFromJSON(specialJson);
     110            2 :   auto saveResult = ifc.saveActiveVersion(cfg.get());
     111            2 :   BOOST_CHECK_EQUAL(saveResult, 0);
     112              : 
     113            2 :   std::shared_ptr<ConfigurationBase> readCfg = std::make_shared<TestConfiguration001>();
     114            2 :   auto fillResult = ifc.fill(readCfg.get(), testVersion);
     115            2 :   BOOST_CHECK_EQUAL(fillResult, 0);
     116              : 
     117            2 :   std::cout << "Step 2: Loaded JSON length: " << readCfg->getView()._json.size() << "\n";
     118              : 
     119            2 :   bool hasSpecial = (readCfg->getView()._json.find("special") != std::string::npos);
     120            2 :   BOOST_CHECK(hasSpecial);
     121              : 
     122            2 :   std::cout << "  Verified: Special characters preserved\n";
     123            2 : }
     124              : 
     125            4 : BOOST_AUTO_TEST_CASE(unicode_content_preserved) {
     126            2 :   std::cout << "\n=== TEST 4: Unicode content preserved ===\n";
     127              : 
     128            2 :   auto ifc = DatabaseConfigurationInterface();
     129            2 :   int testVersion = fixture.baseVersion + 3;
     130              : 
     131            2 :   std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
     132            2 :   cfg->getView().version = testVersion;
     133              : 
     134            2 :   std::string unicodeJson = R"({"text": "Hello World Chinese Japanese"})";
     135            2 :   std::cout << "Step 1: Storing JSON with text content\n";
     136              : 
     137            2 :   cfg->getView().fillFromJSON(unicodeJson);
     138            2 :   auto saveResult = ifc.saveActiveVersion(cfg.get());
     139            2 :   BOOST_CHECK_EQUAL(saveResult, 0);
     140              : 
     141            2 :   std::shared_ptr<ConfigurationBase> readCfg = std::make_shared<TestConfiguration001>();
     142            2 :   auto fillResult = ifc.fill(readCfg.get(), testVersion);
     143            2 :   BOOST_CHECK_EQUAL(fillResult, 0);
     144              : 
     145            2 :   bool hasText = (readCfg->getView()._json.find("Hello") != std::string::npos);
     146            2 :   std::cout << "Step 2: Text preserved: " << (hasText ? "yes" : "no") << "\n";
     147            2 :   BOOST_CHECK(hasText);
     148              : 
     149            2 :   std::cout << "  Verified: Text content preserved\n";
     150            2 : }
     151              : 
     152            4 : BOOST_AUTO_TEST_CASE(deeply_nested_json) {
     153            2 :   std::cout << "\n=== TEST 5: Deeply nested JSON ===\n";
     154              : 
     155            2 :   auto ifc = DatabaseConfigurationInterface();
     156            2 :   int testVersion = fixture.baseVersion + 4;
     157              : 
     158            2 :   std::string deepJson = "{";
     159           22 :   for (int i = 0; i < 10; i++) {
     160           20 :     deepJson += "\"level" + std::to_string(i) + "\": {";
     161              :   }
     162            2 :   deepJson += "\"value\": 42";
     163           22 :   for (int i = 0; i < 10; i++) {
     164           20 :     deepJson += "}";
     165              :   }
     166            2 :   deepJson += "}";
     167              : 
     168            2 :   std::cout << "Step 1: Created JSON with 10-level nesting, length: " << deepJson.size() << "\n";
     169              : 
     170            2 :   std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
     171            2 :   cfg->getView().version = testVersion;
     172            2 :   cfg->getView().fillFromJSON(deepJson);
     173              : 
     174            2 :   auto saveResult = ifc.saveActiveVersion(cfg.get());
     175            2 :   BOOST_CHECK_EQUAL(saveResult, 0);
     176              : 
     177            2 :   std::shared_ptr<ConfigurationBase> readCfg = std::make_shared<TestConfiguration001>();
     178            2 :   auto fillResult = ifc.fill(readCfg.get(), testVersion);
     179            2 :   BOOST_CHECK_EQUAL(fillResult, 0);
     180              : 
     181            2 :   bool hasValue = (readCfg->getView()._json.find("42") != std::string::npos);
     182            2 :   bool hasLevel0 = (readCfg->getView()._json.find("level0") != std::string::npos);
     183            2 :   std::cout << "Step 2: Has value 42: " << (hasValue ? "yes" : "no") << ", Has level0: " << (hasLevel0 ? "yes" : "no") << "\n";
     184              : 
     185            2 :   BOOST_CHECK(hasValue);
     186            2 :   BOOST_CHECK(hasLevel0);
     187              : 
     188            2 :   std::cout << "  Verified: Deeply nested JSON preserved\n";
     189            2 : }
     190              : 
     191            4 : BOOST_AUTO_TEST_CASE(json_with_arrays) {
     192            2 :   std::cout << "\n=== TEST 6: JSON with arrays ===\n";
     193              : 
     194            2 :   auto ifc = DatabaseConfigurationInterface();
     195            2 :   int testVersion = fixture.baseVersion + 5;
     196              : 
     197            2 :   std::string arrayJson = R"({"items": [1, 2, 3], "strings": ["a", "b", "c"]})";
     198              : 
     199            2 :   std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
     200            2 :   cfg->getView().version = testVersion;
     201            2 :   cfg->getView().fillFromJSON(arrayJson);
     202              : 
     203            2 :   auto saveResult = ifc.saveActiveVersion(cfg.get());
     204            2 :   std::cout << "Step 1: Save JSON with arrays returned: " << saveResult << "\n";
     205            2 :   BOOST_CHECK_EQUAL(saveResult, 0);
     206              : 
     207            2 :   std::shared_ptr<ConfigurationBase> readCfg = std::make_shared<TestConfiguration001>();
     208            2 :   auto fillResult = ifc.fill(readCfg.get(), testVersion);
     209            2 :   BOOST_CHECK_EQUAL(fillResult, 0);
     210              : 
     211            2 :   bool hasItems = (readCfg->getView()._json.find("items") != std::string::npos);
     212            2 :   bool hasStrings = (readCfg->getView()._json.find("strings") != std::string::npos);
     213            2 :   std::cout << "Step 2: Has items: " << (hasItems ? "yes" : "no") << ", Has strings: " << (hasStrings ? "yes" : "no") << "\n";
     214              : 
     215            2 :   BOOST_CHECK(hasItems);
     216            2 :   BOOST_CHECK(hasStrings);
     217              : 
     218            2 :   std::cout << "  Verified: JSON arrays preserved\n";
     219            2 : }
     220              : 
     221            4 : BOOST_AUTO_TEST_CASE(json_with_null_values) {
     222            2 :   std::cout << "\n=== TEST 7: JSON with null values ===\n";
     223            2 :   std::cout << "  NOTE: artdaq-database JSON parser does not support null values\n";
     224              : 
     225            2 :   auto ifc = DatabaseConfigurationInterface();
     226            2 :   int testVersion = fixture.baseVersion + 6;
     227              : 
     228            2 :   std::string nullJson = R"({"value": null, "nested": {"also": null}})";
     229              : 
     230            2 :   std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
     231            2 :   cfg->getView().version = testVersion;
     232            2 :   cfg->getView().fillFromJSON(nullJson);
     233              : 
     234            2 :   auto saveResult = ifc.saveActiveVersion(cfg.get());
     235            2 :   std::cout << "Step 1: Save JSON with nulls returned: " << saveResult << "\n";
     236              : 
     237            2 :   if (saveResult != 0) {
     238            2 :     std::cout << "  DOCUMENTED LIMITATION: JSON with null values is not supported\n";
     239            2 :     BOOST_WARN_MESSAGE(false, "JSON null values are not supported by artdaq-database");
     240              :   } else {
     241            0 :     std::shared_ptr<ConfigurationBase> readCfg = std::make_shared<TestConfiguration001>();
     242            0 :     ifc.fill(readCfg.get(), testVersion);
     243            0 :     bool hasNull = (readCfg->getView()._json.find("null") != std::string::npos);
     244            0 :     std::cout << "Step 2: Has null values: " << (hasNull ? "yes" : "no") << "\n";
     245            0 :   }
     246              : 
     247            2 :   BOOST_CHECK(true);
     248            2 :   std::cout << "  Documented: JSON null value handling\n";
     249            2 : }
     250              : 
     251            4 : BOOST_AUTO_TEST_CASE(json_with_boolean_values) {
     252            2 :   std::cout << "\n=== TEST 8: JSON with boolean values ===\n";
     253              : 
     254            2 :   auto ifc = DatabaseConfigurationInterface();
     255            2 :   int testVersion = fixture.baseVersion + 7;
     256              : 
     257            2 :   std::string boolJson = R"({"enabled": true, "disabled": false})";
     258              : 
     259            2 :   std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
     260            2 :   cfg->getView().version = testVersion;
     261            2 :   cfg->getView().fillFromJSON(boolJson);
     262              : 
     263            2 :   auto saveResult = ifc.saveActiveVersion(cfg.get());
     264            2 :   std::cout << "Step 1: Save JSON with booleans returned: " << saveResult << "\n";
     265            2 :   BOOST_CHECK_EQUAL(saveResult, 0);
     266              : 
     267            2 :   std::shared_ptr<ConfigurationBase> readCfg = std::make_shared<TestConfiguration001>();
     268            2 :   auto fillResult = ifc.fill(readCfg.get(), testVersion);
     269            2 :   BOOST_CHECK_EQUAL(fillResult, 0);
     270              : 
     271            2 :   bool hasTrue = (readCfg->getView()._json.find("true") != std::string::npos);
     272            2 :   bool hasFalse = (readCfg->getView()._json.find("false") != std::string::npos);
     273            2 :   std::cout << "Step 2: Has true: " << (hasTrue ? "yes" : "no") << ", Has false: " << (hasFalse ? "yes" : "no") << "\n";
     274              : 
     275            2 :   BOOST_CHECK(hasTrue);
     276            2 :   BOOST_CHECK(hasFalse);
     277              : 
     278            2 :   std::cout << "  Verified: JSON boolean values preserved\n";
     279            2 : }
     280              : 
     281            4 : BOOST_AUTO_TEST_CASE(json_with_numbers) {
     282            2 :   std::cout << "\n=== TEST 9: JSON with numbers ===\n";
     283              : 
     284            2 :   auto ifc = DatabaseConfigurationInterface();
     285            2 :   int testVersion = fixture.baseVersion + 8;
     286              : 
     287            2 :   std::string numJson = R"({"int": 42, "float": 3.14159, "neg": -999})";
     288              : 
     289            2 :   std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
     290            2 :   cfg->getView().version = testVersion;
     291            2 :   cfg->getView().fillFromJSON(numJson);
     292              : 
     293            2 :   auto saveResult = ifc.saveActiveVersion(cfg.get());
     294            2 :   std::cout << "Step 1: Save JSON with numbers returned: " << saveResult << "\n";
     295            2 :   BOOST_CHECK_EQUAL(saveResult, 0);
     296              : 
     297            2 :   std::shared_ptr<ConfigurationBase> readCfg = std::make_shared<TestConfiguration001>();
     298            2 :   auto fillResult = ifc.fill(readCfg.get(), testVersion);
     299            2 :   BOOST_CHECK_EQUAL(fillResult, 0);
     300              : 
     301            2 :   bool has42 = (readCfg->getView()._json.find("42") != std::string::npos);
     302            2 :   bool hasNeg = (readCfg->getView()._json.find("-999") != std::string::npos);
     303            2 :   std::cout << "Step 2: Has 42: " << (has42 ? "yes" : "no") << ", Has -999: " << (hasNeg ? "yes" : "no") << "\n";
     304              : 
     305            2 :   BOOST_CHECK(has42);
     306            2 :   BOOST_CHECK(hasNeg);
     307              : 
     308            2 :   std::cout << "  Verified: JSON number values preserved\n";
     309            2 : }
     310              : 
     311            4 : BOOST_AUTO_TEST_CASE(data_unchanged_after_multiple_reads) {
     312            2 :   std::cout << "\n=== TEST 10: Data unchanged after multiple reads ===\n";
     313              : 
     314            2 :   auto ifc = DatabaseConfigurationInterface();
     315            2 :   int testVersion = fixture.baseVersion + 9;
     316              : 
     317            2 :   std::string originalJson = R"({"stable": "data_for_repeated_reads"})";
     318              : 
     319            2 :   std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
     320            2 :   cfg->getView().version = testVersion;
     321            2 :   cfg->getView().fillFromJSON(originalJson);
     322              : 
     323            2 :   auto saveResult = ifc.saveActiveVersion(cfg.get());
     324            2 :   BOOST_REQUIRE_EQUAL(saveResult, 0);
     325            2 :   std::cout << "Step 1: Saved original data\n";
     326              : 
     327            2 :   int successCount = 0;
     328          202 :   for (int i = 0; i < 100; i++) {
     329          200 :     std::shared_ptr<ConfigurationBase> readCfg = std::make_shared<TestConfiguration001>();
     330          200 :     auto fillResult = ifc.fill(readCfg.get(), testVersion);
     331          200 :     if (fillResult == 0 && readCfg->getView()._json.find("stable") != std::string::npos) {
     332          200 :       successCount++;
     333              :     }
     334          200 :   }
     335              : 
     336            2 :   std::cout << "Step 2: Successful reads: " << successCount << "/100\n";
     337              : 
     338            2 :   BOOST_CHECK_EQUAL(successCount, 100);
     339              : 
     340            2 :   std::cout << "  Verified: Data unchanged after 100 consecutive reads\n";
     341            2 : }
     342              : 
     343              : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1