LCOV - code coverage report
Current view: top level - model - TypeConverter.cpp (source / functions) Coverage Total Hit
Test: final-coverage.info Lines: 100.0 % 239 239
Test Date: 2025-02-14 17:40:40 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, const std::unordered_map<std::string,std::string> &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           23 :     for (auto pit = patterns.begin(); pit != patterns.end(); pit++) {
      77              : 
      78              :         // local var has priority over a global var with the same name
      79           13 :         if (!vars.empty()) {
      80            7 :             it = vars.find(pit->second);
      81            7 :             if (it != vars.end()) {
      82            6 :                 searchReplaceAll(str, pit->first, it->second);
      83            6 :                 continue; // all is done
      84              :             }
      85              :         }
      86              : 
      87            7 :         if (!gvars.empty()) { // this is much more efficient that find() == end() below
      88            7 :             git = gvars.find(pit->second);
      89            7 :             if (git != gvars.end()) {
      90            7 :                 searchReplaceAll(str, pit->first, git->second);
      91              :             }
      92              :         }
      93              :     }
      94              : }
      95              : 
      96          113 : void TypeConverter::setString(const std::string &str) {
      97          113 :     clear();
      98          113 :     s_value_ = str;
      99          113 :     native_type_ = NativeType::String;
     100          113 :     LOGDEBUG(ert::tracing::Logger::debug(ert::tracing::Logger::asString("String value: %s", s_value_.c_str()), ERT_FILE_LOCATION));
     101          113 : }
     102              : 
     103           11 : void TypeConverter::setInteger(const std::int64_t i) {
     104           11 :     clear();
     105           11 :     i_value_ = i;
     106           11 :     native_type_ = NativeType::Integer;
     107           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));
     108           11 : }
     109              : 
     110            5 : void TypeConverter::setUnsigned(const std::uint64_t u) {
     111            5 :     clear();
     112            5 :     u_value_ = u;
     113            5 :     native_type_ = NativeType::Unsigned;
     114            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));
     115            5 : }
     116              : 
     117            4 : void TypeConverter::setFloat(const double f) {
     118            4 :     clear();
     119            4 :     f_value_ = f;
     120            4 :     native_type_ = NativeType::Float;
     121            4 :     LOGDEBUG(ert::tracing::Logger::debug(ert::tracing::Logger::asString("Float value: %lf", f_value_), ERT_FILE_LOCATION));
     122            4 : }
     123              : 
     124            1 : void TypeConverter::setBoolean(bool boolean) {
     125            1 :     clear();
     126            1 :     b_value_ = boolean;
     127            1 :     native_type_ = NativeType::Boolean;
     128            1 :     LOGDEBUG(ert::tracing::Logger::debug(ert::tracing::Logger::asString("Boolean value: %s", b_value_ ? "true":"false"), ERT_FILE_LOCATION));
     129            1 : }
     130              : 
     131           53 : void TypeConverter::setStringReplacingVariables(const std::string &str, const std::map<std::string, std::string> &patterns, const std::map<std::string,std::string> &vars, const std::unordered_map<std::string,std::string> &gvars) {
     132              : 
     133           53 :     setString(str);
     134           53 :     replaceVariables(s_value_, patterns, vars, gvars);
     135           53 : }
     136              : 
     137          112 : const std::string &TypeConverter::getString(bool &success) {
     138              : 
     139          112 :     success = true; // actually, always true
     140              : 
     141          112 :     switch (native_type_) {
     142            7 :     case NativeType::Object:
     143              :     {
     144            7 :         s_value_ = j_value_.dump();
     145            7 :         break;
     146              :     }
     147            5 :     case NativeType::Integer:
     148              :     {
     149            5 :         s_value_ = std::to_string(i_value_);
     150            5 :         break;
     151              :     }
     152            6 :     case NativeType::Unsigned:
     153              :     {
     154            6 :         s_value_ = std::to_string(u_value_);
     155            6 :         break;
     156              :     }
     157            2 :     case NativeType::Float:
     158              :     {
     159            2 :         s_value_ = std::to_string(f_value_); // we should remove trailing decimal zeroes:
     160              :         // Using stringstream formatter is less efficient than post-processing its result:
     161              :         //  (https://stackoverflow.com/questions/13686482/c11-stdto-stringdouble-no-trailing-zeros)
     162            2 :         s_value_.erase ( s_value_.find_last_not_of('0') + 1, std::string::npos );
     163            2 :         s_value_.erase ( s_value_.find_last_not_of('.') + 1, std::string::npos );
     164            2 :         break;
     165              :     }
     166            1 :     case NativeType::Boolean:
     167              :     {
     168            1 :         s_value_ = b_value_ ? "true":"false";
     169            1 :         break;
     170              :     }
     171           91 :     case NativeType::String:
     172           91 :         break;
     173              :     }
     174              : 
     175          112 :     LOGDEBUG(
     176              :         std::string msg;
     177              :     if (success) {
     178              :     msg = ert::tracing::Logger::asString("String value: %s", s_value_.c_str());
     179              :     }
     180              :     else {
     181              :         msg = ert::tracing::Logger::asString("Unable to get string representation for source: %s", asString().c_str());
     182              :     }
     183              : 
     184              :     ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     185              :     );
     186              : 
     187          112 :     return s_value_;
     188              : }
     189              : 
     190           16 : std::int64_t TypeConverter::getInteger(bool &success) {
     191              : 
     192           16 :     success = true;
     193              : 
     194           16 :     switch (native_type_) {
     195            1 :     case NativeType::Object:
     196              :     {
     197            1 :         success = false;
     198            1 :         break;
     199              :     }
     200            5 :     case NativeType::String:
     201              :     {
     202              :         try {
     203            5 :             i_value_ = std::stoll(s_value_);
     204              :         }
     205            1 :         catch(std::exception &e)
     206              :         {
     207            1 :             std::string msg = ert::tracing::Logger::asString("Error converting string '%s' to long long integer: %s", s_value_.c_str(), e.what());
     208            1 :             ert::tracing::Logger::error(msg, ERT_FILE_LOCATION);
     209            1 :             success = false;
     210            1 :         }
     211            5 :         break;
     212              :     }
     213            1 :     case NativeType::Unsigned:
     214              :     {
     215            1 :         i_value_ = std::int64_t(u_value_);
     216            1 :         break;
     217              :     }
     218            1 :     case NativeType::Float:
     219              :     {
     220            1 :         i_value_ = std::int64_t(f_value_);
     221            1 :         break;
     222              :     }
     223            1 :     case NativeType::Boolean:
     224              :     {
     225            1 :         i_value_ = std::int64_t(b_value_ ? 1:0);
     226            1 :         break;
     227              :     }
     228            7 :     case NativeType::Integer:
     229            7 :         break;
     230              :     }
     231              : 
     232           16 :     LOGDEBUG(
     233              :         std::string msg;
     234              :     if (success) {
     235              :     std::string fmt = std::string("Integer value: %") + PRIi64;
     236              :         msg = ert::tracing::Logger::asString(fmt.c_str(), i_value_);
     237              :     }
     238              :     else {
     239              :         msg = ert::tracing::Logger::asString("Unable to get integer representation for source: %s", asString().c_str());
     240              :     }
     241              : 
     242              :     ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     243              :     );
     244              : 
     245           16 :     return i_value_;
     246              : }
     247              : 
     248           18 : std::uint64_t TypeConverter::getUnsigned(bool &success) {
     249              : 
     250           18 :     success = true;
     251              : 
     252           18 :     switch (native_type_) {
     253            1 :     case NativeType::Object:
     254              :     {
     255            1 :         success = false;
     256            1 :         break;
     257              :     }
     258            9 :     case NativeType::String:
     259              :     {
     260              :         try {
     261            9 :             u_value_ = std::stoull(s_value_);
     262              :         }
     263            1 :         catch(std::exception &e)
     264              :         {
     265            1 :             std::string msg = ert::tracing::Logger::asString("Error converting string '%s' to unsigned long long integer: %s", s_value_.c_str(), e.what());
     266            1 :             ert::tracing::Logger::error(msg, ERT_FILE_LOCATION);
     267            1 :             success = false;
     268            1 :         }
     269            9 :         break;
     270              :     }
     271            2 :     case NativeType::Integer:
     272              :     {
     273            2 :         u_value_ = std::uint64_t(i_value_);
     274            2 :         break;
     275              :     }
     276            2 :     case NativeType::Float:
     277              :     {
     278            2 :         u_value_ = std::uint64_t(f_value_);
     279            2 :         break;
     280              :     }
     281            1 :     case NativeType::Boolean:
     282              :     {
     283            1 :         u_value_ = std::uint64_t(b_value_ ? 1:0);
     284            1 :         break;
     285              :     }
     286            3 :     case NativeType::Unsigned:
     287            3 :         break;
     288              :     }
     289              : 
     290           18 :     LOGDEBUG(
     291              :         std::string msg;
     292              :     if (success) {
     293              :     std::string fmt = std::string("Unsigned value: %") + PRIu64;
     294              :         msg = ert::tracing::Logger::asString(fmt.c_str(), u_value_);
     295              :     }
     296              :     else {
     297              :         msg = ert::tracing::Logger::asString("Unable to get unsigned integer representation for source: %s", asString().c_str());
     298              :     }
     299              : 
     300              :     ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     301              :     );
     302              : 
     303           18 :     return u_value_;
     304              : }
     305              : 
     306           12 : double TypeConverter::getFloat(bool &success) {
     307              : 
     308           12 :     success = true;
     309              : 
     310           12 :     switch (native_type_) {
     311            1 :     case NativeType::Object:
     312              :     {
     313            1 :         success = false;
     314            1 :         break;
     315              :     }
     316            5 :     case NativeType::String:
     317              :     {
     318              :         try {
     319            5 :             f_value_ = std::stod(s_value_);
     320              :         }
     321            1 :         catch(std::exception &e)
     322              :         {
     323            1 :             std::string msg = ert::tracing::Logger::asString("Error converting string '%s' to float number: %s", s_value_.c_str(), e.what());
     324            1 :             ert::tracing::Logger::error(msg, ERT_FILE_LOCATION);
     325            1 :             success = false;
     326            1 :         }
     327            5 :         break;
     328              :     }
     329            1 :     case NativeType::Integer:
     330              :     {
     331            1 :         f_value_ = double(i_value_);
     332            1 :         break;
     333              :     }
     334            1 :     case NativeType::Unsigned:
     335              :     {
     336            1 :         f_value_ = double(u_value_);
     337            1 :         break;
     338              :     }
     339            1 :     case NativeType::Boolean:
     340              :     {
     341            1 :         f_value_ = double(b_value_ ? 1:0);
     342            1 :         break;
     343              :     }
     344            3 :     case NativeType::Float:
     345            3 :         break;
     346              :     }
     347              : 
     348           12 :     LOGDEBUG(
     349              :         std::string msg;
     350              :     if (success) {
     351              :     msg = ert::tracing::Logger::asString("Float value: %lf", f_value_);
     352              :     }
     353              :     else {
     354              :         msg = ert::tracing::Logger::asString("Unable to get float number representation for source: %s", asString().c_str());
     355              :     }
     356              : 
     357              :     ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     358              :     );
     359              : 
     360           12 :     return f_value_;
     361              : }
     362              : 
     363           10 : bool TypeConverter::getBoolean(bool &success) {
     364              : 
     365           10 :     success = true;
     366              : 
     367           10 :     switch (native_type_) {
     368            1 :     case NativeType::Object:
     369              :     {
     370            1 :         success = false;
     371            1 :         break;
     372              :     }
     373            3 :     case NativeType::String:
     374              :     {
     375            3 :         b_value_ = (s_value_.empty() ? false:true);
     376            3 :         break;
     377              :     }
     378            1 :     case NativeType::Integer:
     379              :     {
     380            1 :         b_value_ = ((i_value_ != (std::int64_t)0) ? true:false);
     381            1 :         break;
     382              :     }
     383            1 :     case NativeType::Unsigned:
     384              :     {
     385            1 :         b_value_ = ((u_value_ != (std::uint64_t)0) ? true:false);
     386            1 :         break;
     387              :     }
     388            1 :     case NativeType::Float:
     389              :     {
     390            1 :         b_value_ = ((f_value_ != (double)0) ? true:false);
     391            1 :         break;
     392              :     }
     393            3 :     case NativeType::Boolean:
     394            3 :         break;
     395              :     }
     396              : 
     397           10 :     LOGDEBUG(
     398              :         std::string msg;
     399              :     if (success) {
     400              :     msg = ert::tracing::Logger::asString("Boolean value: %s", b_value_ ? "true":"false");
     401              :     }
     402              :     else {
     403              :         msg = ert::tracing::Logger::asString("Unable to get boolean representation for source: %s", asString().c_str());
     404              :     }
     405              : 
     406              :     ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     407              :     );
     408              : 
     409           10 :     return b_value_;
     410              : }
     411              : 
     412           13 : const nlohmann::json &TypeConverter::getObject(bool &success) {
     413              : 
     414           13 :     success = (native_type_ == NativeType::Object);
     415              : 
     416           13 :     LOGDEBUG(
     417              :         std::string msg;
     418              :     if (success) {
     419              :     msg = ert::tracing::Logger::asString("Json object value: %s", j_value_.dump().c_str());
     420              :     }
     421              :     else {
     422              :         msg = ert::tracing::Logger::asString("Unable to get json object from source: %s", asString().c_str());
     423              :     }
     424              : 
     425              :     ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     426              :     );
     427              : 
     428           13 :     return j_value_;
     429              : }
     430              : 
     431          270 : void TypeConverter::clear() {
     432          270 :     s_value_ = "";
     433          270 :     i_value_ = 0;
     434          270 :     u_value_ = 0;
     435          270 :     f_value_ = 0;
     436          270 :     b_value_ = false;
     437          270 :     j_value_.clear();
     438          270 :     native_type_ = NativeType::String;
     439          270 : }
     440              : 
     441           24 : bool TypeConverter::setObject(const nlohmann::json &jsonSource, const std::string &path) {
     442           24 :     clear();
     443              : 
     444           24 :     LOGDEBUG(
     445              :         std::string msg = ert::tracing::Logger::asString("Json path: %s | Json object: %s", path.c_str(), jsonSource.dump().c_str());
     446              :         ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     447              :     );
     448              : 
     449           24 :     if (path.empty()) {
     450           10 :         j_value_ = jsonSource;
     451              :     }
     452              :     else {
     453              :         try {
     454           14 :             nlohmann::json::json_pointer j_ptr(path);
     455              :             // operator[] aborts in debug compilation when the json pointer path is not found.
     456              :             // It is safer to use at() method which has "bounds checking":
     457              :             // j_value_ = jsonSource[j_ptr];
     458           14 :             j_value_ = jsonSource.at(j_ptr);
     459           10 :             if (j_value_.empty()) return false; // null extracted (path not found)
     460           14 :         }
     461            4 :         catch (std::exception& e)
     462              :         {
     463            4 :             ert::tracing::Logger::error(e.what(), ERT_FILE_LOCATION);
     464            4 :             return false;
     465            4 :         }
     466              :     }
     467              : 
     468           20 :     if (j_value_.is_object()) {
     469           10 :         native_type_ = NativeType::Object;
     470              :     }
     471           10 :     else if (j_value_.is_string()) {
     472            3 :         s_value_ = j_value_;
     473            3 :         native_type_ = NativeType::String;
     474              :     }
     475            7 :     else if (j_value_.is_number_unsigned()) { // this condition here (before integer), because integer also becomes true for unsigned source
     476            3 :         u_value_ = j_value_;
     477            3 :         native_type_ = NativeType::Unsigned;
     478              :     }
     479            4 :     else if (j_value_.is_number_integer()) {
     480            1 :         i_value_ = j_value_;
     481            1 :         native_type_ = NativeType::Integer;
     482              :     }
     483            3 :     else if (j_value_.is_number_float()) {
     484            1 :         f_value_ = j_value_;
     485            1 :         native_type_ = NativeType::Float;
     486              :     }
     487            2 :     else if (j_value_.is_boolean()) {
     488            2 :         b_value_ = j_value_;
     489            2 :         native_type_ = NativeType::Boolean;
     490              :     }
     491              :     //else {
     492              :     //    ert::tracing::Logger::error("Unrecognized json pointer value format", ERT_FILE_LOCATION); // this shouldn't happen as all the possible formats are checked above
     493              :     //    return false;
     494              :     //}
     495              : 
     496           20 :     return true;
     497              : }
     498              : 
     499            6 : std::string TypeConverter::asString() {
     500              : 
     501            6 :     std::stringstream ss;
     502            6 :     ss << "NativeType (String = 0, Integer, Unsigned, Float, Boolean, Object): " << getNativeType()
     503           12 :        << " | " << ((getNativeType() == NativeType::String) ? "STRING":"String") << ": " << s_value_
     504            6 :        << " | " << ((getNativeType() == NativeType::Integer) ? "INTEGER":"Integer") << ": " << i_value_
     505            6 :        << " | " << ((getNativeType() == NativeType::Unsigned) ? "UNSIGNED":"Unsigned") << ": " << u_value_
     506            6 :        << " | " << ((getNativeType() == NativeType::Float) ? "FLOAT":"Float") << ": " << f_value_
     507           12 :        << " | " << ((getNativeType() == NativeType::Boolean) ? "BOOLEAN":"Boolean") << ": " << (b_value_ ? "true":"false")
     508            6 :        << " | " << ((getNativeType() == NativeType::Object) ? "OBJECT":"Object") << ": " << j_value_.dump();
     509              : 
     510           12 :     return (ss.str());
     511            6 : }
     512              : 
     513              : }
     514              : }
        

Generated by: LCOV version 2.0-1