LCOV - code coverage report
Current view: top level - tests - catch_validator.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 803 818 98.2 %
Date: 2022-07-15 09:02:52 Functions: 27 33 81.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2006-2022  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/advgetopt
       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             : // advgetopt
      21             : //
      22             : #include    <advgetopt/validator_duration.h>
      23             : #include    <advgetopt/validator_size.h>
      24             : 
      25             : #include    <advgetopt/exception.h>
      26             : 
      27             : 
      28             : // self
      29             : //
      30             : #include    "catch_main.h"
      31             : 
      32             : 
      33             : // snapdev
      34             : //
      35             : #include    <snapdev/ostream_int128.h>
      36             : 
      37             : 
      38             : // C++
      39             : //
      40             : #include    <cmath>
      41             : #include    <fstream>
      42             : #include    <iomanip>
      43             : 
      44             : 
      45             : // last include
      46             : //
      47             : #include    <snapdev/poison.h>
      48             : 
      49             : 
      50             : 
      51             : 
      52             : 
      53             : namespace
      54             : {
      55             : 
      56             : struct duration_t
      57             : {
      58             :     char const * const      f_suffix = nullptr;
      59             :     double                  f_factor = 1.0;
      60             : };
      61             : 
      62             : constexpr duration_t const g_duration_suffixes[] =
      63             : {
      64             :     { "",                      1.0 },
      65             :     { "s",                     1.0 },
      66             :     { "second",                1.0 },
      67             :     { "seconds",               1.0 },
      68             : 
      69             :     { "m",                    -1.0 },   // may represent minutes or months
      70             :     { "minute",               60.0 },
      71             :     { "minutes",              60.0 },
      72             : 
      73             :     { "h",                  3600.0 },
      74             :     { "hour",               3600.0 },
      75             :     { "hours",              3600.0 },
      76             : 
      77             :     { "d",                 86400.0 },
      78             :     { "day",               86400.0 },
      79             :     { "days",              86400.0 },
      80             : 
      81             :     { "w",           86400.0 * 7.0 },
      82             :     { "week",        86400.0 * 7.0 },
      83             :     { "weeks",       86400.0 * 7.0 },
      84             : 
      85             :     { "month",      86400.0 * 30.0 },
      86             :     { "months",     86400.0 * 30.0 },
      87             : 
      88             :     { "y",         86400.0 * 365.0 },
      89             :     { "year",      86400.0 * 365.0 },
      90             :     { "years",     86400.0 * 365.0 },
      91             : };
      92             : 
      93             : struct size_suffix_t
      94             : {
      95             :     char const * const      f_suffix = nullptr;
      96             :     int                     f_base = 1000.0;
      97             :     int                     f_power = 0.0;
      98             : };
      99             : 
     100             : constexpr size_suffix_t const g_size_suffixes[] =
     101             : {
     102             :     { "",     1000, 0 },
     103             :     { "B",    1000, 0 },
     104             : 
     105             :     { "kB",   1000, 1 },
     106             :     { "KiB",  1024, 1 },
     107             : 
     108             :     { "MB",   1000, 2 },
     109             :     { "MiB",  1024, 2 },
     110             : 
     111             :     { "GB",   1000, 3 },
     112             :     { "GiB",  1024, 3 },
     113             : 
     114             :     { "TB",   1000, 4 },
     115             :     { "TiB",  1024, 4 },
     116             : 
     117             :     { "PB",   1000, 5 },
     118             :     { "PiB",  1024, 5 },
     119             : 
     120             :     { "EB",   1000, 6 },
     121             :     { "EiB",  1024, 6 },
     122             : 
     123             :     { "ZB",   1000, 7 },
     124             :     { "ZiB",  1024, 7 },
     125             : 
     126             :     { "YB",   1000, 8 },
     127             :     { "YiB",  1024, 8 },
     128             : };
     129             : 
     130      123683 : std::int64_t large_rnd(bool zero_allowed = true)
     131             : {
     132             :     for(;;)
     133             :     {
     134      123683 :         std::int64_t const result((static_cast<std::int64_t>(rand()) <<  0)
     135      123683 :                                 ^ (static_cast<std::int64_t>(rand()) << 16)
     136      123683 :                                 ^ (static_cast<std::int64_t>(rand()) << 32)
     137      123683 :                                 ^ (static_cast<std::int64_t>(rand()) << 48));
     138      123683 :         if(result != 0
     139           0 :         || zero_allowed)
     140             :         {
     141      247366 :             return result;
     142             :         }
     143           0 :     }
     144             : }
     145             : 
     146             : }
     147             : 
     148             : 
     149             : 
     150           4 : CATCH_TEST_CASE("unknown_validator", "[validator][valid][validation]")
     151             : {
     152           4 :     CATCH_START_SECTION("Undefined validator")
     153             :         // this is a valid case, it does not throw, it just returns a nullptr
     154             :         //
     155           1 :         CATCH_REQUIRE(advgetopt::validator::create("unknown", advgetopt::string_list_t()) == nullptr);
     156             :     CATCH_END_SECTION()
     157             : 
     158           4 :     CATCH_START_SECTION("Empty string")
     159           1 :         CATCH_REQUIRE(advgetopt::validator::create(std::string()) == nullptr);
     160             :     CATCH_END_SECTION()
     161           2 : }
     162             : 
     163             : 
     164             : 
     165           5 : CATCH_TEST_CASE("email_validator", "[invalid][validation]")
     166             : {
     167           6 :     CATCH_START_SECTION("email_validator: Verify that email verification works.")
     168             :     {
     169           2 :         advgetopt::validator::pointer_t email(advgetopt::validator::create("email"));
     170             : 
     171           1 :         CATCH_REQUIRE(email != nullptr);
     172           1 :         CATCH_REQUIRE(email->name() == "email");
     173             : 
     174           1 :         CATCH_REQUIRE_FALSE(email->validate(""));
     175           1 :         CATCH_REQUIRE(email->validate("user@example.com"));
     176           1 :         CATCH_REQUIRE(email->validate("USER@EXAMPLE.COM"));
     177           1 :         CATCH_REQUIRE_FALSE(email->validate("user1@example.com, user2@example.com, user3@example.com"));
     178           1 :         CATCH_REQUIRE_FALSE(email->validate("User!example.com"));
     179           1 :         CATCH_REQUIRE_FALSE(email->validate("@example.com"));
     180           1 :         CATCH_REQUIRE_FALSE(email->validate("uSeR@"));
     181           1 :         CATCH_REQUIRE_FALSE(email->validate("uSeR@com"));
     182             :     }
     183             :     CATCH_END_SECTION()
     184             : 
     185           6 :     CATCH_START_SECTION("email_validator: Verify that one email verification works (single explicitly).")
     186             :     {
     187           2 :         advgetopt::validator::pointer_t email(advgetopt::validator::create("email(single)"));
     188             : 
     189           1 :         CATCH_REQUIRE(email != nullptr);
     190           1 :         CATCH_REQUIRE(email->name() == "email");
     191             : 
     192           1 :         CATCH_REQUIRE_FALSE(email->validate(""));
     193           1 :         CATCH_REQUIRE(email->validate("user@example.com"));
     194           1 :         CATCH_REQUIRE(email->validate("USER@EXAMPLE.COM"));
     195           1 :         CATCH_REQUIRE_FALSE(email->validate("user1@example.com, user2@example.com, user3@example.com"));
     196           1 :         CATCH_REQUIRE_FALSE(email->validate("User!example.com"));
     197           1 :         CATCH_REQUIRE_FALSE(email->validate("@example.com"));
     198           1 :         CATCH_REQUIRE_FALSE(email->validate("uSeR@"));
     199           1 :         CATCH_REQUIRE_FALSE(email->validate("uSeR@com"));
     200             :     }
     201             :     CATCH_END_SECTION()
     202             : 
     203           6 :     CATCH_START_SECTION("email_validator: Verify that multiple emails verification works.")
     204             :     {
     205           2 :         advgetopt::validator::pointer_t email(advgetopt::validator::create("email(multiple)"));
     206             : 
     207           1 :         CATCH_REQUIRE(email != nullptr);
     208           1 :         CATCH_REQUIRE(email->name() == "email");
     209             : 
     210           1 :         CATCH_REQUIRE_FALSE(email->validate(""));
     211           1 :         CATCH_REQUIRE(email->validate("user1@example.com, user2@example.com, user3@example.com"));
     212           1 :         CATCH_REQUIRE(email->validate("USER@EXAMPLE.COM"));
     213           1 :         CATCH_REQUIRE_FALSE(email->validate("User!example.com"));
     214           1 :         CATCH_REQUIRE_FALSE(email->validate("@example.com"));
     215           1 :         CATCH_REQUIRE_FALSE(email->validate("uSeR@"));
     216           1 :         CATCH_REQUIRE_FALSE(email->validate("uSeR@com"));
     217             :     }
     218             :     CATCH_END_SECTION()
     219           3 : }
     220             : 
     221             : 
     222             : 
     223           5 : CATCH_TEST_CASE("integer_validator", "[validator][valid][validation]")
     224             : {
     225           6 :     CATCH_START_SECTION("integer_validator: Verify the integer validator")
     226             :     {
     227           2 :         advgetopt::validator::pointer_t integer_validator(advgetopt::validator::create("integer", advgetopt::string_list_t()));
     228             : 
     229           1 :         CATCH_REQUIRE(integer_validator != nullptr);
     230           1 :         CATCH_REQUIRE(integer_validator->name() == "integer");
     231             : 
     232           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate(""));
     233           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("+"));
     234           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("-"));
     235             : 
     236        1001 :         for(int idx(0); idx < 1000; ++idx)
     237             :         {
     238        1000 :             std::int64_t value(large_rnd());
     239        2000 :             std::string const v(std::to_string(value));
     240             : 
     241        1000 :             CATCH_REQUIRE(integer_validator->validate(v));
     242             : 
     243        1000 :             if(value >= 0)
     244             :             {
     245         520 :                 CATCH_REQUIRE(integer_validator->validate('+' + v));
     246             :             }
     247             : 
     248        2000 :             std::string const space_before(' ' + v);
     249        1000 :             CATCH_REQUIRE_FALSE(integer_validator->validate(space_before));
     250             : 
     251        2000 :             std::string const space_after(v + ' ');
     252        1000 :             CATCH_REQUIRE_FALSE(integer_validator->validate(space_after));
     253             : 
     254        2000 :             std::string const before(static_cast<char>(rand() % 26 + 'a') + v);
     255        1000 :             CATCH_REQUIRE_FALSE(integer_validator->validate(before));
     256             : 
     257        2000 :             std::string const after(v + static_cast<char>(rand() % 26 + 'a'));
     258        1000 :             CATCH_REQUIRE_FALSE(integer_validator->validate(after));
     259             :         }
     260             : 
     261             :         // max number
     262           1 :         CATCH_REQUIRE(integer_validator->validate("9223372036854775807"));
     263           1 :         CATCH_REQUIRE(integer_validator->validate("+9223372036854775807"));
     264             : 
     265             :         // overflow
     266           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("9223372036854775808"));
     267           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("+9223372036854775808"));
     268             : 
     269             :         // min number
     270           1 :         CATCH_REQUIRE(integer_validator->validate("-9223372036854775808"));
     271             : 
     272             :         // underflow
     273           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("-9223372036854775809"));
     274             : 
     275             :         // too many digits
     276           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("92233720368547758091"));
     277           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("+92233720368547758092"));
     278           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("-92233720368547758093"));
     279             :     }
     280             :     CATCH_END_SECTION()
     281             : 
     282           6 :     CATCH_START_SECTION("integer_validator: Verify the integer ranges")
     283             :     {
     284           1 :         bool had_standalone(false);
     285          21 :         for(int count(0); count < 20 || !had_standalone; ++count)
     286             :         {
     287          20 :             std::int64_t min(large_rnd());
     288          20 :             std::int64_t max(large_rnd());
     289          20 :             if(min > max)
     290             :             {
     291          11 :                 std::swap(min, max);
     292             :             }
     293             : 
     294          40 :             std::string const & smin(std::to_string(min));
     295          40 :             std::string const & smax(std::to_string(max));
     296             : 
     297          40 :             std::string range("...");
     298          80 :             for(int three(0); three < 3; ++three)
     299             :             {
     300          60 :                 if(rand() % 5 == 0)
     301             :                 {
     302          15 :                     range = ' ' + range;
     303             :                 }
     304          60 :                 if(rand() % 5 == 0)
     305             :                 {
     306          10 :                     range = range + ' ';
     307             :                 }
     308             :             }
     309          20 :             range = smin + range + smax;
     310          80 :             for(int three(0); three < 3; ++three)
     311             :             {
     312          60 :                 if(rand() % 5 == 0)
     313             :                 {
     314          13 :                     range = ' ' + range;
     315             :                 }
     316          60 :                 if(rand() % 5 == 0)
     317             :                 {
     318           7 :                     range = range + ' ';
     319             :                 }
     320             :             }
     321             : 
     322          20 :             std::int64_t standalone(0);
     323          20 :             bool standalone_included(rand() % 4 == 0);
     324          20 :             if(standalone_included)
     325             :             {
     326           6 :                 if(min == std::numeric_limits<std::int64_t>::min()
     327           3 :                 && max == std::numeric_limits<std::int64_t>::max())
     328             :                 {
     329           0 :                     standalone_included = false;
     330             :                 }
     331             :                 else
     332             :                 {
     333           3 :                     had_standalone = true;
     334           2 :                     do
     335             :                     {
     336           5 :                         standalone = large_rnd();
     337             :                     }
     338           5 :                     while(standalone >= min && standalone <= max);
     339             : 
     340           6 :                     std::string sep(",");
     341           3 :                     if(rand() % 3 == 0)
     342             :                     {
     343           2 :                         sep = ' ' + sep;
     344             :                     }
     345           3 :                     if(rand() % 3 == 0)
     346             :                     {
     347           0 :                         sep = sep + ' ';
     348             :                     }
     349           3 :                     if(rand() % 2 == 0)
     350             :                     {
     351           2 :                         range = std::to_string(standalone) + "," + range;
     352             :                     }
     353             :                     else
     354             :                     {
     355           1 :                         range = range + "," + std::to_string(standalone);
     356             :                     }
     357             :                 }
     358             :             }
     359          40 :             advgetopt::string_list_t range_list;
     360          40 :             advgetopt::split_string(range
     361             :                        , range_list
     362          20 :                        , {","});
     363          40 :             advgetopt::validator::pointer_t integer_validator(advgetopt::validator::create("integer", range_list));
     364             : 
     365          20 :             CATCH_REQUIRE(integer_validator != nullptr);
     366          20 :             CATCH_REQUIRE(integer_validator->name() == "integer");
     367             : 
     368       20020 :             for(int idx(0); idx < 1000; ++idx)
     369             :             {
     370       20000 :                 std::int64_t value(large_rnd());
     371             : 
     372             :                 // force valid values otherwise we're likely to only have
     373             :                 // invalid ones
     374             :                 //
     375       20000 :                 if(idx % 10 == 0)
     376             :                 {
     377        2000 :                     value %= max - min + 1;
     378        2000 :                     value += min;
     379             :                 }
     380       18000 :                 else if(idx % 50 == 1 && standalone_included)
     381             :                 {
     382          60 :                     value = standalone;
     383             :                 }
     384             : 
     385       40000 :                 std::string const v(std::to_string(value));
     386             : 
     387       20000 :                 if((standalone_included && value == standalone)
     388       19940 :                 || (value >= min && value <= max))
     389             :                 {
     390        7526 :                     CATCH_REQUIRE(integer_validator->validate(v));
     391             :                 }
     392             :                 else
     393             :                 {
     394       12474 :                     CATCH_REQUIRE_FALSE(integer_validator->validate(v));
     395             :                 }
     396             : 
     397       20000 :                 if(value >= 0)
     398             :                 {
     399        9812 :                     if((standalone_included && value == standalone)
     400        9772 :                     || (value >= min && value <= max))
     401             :                     {
     402        3753 :                         CATCH_REQUIRE(integer_validator->validate('+' + v));
     403             :                     }
     404             :                     else
     405             :                     {
     406        6059 :                         CATCH_REQUIRE_FALSE(integer_validator->validate('+' + v));
     407             :                     }
     408             :                 }
     409             : 
     410       40000 :                 std::string const space_before(' ' + v);
     411       20000 :                 CATCH_REQUIRE_FALSE(integer_validator->validate(space_before));
     412             : 
     413       40000 :                 std::string const space_after(v + ' ');
     414       20000 :                 CATCH_REQUIRE_FALSE(integer_validator->validate(space_after));
     415             : 
     416       40000 :                 std::string const before(static_cast<char>(rand() % 26 + 'a') + v);
     417       20000 :                 CATCH_REQUIRE_FALSE(integer_validator->validate(before));
     418             : 
     419       40000 :                 std::string const after(v + static_cast<char>(rand() % 26 + 'a'));
     420       20000 :                 CATCH_REQUIRE_FALSE(integer_validator->validate(after));
     421             :             }
     422             :         }
     423             :     }
     424             :     CATCH_END_SECTION()
     425             : 
     426           6 :     CATCH_START_SECTION("integer_validator: Verify the integer standalone list")
     427             :     {
     428          21 :         for(int count(0); count < 20; ++count)
     429             :         {
     430          20 :             int valid(rand() % 10 + 5);
     431          40 :             std::vector<std::int64_t> numbers;
     432          20 :             numbers.reserve(valid);
     433          40 :             std::string standalone_values;
     434         198 :             for(int idx(0); idx < valid; ++idx)
     435             :             {
     436         178 :                 std::int64_t const value(large_rnd());
     437         178 :                 numbers.push_back(value);
     438         356 :                 std::string const & svalue(std::to_string(value));
     439         178 :                 if(rand() % 5 == 0)
     440             :                 {
     441          42 :                     standalone_values += ' ';
     442             :                 }
     443         178 :                 if(idx != 0)
     444             :                 {
     445         158 :                     standalone_values += ',';
     446             :                 }
     447         178 :                 if(rand() % 5 == 0)
     448             :                 {
     449          38 :                     standalone_values += ' ';
     450             :                 }
     451         178 :                 standalone_values += svalue;
     452             :             }
     453          20 :             if(rand() % 5 == 0)
     454             :             {
     455           5 :                 standalone_values += ' ';
     456             :             }
     457          40 :             advgetopt::string_list_t range_list;
     458          40 :             advgetopt::split_string(standalone_values
     459             :                        , range_list
     460          20 :                        , {","});
     461             : 
     462          40 :             advgetopt::validator::pointer_t integer_validator(advgetopt::validator::create("integer", range_list));
     463             : 
     464          20 :             CATCH_REQUIRE(integer_validator != nullptr);
     465          20 :             CATCH_REQUIRE(integer_validator->name() == "integer");
     466             : 
     467         198 :             for(size_t idx(0); idx < numbers.size(); ++idx)
     468             :             {
     469         356 :                 std::string const svalue(std::to_string(numbers[idx]));
     470             : 
     471         178 :                 CATCH_REQUIRE(integer_validator->validate(svalue));
     472             :             }
     473             : 
     474       20020 :             for(int idx(0); idx < 1000; ++idx)
     475             :             {
     476       20000 :                 std::int64_t value;
     477             : 
     478             :                 for(;;)
     479             :                 {
     480       20000 :                     value = large_rnd();
     481       20000 :                     if(std::find(numbers.begin(), numbers.end(), value) == numbers.end())
     482             :                     {
     483       20000 :                         break;
     484             :                     }
     485             :                 }
     486             : 
     487       20000 :                 CATCH_REQUIRE_FALSE(integer_validator->validate(std::to_string(value)));
     488             :             }
     489             :         }
     490             :     }
     491             :     CATCH_END_SECTION()
     492           3 : }
     493             : 
     494             : 
     495             : 
     496             : 
     497           5 : CATCH_TEST_CASE("length_validator", "[validator][valid][validation]")
     498             : {
     499           6 :     CATCH_START_SECTION("length_validator: Verify the length validator")
     500             :     {
     501           2 :         advgetopt::validator::pointer_t length_validator(advgetopt::validator::create("length", advgetopt::string_list_t()));
     502             : 
     503           1 :         CATCH_REQUIRE(length_validator != nullptr);
     504           1 :         CATCH_REQUIRE(length_validator->name() == "length");
     505             : 
     506           1 :         CATCH_REQUIRE(length_validator->validate("Anything works in this case"));
     507           1 :         CATCH_REQUIRE(length_validator->validate("since the length won't be checked"));
     508           1 :         CATCH_REQUIRE(length_validator->validate(""));
     509           1 :         CATCH_REQUIRE(length_validator->validate("even an empty string"));
     510             :     }
     511             :     CATCH_END_SECTION()
     512             : 
     513           6 :     CATCH_START_SECTION("length_validator: Verify the length ranges")
     514             :     {
     515           1 :         bool had_standalone(false);
     516          21 :         for(int count(0); count < 20 || !had_standalone; ++count)
     517             :         {
     518          20 :             std::uint64_t min(rand() % 25 + 5);
     519          20 :             std::uint64_t max(rand() % 25 + 5);
     520          20 :             if(min > max)
     521             :             {
     522           9 :                 std::swap(min, max);
     523             :             }
     524             : 
     525          40 :             std::string const & smin(std::to_string(min));
     526          40 :             std::string const & smax(std::to_string(max));
     527             : 
     528          40 :             std::string range("...");
     529          80 :             for(int three(0); three < 3; ++three)
     530             :             {
     531          60 :                 if(rand() % 5 == 0)
     532             :                 {
     533          13 :                     range = ' ' + range;
     534             :                 }
     535          60 :                 if(rand() % 5 == 0)
     536             :                 {
     537           8 :                     range = range + ' ';
     538             :                 }
     539             :             }
     540          20 :             range = smin + range + smax;
     541          80 :             for(int three(0); three < 3; ++three)
     542             :             {
     543          60 :                 if(rand() % 5 == 0)
     544             :                 {
     545           8 :                     range = ' ' + range;
     546             :                 }
     547          60 :                 if(rand() % 5 == 0)
     548             :                 {
     549          10 :                     range = range + ' ';
     550             :                 }
     551             :             }
     552             : 
     553          20 :             std::uint64_t standalone(0);
     554          20 :             bool const standalone_included(rand() % 4 == 0);
     555          20 :             if(standalone_included)
     556             :             {
     557           6 :                 had_standalone = true;
     558           4 :                 do
     559             :                 {
     560          10 :                     standalone = rand() % 35;
     561             :                 }
     562          10 :                 while(standalone >= min && standalone <= max);
     563             : 
     564          12 :                 std::string sep(",");
     565           6 :                 if(rand() % 3 == 0)
     566             :                 {
     567           3 :                     sep = ' ' + sep;
     568             :                 }
     569           6 :                 if(rand() % 3 == 0)
     570             :                 {
     571           3 :                     sep = sep + ' ';
     572             :                 }
     573           6 :                 if(rand() % 2 == 0)
     574             :                 {
     575           2 :                     range = std::to_string(standalone) + "," + range;
     576             :                 }
     577             :                 else
     578             :                 {
     579           4 :                     range = range + "," + std::to_string(standalone);
     580             :                 }
     581             :             }
     582          40 :             advgetopt::string_list_t range_list;
     583          40 :             advgetopt::split_string(range
     584             :                        , range_list
     585          20 :                        , {","});
     586          40 :             advgetopt::validator::pointer_t length_validator(advgetopt::validator::create("length", range_list));
     587             : 
     588          20 :             CATCH_REQUIRE(length_validator != nullptr);
     589          20 :             CATCH_REQUIRE(length_validator->name() == "length");
     590             : 
     591         618 :             for(std::size_t idx(0); idx < std::max(max, standalone) + 5; ++idx)
     592             :             {
     593        1196 :                 std::string value;
     594        9417 :                 for(std::size_t n(0); n < idx; ++n)
     595             :                 {
     596        8819 :                     value += rand() % 26 + 'a';
     597             :                 }
     598             : 
     599         790 :                 if((standalone_included && value.length() == standalone)
     600        1190 :                 || (value.length() >= min && value.length() <= max))
     601             :                 {
     602         207 :                     CATCH_REQUIRE(length_validator->validate(value));
     603             :                 }
     604             :                 else
     605             :                 {
     606         391 :                     CATCH_REQUIRE_FALSE(length_validator->validate(value));
     607             :                 }
     608             :             }
     609             :         }
     610             :     }
     611             :     CATCH_END_SECTION()
     612             : 
     613           6 :     CATCH_START_SECTION("length_validator: Verify the length standalone list")
     614             :     {
     615          21 :         for(int count(0); count < 20; ++count)
     616             :         {
     617          20 :             int valid(rand() % 10 + 5);
     618          40 :             std::vector<std::uint64_t> string_lengths;
     619          20 :             string_lengths.reserve(valid);
     620          40 :             std::string standalone_lengths;
     621         194 :             for(int idx(0); idx < valid; ++idx)
     622             :             {
     623         174 :                 std::int64_t const length(rand() % 25 + 5);
     624         174 :                 string_lengths.push_back(length);
     625         348 :                 std::string const & slength(std::to_string(length));
     626         174 :                 if(rand() % 5 == 0)
     627             :                 {
     628          36 :                     standalone_lengths += ' ';
     629             :                 }
     630         174 :                 if(idx != 0)
     631             :                 {
     632         154 :                     standalone_lengths += ',';
     633             :                 }
     634         174 :                 if(rand() % 5 == 0)
     635             :                 {
     636          30 :                     standalone_lengths += ' ';
     637             :                 }
     638         174 :                 standalone_lengths += slength;
     639             :             }
     640          20 :             if(rand() % 5 == 0)
     641             :             {
     642           4 :                 standalone_lengths += ' ';
     643             :             }
     644          40 :             advgetopt::string_list_t range_list;
     645          40 :             advgetopt::split_string(standalone_lengths
     646             :                        , range_list
     647          20 :                        , {","});
     648             : 
     649          40 :             advgetopt::validator::pointer_t length_validator(advgetopt::validator::create("length", range_list));
     650             : 
     651          20 :             CATCH_REQUIRE(length_validator != nullptr);
     652          20 :             CATCH_REQUIRE(length_validator->name() == "length");
     653             : 
     654         194 :             for(std::size_t idx(0); idx < string_lengths.size(); ++idx)
     655             :             {
     656         348 :                 std::string value;
     657        3244 :                 for(std::uint64_t n(0); n < string_lengths[idx]; ++n)
     658             :                 {
     659        3070 :                     value += rand() % 26 + 'a';
     660             :                 }
     661         174 :                 CATCH_REQUIRE(length_validator->validate(value));
     662             :             }
     663             : 
     664          20 :             std::size_t const longest(*std::max_element(string_lengths.begin(), string_lengths.end()));
     665         674 :             for(std::size_t idx(0); idx <= longest + 5; ++idx)
     666             :             {
     667         654 :                 if(std::find(string_lengths.begin(), string_lengths.end(), idx) != string_lengths.end())
     668             :                 {
     669         140 :                     continue;
     670             :                 }
     671             : 
     672        1028 :                 std::string value;
     673        8456 :                 for(std::size_t n(0); n < idx; ++n)
     674             :                 {
     675        7942 :                     value += rand() % 26 + 'a';
     676             :                 }
     677             : 
     678         514 :                 CATCH_REQUIRE_FALSE(length_validator->validate(value));
     679             :             }
     680             :         }
     681             :     }
     682             :     CATCH_END_SECTION()
     683           3 : }
     684             : 
     685             : 
     686             : 
     687             : 
     688           3 : CATCH_TEST_CASE("multi_validators", "[validator][valid][validation]")
     689             : {
     690           2 :     CATCH_START_SECTION("multi_validators: Verify an integer along a few keywords")
     691             :     {
     692           2 :         advgetopt::validator::pointer_t list_validator(advgetopt::validator::create("keywords(off,min,max) | integer(1...100)"));
     693             : 
     694           1 :         CATCH_REQUIRE(list_validator != nullptr);
     695           1 :         CATCH_REQUIRE(list_validator->name() == "list");
     696             : 
     697           1 :         CATCH_REQUIRE(list_validator->validate("off"));
     698           1 :         CATCH_REQUIRE(list_validator->validate("min"));
     699           1 :         CATCH_REQUIRE(list_validator->validate("max"));
     700             : 
     701         122 :         for(int idx(-10); idx <= 110; ++idx)
     702             :         {
     703         242 :             std::string const v(std::to_string(idx));
     704             : 
     705         121 :             if(idx < 1 || idx > 100)
     706             :             {
     707          21 :                 CATCH_REQUIRE_FALSE(list_validator->validate(v));
     708             :             }
     709             :             else
     710             :             {
     711         100 :                 CATCH_REQUIRE(list_validator->validate(v));
     712             :             }
     713             :         }
     714             :     }
     715             :     CATCH_END_SECTION()
     716           1 : }
     717             : 
     718             : 
     719             : 
     720           3 : CATCH_TEST_CASE("keywords_validator", "[validator][valid][validation]")
     721             : {
     722           2 :     CATCH_START_SECTION("keywords_validator: Verify simple keywords")
     723             :     {
     724           2 :         advgetopt::validator::pointer_t list_validator(advgetopt::validator::create("keywords(angle, corner ,, ceiling)"));
     725             : 
     726           1 :         CATCH_REQUIRE(list_validator != nullptr);
     727           1 :         CATCH_REQUIRE(list_validator->name() == "keywords");
     728             : 
     729           1 :         CATCH_REQUIRE(list_validator->validate("angle"));
     730           1 :         CATCH_REQUIRE(list_validator->validate("corner"));
     731           1 :         CATCH_REQUIRE(list_validator->validate("ceiling"));
     732             : 
     733           1 :         CATCH_REQUIRE_FALSE(list_validator->validate(""));
     734           1 :         CATCH_REQUIRE_FALSE(list_validator->validate("other"));
     735             :     }
     736             :     CATCH_END_SECTION()
     737           1 : }
     738             : 
     739             : 
     740             : 
     741             : 
     742           5 : CATCH_TEST_CASE("double_validator", "[validator][valid][validation]")
     743             : {
     744           6 :     CATCH_START_SECTION("Verify the double validator")
     745           2 :         advgetopt::validator::pointer_t double_validator(advgetopt::validator::create("double", advgetopt::string_list_t()));
     746             : 
     747           1 :         CATCH_REQUIRE(double_validator != nullptr);
     748           1 :         CATCH_REQUIRE(double_validator->name() == "double");
     749             : 
     750           1 :         CATCH_REQUIRE_FALSE(double_validator->validate(""));
     751           1 :         CATCH_REQUIRE_FALSE(double_validator->validate("+"));
     752           1 :         CATCH_REQUIRE_FALSE(double_validator->validate("-"));
     753           1 :         CATCH_REQUIRE_FALSE(double_validator->validate("alpha"));
     754             : 
     755        1001 :         for(int idx(0); idx < 1000; ++idx)
     756             :         {
     757        1000 :             double value(static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false)));
     758        2000 :             std::string const v(std::to_string(value));
     759             : 
     760        1000 :             CATCH_REQUIRE(double_validator->validate(v));
     761             : 
     762        1000 :             if(value >= 0)
     763             :             {
     764         522 :                 CATCH_REQUIRE(double_validator->validate('+' + v));
     765             :             }
     766             : 
     767        2000 :             std::string const space_before(' ' + v);
     768        1000 :             CATCH_REQUIRE_FALSE(double_validator->validate(space_before));
     769             : 
     770        2000 :             std::string const space_after(v + ' ');
     771        1000 :             CATCH_REQUIRE_FALSE(double_validator->validate(space_after));
     772             : 
     773        2000 :             std::string const before(static_cast<char>(rand() % 26 + 'a') + v);
     774        1000 :             CATCH_REQUIRE_FALSE(double_validator->validate(before));
     775             : 
     776        2000 :             std::string const after(v + static_cast<char>(rand() % 26 + 'a'));
     777        1000 :             CATCH_REQUIRE_FALSE(double_validator->validate(after));
     778             :         }
     779             :     CATCH_END_SECTION()
     780             : 
     781           6 :     CATCH_START_SECTION("Verify the double ranges")
     782           1 :         bool had_standalone(false);
     783          21 :         for(int count(0); count < 20 || !had_standalone; ++count)
     784             :         {
     785          20 :             double min(static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false)));
     786          20 :             double max(static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false)));
     787          20 :             if(min > max)
     788             :             {
     789          10 :                 std::swap(min, max);
     790             :             }
     791             : 
     792          40 :             std::string const & smin(std::to_string(min));
     793          40 :             std::string const & smax(std::to_string(max));
     794             : 
     795          40 :             std::string range("...");
     796          80 :             for(int three(0); three < 3; ++three)
     797             :             {
     798          60 :                 if(rand() % 5 == 0)
     799             :                 {
     800          13 :                     range = ' ' + range;
     801             :                 }
     802          60 :                 if(rand() % 5 == 0)
     803             :                 {
     804           9 :                     range = range + ' ';
     805             :                 }
     806             :             }
     807          20 :             range = smin + range + smax;
     808          80 :             for(int three(0); three < 3; ++three)
     809             :             {
     810          60 :                 if(rand() % 5 == 0)
     811             :                 {
     812          16 :                     range = ' ' + range;
     813             :                 }
     814          60 :                 if(rand() % 5 == 0)
     815             :                 {
     816           7 :                     range = range + ' ';
     817             :                 }
     818             :             }
     819             : 
     820          20 :             double standalone(0);
     821          20 :             bool standalone_included(rand() % 4 == 0);
     822          20 :             if(standalone_included)
     823             :             {
     824          10 :                 if(min <= std::numeric_limits<double>::min()
     825           5 :                 && max >= std::numeric_limits<double>::max())
     826             :                 {
     827           0 :                     standalone_included = false;
     828             :                 }
     829             :                 else
     830             :                 {
     831           5 :                     had_standalone = true;
     832           0 :                     do
     833             :                     {
     834           5 :                         standalone = static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false));
     835             :                     }
     836           5 :                     while(standalone >= min && standalone <= max);
     837             : 
     838          10 :                     std::string sep(",");
     839           5 :                     if(rand() % 3 == 0)
     840             :                     {
     841           1 :                         sep = ' ' + sep;
     842             :                     }
     843           5 :                     if(rand() % 3 == 0)
     844             :                     {
     845           1 :                         sep = sep + ' ';
     846             :                     }
     847           5 :                     if(rand() % 2 == 0)
     848             :                     {
     849           1 :                         range = std::to_string(standalone) + "," + range;
     850             :                     }
     851             :                     else
     852             :                     {
     853           4 :                         range = range + "," + std::to_string(standalone);
     854             :                     }
     855             :                 }
     856             :             }
     857          40 :             advgetopt::string_list_t range_list;
     858          40 :             advgetopt::split_string(range
     859             :                        , range_list
     860          20 :                        , {","});
     861          40 :             advgetopt::validator::pointer_t double_validator(advgetopt::validator::create("double", range_list));
     862             : 
     863          20 :             CATCH_REQUIRE(double_validator != nullptr);
     864          20 :             CATCH_REQUIRE(double_validator->name() == "double");
     865             : 
     866       20020 :             for(int idx(0); idx < 1000; ++idx)
     867             :             {
     868       20000 :                 double value(static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false)));
     869             : 
     870             :                 // force valid values otherwise we're likely to only have
     871             :                 // invalid ones
     872             :                 //
     873       20000 :                 if(idx % 10 == 0)
     874             :                 {
     875        2000 :                     value = fmod(value, max - min + 1.0) + min;
     876             :                 }
     877       18000 :                 else if(idx % 50 == 1 && standalone_included)
     878             :                 {
     879         100 :                     value = standalone;
     880             :                 }
     881             : 
     882       40000 :                 std::string const v(std::to_string(value));
     883             : 
     884             : #pragma GCC diagnostic push
     885             : #pragma GCC diagnostic ignored "-Wfloat-equal"
     886       20000 :                 if((standalone_included && value == standalone)
     887       19900 :                 || (value >= min && value <= max))
     888             :                 {
     889        5105 :                     CATCH_REQUIRE(double_validator->validate(v));
     890             :                 }
     891             :                 else
     892             :                 {
     893       14895 :                     CATCH_REQUIRE_FALSE(double_validator->validate(v));
     894             :                 }
     895             : 
     896       20000 :                 if(value >= 0.0)
     897             :                 {
     898        9824 :                     if((standalone_included && value == standalone)
     899        9784 :                     || (value >= min && value <= max))
     900             :                     {
     901        3406 :                         CATCH_REQUIRE(double_validator->validate('+' + v));
     902             :                     }
     903             :                     else
     904             :                     {
     905        6418 :                         CATCH_REQUIRE_FALSE(double_validator->validate('+' + v));
     906             :                     }
     907             :                 }
     908             : #pragma GCC diagnostic pop
     909             : 
     910       40000 :                 std::string const space_before(' ' + v);
     911       20000 :                 CATCH_REQUIRE_FALSE(double_validator->validate(space_before));
     912             : 
     913       40000 :                 std::string const space_after(v + ' ');
     914       20000 :                 CATCH_REQUIRE_FALSE(double_validator->validate(space_after));
     915             : 
     916       40000 :                 std::string const before(static_cast<char>(rand() % 26 + 'a') + v);
     917       20000 :                 CATCH_REQUIRE_FALSE(double_validator->validate(before));
     918             : 
     919       40000 :                 std::string const after(v + static_cast<char>(rand() % 26 + 'a'));
     920       20000 :                 CATCH_REQUIRE_FALSE(double_validator->validate(after));
     921             :             }
     922             :         }
     923             :     CATCH_END_SECTION()
     924             : 
     925           6 :     CATCH_START_SECTION("Verify the double standalone list")
     926          21 :         for(int count(0); count < 20; ++count)
     927             :         {
     928          20 :             int valid(rand() % 10 + 5);
     929          40 :             std::vector<double> numbers;
     930          20 :             numbers.reserve(valid);
     931          40 :             std::string standalone_values;
     932         205 :             for(int idx(0); idx < valid; ++idx)
     933             :             {
     934         185 :                 double const value(static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false)));
     935         185 :                 numbers.push_back(value);
     936         370 :                 std::string const & svalue(std::to_string(value));
     937         185 :                 if(rand() % 5 == 0)
     938             :                 {
     939          32 :                     standalone_values += ' ';
     940             :                 }
     941         185 :                 if(idx != 0)
     942             :                 {
     943         165 :                     standalone_values += ',';
     944             :                 }
     945         185 :                 if(rand() % 5 == 0)
     946             :                 {
     947          40 :                     standalone_values += ' ';
     948             :                 }
     949         185 :                 standalone_values += svalue;
     950             :             }
     951          20 :             if(rand() % 5 == 0)
     952             :             {
     953           8 :                 standalone_values += ' ';
     954             :             }
     955          40 :             advgetopt::string_list_t range_list;
     956          40 :             advgetopt::split_string(standalone_values
     957             :                        , range_list
     958          20 :                        , {","});
     959             : 
     960          40 :             advgetopt::validator::pointer_t double_validator(advgetopt::validator::create("double", range_list));
     961             : 
     962          20 :             CATCH_REQUIRE(double_validator != nullptr);
     963          20 :             CATCH_REQUIRE(double_validator->name() == "double");
     964             : 
     965         205 :             for(size_t idx(0); idx < numbers.size(); ++idx)
     966             :             {
     967         370 :                 std::string const svalue(std::to_string(numbers[idx]));
     968             : 
     969         185 :                 CATCH_REQUIRE(double_validator->validate(svalue));
     970             :             }
     971             : 
     972       20020 :             for(int idx(0); idx < 1000; ++idx)
     973             :             {
     974       20000 :                 std::int64_t value;
     975             : 
     976             :                 for(;;)
     977             :                 {
     978       20000 :                     value = static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false));
     979       20000 :                     if(std::find(numbers.begin(), numbers.end(), value) == numbers.end())
     980             :                     {
     981       20000 :                         break;
     982             :                     }
     983             :                 }
     984             : 
     985       20000 :                 CATCH_REQUIRE_FALSE(double_validator->validate(std::to_string(value)));
     986             :             }
     987             :         }
     988             :     CATCH_END_SECTION()
     989           3 : }
     990             : 
     991             : 
     992             : 
     993             : 
     994           5 : CATCH_TEST_CASE("duration_validator", "[validator][valid][validation]")
     995             : {
     996           6 :     CATCH_START_SECTION("Verify the duration validator (simple values)")
     997             :     {
     998           1 :         double duration(0.0);
     999             : 
    1000             :         // simple seconds with decimal point
    1001             :         //
    1002           1 :         CATCH_REQUIRE(advgetopt::validator_duration::convert_string("22.3s", 0, duration));
    1003           1 :         CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(duration, 22.3, 0.0));
    1004             : 
    1005             :         // "seconds" is the default
    1006             :         //
    1007           1 :         CATCH_REQUIRE(advgetopt::validator_duration::convert_string("1.05", 0, duration));
    1008           1 :         CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(duration, 1.05, 0.0));
    1009             : 
    1010             :         // number can start with a decimal point
    1011             :         //
    1012           1 :         CATCH_REQUIRE(advgetopt::validator_duration::convert_string(".0503", 0, duration));
    1013           1 :         CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(duration, 0.0503, 0.0));
    1014             :     }
    1015             :     CATCH_END_SECTION()
    1016             : 
    1017           6 :     CATCH_START_SECTION("Verify the duration validator (multiple values)")
    1018             :     {
    1019           1 :         double duration(0.0);
    1020           1 :         CATCH_REQUIRE(advgetopt::validator_duration::convert_string("1d 3h 2m 15.3s", 0, duration));
    1021           1 :         CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(duration, 1.0 * 86400.0 + 3.0 * 3600.0 + 2.0 * 60.0 + 15.3, 0.0));
    1022             : 
    1023             :         // same in uppercase
    1024           1 :         CATCH_REQUIRE(advgetopt::validator_duration::convert_string("1D 3H 2M 15.3S", 0, duration));
    1025           1 :         CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(duration, 1.0 * 86400.0 + 3.0 * 3600.0 + 2.0 * 60.0 + 15.3, 0.0));
    1026             : 
    1027           1 :         CATCH_REQUIRE(advgetopt::validator_duration::convert_string("3d 15h 52m 21.801s", 0, duration));
    1028           1 :         CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(duration, 3.0 * 86400.0 + 15.0 * 3600.0 + 52.0 * 60.0 + 21.801, 0.0));
    1029             :     }
    1030             :     CATCH_END_SECTION()
    1031             : 
    1032           6 :     CATCH_START_SECTION("Verify the duration validator (one value)")
    1033             :     {
    1034             :         // this test does not verify that double conversion works since we
    1035             :         // have a separate test for that specific validator
    1036             :         //
    1037           4 :         for(int size(0); size < 3; ++size)
    1038             :         {
    1039           3 :             advgetopt::validator_duration::flag_t flg(advgetopt::validator_duration::VALIDATOR_DURATION_DEFAULT_FLAGS);
    1040           6 :             advgetopt::string_list_t flags;
    1041           3 :             if(size == 1)
    1042             :             {
    1043           1 :                 flags.push_back("small");
    1044             :             }
    1045           2 :             else if(size == 2)
    1046             :             {
    1047           1 :                 flags.push_back("large");
    1048           1 :                 flg = advgetopt::validator_duration::VALIDATOR_DURATION_LONG;
    1049             :             }
    1050           6 :             advgetopt::validator::pointer_t duration_validator(advgetopt::validator::create("duration", flags));
    1051             : 
    1052           3 :             CATCH_REQUIRE(duration_validator != nullptr);
    1053           3 :             CATCH_REQUIRE(duration_validator->name() == "duration");
    1054             : 
    1055        3003 :             for(int idx(0); idx < 1000; ++idx)
    1056             :             {
    1057             :                 // use smaller values between 0 and 1
    1058             :                 // (the loop is to make sure we don't end up with "123e-10"
    1059             :                 // type of numbers... which do not work here)
    1060             :                 //
    1061        3000 :                 double value(0.0);
    1062             : #pragma GCC diagnostic push
    1063             : #pragma GCC diagnostic ignored "-Wfloat-equal"
    1064           0 :                 do
    1065             :                 {
    1066        3000 :                     value = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
    1067             :                 }
    1068        3000 :                 while(value < 0.0001 && value != 0.0);
    1069             : #pragma GCC diagnostic pop
    1070        3000 :                 if(rand() % 2 == 0)
    1071             :                 {
    1072        1515 :                     value *= -1.0;
    1073             :                 }
    1074        6000 :                 std::stringstream ss;
    1075        3000 :                 ss.precision(std::numeric_limits<double>::max_digits10);
    1076        3000 :                 ss << value;
    1077        6000 :                 std::string const v(ss.str());
    1078             : 
    1079       66000 :                 for(std::size_t i(0); i < std::size(g_duration_suffixes); ++i)
    1080             :                 {
    1081      441000 :                     for(int j(0); j <= 5; ++j)
    1082             :                     {
    1083      756000 :                         std::string duration(v);
    1084     1323000 :                         for(int k(0); k < j; ++k)
    1085             :                         {
    1086             :                             // any number of spaces in between are allowed
    1087             :                             //
    1088      945000 :                             duration += ' ';
    1089             :                         }
    1090      378000 :                         duration += g_duration_suffixes[i].f_suffix;
    1091             : 
    1092      378000 :                         CATCH_REQUIRE(duration_validator->validate(duration));
    1093      378000 :                         if(value >= 0)
    1094             :                         {
    1095      187110 :                             CATCH_REQUIRE(duration_validator->validate('+' + duration));
    1096             :                         }
    1097             : 
    1098      378000 :                         double result(0.0);
    1099      378000 :                         CATCH_REQUIRE(advgetopt::validator_duration::convert_string(duration, flg, result));
    1100      378000 :                         if(g_duration_suffixes[i].f_factor < 0.0)
    1101             :                         {
    1102             :                             // the 'm' special case
    1103             :                             //
    1104       18000 :                             if(size == 2)
    1105             :                             {
    1106             :                                 // 'large' -- 1 month
    1107             :                                 //
    1108        6000 :                                 CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(result, value * (86400.0 * 30.0)));
    1109             :                             }
    1110             :                             else
    1111             :                             {
    1112             :                                 // 'small' -- 1 minute
    1113             :                                 //
    1114       12000 :                                 CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(result, value * 60.0));
    1115             :                             }
    1116             :                         }
    1117             :                         else
    1118             :                         {
    1119      360000 :                             CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(result, value * g_duration_suffixes[i].f_factor));
    1120             :                         }
    1121             :                     }
    1122             :                 }
    1123             :             }
    1124             :         }
    1125             :     }
    1126             :     CATCH_END_SECTION()
    1127           3 : }
    1128             : 
    1129             : 
    1130             : 
    1131             : 
    1132           3 : CATCH_TEST_CASE("size_validator", "[validator][valid][validation]")
    1133             : {
    1134             : #pragma GCC diagnostic push
    1135             : #pragma GCC diagnostic ignored "-Wpedantic"
    1136           2 :     CATCH_START_SECTION("Verify the size validator")
    1137             :     {
    1138             :         // this test does not verify that double conversion works since we
    1139             :         // have a separate test for that specific validator
    1140             :         //
    1141           4 :         for(int mode(0); mode < 3; ++mode)
    1142             :         {
    1143           3 :             advgetopt::validator_size::flag_t flg(advgetopt::validator_size::VALIDATOR_SIZE_DEFAULT_FLAGS);
    1144           6 :             advgetopt::string_list_t flags;
    1145           3 :             if(mode == 1)
    1146             :             {
    1147           1 :                 flags.push_back("si");
    1148             :             }
    1149           2 :             else if(mode == 2)
    1150             :             {
    1151           1 :                 flags.push_back("legacy");
    1152           1 :                 flg = advgetopt::validator_size::VALIDATOR_SIZE_POWER_OF_TWO;
    1153             :             }
    1154           6 :             advgetopt::validator::pointer_t size_validator(advgetopt::validator::create("size", flags));
    1155             : 
    1156           3 :             CATCH_REQUIRE(size_validator != nullptr);
    1157           3 :             CATCH_REQUIRE(size_validator->name() == "size");
    1158             : 
    1159        3003 :             for(int idx(0); idx < 1000; ++idx)
    1160             :             {
    1161             :                 // use smaller values between 0 and about 5
    1162             :                 //
    1163        3000 :                 double value(static_cast<double>(rand()) / static_cast<double>(RAND_MAX / 5));
    1164        3000 :                 if(rand() % 2 == 0)
    1165             :                 {
    1166        1483 :                     value *= -1.0;
    1167             :                 }
    1168        6000 :                 std::stringstream ss;
    1169        3000 :                 ss.precision(std::numeric_limits<double>::max_digits10);
    1170        3000 :                 ss << value;
    1171        6000 :                 std::string const v(ss.str());
    1172             : 
    1173       57000 :                 for(std::size_t i(0); i < std::size(g_size_suffixes); ++i)
    1174             :                 {
    1175      378000 :                     for(int j(0); j <= 5; ++j)
    1176             :                     {
    1177      648000 :                         std::string size(v);
    1178     1134000 :                         for(int k(0); k < j; ++k)
    1179             :                         {
    1180             :                             // any number of spaces in between are allowed
    1181             :                             //
    1182      810000 :                             size += ' ';
    1183             :                         }
    1184      324000 :                         size += g_size_suffixes[i].f_suffix;
    1185             : 
    1186      324000 :                         CATCH_REQUIRE(size_validator->validate(size));
    1187      324000 :                         if(value >= 0)
    1188             :                         {
    1189      163836 :                             CATCH_REQUIRE(size_validator->validate('+' + size));
    1190             :                         }
    1191             : 
    1192      324000 :                         __int128 result(0.0);
    1193      324000 :                         CATCH_REQUIRE(advgetopt::validator_size::convert_string(size, flg, result));
    1194             : 
    1195      324000 :                         long double const base(mode == 2 ? 1024.0L : g_size_suffixes[i].f_base);
    1196      324000 :                         long double expected(1);
    1197     1620000 :                         for(int p(0); p < g_size_suffixes[i].f_power; ++p)
    1198             :                         {
    1199     1296000 :                             expected *= base;
    1200             :                         }
    1201      324000 :                         __int128 int_expected(expected * static_cast<long double>(value));
    1202             : 
    1203             : //std::cerr << "converted [" << size << "] to [" << result << "] wanted [" << int_expected << "]\n";
    1204      324000 :                         CATCH_REQUIRE(result == int_expected);
    1205             :                     }
    1206             :                 }
    1207             :             }
    1208             :         }
    1209             :     }
    1210             :     CATCH_END_SECTION()
    1211             : #pragma GCC diagnostic pop
    1212           1 : }
    1213             : 
    1214             : 
    1215             : 
    1216             : 
    1217           6 : CATCH_TEST_CASE("regex_validator", "[validator][valid][validation]")
    1218             : {
    1219           8 :     CATCH_START_SECTION("regex_validator: Verify the regex validator")
    1220           2 :         advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex", {".*@.*\\..*"}));
    1221             : 
    1222           1 :         CATCH_REQUIRE(regex_validator != nullptr);
    1223           1 :         CATCH_REQUIRE(regex_validator->name() == "regex");
    1224             : 
    1225           1 :         CATCH_REQUIRE(regex_validator->validate("@m2osw."));
    1226           1 :         CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
    1227           1 :         CATCH_REQUIRE(regex_validator->validate("Contact@m2osw.com"));
    1228           1 :         CATCH_REQUIRE(regex_validator->validate("Contact@M2OSW.com"));
    1229             : 
    1230           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
    1231           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
    1232             :     CATCH_END_SECTION()
    1233             : 
    1234           8 :     CATCH_START_SECTION("regex_validator: Verify the regex string (case sensitive)")
    1235           2 :         advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex", {"/contact@.*\\..*/"}));
    1236             : 
    1237           1 :         CATCH_REQUIRE(regex_validator != nullptr);
    1238           1 :         CATCH_REQUIRE(regex_validator->name() == "regex");
    1239             : 
    1240           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
    1241           1 :         CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
    1242           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@m2osw.com"));
    1243           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@M2OSW.com"));
    1244             : 
    1245           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
    1246           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
    1247             :     CATCH_END_SECTION()
    1248             : 
    1249           8 :     CATCH_START_SECTION("regex_validator: Verify the regex string (case insensitive)")
    1250           2 :         advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex", {"/contact@.*\\..*/i"}));
    1251             : 
    1252           1 :         CATCH_REQUIRE(regex_validator != nullptr);
    1253           1 :         CATCH_REQUIRE(regex_validator->name() == "regex");
    1254             : 
    1255           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
    1256           1 :         CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
    1257           1 :         CATCH_REQUIRE(regex_validator->validate("Contact@m2osw.com"));
    1258           1 :         CATCH_REQUIRE(regex_validator->validate("Contact@M2OSW.com"));
    1259             : 
    1260           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
    1261           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
    1262             :     CATCH_END_SECTION()
    1263             : 
    1264           8 :     CATCH_START_SECTION("regex_validator: Verify direct regex string (case insensitive)")
    1265           2 :         advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("/contact@.*\\..*/i"));
    1266             : 
    1267           1 :         CATCH_REQUIRE(regex_validator != nullptr);
    1268           1 :         CATCH_REQUIRE(regex_validator->name() == "regex");
    1269             : 
    1270           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
    1271           1 :         CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
    1272           1 :         CATCH_REQUIRE(regex_validator->validate("Contact@m2osw.com"));
    1273           1 :         CATCH_REQUIRE(regex_validator->validate("Contact@M2OSW.com"));
    1274             : 
    1275           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
    1276           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
    1277             :     CATCH_END_SECTION()
    1278           4 : }
    1279             : 
    1280             : 
    1281             : 
    1282             : 
    1283             : 
    1284             : 
    1285             : 
    1286             : 
    1287           3 : CATCH_TEST_CASE("invalid_validator_factory", "[validator][invalid][validation]")
    1288             : {
    1289           2 :     CATCH_START_SECTION("invalid_validator_factory: Register duplicated factories")
    1290             :     {
    1291           0 :         class duplicate_integer
    1292             :             : public advgetopt::validator
    1293             :         {
    1294             :         public:
    1295           0 :             virtual std::string name() const override
    1296             :             {
    1297           0 :                 return "integer";
    1298             :             }
    1299             : 
    1300           0 :             virtual bool validate(std::string const & value) const override
    1301             :             {
    1302           0 :                 return value == "123";
    1303             :             }
    1304             :         };
    1305           3 :         class duplicate_factory
    1306             :             : public advgetopt::validator_factory
    1307             :         {
    1308             :         public:
    1309           2 :             virtual std::string get_name() const override
    1310             :             {
    1311           2 :                 return "integer";
    1312             :             }
    1313             : 
    1314           0 :             virtual std::shared_ptr<advgetopt::validator> create(advgetopt::string_list_t const & data) const override
    1315             :             {
    1316           0 :                 snapdev::NOT_USED(data); // ignore `data`
    1317           0 :                 return std::make_shared<duplicate_integer>();
    1318             :             }
    1319             :         };
    1320           2 :         std::unique_ptr<advgetopt::validator_factory> factory(new duplicate_factory());
    1321           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    1322             :                   advgetopt::validator::register_validator(*factory.get())
    1323             :                 , advgetopt::getopt_logic_error
    1324             :                 , Catch::Matchers::ExceptionMessage(
    1325             :                           "getopt_logic_error: you have two or more validator factories named \"integer\"."));
    1326             :     }
    1327             :     CATCH_END_SECTION()
    1328           1 : }
    1329             : 
    1330           3 : CATCH_TEST_CASE("invalid_validator_create", "[validator][invalid][validation]")
    1331             : {
    1332           2 :     CATCH_START_SECTION("invalid_validator_create: Verify missing ')' in string based create")
    1333             :     {
    1334           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): parameter list must end with ')'. Remaining input: \"...EOS\"");
    1335           2 :         advgetopt::validator::pointer_t validator(advgetopt::validator::create("integer(1...7, 11...15"));
    1336           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1337           1 :         CATCH_REQUIRE(validator == nullptr);
    1338             : 
    1339           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): parameter list must end with ')'. Remaining input: \"...EOS\"");
    1340           1 :         validator = advgetopt::validator::create("regex([a-z]+");
    1341           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1342           1 :         CATCH_REQUIRE(validator == nullptr);
    1343             : 
    1344           1 :         validator = advgetopt::validator::create(" ");
    1345           1 :         CATCH_REQUIRE(validator == nullptr);
    1346             : 
    1347           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): expected a regex, an identifier or a string inside the () of a parameter. Remaining input: \"[a-z]+))\"");
    1348           1 :         validator = advgetopt::validator::create("regex(([a-z]+))");
    1349           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1350           1 :         CATCH_REQUIRE(validator == nullptr);
    1351             : 
    1352           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): parameters must be separated by ','. Remaining input: \"...EOS\"");
    1353           1 :         validator = advgetopt::validator::create("keywords(foo, blah error)");
    1354           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1355           1 :         CATCH_REQUIRE(validator == nullptr);
    1356             : 
    1357           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): unexpected token in validator definition; expected an identifier. Remaining input: \"missing, name)\".");
    1358           1 :         validator = advgetopt::validator::create("(missing, name)");
    1359           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1360           1 :         CATCH_REQUIRE(validator == nullptr);
    1361             : 
    1362           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): unexpected character for an identifier (10).");
    1363           1 :         validator = advgetopt::validator::create("keywords(missing, name)\n|\ninteger(33)");
    1364           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1365           1 :         CATCH_REQUIRE(validator == nullptr);
    1366             : 
    1367           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): validator definitions must be separated by '|'. Remaining input: \"33)\"");
    1368           1 :         validator = advgetopt::validator::create("keywords(missing, name) integer(33)");
    1369           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1370           1 :         CATCH_REQUIRE(validator == nullptr);
    1371             :     }
    1372             :     CATCH_END_SECTION()
    1373           1 : }
    1374             : 
    1375           3 : CATCH_TEST_CASE("invalid_integer_validator", "[validator][invalid][validation]")
    1376             : {
    1377           2 :     CATCH_START_SECTION("invalid_integer_validator: Verify invalid integer ranges")
    1378             :     {
    1379           1 :         advgetopt::string_list_t range{
    1380             :             "abc",
    1381             :             "abc...6",
    1382             :             "3...def",
    1383           2 :             "10...1"};
    1384             : 
    1385           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: abc is not a valid standalone value for your ranges; it must only be digits, optionally preceeded by a sign (+ or -) and not overflow an int64_t value.");
    1386           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: abc is not a valid value for your range's start; it must only be digits, optionally preceeded by a sign (+ or -) and not overflow an int64_t value.");
    1387           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: def is not a valid value for your range's end; it must only be digits, optionally preceeded by a sign (+ or -) and not overflow an int64_t value.");
    1388           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: 10 has to be smaller or equal to 1; you have an invalid range.");
    1389             : 
    1390           2 :         advgetopt::validator::pointer_t integer_validator(advgetopt::validator::create("integer", range));
    1391           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1392             :     }
    1393             :     CATCH_END_SECTION()
    1394           1 : }
    1395             : 
    1396           3 : CATCH_TEST_CASE("invalid_double_validator", "[validator][invalid][validation]")
    1397             : {
    1398           2 :     CATCH_START_SECTION("invalid_double_validator: Verify invalid double ranges")
    1399             :     {
    1400           1 :         advgetopt::string_list_t range{
    1401             :             "abc",
    1402             :             "abc...6.3",
    1403             :             "13.3...def",
    1404           2 :             "10.5...1.2"};
    1405             : 
    1406           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: abc is not a valid standalone value; it must be a valid floating point, optionally preceeded by a sign (+ or -).");
    1407           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: abc is not a valid value for your range's start; it must be a valid floating point, optionally preceeded by a sign (+ or -).");
    1408           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: def is not a valid value for your range's end; it must be a valid floating point, optionally preceeded by a sign (+ or -).");
    1409           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: 10.5 has to be smaller or equal to 1.2; you have an invalid range.");
    1410             : 
    1411           2 :         advgetopt::validator::pointer_t integer_validator(advgetopt::validator::create("double", range));
    1412           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1413             :     }
    1414             :     CATCH_END_SECTION()
    1415           1 : }
    1416             : 
    1417           3 : CATCH_TEST_CASE("invalid_duration_validator", "[invalid][validation]")
    1418             : {
    1419           2 :     CATCH_START_SECTION("invalid_duration_validator: Verify invalid duration flags")
    1420             :     {
    1421           1 :         advgetopt::string_list_t range{
    1422             :             "small",
    1423             :             "medium",
    1424           2 :             "large"};
    1425             : 
    1426           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: medium is not a valid flag for the duration validator.");
    1427           2 :         advgetopt::validator::pointer_t duration_validator(advgetopt::validator::create("duration", range));
    1428           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1429             : 
    1430           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate(""));
    1431           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate("  "));
    1432           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate("+"));
    1433           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate("-"));
    1434           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate("alpha"));
    1435           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate("3.5 beta"));
    1436           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate("7.5delta"));
    1437           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate("+8.1 gamma"));
    1438           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate("-2.3eta"));
    1439           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate("-202.3   HERO"));
    1440           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate("-7.31Hr"));
    1441           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate("-1.32mom"));
    1442           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate("-5.36 secs"));
    1443           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate("28.901 wkS"));
    1444           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate("28 YY"));
    1445           1 :         CATCH_REQUIRE_FALSE(duration_validator->validate("2..8 year"));
    1446             :     }
    1447             :     CATCH_END_SECTION()
    1448           1 : }
    1449             : 
    1450             : 
    1451             : 
    1452           3 : CATCH_TEST_CASE("invalid_email_validator", "[invalid][validation]")
    1453             : {
    1454           2 :     CATCH_START_SECTION("invalid_email_validator: Verify emails with invalid parameters.")
    1455             :     {
    1456           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator_email() supports zero or one parameter.");
    1457           2 :         advgetopt::validator::pointer_t keywords(advgetopt::validator::create("email(single, multiple)"));
    1458           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1459           1 :         CATCH_REQUIRE(keywords != nullptr);
    1460             : 
    1461           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator_email(): unknown parameter \"orange\".");
    1462           1 :         keywords = advgetopt::validator::create("email(orange)");
    1463           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1464           1 :         CATCH_REQUIRE(keywords != nullptr);
    1465             :     }
    1466             :     CATCH_END_SECTION()
    1467           1 : }
    1468             : 
    1469             : 
    1470             : 
    1471           3 : CATCH_TEST_CASE("invalid_keywords_validator", "[invalid][validation]")
    1472             : {
    1473           2 :     CATCH_START_SECTION("invalid_keywords_validator: Verify that keywords without parameters fail.")
    1474             :     {
    1475           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator_keywords() requires at least one parameter.");
    1476           2 :         advgetopt::validator::pointer_t keywords(advgetopt::validator::create("keywords"));
    1477           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1478           1 :         CATCH_REQUIRE(keywords != nullptr);
    1479             : 
    1480           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator_keywords() requires at least one parameter.");
    1481           1 :         keywords = advgetopt::validator::create("keywords()");
    1482           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1483           1 :         CATCH_REQUIRE(keywords != nullptr);
    1484             :     }
    1485             :     CATCH_END_SECTION()
    1486           1 : }
    1487             : 
    1488             : 
    1489             : 
    1490           3 : CATCH_TEST_CASE("invalid_list_validator", "[invalid][validation]")
    1491             : {
    1492           2 :     CATCH_START_SECTION("invalid_list_validator: Verify that list validators do not accept parameters.")
    1493             :     {
    1494           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator_list() does not support any parameter.");
    1495           2 :         advgetopt::validator::pointer_t list(advgetopt::validator::create("list(with, parameters)"));
    1496           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1497           1 :         CATCH_REQUIRE(list != nullptr);
    1498             :     }
    1499             :     CATCH_END_SECTION()
    1500           1 : }
    1501             : 
    1502             : 
    1503             : 
    1504           3 : CATCH_TEST_CASE("invalid_size_validator", "[invalid][validation]")
    1505             : {
    1506           2 :     CATCH_START_SECTION("invalid_size_validator: Verify invalid duration flags")
    1507             :     {
    1508           1 :         advgetopt::string_list_t flags{
    1509             :             "si",
    1510             :             "future",
    1511           2 :             "legacy"};
    1512             : 
    1513           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: future is not a valid flag for the size validator.");
    1514           2 :         advgetopt::validator::pointer_t size_validator(advgetopt::validator::create("size", flags));
    1515           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1516             : 
    1517           1 :         CATCH_REQUIRE_FALSE(size_validator->validate(""));
    1518           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("  "));
    1519           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("+"));
    1520           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("-"));
    1521           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("size"));
    1522           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("3.5 large"));
    1523           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("-1.31body"));
    1524           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("7.5small"));
    1525           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("+8.1 tiny"));
    1526           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("-2.3medium"));
    1527           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("1000kbit"));
    1528           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("7 monster"));
    1529           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("-101.101egret"));
    1530           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("11 products"));
    1531           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("1.01 tractor"));
    1532           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("+7.0 years"));
    1533           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("-51.7zeroes"));
    1534           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("+121gruffalos"));
    1535           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("++1.7 KiB"));
    1536           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("-+3.1 MiB"));
    1537           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("+-9.2 GiB"));
    1538           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("--19.4 PiB"));
    1539           1 :         CATCH_REQUIRE_FALSE(size_validator->validate("-3.5.4B"));
    1540             :     }
    1541             :     CATCH_END_SECTION()
    1542           1 : }
    1543             : 
    1544           8 : CATCH_TEST_CASE("invalid_regex_validator", "[validator][invalid][validation]")
    1545             : {
    1546          12 :     CATCH_START_SECTION("invalid_regex_validator: Verify invalid regex flags")
    1547             :     {
    1548           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag f in regular expression \"/contact@.*\\..*/f\".");
    1549           2 :         advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex", {"/contact@.*\\..*/f"}));
    1550           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1551             : 
    1552           1 :         CATCH_REQUIRE(regex_validator != nullptr);
    1553           1 :         CATCH_REQUIRE(regex_validator->name() == "regex");
    1554             : 
    1555           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
    1556           1 :         CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
    1557           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@m2osw.com"));
    1558           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@M2OSW.com"));
    1559             : 
    1560           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
    1561           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
    1562             :     }
    1563             :     CATCH_END_SECTION()
    1564             : 
    1565          12 :     CATCH_START_SECTION("invalid_regex_validator: Verify invalid regex character")
    1566             :     {
    1567           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): unexpected character for a regular expression (10).");
    1568           2 :         advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex(/contact@.*\n..*/)"));
    1569           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1570           1 :         CATCH_REQUIRE(regex_validator == nullptr);
    1571             : 
    1572           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): unexpected escaped character for a regular expression (13).");
    1573           1 :         regex_validator = advgetopt::validator::create("regex(/contact@.*\\\r..*/)");
    1574           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1575           1 :         CATCH_REQUIRE(regex_validator == nullptr);
    1576             : 
    1577           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): unexpected flag character for a regular expression (57).");
    1578           1 :         regex_validator = advgetopt::validator::create("regex(/contact@.*..*/91)");
    1579           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1580           1 :         CATCH_REQUIRE(regex_validator == nullptr);
    1581             : 
    1582           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): unexpected character for an identifier (10).");
    1583           1 :         regex_validator = advgetopt::validator::create("regex(not\nexpected)");
    1584           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1585           1 :         CATCH_REQUIRE(regex_validator == nullptr);
    1586             :     }
    1587             :     CATCH_END_SECTION()
    1588             : 
    1589          12 :     CATCH_START_SECTION("invalid_regex_validator: Verify invalid regex: missing ending /")
    1590             :     {
    1591           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag * in regular expression \"/contact@.*\\..*\".");
    1592           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag . in regular expression \"/contact@.*\\..*\".");
    1593           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag . in regular expression \"/contact@.*\\..*\".");
    1594           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag \\ in regular expression \"/contact@.*\\..*\".");
    1595           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag * in regular expression \"/contact@.*\\..*\".");
    1596           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag . in regular expression \"/contact@.*\\..*\".");
    1597           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag @ in regular expression \"/contact@.*\\..*\".");
    1598           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag t in regular expression \"/contact@.*\\..*\".");
    1599           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag c in regular expression \"/contact@.*\\..*\".");
    1600           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag a in regular expression \"/contact@.*\\..*\".");
    1601           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag t in regular expression \"/contact@.*\\..*\".");
    1602           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag n in regular expression \"/contact@.*\\..*\".");
    1603           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag o in regular expression \"/contact@.*\\..*\".");
    1604           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag c in regular expression \"/contact@.*\\..*\".");
    1605           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: invalid regex definition, ending / is missing in \"/contact@.*\\..*\".");
    1606             : 
    1607           2 :         advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex", {"/contact@.*\\..*"}));
    1608           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1609             : 
    1610           1 :         CATCH_REQUIRE(regex_validator != nullptr);
    1611           1 :         CATCH_REQUIRE(regex_validator->name() == "regex");
    1612             : 
    1613           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
    1614           1 :         CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
    1615           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@m2osw.com"));
    1616           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@M2OSW.com"));
    1617             : 
    1618           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
    1619           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
    1620             :     }
    1621             :     CATCH_END_SECTION()
    1622             : 
    1623          12 :     CATCH_START_SECTION("invalid_regex_validator: Verify regex refuses more than one parameter")
    1624             :     {
    1625           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    1626             :                           "error: validator_regex() only supports one parameter;"
    1627             :                           " 2 were supplied;"
    1628             :                           " single or double quotation may be required?");
    1629           1 :         advgetopt::validator::create("regex", {"[a-z]+", "[0-9]+"});
    1630           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1631             : 
    1632           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    1633             :                           "error: validator_regex() only supports one parameter;"
    1634             :                           " 2 were supplied;"
    1635             :                           " single or double quotation may be required?");
    1636           1 :         advgetopt::validator::create("regex([a-z]+, [0-9]+)");
    1637           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1638             : 
    1639           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    1640             :                           "error: validator_regex() only supports one parameter;"
    1641             :                           " 3 were supplied;"
    1642             :                           " single or double quotation may be required?");
    1643           1 :         advgetopt::validator::create("regex", {"[a-z]+", "[0-9]+", "[#!@]"});
    1644           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1645             : 
    1646           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    1647             :                           "error: validator_regex() only supports one parameter;"
    1648             :                           " 3 were supplied;"
    1649             :                           " single or double quotation may be required?");
    1650           1 :         advgetopt::validator::create("regex(\"[a-z]+\", \"[0-9]+\", \"[#!@]\")");
    1651           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1652             :     }
    1653             :     CATCH_END_SECTION()
    1654             : 
    1655          12 :     CATCH_START_SECTION("invalid_regex_validator: Verify two regex params")
    1656             :     {
    1657           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator_regex() only supports one parameter; 2 were supplied; single or double quotation may be required?");
    1658           2 :         advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex(/one/a, /two/b)"));
    1659           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1660             : 
    1661           1 :         CATCH_REQUIRE(regex_validator != nullptr);
    1662           1 :         CATCH_REQUIRE(regex_validator->name() == "regex");
    1663             : 
    1664           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
    1665           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw.com"));
    1666           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@m2osw.com"));
    1667           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@M2OSW.com"));
    1668             : 
    1669           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
    1670           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
    1671             :     }
    1672             :     CATCH_END_SECTION()
    1673             : 
    1674          12 :     CATCH_START_SECTION("invalid_regex_validator: Verify two regex params")
    1675             :     {
    1676           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): unexpected character for an identifier (10).");
    1677           2 :         advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex('/one/'\n,'/two/b')"));
    1678           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1679           1 :         CATCH_REQUIRE(regex_validator == nullptr);
    1680             :     }
    1681             :     CATCH_END_SECTION()
    1682             : 
    1683          12 : }
    1684             : 
    1685             : 
    1686             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13