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

Generated by: LCOV version 2.0-1