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: 2025-12-21 13:07:08 Functions: 0.0 % 5 0

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

Generated by: LCOV version 2.0-1