LCOV - code coverage report
Current view: top level - oksutils/apps - oks_diff_data.cxx (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 220 0
Test Date: 2026-10-11 15:05:20 Functions: 0.0 % 5 0

            Line data    Source code
       1              : //
       2              : // DUNE DAQ modification notice:
       3              : // This file has been modified from the original ATLAS oks_utils source for the DUNE DAQ project.
       4              : // Fork baseline commit: c2e7dfc7 (2022-03-30).
       5              : // Renamed since fork: yes (from src/bin/oks_diff_data.cpp to apps/oks_diff_data.cxx).
       6              : //
       7              : 
       8              : /**
       9              :  *  \file oks_diff_data.cpp
      10              :  *
      11              :  *  This file is part of the OKS package.
      12              :  *  Author: <Igor.Soloviev@cern.ch>
      13              :  *
      14              :  *  This file contains the implementation of the OKS application to show
      15              :  *  differences between two data files.
      16              :  *
      17              :  *  Usage:
      18              :  *
      19              :  *    oks_diff_data [--attributes] [--relationships] [--composite-parents]
      20              :  *                  [-all] [--help] [--version] [--schema-files schema_file(s)]
      21              :  *                  [--class-name name_of_class [--object-id id_of_object]]
      22              :  *                  --data-file1 data_file1 --data-file2 data_file2
      23              :  *
      24              :  *    Options (if two objects differed):
      25              :  *      \param --attributes                produce a listing of differences for object's attributes
      26              :  *      \param --relationships             produce a listing of differences for object's relationships
      27              :  *      \param --composite-parents         produce a listing of object's composite parents
      28              :  *      \param --all                       the same as '--attributes --relationships --composite-parents'
      29              :  *
      30              :  *    General Options/Arguments:
      31              :  *      \param --class-name class-name     optional name of class which objects to be checked\n"
      32              :  *      \param --object-id object-id       optional id to check only this object (only used with --class-name)\n"
      33              :  *      \param --schema-files schema-file  optional list of schema files
      34              :  *      \param --data-file1 data-file      first compared datafile
      35              :  *      \param --data-file2 data-file      second compared datafile
      36              :  *      \param --version                   print version
      37              :  *      \param --verbose                   verbose mode
      38              :  *      \param --help                      print help text
      39              :  */
      40              : 
      41              : #include <iostream>
      42              : 
      43              : #include <set>
      44              : 
      45              : #include "oks/attribute.hpp"
      46              : #include "oks/class.hpp"
      47              : #include "oks/kernel.hpp"
      48              : #include "oks/object.hpp"
      49              : #include "oks/relationship.hpp"
      50              : 
      51              : using namespace dunedaq;
      52              : using namespace dunedaq::oks;
      53              : 
      54              : std::string appTitle;
      55              : 
      56              : static void
      57            0 : printRecursion(int level)
      58              : {
      59            0 :   while (level--)
      60            0 :     std::cout << "  ";
      61            0 : }
      62              : 
      63              : static void
      64            0 : ReportCompositeParents(OksObject* o, int recursionLevel = -1)
      65              : {
      66            0 :   static std::set<OksRCR*, std::less<OksRCR*>> rcr_set;
      67              : 
      68            0 :   recursionLevel++;
      69              : 
      70            0 :   const std::list<OksRCR*>* rcr_list = o->reverse_composite_rels();
      71              : 
      72            0 :   if (rcr_list) {
      73            0 :     for (std::list<OksRCR*>::const_iterator i = rcr_list->begin(); i != rcr_list->end(); ++i) {
      74            0 :       OksRCR* rcr = *i;
      75              : 
      76            0 :       printRecursion(recursionLevel);
      77              : 
      78            0 :       std::cout << "     " << rcr->obj << " ==\\" << rcr->relationship->get_name() << "\\==> " << o << std::endl;
      79              : 
      80            0 :       if (!rcr_set.empty() && rcr_set.find(rcr) != rcr_set.end()) {
      81            0 :         printRecursion(recursionLevel);
      82            0 :         std::cout << "     The composite parent(s) of " << rcr->obj
      83            0 :                   << " were reported in this loop (circular references)\n";
      84              :       } else {
      85            0 :         rcr_set.insert(rcr);
      86            0 :         ReportCompositeParents(rcr->obj, recursionLevel);
      87            0 :         rcr_set.erase(rcr);
      88              :       }
      89              :     }
      90              :   } else {
      91            0 :     printRecursion(recursionLevel);
      92            0 :     std::cout << "     " << o << " has no composite parents\n";
      93              :   }
      94              : 
      95            0 :   recursionLevel--;
      96            0 : }
      97              : 
      98              : static void
      99            0 : printShortUsage(const char* appName, std::ostream& s)
     100              : {
     101            0 :   s << appTitle
     102              :     << "\n"
     103              :        "Usage: "
     104              :     << appName
     105              :     << " [-a] [-r] [-p] [-all] [-h] [-v] [-c class [-o object_id]] "
     106              :        "[-s schema_file(s)] -d1 data_file1 -d2 data_file2\n"
     107              :        "\n"
     108              :        "  Options (if two objects differed):\n"
     109              :        "\t-a              produce a listing of differences for object's attributes\n"
     110              :        "\t-r              produce a listing of differences for object's relationships\n"
     111              :        "\t-p              produce a listing of object's composite parents\n"
     112              :        "\t-all            the same as \'-a -r -p\'\n"
     113              :        "\n"
     114              :        "  General Options/Arguments:\n"
     115              :        "\t-c class-name   optional name of class which objects to be checked\n"
     116              :        "\t-o object-id    optional id to check only this object (only used with -c)\n"
     117              :        "\t-s schema-file  optional list of schema files\n"
     118              :        "\t-d1 data-file   first compared datafile\n"
     119              :        "\t-d2 data-file   second compared datafile\n"
     120              :        "\t-v              print version\n"
     121              :        "\t-b              verbose mode\n"
     122              :        "\t-h              print this text\n"
     123            0 :        "\n";
     124            0 : }
     125              : 
     126              : static void
     127            0 : printUsage(const char* appName, std::ostream& s)
     128              : {
     129            0 :   s << appTitle
     130              :     << "\n"
     131              :        "Usage: "
     132              :     << appName
     133              :     << " [--attributes] [--relationships] [--composite-parents] [--all] [--help] [--version]"
     134              :        " [--class-name name_of_class [--object-id id_of_object]]\n"
     135              :        " [--schema-files schema_file(s)] --data-file1 data_file1 --data-file2 data_file2\n"
     136              :        "\n"
     137              :        "  Options (if two objects differed):\n"
     138              :        "\t--attributes                produce a listing of differences for object's attributes\n"
     139              :        "\t--relationships             produce a listing of differences for object's relationships\n"
     140              :        "\t--composite-parents         produce a listing of object's composite parents\n"
     141              :        "\t-all                        the same as \'--attributes --relationships --composite-parents\'\n"
     142              :        "\n"
     143              :        "  General Options/Arguments:\n"
     144              :        "\t--class-name class-name     optional name of class which objects to be checked\n"
     145              :        "\t--object-id object-id       optional id to check only this object (only used with --class-name)\n"
     146              :        "\t--schema-files schema-file  optional list of schema files\n"
     147              :        "\t--data-file1 data-file      first compared datafile\n"
     148              :        "\t--data-file2 data-file      second compared datafile\n"
     149              :        "\t--version                   print version\n"
     150              :        "\t--verbose                   verbose mode\n"
     151              :        "\t--help                      print this text\n"
     152            0 :        "\n";
     153            0 : }
     154              : 
     155              : int
     156            0 : main(int argc, const char* argv[])
     157              : {
     158            0 :   appTitle = "OKS data files comparer. OKS kernel version ";
     159            0 :   appTitle += OksKernel::GetVersion();
     160              : 
     161            0 :   bool printAttributeDifferences = false;
     162            0 :   bool printRelationshipDifferences = false;
     163            0 :   bool printCompositeParentsMode = false;
     164            0 :   bool verboseMode = false;
     165              : 
     166            0 :   const char* appName = "oks_diff_data";
     167              : 
     168            0 :   if (argc == 1) {
     169            0 :     printUsage(appName, std::cerr);
     170            0 :     return 1;
     171              :   }
     172              : 
     173              :   // allocate enough space for list of schema files
     174              : 
     175            0 :   const char** schemaFiles = new const char*[argc];
     176            0 :   schemaFiles[0] = 0;
     177              : 
     178            0 :   const char* dataFile1 = 0;
     179            0 :   const char* dataFile2 = 0;
     180              : 
     181            0 :   const char* class_name = 0;
     182            0 :   const char* object_id = 0;
     183              : 
     184            0 :   for (int i = 1; i < argc; i++) {
     185            0 :     if (!strcmp(argv[i], "-a") || !strcmp(argv[i], "--attributes"))
     186              :       printAttributeDifferences = true;
     187            0 :     else if (!strcmp(argv[i], "-r") || !strcmp(argv[i], "--relationships"))
     188              :       printRelationshipDifferences = true;
     189            0 :     else if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--composite-parents"))
     190              :       printCompositeParentsMode = true;
     191            0 :     else if (!strcmp(argv[i], "-all") || !strcmp(argv[i], "--all")) {
     192              :       printAttributeDifferences = true;
     193              :       printRelationshipDifferences = true;
     194              :       printCompositeParentsMode = true;
     195            0 :     } else if (!strcmp(argv[i], "-b") || !strcmp(argv[i], "--verbose"))
     196              :       verboseMode = true;
     197            0 :     else if (!strcmp(argv[i], "-h")) {
     198            0 :       printShortUsage(appName, std::cout);
     199            0 :       return 0;
     200            0 :     } else if (!strcmp(argv[i], "--help")) {
     201            0 :       printUsage(appName, std::cout);
     202            0 :       return 0;
     203            0 :     } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
     204            0 :       std::cout << appTitle << std::endl;
     205            0 :       return 0;
     206            0 :     } else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--schema-files")) {
     207            0 :       for (int j = 0; j < argc - i - 1; ++j) {
     208            0 :         if (argv[i + 1 + j][0] != '-')
     209            0 :           schemaFiles[j] = argv[i + 1 + j];
     210              :         else {
     211            0 :           schemaFiles[j] = 0;
     212            0 :           i += j;
     213            0 :           break;
     214              :         }
     215              :       }
     216            0 :     } else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--class-name")) {
     217            0 :       if (argv[i + 1][0] != '-')
     218            0 :         class_name = argv[++i];
     219            0 :     } else if (!strcmp(argv[i], "-o") || !strcmp(argv[i], "--object-id")) {
     220            0 :       if (argv[i + 1][0] != '-')
     221            0 :         object_id = argv[++i];
     222            0 :     } else if (!strcmp(argv[i], "-d1") || !strcmp(argv[i], "--data-file1")) {
     223            0 :       if (argv[i + 1][0] != '-')
     224            0 :         dataFile1 = argv[++i];
     225            0 :     } else if (!strcmp(argv[i], "-d2") || !strcmp(argv[i], "--data-file2")) {
     226            0 :       if (argv[i + 1][0] != '-')
     227            0 :         dataFile2 = argv[++i];
     228              :     } else {
     229            0 :       std::cerr << "ERROR: Unknown parameter: \"" << argv[i] << "\"\n\n";
     230            0 :       printUsage(appName, std::cerr);
     231            0 :       return 1;
     232              :     }
     233              :   }
     234              : 
     235              :   // check schema and data files
     236              : 
     237            0 :   if (dataFile1 == 0) {
     238            0 :     std::cerr << "ERROR: First data file is not defined.\n\n";
     239            0 :     printUsage(appName, std::cerr);
     240            0 :     return 1;
     241              :   }
     242              : 
     243            0 :   if (dataFile2 == 0) {
     244            0 :     std::cerr << "ERROR: Second data file is not defined.\n\n";
     245            0 :     printUsage(appName, std::cerr);
     246            0 :     return 1;
     247              :   }
     248              : 
     249              :   // check object id and class name
     250              : 
     251            0 :   if (object_id && !class_name) {
     252            0 :     std::cerr << "ERROR: object ID cannot be used without class name.\n\n";
     253            0 :     printUsage(appName, std::cerr);
     254            0 :     return 1;
     255              :   }
     256              : 
     257            0 :   int return_status = 0;
     258              : 
     259              :   // create two kernels and load the data
     260              : 
     261            0 :   OksKernel kernel1;
     262            0 :   OksKernel kernel2;
     263              : 
     264            0 :   try {
     265              : 
     266            0 :     if (!verboseMode) {
     267            0 :       kernel1.set_silence_mode(true);
     268            0 :       kernel2.set_silence_mode(true);
     269              :     }
     270              : 
     271            0 :     for (int i = 0; schemaFiles[i] != 0; ++i) {
     272            0 :       const char* s_file = schemaFiles[i];
     273              : 
     274            0 :       kernel1.load_schema(s_file);
     275            0 :       kernel2.load_schema(s_file);
     276              :     }
     277              : 
     278            0 :     kernel1.load_data(dataFile1);
     279            0 :     kernel2.load_data(dataFile2);
     280              : 
     281            0 :     const OksClass::Map& classes = kernel1.classes();
     282            0 :     OksClass::Map::const_iterator class_iterator = classes.begin();
     283              : 
     284            0 :     if (classes.empty()) {
     285            0 :       std::cerr << "ERROR: No classes were found in loaded schema file(s), exiting ...\n";
     286            0 :       return 4;
     287              :     }
     288              : 
     289            0 :     std::cout << std::endl;
     290              : 
     291              :     int classDiffsCount = 0;
     292              : 
     293              :     OksClass *c1, *c2;
     294            0 :     for (; class_iterator != classes.end(); ++class_iterator) {
     295            0 :       c1 = class_iterator->second;
     296            0 :       std::string className(c1->get_name());
     297              : 
     298            0 :       if (class_name && className != class_name) {
     299            0 :         continue;
     300              :       }
     301              : 
     302            0 :       if (verboseMode)
     303            0 :         classDiffsCount = 0;
     304              : 
     305            0 :       if (verboseMode) {
     306            0 :         std::cout << "TESTING IN CLASS \"" << className << "\"... ";
     307            0 :         std::cout.flush();
     308              :       }
     309              : 
     310            0 :       if (!(c2 = kernel2.find_class(className))) {
     311            0 :         if (verboseMode && !classDiffsCount)
     312            0 :           std::cout << std::endl;
     313            0 :         std::cout << " DIFFERENCE " << ++classDiffsCount
     314              :                   << "."
     315              :                      " Database \'"
     316            0 :                   << dataFile2 << "\' does not have class \"" << className << "\", skip testing ...\n";
     317            0 :         continue;
     318              :       }
     319              : 
     320            0 :       if (*c1 != *c2) {
     321            0 :         if (verboseMode && !classDiffsCount)
     322            0 :           std::cout << std::endl;
     323            0 :         std::cout << " DIFFERENCE " << ++classDiffsCount
     324              :                   << "."
     325              :                      " Class \""
     326              :                   << className << "\" is different in \"" << dataFile1 << "\" and \"" << dataFile2
     327            0 :                   << "\", skip testing ...\n";
     328            0 :         continue;
     329              :       }
     330              : 
     331            0 :       const OksObject::Map* objects1 = c1->objects();
     332            0 :       const OksObject::Map* objects2 = c2->objects();
     333            0 :       OksObject::Map::const_iterator object_iterator = objects1->begin();
     334              : 
     335            0 :       for (; object_iterator != objects1->end(); ++object_iterator) {
     336            0 :         const std::string* objUID = (*object_iterator).first;
     337            0 :         OksObject* o1 = (*object_iterator).second;
     338              : 
     339            0 :         if (object_id && o1->GetId() != object_id) {
     340            0 :           continue;
     341              :         }
     342              : 
     343            0 :         OksObject* o2 = c2->get_object(objUID);
     344              : 
     345            0 :         if (!o2) {
     346            0 :           if (verboseMode && !classDiffsCount)
     347            0 :             std::cout << std::endl;
     348            0 :           std::cout << " DIFFERENCE " << ++classDiffsCount
     349              :                     << "."
     350            0 :                        " There is no object "
     351            0 :                     << o1 << " in the \"" << dataFile2 << "\" database file.\n";
     352            0 :           continue;
     353              :         }
     354              : 
     355            0 :         if (*o1 == *o2)
     356            0 :           continue;
     357              : 
     358            0 :         if (verboseMode && !classDiffsCount)
     359            0 :           std::cout << std::endl;
     360            0 :         std::cout << " DIFFERENCE " << ++classDiffsCount << ". The OBJECTS " << o1 << " differed:\n";
     361              : 
     362            0 :         int objDiffsCount = 0;
     363              : 
     364            0 :         const std::list<OksAttribute*>* alist = c1->all_attributes();
     365            0 :         const std::list<OksRelationship*>* rlist = c1->all_relationships();
     366              : 
     367            0 :         if (alist) {
     368            0 :           for (std::list<OksAttribute*>::const_iterator ai = alist->begin(); ai != alist->end(); ++ai) {
     369            0 :             OksAttribute* a = *ai;
     370            0 :             OksData* d1(o1->GetAttributeValue(a->get_name()));
     371            0 :             OksData* d2(o2->GetAttributeValue(a->get_name()));
     372              : 
     373            0 :             if (!(*d1 == *d2)) {
     374            0 :               ++objDiffsCount;
     375              : 
     376            0 :               if (printAttributeDifferences) {
     377            0 :                 std::cout << "   " << classDiffsCount << "." << objDiffsCount << " The ATTRIBUTE \"" << a->get_name()
     378              :                           << "\" values differed:\n"
     379              :                              "    the value in the FILE \""
     380            0 :                           << dataFile1 << "\" is: " << *d1
     381              :                           << "\n"
     382              :                              "    the value in the FILE \""
     383            0 :                           << dataFile2 << "\" is: " << *d2 << std::endl;
     384              :               }
     385              :             }
     386              :           }
     387              :         }
     388              : 
     389            0 :         if (rlist) {
     390            0 :           for (std::list<OksRelationship*>::const_iterator ri = rlist->begin(); ri != rlist->end(); ++ri) {
     391            0 :             OksRelationship* r = *ri;
     392            0 :             OksData* d1(o1->GetRelationshipValue(r->get_name()));
     393            0 :             OksData* d2(o2->GetRelationshipValue(r->get_name()));
     394              : 
     395            0 :             if (!(*d1 == *d2)) {
     396            0 :               ++objDiffsCount;
     397              : 
     398            0 :               if (printRelationshipDifferences) {
     399            0 :                 std::cout << "   " << classDiffsCount << '.' << objDiffsCount << " The RELATIONSHIP \"" << r->get_name()
     400              :                           << "\" values differed:\n"
     401              :                              "    the value in the FILE \""
     402            0 :                           << dataFile1 << "\" is: " << *d1
     403              :                           << "\n"
     404              :                              "    the value in the FILE \""
     405            0 :                           << dataFile2 << "\" is: " << *d2 << std::endl;
     406              :               }
     407              :             }
     408              :           }
     409              :         }
     410              : 
     411            0 :         if (objDiffsCount && printCompositeParentsMode) {
     412            0 :           std::cout << "   COMPOSITE PARENT(S) of the OBJECTS " << o1 << ":\n";
     413            0 :           std::cout << "    In the FILE \"" << dataFile1 << "\"\n";
     414            0 :           ReportCompositeParents(o1);
     415            0 :           std::cout << "    In the FILE \"" << dataFile2 << "\"\n";
     416            0 :           ReportCompositeParents(o2);
     417              :         }
     418              :       }
     419              : 
     420            0 :       object_iterator = objects2->begin();
     421              : 
     422            0 :       for (; object_iterator != objects2->end(); ++object_iterator) {
     423            0 :         const std::string* objUID = (*object_iterator).first;
     424            0 :         OksObject* o1 = c1->get_object(objUID);
     425              : 
     426            0 :         if (!o1 && (!object_id || *objUID == object_id)) {
     427            0 :           if (!classDiffsCount)
     428            0 :             std::cout << std::endl;
     429            0 :           std::cout << " DIFFERENCE " << ++classDiffsCount
     430              :                     << "."
     431            0 :                        " There is no object "
     432            0 :                     << (*object_iterator).second << " in the \"" << dataFile1 << "\" database file.\n";
     433              :         }
     434              :       }
     435              : 
     436            0 :       if (verboseMode && !classDiffsCount) {
     437            0 :         std::cout << " no differences were found\n";
     438              :       }
     439            0 :     }
     440              :   }
     441              : 
     442            0 :   catch (oks::exception& ex) {
     443            0 :     std::cerr << "Caught oks exception:\n" << ex << std::endl;
     444            0 :     return_status = 10;
     445            0 :   }
     446              : 
     447            0 :   catch (std::exception& e) {
     448            0 :     std::cerr << "Caught standard C++ exception: " << e.what() << std::endl;
     449            0 :     return_status = 10;
     450            0 :   }
     451              : 
     452            0 :   catch (...) {
     453            0 :     std::cerr << "Caught unknown exception" << std::endl;
     454            0 :     return_status = 10;
     455            0 :   }
     456              : 
     457            0 :   delete[] schemaFiles;
     458              : 
     459            0 :   if (verboseMode)
     460            0 :     std::cout << "\nExiting " << appName << "...\n";
     461              : 
     462              :   return return_status;
     463            0 : }
        

Generated by: LCOV version 2.0-1