LCOV - code coverage report
Current view: top level - tests - catch_severity.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 96.4 % 166 160
Test Date: 2025-07-26 11:53:05 Functions: 100.0 % 2 2
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2006-2025  Made to Order Software Corp.  All Rights Reserved
       2              : //
       3              : // https://snapwebsites.org/project/snaplogger
       4              : // contact@m2osw.com
       5              : //
       6              : // This program is free software; you can redistribute it and/or modify
       7              : // it under the terms of the GNU General Public License as published by
       8              : // the Free Software Foundation; either version 2 of the License, or
       9              : // (at your option) any later version.
      10              : //
      11              : // This program is distributed in the hope that it will be useful,
      12              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14              : // GNU General Public License for more details.
      15              : //
      16              : // You should have received a copy of the GNU General Public License along
      17              : // with this program; if not, write to the Free Software Foundation, Inc.,
      18              : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19              : 
      20              : // self
      21              : //
      22              : #include    "catch_main.h"
      23              : 
      24              : 
      25              : // snaplogger
      26              : //
      27              : #include    <snaplogger/buffer_appender.h>
      28              : #include    <snaplogger/exception.h>
      29              : #include    <snaplogger/format.h>
      30              : #include    <snaplogger/logger.h>
      31              : #include    <snaplogger/map_diagnostic.h>
      32              : #include    <snaplogger/message.h>
      33              : #include    <snaplogger/severity.h>
      34              : #include    <snaplogger/version.h>
      35              : 
      36              : 
      37              : // advgetopt
      38              : //
      39              : #include    <advgetopt/conf_file.h>
      40              : #include    <advgetopt/validator_integer.h>
      41              : 
      42              : 
      43              : // snapdev
      44              : //
      45              : #include    <snapdev/enum_class_math.h>
      46              : 
      47              : 
      48              : // C
      49              : //
      50              : #include    <unistd.h>
      51              : #include    <netdb.h>
      52              : #include    <sys/param.h>
      53              : 
      54              : 
      55              : 
      56              : 
      57            4 : CATCH_TEST_CASE("severity", "[severity]")
      58              : {
      59            4 :     CATCH_START_SECTION("severity: Create Severity")
      60              :     {
      61            1 :         snaplogger::severity_t const err_plus_one(static_cast<snaplogger::severity_t>(static_cast<int>(snaplogger::severity_t::SEVERITY_ERROR) + 1));
      62              : 
      63              :         // user severity by name
      64              :         {
      65            1 :             snaplogger::severity::pointer_t s(std::make_shared<snaplogger::severity>(err_plus_one, "error"));
      66              : 
      67            5 :             CATCH_REQUIRE_THROWS_MATCHES(
      68              :                       snaplogger::add_severity(s)
      69              :                     , snaplogger::duplicate_error
      70              :                     , Catch::Matchers::ExceptionMessage(
      71              :                               "logger_error: a system severity (error) cannot be replaced (same name)."));
      72            1 :         }
      73              : 
      74              :         // system severity by name
      75              :         {
      76            1 :             snaplogger::severity::pointer_t s(std::make_shared<snaplogger::severity>(err_plus_one, "error", true));
      77              : 
      78            5 :             CATCH_REQUIRE_THROWS_MATCHES(
      79              :                       snaplogger::add_severity(s)
      80              :                     , snaplogger::duplicate_error
      81              :                     , Catch::Matchers::ExceptionMessage(
      82              :                               "logger_error: a system severity (error) cannot be replaced (same name)."));
      83            1 :         }
      84              : 
      85              :         // user severity by severity
      86              :         {
      87            1 :             snaplogger::severity::pointer_t s(std::make_shared<snaplogger::severity>(snaplogger::severity_t::SEVERITY_ERROR, "bad-error"));
      88              : 
      89            3 :             CATCH_REQUIRE_THROWS_MATCHES(
      90              :                       snaplogger::add_severity(s)
      91              :                     , snaplogger::duplicate_error
      92              :                     , Catch::Matchers::ExceptionMessage(
      93              :                                 "logger_error: a system severity ("
      94              :                               + std::to_string(static_cast<int>(snaplogger::severity_t::SEVERITY_ERROR))
      95              :                               + ") cannot be replaced (same severity level: "
      96              :                               + std::to_string(static_cast<int>(snaplogger::severity_t::SEVERITY_ERROR))
      97              :                               + ")."));
      98            1 :         }
      99              : 
     100              :         // user severity by severity
     101              :         {
     102            1 :             snaplogger::severity::pointer_t s(std::make_shared<snaplogger::severity>(snaplogger::severity_t::SEVERITY_ERROR, "bad-error", true));
     103              : 
     104            3 :             CATCH_REQUIRE_THROWS_MATCHES(
     105              :                       snaplogger::add_severity(s)
     106              :                     , snaplogger::duplicate_error
     107              :                     , Catch::Matchers::ExceptionMessage(
     108              :                                     "logger_error: a system severity ("
     109              :                                   + std::to_string(static_cast<int>(snaplogger::severity_t::SEVERITY_ERROR))
     110              :                                   + ") cannot be replaced (same severity level: "
     111              :                                   + std::to_string(static_cast<int>(snaplogger::severity_t::SEVERITY_ERROR))
     112              :                                   + ")."));
     113            1 :         }
     114              : 
     115              :         // actually create a valid severity
     116              :         {
     117            3 :             CATCH_REQUIRE(snaplogger::get_severity("bad-error") == nullptr);
     118            3 :             CATCH_REQUIRE(snaplogger::get_severity("big-error") == nullptr);
     119              : 
     120            1 :             snaplogger::severity_t const level(static_cast<snaplogger::severity_t>(205));
     121            1 :             snaplogger::severity::pointer_t s(std::make_shared<snaplogger::severity>(level, "bad-error"));
     122              : 
     123            1 :             CATCH_REQUIRE(s->get_severity() == level);
     124            1 :             CATCH_REQUIRE(s->get_name() == "bad-error");
     125              : 
     126            1 :             CATCH_REQUIRE(s->get_all_names().size() == 1);
     127            1 :             CATCH_REQUIRE(s->get_all_names()[0] == "bad-error");
     128              : 
     129            3 :             CATCH_REQUIRE(snaplogger::get_severity("bad-error") == nullptr);
     130            3 :             CATCH_REQUIRE(snaplogger::get_severity("big-error") == nullptr);
     131              : 
     132              :             // duplicates are not allowed
     133              :             //
     134            7 :             CATCH_REQUIRE_THROWS_MATCHES(
     135              :                       s->add_alias("bad-error")
     136              :                     , snaplogger::duplicate_error
     137              :                     , Catch::Matchers::ExceptionMessage(
     138              :                               "logger_error: severity \""
     139              :                               "bad-error"
     140              :                               "\" already has an alias \""
     141              :                               "bad-error"
     142              :                               "\"."));
     143              : 
     144            1 :             snaplogger::add_severity(s);
     145              : 
     146            3 :             CATCH_REQUIRE(snaplogger::get_severity("bad-error") == s);
     147            3 :             CATCH_REQUIRE(snaplogger::get_severity("big-error") == nullptr);
     148              : 
     149            3 :             s->add_alias("big-error");
     150              : 
     151              :             // duplicates are not allowed
     152              :             //
     153            7 :             CATCH_REQUIRE_THROWS_MATCHES(
     154              :                       s->add_alias("big-error")
     155              :                     , snaplogger::duplicate_error
     156              :                     , Catch::Matchers::ExceptionMessage(
     157              :                               "logger_error: severity \""
     158              :                               "bad-error"
     159              :                               "\" already has an alias \""
     160              :                               "big-error"
     161              :                               "\"."));
     162              : 
     163            1 :             CATCH_REQUIRE(s->get_all_names().size() == 2);
     164            1 :             CATCH_REQUIRE(s->get_all_names()[0] == "bad-error");
     165            1 :             CATCH_REQUIRE(s->get_all_names()[1] == "big-error");
     166              : 
     167            1 :             CATCH_REQUIRE(s->get_description() == "bad-error");
     168              : 
     169            3 :             s->set_description("bad error");
     170            1 :             CATCH_REQUIRE(s->get_description() == "bad error");
     171              : 
     172            1 :             s->set_description(std::string());
     173            1 :             CATCH_REQUIRE(s->get_description() == "bad-error");
     174              : 
     175            3 :             CATCH_REQUIRE(snaplogger::get_severity("bad-error") == s);
     176            3 :             CATCH_REQUIRE(snaplogger::get_severity("big-error") == s);
     177            1 :             CATCH_REQUIRE(snaplogger::get_severity(level) == s);
     178              : 
     179            3 :             s->set_styles("orange");
     180            1 :             CATCH_REQUIRE(s->get_styles() == "orange");
     181              : 
     182            1 :             snaplogger::severity_t const level_plus_one(static_cast<snaplogger::severity_t>(static_cast<int>(level) + 1));
     183            1 :             CATCH_REQUIRE(snaplogger::get_severity(level_plus_one) == nullptr);
     184              : 
     185            1 :             snaplogger::message msg(::snaplogger::severity_t::SEVERITY_ERROR);
     186            3 :             CATCH_REQUIRE(snaplogger::get_severity(msg, "bad-error") == s);
     187            3 :             CATCH_REQUIRE(snaplogger::get_severity(msg, "big-error") == s);
     188            1 :         }
     189              : 
     190              :         // verify that the "<name>"_sev syntax works as expected
     191              :         {
     192            1 :             snaplogger::severity_t const level(static_cast<snaplogger::severity_t>(25));
     193            1 :             snaplogger::severity::pointer_t s(std::make_shared<snaplogger::severity>(level, "remark"));
     194              : 
     195            1 :             snaplogger::add_severity(s);
     196              : 
     197            1 :             CATCH_REQUIRE(s->get_severity() == level);
     198            1 :             CATCH_REQUIRE(s->get_name() == "remark");
     199              : 
     200              : #if SNAPDEV_CHECK_GCC_VERSION(7, 5, 0)
     201            1 :             snaplogger::severity::pointer_t r("remark"_sev);
     202            1 :             CATCH_REQUIRE(r == s);
     203              : 
     204            1 :             CATCH_REQUIRE(r->get_severity() == level);
     205            1 :             CATCH_REQUIRE(r->get_name() == "remark");
     206              : #endif
     207            1 :         }
     208              :     }
     209            4 :     CATCH_END_SECTION()
     210              : 
     211            4 :     CATCH_START_SECTION("severity: Print Severity")
     212              :     {
     213              :         struct level_and_name_t
     214              :         {
     215              :             ::snaplogger::severity_t    f_level = ::snaplogger::severity_t::SEVERITY_ERROR;
     216              :             std::string                 f_name = std::string();
     217              :         };
     218              : 
     219            1 :         std::vector<level_and_name_t> level_and_name =
     220              :         {
     221              :             { ::snaplogger::severity_t::SEVERITY_ALL,                   "all" },
     222              :             { ::snaplogger::severity_t::SEVERITY_TRACE,                 "trace" },
     223              :             { ::snaplogger::severity_t::SEVERITY_NOISY,                 "noisy" },
     224              :             { ::snaplogger::severity_t::SEVERITY_DEBUG,                 "debug" },
     225              :             { ::snaplogger::severity_t::SEVERITY_NOTICE,                "notice" },
     226              :             { ::snaplogger::severity_t::SEVERITY_UNIMPORTANT,           "unimportant" },
     227              :             { ::snaplogger::severity_t::SEVERITY_VERBOSE,               "verbose" },
     228              :             { ::snaplogger::severity_t::SEVERITY_CONFIGURATION,         "configuration" },
     229              :             { ::snaplogger::severity_t::SEVERITY_CONFIGURATION_WARNING, "configuration-warning" },
     230              :             { ::snaplogger::severity_t::SEVERITY_INFORMATION,           "information" },
     231              :             { ::snaplogger::severity_t::SEVERITY_IMPORTANT,             "important" },
     232              :             { ::snaplogger::severity_t::SEVERITY_MINOR,                 "minor" },
     233              :             { ::snaplogger::severity_t::SEVERITY_DEPRECATED,            "deprecated" },
     234              :             { ::snaplogger::severity_t::SEVERITY_WARNING,               "warning" },
     235              :             { ::snaplogger::severity_t::SEVERITY_MAJOR,                 "major" },
     236              :             { ::snaplogger::severity_t::SEVERITY_RECOVERABLE_ERROR,     "recoverable-error" },
     237              :             { ::snaplogger::severity_t::SEVERITY_ERROR,                 "error" },
     238              :             { ::snaplogger::severity_t::SEVERITY_NOISY_ERROR,           "noisy-error" },
     239              :             { ::snaplogger::severity_t::SEVERITY_SEVERE,                "severe" },
     240              :             { ::snaplogger::severity_t::SEVERITY_EXCEPTION,             "exception" },
     241              :             { ::snaplogger::severity_t::SEVERITY_CRITICAL,              "critical" },
     242              :             { ::snaplogger::severity_t::SEVERITY_ALERT,                 "alert" },
     243              :             { ::snaplogger::severity_t::SEVERITY_EMERGENCY,             "emergency" },
     244              :             { ::snaplogger::severity_t::SEVERITY_FATAL,                 "fatal" },
     245              :             { ::snaplogger::severity_t::SEVERITY_OFF,                   "off" },
     246           29 :         };
     247              : 
     248           26 :         for(auto const & ln : level_and_name)
     249              :         {
     250           25 :             std::stringstream buffer;
     251           25 :             buffer << ln.f_level;
     252           25 :             CATCH_REQUIRE(buffer.str() == ln.f_name);
     253           25 :         }
     254              : 
     255              :         {
     256            1 :             std::stringstream buffer;
     257            1 :             buffer << static_cast<::snaplogger::severity_t>(254);
     258            1 :             CATCH_REQUIRE(buffer.str() == "(unknown severity: 254)");
     259            1 :         }
     260            1 :     }
     261            4 :     CATCH_END_SECTION()
     262              : 
     263            4 :     CATCH_START_SECTION("severity: Severity by Level or Name")
     264              :     {
     265            1 :         snaplogger::severity_by_severity_t severities(snaplogger::get_severities_by_severity());
     266            1 :         snaplogger::severity_by_name_t names(snaplogger::get_severities_by_name());
     267              : 
     268              :         // this is not true, there are more names than severity levels
     269              :         //
     270              :         //CATCH_REQUIRE(severities.size() == names.size());
     271              : 
     272              : // this does not hold true, that is, the map is properly sorted, but for
     273              : // entries with an alias, the s->get_name() returns the base name, not the
     274              : // alias, and thus, the order may be skewed for all aliases
     275              : //
     276              : //        std::string previous_name;
     277              : //        for(auto const & s : names)
     278              : //        {
     279              : //            CATCH_REQUIRE(s.second->get_name() > previous_name);
     280              : //            previous_name = s.second->get_name();
     281              : //        }
     282              : 
     283            1 :         snaplogger::severity_t previous_severity(snaplogger::severity_t::SEVERITY_ALL - 1);
     284           29 :         for(auto const & s : severities)
     285              :         {
     286           28 :             CATCH_REQUIRE(s.second->get_severity() > previous_severity);
     287           28 :             previous_severity = s.second->get_severity();
     288              :         }
     289            1 :     }
     290            4 :     CATCH_END_SECTION()
     291              : 
     292            4 :     CATCH_START_SECTION("severity: severity.ini file matches")
     293              :     {
     294              :         // whenever I make an edit to the list of severity levels, I have to
     295              :         // keep the severity.ini up to date or the system won't be able to
     296              :         // load the file properly; this test verifies the one found in the
     297              :         // source tree against the severity levels defined in the header
     298              :         //
     299            1 :         std::string severity_ini_filename(SNAP_CATCH2_NAMESPACE::g_source_dir());
     300            1 :         severity_ini_filename += "/conf/severity.ini";
     301            1 :         advgetopt::conf_file_setup setup(severity_ini_filename);
     302            1 :         CATCH_REQUIRE(setup.is_valid());
     303              : 
     304            1 :         advgetopt::conf_file::pointer_t severity_ini(advgetopt::conf_file::get_conf_file(setup));
     305            1 :         CATCH_REQUIRE(severity_ini != nullptr);
     306              : 
     307            1 :         std::set<std::string> found;
     308              : 
     309            1 :         advgetopt::conf_file::sections_t sections(severity_ini->get_sections());
     310           27 :         for(auto const & s : sections)
     311              :         {
     312           26 :             snaplogger::severity::pointer_t severity(snaplogger::get_severity(s));
     313              : 
     314              :             // the default severity.ini file only defines system severities
     315              :             //
     316           26 :             CATCH_REQUIRE(severity->is_system());
     317              : 
     318              :             // make sure the entry includes a severity=... value
     319              :             //
     320           26 :             std::string const level_name(s + "::severity");
     321           26 :             CATCH_REQUIRE(severity_ini->has_parameter(level_name));
     322              : 
     323           26 :             std::string const level(severity_ini->get_parameter(level_name));
     324              : 
     325              :             // the level must be a valid integer
     326              :             //
     327           26 :             std::int64_t value(0);
     328           26 :             CATCH_REQUIRE(advgetopt::validator_integer::convert_string(level, value));
     329              : 
     330              :             // the .ini level must match the internal (library) level
     331              :             //
     332           26 :             CATCH_REQUIRE(severity->get_severity() == static_cast<snaplogger::severity_t>(value));
     333              : 
     334           26 :             found.insert(s);
     335              : 
     336              :             // severities may have aliases which needs to be added to `found`
     337              :             //
     338           26 :             std::string const aliases_name(s + "::aliases");
     339           26 :             if(severity_ini->has_parameter(aliases_name))
     340              :             {
     341           17 :                 std::string const aliases(severity_ini->get_parameter(aliases_name));
     342           17 :                 advgetopt::string_list_t names;
     343           51 :                 advgetopt::split_string(aliases, names, {","});
     344           35 :                 for(auto const & n : names)
     345              :                 {
     346           18 :                     found.insert(n);
     347              :                 }
     348           17 :             }
     349              : 
     350              :             // verify mismatches in other parameters if defined
     351              :             //
     352           26 :             std::string const description_name(s + "::description");
     353           26 :             if(severity_ini->has_parameter(description_name))
     354              :             {
     355           25 :                 std::string const description(severity_ini->get_parameter(description_name));
     356           25 :                 CATCH_REQUIRE(severity->get_description() == description);
     357           25 :             }
     358              : 
     359           26 :             std::string const styles_name(s + "::styles");
     360           26 :             if(severity_ini->has_parameter(styles_name))
     361              :             {
     362           17 :                 std::string const styles(severity_ini->get_parameter(styles_name));
     363           17 :                 CATCH_REQUIRE(severity->get_styles() == styles);
     364           17 :             }
     365              : 
     366           26 :             std::string const default_name(s + "::default");
     367           26 :             if(severity_ini->has_parameter(default_name))
     368              :             {
     369            1 :                 std::string const default_value(severity_ini->get_parameter(default_name));
     370            1 :                 bool const valid_default(advgetopt::is_true(default_value) || advgetopt::is_false(default_value));
     371            1 :                 CATCH_REQUIRE(valid_default);
     372            1 :             }
     373           26 :         }
     374              : 
     375              :         // make sure all the parameters are known
     376              :         // (for our file, that's best in case we misspell something)
     377              :         //
     378            1 :         std::string default_severity;
     379           87 :         for(auto const & p : severity_ini->get_parameters())
     380              :         {
     381           86 :             advgetopt::string_list_t names;
     382          258 :             advgetopt::split_string(p.first, names, {"::"});
     383              : 
     384              :             // first of all, we do not support global definition in the
     385              :             // severity.ini file so we should only have names within a
     386              :             // section and no sub-section thus two names exactly
     387              :             //
     388           86 :             CATCH_REQUIRE(names.size() == 2);
     389              : 
     390           86 :             if(names[1] == "default")
     391              :             {
     392            1 :                 if(advgetopt::is_true(p.second))
     393              :                 {
     394              :                     // there can be only one default
     395              :                     //
     396            1 :                     if(!default_severity.empty())
     397              :                     {
     398              :                         std::cerr
     399              :                             << "--- found more than one default: \""
     400              :                             << default_severity
     401              :                             << "\" and \""
     402            0 :                             << names[0]
     403            0 :                             << "\"\n";
     404              :                     }
     405            1 :                     CATCH_REQUIRE(default_severity.empty());
     406              : 
     407            1 :                     default_severity = names[0];
     408              :                 }
     409              :             }
     410           85 :             else if(names[1] != "aliases"
     411           68 :                  && names[1] != "description"
     412           43 :                  && names[1] != "severity"
     413          153 :                  && names[1] != "styles")
     414              :             {
     415            0 :                 std::cerr << "--- found unknown parameter \"" << names[1] << "\"\n";
     416            0 :                 CATCH_REQUIRE(!"parameter not known");
     417              :             }
     418           87 :         }
     419              : 
     420              :         // further, make sure that all system severities defined in the
     421              :         // library are found in the .ini file
     422              :         //
     423              :         // with aliases, this is not 100% true, maybe we should check
     424              :         // with the by_severity() list instead...
     425              :         //
     426           47 :         for(auto const & s : snaplogger::get_severities_by_name())
     427              :         {
     428           46 :             if(s.second->is_system())
     429              :             {
     430           43 :                 bool const contained(found.contains(s.first));
     431           43 :                 if(!contained)
     432              :                 {
     433              :                     std::cout
     434              :                         << "--- system severity \""
     435            0 :                         << s.first
     436              :                         << "\" is not defined in \""
     437              :                         << severity_ini_filename
     438            0 :                         << "\" file.\n";
     439              :                 }
     440           43 :                 CATCH_REQUIRE(contained);
     441              :             }
     442            1 :         }
     443            1 :     }
     444            4 :     CATCH_END_SECTION()
     445            7 : }
     446              : 
     447              : 
     448            2 : CATCH_TEST_CASE("severity_error", "[severity][error]")
     449              : {
     450            2 :     CATCH_START_SECTION("severity: too small")
     451              :     {
     452            6 :         CATCH_REQUIRE_THROWS_MATCHES(
     453              :                   snaplogger::severity(snaplogger::severity_t::SEVERITY_MIN - 1, "TOO_SMALL")
     454              :                 , snaplogger::invalid_severity
     455              :                 , Catch::Matchers::ExceptionMessage(
     456              :                           "logger_error: the severity level cannot be "
     457              :                         + std::to_string(static_cast<int>(snaplogger::severity_t::SEVERITY_MIN - 1))
     458              :                         + ". The possible range is ["
     459              :                         + std::to_string(static_cast<int>(snaplogger::severity_t::SEVERITY_MIN))
     460              :                         + ".."
     461              :                         + std::to_string(static_cast<int>(snaplogger::severity_t::SEVERITY_MAX))
     462              :                         + "]."));
     463              :     }
     464            2 :     CATCH_END_SECTION()
     465              : 
     466            2 :     CATCH_START_SECTION("severity: too large")
     467              :     {
     468            6 :         CATCH_REQUIRE_THROWS_MATCHES(
     469              :                   snaplogger::severity(snaplogger::severity_t::SEVERITY_MAX + 1, "TOO_LARGE")
     470              :                 , snaplogger::invalid_severity
     471              :                 , Catch::Matchers::ExceptionMessage(
     472              :                           "logger_error: the severity level cannot be "
     473              :                         + std::to_string(static_cast<int>(snaplogger::severity_t::SEVERITY_MAX + 1))
     474              :                         + ". The possible range is ["
     475              :                         + std::to_string(static_cast<int>(snaplogger::severity_t::SEVERITY_MIN))
     476              :                         + ".."
     477              :                         + std::to_string(static_cast<int>(snaplogger::severity_t::SEVERITY_MAX))
     478              :                         + "]."));
     479              :     }
     480            2 :     CATCH_END_SECTION()
     481            2 : }
     482              : 
     483              : 
     484              : 
     485              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions