LCOV - code coverage report
Current view: top level - oks/apps - oks_check_schema.cxx (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 101 0
Test Date: 2026-07-12 15:23:06 Functions: 0.0 % 11 0

            Line data    Source code
       1              : /**
       2              :  * @file oks_check_schema.cxx
       3              :  *
       4              :  * Program to do some simple integrity checks on a schema file
       5              :  *
       6              :  * This is part of the DUNE DAQ Application Framework, copyright 2025.
       7              :  * Licensing/copyright details are in the COPYING file that you should have
       8              :  * received with this code.
       9              :  */
      10              : 
      11              : #include "CLI/CLI.hpp"
      12              : #include "logging/Logging.hpp"
      13              : #include "oks/class.hpp"
      14              : #include "oks/file.hpp"
      15              : #include "oks/kernel.hpp"
      16              : #include "oks/relationship.hpp"
      17              : 
      18              : #include <fmt/core.h>
      19              : #include <set>
      20              : #include <string>
      21              : 
      22              : using namespace dunedaq::oks;
      23              : 
      24              : 
      25              : 
      26            0 : int main(int argc, char **argv) {
      27            0 :   enum Exitcode : int {SUCCESS, BADCMD, NOFILE, LOADFAIL,
      28              :     BADRELATIONSHIP, UNRESOLVED,
      29              :     MISSING_INCLUDE};
      30              : 
      31            0 :   CLI::App app{"Check consistency of OKS schema file\n"+
      32            0 :     fmt::format("Return codes: {} Success, file is OK\n", Exitcode::SUCCESS)+
      33            0 :     fmt::format("              {} Bad command line\n", Exitcode::BADCMD)+
      34            0 :     fmt::format("              {} Failed to find file\n", Exitcode::NOFILE)+
      35            0 :     fmt::format("              {} Failed to load file -- invalid schema\n", Exitcode::LOADFAIL)+
      36            0 :     fmt::format("              {} File contains relationship to non loaded class\n", Exitcode::BADRELATIONSHIP)+
      37            0 :     fmt::format("              {} File contains object with relationship to non loaded class/object\n", Exitcode::UNRESOLVED)+
      38            0 :     fmt::format("              {} File refers to class in file not directly included\n", Exitcode::MISSING_INCLUDE)
      39            0 :   };
      40              : 
      41            0 :   std::string filename;
      42            0 :   app.add_option("-f,--file", filename, "Schema file")
      43            0 :     ->required();
      44              : 
      45            0 :   CLI11_PARSE(app, argc, argv);
      46              : 
      47            0 :   OksKernel kernel;
      48            0 :   OksFile* file{nullptr};
      49            0 :   try {
      50            0 :     file = kernel.load_file(filename);
      51              :   }
      52            0 :   catch (FailedLoadFile& fail) {
      53            0 :     TLOG() << fail.what() << "\n";
      54            0 :     return Exitcode::LOADFAIL;
      55            0 :   }
      56            0 :   catch (CanNotOpenFile& fail) {
      57            0 :     TLOG() << fail.what() << "\n";
      58            0 :     return Exitcode::NOFILE;
      59            0 :   }
      60            0 :   catch (std::exception& exc) {
      61            0 :     TLOG() << exc.what() << "\n";
      62            0 :     return Exitcode::LOADFAIL;
      63            0 :   }
      64              : 
      65            0 :   if (file == nullptr) {
      66            0 :     TLOG() << "Failed to load " << filename;
      67            0 :     return Exitcode::LOADFAIL;
      68              :   }
      69              : 
      70            0 :   std::set<std::string> includes;
      71            0 :   for (const auto& ifile : file->get_include_files()) {
      72            0 :     includes.insert(ifile);
      73            0 :     TLOG_DEBUG(2) << "direct inserting " << ifile << "\n";
      74              :   }
      75              : 
      76            0 :   Exitcode result=Exitcode::SUCCESS;
      77              : 
      78            0 :   if (filename.ends_with(".schema.xml")) {
      79              :     // Check classes defined in this schema file
      80            0 :     for (auto [name, oks_class] : kernel.classes()) {
      81              : 
      82            0 :       if (file->get_full_file_name() != oks_class->get_file()->get_full_file_name()) {
      83              :         // Class not defined in this file
      84            0 :         continue;
      85              :       }
      86              : 
      87            0 :       auto cfile = oks_class->get_file()->get_short_file_name();
      88            0 :       if (cfile != file->get_short_file_name() && !includes.contains(cfile)) {
      89            0 :         TLOG() << "Error " << filename << " misses include of " << cfile << " required by " << name;
      90            0 :         if (result==Exitcode::SUCCESS) {
      91            0 :           result =  Exitcode::MISSING_INCLUDE;
      92              :         }
      93              :       }
      94            0 :       auto relationships = oks_class->direct_relationships();
      95            0 :       if (relationships != nullptr) {
      96            0 :         for (auto rel: *relationships) {
      97            0 :           auto rel_class = rel->get_class_type();
      98            0 :           if (rel_class == nullptr) {
      99            0 :             TLOG() << "Error class '" << name
     100            0 :                    << "' has relationship '" << rel->get_name()
     101            0 :                    << "' to a class '" << rel->get_type()
     102            0 :                    << "' that is not loaded\n";
     103            0 :             if (result==Exitcode::SUCCESS) {
     104            0 :               result =  Exitcode::BADRELATIONSHIP;
     105              :             }
     106              :           }
     107              : 
     108              :         }
     109              :       }
     110              :       // Could check super-classes but we wouldn't have got past the
     111              :       // load if they referred to a missing class.
     112            0 :     }
     113            0 :   } else if (filename.ends_with(".data.xml")) {
     114              : 
     115            0 :     auto check_relationship = [&](OksData* data) {
     116            0 :       auto relobj = data->data.OBJECT;
     117            0 :       if (relobj == nullptr) {
     118            0 :         return;
     119              :       }
     120            0 :       auto ofile_name = relobj->get_file()->get_short_file_name();
     121            0 :       if (file->get_short_file_name() != ofile_name && !includes.contains(ofile_name)) {
     122            0 :         TLOG() << "Error " << filename << " misses include of " << ofile_name
     123            0 :                << " required by " << relobj->GetId();
     124            0 :         if (result==Exitcode::SUCCESS) {
     125            0 :           result =  Exitcode::MISSING_INCLUDE;
     126              :         }
     127              :       }
     128            0 :     };
     129              : 
     130            0 :     auto data_objs = kernel.create_list_of_data_objects(file);
     131            0 :     for (auto obj : *data_objs) {
     132              :       // Check that any objects defined in this data file have their
     133              :       // corresponding schema file included directly in this file
     134            0 :       auto oks_class = obj->GetClass();
     135            0 :       auto cfile = oks_class->get_file()->get_short_file_name();
     136            0 :       if (!includes.contains(cfile)) {
     137            0 :         TLOG() << "Error " << filename << " misses include of " << cfile
     138            0 :                << " required by " << obj->GetId()
     139            0 :                << " of class " << oks_class->get_name();
     140            0 :         if (result==Exitcode::SUCCESS) {
     141            0 :           result =  Exitcode::MISSING_INCLUDE;
     142              :         }
     143              :       }
     144              : 
     145              :       // Check that any objects referenced by objects in this file are
     146              :       // either defined in this file or one that is directly included
     147            0 :       auto relationships = oks_class->all_relationships();
     148            0 :       if (relationships != nullptr) {
     149            0 :         for (auto rel: *relationships) {
     150            0 :           auto relval = obj->GetRelationshipValue(rel->get_name());
     151            0 :           if (relval == nullptr) {
     152            0 :             continue;
     153              :           }
     154            0 :           if (rel->get_high_cardinality_constraint() == OksRelationship::Many) {
     155            0 :             for(OksData::List::iterator iter = relval->data.LIST->begin();
     156            0 :                 iter != relval->data.LIST->end(); ++iter) {
     157            0 :               check_relationship(*iter);
     158              :             }
     159              :           } else {
     160            0 :             check_relationship(relval);
     161              :           }
     162              :         }
     163              :       }
     164            0 :     }
     165            0 :     delete data_objs;
     166              :   }
     167              : 
     168            0 :   auto status = kernel.get_bind_objects_status();
     169            0 :   if (!status.empty()) {
     170            0 :     if (result==Exitcode::SUCCESS) {
     171            0 :       result = Exitcode::UNRESOLVED;
     172              :     }
     173              :   }
     174              : 
     175            0 :   return result;
     176            0 : }
        

Generated by: LCOV version 2.0-1