LCOV - code coverage report
Current view: top level - tests - catch_validator.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 705 720 97.9 %
Date: 2022-07-08 21:04:10 Functions: 26 32 81.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13