LCOV - code coverage report
Current view: top level - tests - catch_validator.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 899 912 98.6 %
Date: 2024-10-05 13:34:54 Functions: 23 26 88.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14

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