LCOV - code coverage report
Current view: top level - model - TypeConverter.cpp (source / functions) Coverage Total Hit
Test: final-coverage.info Lines: 100.0 % 240 240
Test Date: 2025-12-16 15:55:14 Functions: 100.0 % 17 17

            Line data    Source code
       1              : /*
       2              :  ___________________________________________
       3              : |    _     ___                        _     |
       4              : |   | |   |__ \                      | |    |
       5              : |   | |__    ) |__ _  __ _  ___ _ __ | |_   |
       6              : |   | '_ \  / // _` |/ _` |/ _ \ '_ \| __|  |  HTTP/2 AGENT FOR MOCK TESTING
       7              : |   | | | |/ /| (_| | (_| |  __/ | | | |_   |  Version 0.0.z
       8              : |   |_| |_|____\__,_|\__, |\___|_| |_|\__|  |  https://github.com/testillano/h2agent
       9              : |                     __/ |                 |
      10              : |                    |___/                  |
      11              : |___________________________________________|
      12              : 
      13              : Licensed under the MIT License <http://opensource.org/licenses/MIT>.
      14              : SPDX-License-Identifier: MIT
      15              : Copyright (c) 2021 Eduardo Ramos
      16              : 
      17              : Permission is hereby  granted, free of charge, to any  person obtaining a copy
      18              : of this software and associated  documentation files (the "Software"), to deal
      19              : in the Software  without restriction, including without  limitation the rights
      20              : to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
      21              : copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
      22              : furnished to do so, subject to the following conditions:
      23              : 
      24              : The above copyright notice and this permission notice shall be included in all
      25              : copies or substantial portions of the Software.
      26              : 
      27              : THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
      28              : IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
      29              : FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
      30              : AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
      31              : LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      32              : OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
      33              : SOFTWARE.
      34              : */
      35              : 
      36              : #include <cinttypes> // PRIi64, etc.
      37              : 
      38              : #include <ert/tracing/Logger.hpp>
      39              : 
      40              : #include <TypeConverter.hpp>
      41              : 
      42              : 
      43              : namespace h2agent
      44              : {
      45              : namespace model
      46              : {
      47              : 
      48           14 : void searchReplaceAll(std::string& str,
      49              :                       const std::string& from,
      50              :                       const std::string& to)
      51              : {
      52           14 :     LOGDEBUG(
      53              :         std::string msg = ert::tracing::Logger::asString("String source to 'search/replace all': %s | from: %s | to: %s", str.c_str(), from.c_str(), to.c_str());
      54              :         ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
      55              :     );
      56           14 :     std::string::size_type pos = 0u;
      57           31 :     while((pos = str.find(from, pos)) != std::string::npos) {
      58           17 :         str.replace(pos, from.length(), to);
      59           17 :         pos += to.length();
      60              :     }
      61              : 
      62           14 :     LOGDEBUG(
      63              :         std::string msg = ert::tracing::Logger::asString("String result of 'search/replace all': %s", str.c_str());
      64              :         ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
      65              :     );
      66           14 : }
      67              : 
      68          246 : void replaceVariables(std::string &str, const std::map<std::string, std::string> &patterns, const std::map<std::string,std::string> &vars, GlobalVariable *gvars) {
      69              : 
      70          246 :     if (patterns.empty()) return;
      71           10 :     if (vars.empty() && gvars->empty()) return;
      72              : 
      73           10 :     std::map<std::string,std::string>::const_iterator it;
      74           10 :     std::unordered_map<std::string,std::string>::const_iterator git;
      75              : 
      76           10 :     std::string aux{};
      77              : 
      78           23 :     for (auto pit = patterns.begin(); pit != patterns.end(); pit++) {
      79              : 
      80              :         // local var has priority over a global var with the same name
      81           13 :         if (!vars.empty()) {
      82            7 :             it = vars.find(pit->second);
      83            7 :             if (it != vars.end()) {
      84            6 :                 searchReplaceAll(str, pit->first, it->second);
      85            6 :                 continue; // all is done
      86              :             }
      87              :         }
      88              : 
      89            7 :         if (!gvars->empty()) { // this is much more efficient that find() == end() below
      90            7 :             if (gvars->tryGet(pit->second, aux)) {
      91            7 :                 searchReplaceAll(str, pit->first, aux);
      92              :             }
      93              :         }
      94              :     }
      95           10 : }
      96              : 
      97          113 : void TypeConverter::setString(const std::string &str) {
      98          113 :     clear();
      99          113 :     s_value_ = str;
     100          113 :     native_type_ = NativeType::String;
     101          113 :     LOGDEBUG(ert::tracing::Logger::debug(ert::tracing::Logger::asString("String value: %s", s_value_.c_str()), ERT_FILE_LOCATION));
     102          113 : }
     103              : 
     104           11 : void TypeConverter::setInteger(const std::int64_t i) {
     105           11 :     clear();
     106           11 :     i_value_ = i;
     107           11 :     native_type_ = NativeType::Integer;
     108           11 :     LOGDEBUG(std::string fmt = std::string("Integer value: %") + PRIi64; ert::tracing::Logger::debug(ert::tracing::Logger::asString(fmt.c_str(), i_value_), ERT_FILE_LOCATION));
     109           11 : }
     110              : 
     111            5 : void TypeConverter::setUnsigned(const std::uint64_t u) {
     112            5 :     clear();
     113            5 :     u_value_ = u;
     114            5 :     native_type_ = NativeType::Unsigned;
     115            5 :     LOGDEBUG(std::string fmt = std::string("Unsigned value: %") + PRIu64; ert::tracing::Logger::debug(ert::tracing::Logger::asString(fmt.c_str(), u_value_), ERT_FILE_LOCATION));
     116            5 : }
     117              : 
     118            4 : void TypeConverter::setFloat(const double f) {
     119            4 :     clear();
     120            4 :     f_value_ = f;
     121            4 :     native_type_ = NativeType::Float;
     122            4 :     LOGDEBUG(ert::tracing::Logger::debug(ert::tracing::Logger::asString("Float value: %lf", f_value_), ERT_FILE_LOCATION));
     123            4 : }
     124              : 
     125            1 : void TypeConverter::setBoolean(bool boolean) {
     126            1 :     clear();
     127            1 :     b_value_ = boolean;
     128            1 :     native_type_ = NativeType::Boolean;
     129            1 :     LOGDEBUG(ert::tracing::Logger::debug(ert::tracing::Logger::asString("Boolean value: %s", b_value_ ? "true":"false"), ERT_FILE_LOCATION));
     130            1 : }
     131              : 
     132           53 : void TypeConverter::setStringReplacingVariables(const std::string &str, const std::map<std::string, std::string> &patterns, const std::map<std::string,std::string> &vars, GlobalVariable *gvars) {
     133              : 
     134           53 :     setString(str);
     135           53 :     replaceVariables(s_value_, patterns, vars, gvars);
     136           53 : }
     137              : 
     138          112 : const std::string &TypeConverter::getString(bool &success) {
     139              : 
     140          112 :     success = true; // actually, always true
     141              : 
     142          112 :     switch (native_type_) {
     143            7 :     case NativeType::Object:
     144              :     {
     145            7 :         s_value_ = j_value_.dump();
     146            7 :         break;
     147              :     }
     148            5 :     case NativeType::Integer:
     149              :     {
     150            5 :         s_value_ = std::to_string(i_value_);
     151            5 :         break;
     152              :     }
     153            6 :     case NativeType::Unsigned:
     154              :     {
     155            6 :         s_value_ = std::to_string(u_value_);
     156            6 :         break;
     157              :     }
     158            2 :     case NativeType::Float:
     159              :     {
     160            2 :         s_value_ = std::to_string(f_value_); // we should remove trailing decimal zeroes:
     161              :         // Using stringstream formatter is less efficient than post-processing its result:
     162              :         //  (https://stackoverflow.com/questions/13686482/c11-stdto-stringdouble-no-trailing-zeros)
     163            2 :         s_value_.erase ( s_value_.find_last_not_of('0') + 1, std::string::npos );
     164            2 :         s_value_.erase ( s_value_.find_last_not_of('.') + 1, std::string::npos );
     165            2 :         break;
     166              :     }
     167            1 :     case NativeType::Boolean:
     168              :     {
     169            1 :         s_value_ = b_value_ ? "true":"false";
     170            1 :         break;
     171              :     }
     172           91 :     case NativeType::String:
     173           91 :         break;
     174              :     }
     175              : 
     176          112 :     LOGDEBUG(
     177              :         std::string msg;
     178              :     if (success) {
     179              :     msg = ert::tracing::Logger::asString("String value: %s", s_value_.c_str());
     180              :     }
     181              :     else {
     182              :         msg = ert::tracing::Logger::asString("Unable to get string representation for source: %s", asString().c_str());
     183              :     }
     184              : 
     185              :     ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     186              :     );
     187              : 
     188          112 :     return s_value_;
     189              : }
     190              : 
     191           16 : std::int64_t TypeConverter::getInteger(bool &success) {
     192              : 
     193           16 :     success = true;
     194              : 
     195           16 :     switch (native_type_) {
     196            1 :     case NativeType::Object:
     197              :     {
     198            1 :         success = false;
     199            1 :         break;
     200              :     }
     201            5 :     case NativeType::String:
     202              :     {
     203              :         try {
     204            5 :             i_value_ = std::stoll(s_value_);
     205              :         }
     206            1 :         catch(std::exception &e)
     207              :         {
     208            1 :             std::string msg = ert::tracing::Logger::asString("Error converting string '%s' to long long integer: %s", s_value_.c_str(), e.what());
     209            1 :             ert::tracing::Logger::error(msg, ERT_FILE_LOCATION);
     210            1 :             success = false;
     211            1 :         }
     212            5 :         break;
     213              :     }
     214            1 :     case NativeType::Unsigned:
     215              :     {
     216            1 :         i_value_ = std::int64_t(u_value_);
     217            1 :         break;
     218              :     }
     219            1 :     case NativeType::Float:
     220              :     {
     221            1 :         i_value_ = std::int64_t(f_value_);
     222            1 :         break;
     223              :     }
     224            1 :     case NativeType::Boolean:
     225              :     {
     226            1 :         i_value_ = std::int64_t(b_value_ ? 1:0);
     227            1 :         break;
     228              :     }
     229            7 :     case NativeType::Integer:
     230            7 :         break;
     231              :     }
     232              : 
     233           16 :     LOGDEBUG(
     234              :         std::string msg;
     235              :     if (success) {
     236              :     std::string fmt = std::string("Integer value: %") + PRIi64;
     237              :         msg = ert::tracing::Logger::asString(fmt.c_str(), i_value_);
     238              :     }
     239              :     else {
     240              :         msg = ert::tracing::Logger::asString("Unable to get integer representation for source: %s", asString().c_str());
     241              :     }
     242              : 
     243              :     ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     244              :     );
     245              : 
     246           16 :     return i_value_;
     247              : }
     248              : 
     249           18 : std::uint64_t TypeConverter::getUnsigned(bool &success) {
     250              : 
     251           18 :     success = true;
     252              : 
     253           18 :     switch (native_type_) {
     254            1 :     case NativeType::Object:
     255              :     {
     256            1 :         success = false;
     257            1 :         break;
     258              :     }
     259            9 :     case NativeType::String:
     260              :     {
     261              :         try {
     262            9 :             u_value_ = std::stoull(s_value_);
     263              :         }
     264            1 :         catch(std::exception &e)
     265              :         {
     266            1 :             std::string msg = ert::tracing::Logger::asString("Error converting string '%s' to unsigned long long integer: %s", s_value_.c_str(), e.what());
     267            1 :             ert::tracing::Logger::error(msg, ERT_FILE_LOCATION);
     268            1 :             success = false;
     269            1 :         }
     270            9 :         break;
     271              :     }
     272            2 :     case NativeType::Integer:
     273              :     {
     274            2 :         u_value_ = std::uint64_t(i_value_);
     275            2 :         break;
     276              :     }
     277            2 :     case NativeType::Float:
     278              :     {
     279            2 :         u_value_ = std::uint64_t(f_value_);
     280            2 :         break;
     281              :     }
     282            1 :     case NativeType::Boolean:
     283              :     {
     284            1 :         u_value_ = std::uint64_t(b_value_ ? 1:0);
     285            1 :         break;
     286              :     }
     287            3 :     case NativeType::Unsigned:
     288            3 :         break;
     289              :     }
     290              : 
     291           18 :     LOGDEBUG(
     292              :         std::string msg;
     293              :     if (success) {
     294              :     std::string fmt = std::string("Unsigned value: %") + PRIu64;
     295              :         msg = ert::tracing::Logger::asString(fmt.c_str(), u_value_);
     296              :     }
     297              :     else {
     298              :         msg = ert::tracing::Logger::asString("Unable to get unsigned integer representation for source: %s", asString().c_str());
     299              :     }
     300              : 
     301              :     ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     302              :     );
     303              : 
     304           18 :     return u_value_;
     305              : }
     306              : 
     307           12 : double TypeConverter::getFloat(bool &success) {
     308              : 
     309           12 :     success = true;
     310              : 
     311           12 :     switch (native_type_) {
     312            1 :     case NativeType::Object:
     313              :     {
     314            1 :         success = false;
     315            1 :         break;
     316              :     }
     317            5 :     case NativeType::String:
     318              :     {
     319              :         try {
     320            5 :             f_value_ = std::stod(s_value_);
     321              :         }
     322            1 :         catch(std::exception &e)
     323              :         {
     324            1 :             std::string msg = ert::tracing::Logger::asString("Error converting string '%s' to float number: %s", s_value_.c_str(), e.what());
     325            1 :             ert::tracing::Logger::error(msg, ERT_FILE_LOCATION);
     326            1 :             success = false;
     327            1 :         }
     328            5 :         break;
     329              :     }
     330            1 :     case NativeType::Integer:
     331              :     {
     332            1 :         f_value_ = double(i_value_);
     333            1 :         break;
     334              :     }
     335            1 :     case NativeType::Unsigned:
     336              :     {
     337            1 :         f_value_ = double(u_value_);
     338            1 :         break;
     339              :     }
     340            1 :     case NativeType::Boolean:
     341              :     {
     342            1 :         f_value_ = double(b_value_ ? 1:0);
     343            1 :         break;
     344              :     }
     345            3 :     case NativeType::Float:
     346            3 :         break;
     347              :     }
     348              : 
     349           12 :     LOGDEBUG(
     350              :         std::string msg;
     351              :     if (success) {
     352              :     msg = ert::tracing::Logger::asString("Float value: %lf", f_value_);
     353              :     }
     354              :     else {
     355              :         msg = ert::tracing::Logger::asString("Unable to get float number representation for source: %s", asString().c_str());
     356              :     }
     357              : 
     358              :     ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     359              :     );
     360              : 
     361           12 :     return f_value_;
     362              : }
     363              : 
     364           10 : bool TypeConverter::getBoolean(bool &success) {
     365              : 
     366           10 :     success = true;
     367              : 
     368           10 :     switch (native_type_) {
     369            1 :     case NativeType::Object:
     370              :     {
     371            1 :         success = false;
     372            1 :         break;
     373              :     }
     374            3 :     case NativeType::String:
     375              :     {
     376            3 :         b_value_ = (s_value_.empty() ? false:true);
     377            3 :         break;
     378              :     }
     379            1 :     case NativeType::Integer:
     380              :     {
     381            1 :         b_value_ = ((i_value_ != (std::int64_t)0) ? true:false);
     382            1 :         break;
     383              :     }
     384            1 :     case NativeType::Unsigned:
     385              :     {
     386            1 :         b_value_ = ((u_value_ != (std::uint64_t)0) ? true:false);
     387            1 :         break;
     388              :     }
     389            1 :     case NativeType::Float:
     390              :     {
     391            1 :         b_value_ = ((f_value_ != (double)0) ? true:false);
     392            1 :         break;
     393              :     }
     394            3 :     case NativeType::Boolean:
     395            3 :         break;
     396              :     }
     397              : 
     398           10 :     LOGDEBUG(
     399              :         std::string msg;
     400              :     if (success) {
     401              :     msg = ert::tracing::Logger::asString("Boolean value: %s", b_value_ ? "true":"false");
     402              :     }
     403              :     else {
     404              :         msg = ert::tracing::Logger::asString("Unable to get boolean representation for source: %s", asString().c_str());
     405              :     }
     406              : 
     407              :     ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     408              :     );
     409              : 
     410           10 :     return b_value_;
     411              : }
     412              : 
     413           13 : const nlohmann::json &TypeConverter::getObject(bool &success) {
     414              : 
     415           13 :     success = (native_type_ == NativeType::Object);
     416              : 
     417           13 :     LOGDEBUG(
     418              :         std::string msg;
     419              :     if (success) {
     420              :     msg = ert::tracing::Logger::asString("Json object value: %s", j_value_.dump().c_str());
     421              :     }
     422              :     else {
     423              :         msg = ert::tracing::Logger::asString("Unable to get json object from source: %s", asString().c_str());
     424              :     }
     425              : 
     426              :     ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     427              :     );
     428              : 
     429           13 :     return j_value_;
     430              : }
     431              : 
     432          270 : void TypeConverter::clear() {
     433          270 :     s_value_ = "";
     434          270 :     i_value_ = 0;
     435          270 :     u_value_ = 0;
     436          270 :     f_value_ = 0;
     437          270 :     b_value_ = false;
     438          270 :     j_value_.clear();
     439          270 :     native_type_ = NativeType::String;
     440          270 : }
     441              : 
     442           24 : bool TypeConverter::setObject(const nlohmann::json &jsonSource, const std::string &path) {
     443           24 :     clear();
     444              : 
     445           24 :     LOGDEBUG(
     446              :         std::string msg = ert::tracing::Logger::asString("Json path: %s | Json object: %s", path.c_str(), jsonSource.dump().c_str());
     447              :         ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     448              :     );
     449              : 
     450           24 :     if (path.empty()) {
     451           10 :         j_value_ = jsonSource;
     452              :     }
     453              :     else {
     454              :         try {
     455           14 :             nlohmann::json::json_pointer j_ptr(path);
     456              :             // operator[] aborts in debug compilation when the json pointer path is not found.
     457              :             // It is safer to use at() method which has "bounds checking":
     458              :             // j_value_ = jsonSource[j_ptr];
     459           14 :             j_value_ = jsonSource.at(j_ptr);
     460           10 :             if (j_value_.empty()) return false; // null extracted (path not found)
     461           14 :         }
     462            4 :         catch (std::exception& e)
     463              :         {
     464            4 :             ert::tracing::Logger::error(e.what(), ERT_FILE_LOCATION);
     465            4 :             return false;
     466            4 :         }
     467              :     }
     468              : 
     469           20 :     if (j_value_.is_object()) {
     470           10 :         native_type_ = NativeType::Object;
     471              :     }
     472           10 :     else if (j_value_.is_string()) {
     473            3 :         s_value_ = j_value_;
     474            3 :         native_type_ = NativeType::String;
     475              :     }
     476            7 :     else if (j_value_.is_number_unsigned()) { // this condition here (before integer), because integer also becomes true for unsigned source
     477            3 :         u_value_ = j_value_;
     478            3 :         native_type_ = NativeType::Unsigned;
     479              :     }
     480            4 :     else if (j_value_.is_number_integer()) {
     481            1 :         i_value_ = j_value_;
     482            1 :         native_type_ = NativeType::Integer;
     483              :     }
     484            3 :     else if (j_value_.is_number_float()) {
     485            1 :         f_value_ = j_value_;
     486            1 :         native_type_ = NativeType::Float;
     487              :     }
     488            2 :     else if (j_value_.is_boolean()) {
     489            2 :         b_value_ = j_value_;
     490            2 :         native_type_ = NativeType::Boolean;
     491              :     }
     492              :     //else {
     493              :     //    ert::tracing::Logger::error("Unrecognized json pointer value format", ERT_FILE_LOCATION); // this shouldn't happen as all the possible formats are checked above
     494              :     //    return false;
     495              :     //}
     496              : 
     497           20 :     return true;
     498              : }
     499              : 
     500            6 : std::string TypeConverter::asString() {
     501              : 
     502            6 :     std::stringstream ss;
     503            6 :     ss << "NativeType (String = 0, Integer, Unsigned, Float, Boolean, Object): " << getNativeType()
     504           12 :        << " | " << ((getNativeType() == NativeType::String) ? "STRING":"String") << ": " << s_value_
     505            6 :        << " | " << ((getNativeType() == NativeType::Integer) ? "INTEGER":"Integer") << ": " << i_value_
     506            6 :        << " | " << ((getNativeType() == NativeType::Unsigned) ? "UNSIGNED":"Unsigned") << ": " << u_value_
     507            6 :        << " | " << ((getNativeType() == NativeType::Float) ? "FLOAT":"Float") << ": " << f_value_
     508           12 :        << " | " << ((getNativeType() == NativeType::Boolean) ? "BOOLEAN":"Boolean") << ": " << (b_value_ ? "true":"false")
     509            6 :        << " | " << ((getNativeType() == NativeType::Object) ? "OBJECT":"Object") << ": " << j_value_.dump();
     510              : 
     511           12 :     return (ss.str());
     512            6 : }
     513              : 
     514              : }
     515              : }
        

Generated by: LCOV version 2.0-1