LCOV - code coverage report
Current view: top level - tests - catch_validator.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 496 509 97.4 %
Date: 2022-03-01 20:39:45 Functions: 14 20 70.0 %
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             : // self
      21             : //
      22             : #include    "catch_main.h"
      23             : 
      24             : 
      25             : // advgetopt lib
      26             : //
      27             : #include    <advgetopt/exception.h>
      28             : #include    <advgetopt/validator_duration.h>
      29             : #include    <advgetopt/validator_size.h>
      30             : 
      31             : 
      32             : // snapdev lib
      33             : //
      34             : #include    <snapdev/ostream_int128.h>
      35             : 
      36             : 
      37             : // C++ lib
      38             : //
      39             : #include <cmath>
      40             : #include <fstream>
      41             : #include <iomanip>
      42             : 
      43             : 
      44             : // last include
      45             : //
      46             : #include    <snapdev/poison.h>
      47             : 
      48             : 
      49             : 
      50             : 
      51             : 
      52             : namespace
      53             : {
      54             : 
      55             : struct duration_t
      56             : {
      57             :     char const * const      f_suffix = nullptr;
      58             :     double                  f_factor = 1.0;
      59             : };
      60             : 
      61             : constexpr duration_t const g_duration_suffixes[] =
      62             : {
      63             :     { "",                      1.0 },
      64             :     { "s",                     1.0 },
      65             :     { "second",                1.0 },
      66             :     { "seconds",               1.0 },
      67             : 
      68             :     { "m",                    -1.0 },   // may represent minutes or months
      69             :     { "minute",               60.0 },
      70             :     { "minutes",              60.0 },
      71             : 
      72             :     { "h",                  3600.0 },
      73             :     { "hour",               3600.0 },
      74             :     { "hours",              3600.0 },
      75             : 
      76             :     { "d",                 86400.0 },
      77             :     { "day",               86400.0 },
      78             :     { "days",              86400.0 },
      79             : 
      80             :     { "w",           86400.0 * 7.0 },
      81             :     { "week",        86400.0 * 7.0 },
      82             :     { "weeks",       86400.0 * 7.0 },
      83             : 
      84             :     { "month",      86400.0 * 30.0 },
      85             :     { "months",     86400.0 * 30.0 },
      86             : 
      87             :     { "y",         86400.0 * 365.0 },
      88             :     { "year",      86400.0 * 365.0 },
      89             :     { "years",     86400.0 * 365.0 },
      90             : };
      91             : 
      92             : struct size_suffix_t
      93             : {
      94             :     char const * const      f_suffix = nullptr;
      95             :     int                     f_base = 1000.0;
      96             :     int                     f_power = 0.0;
      97             : };
      98             : 
      99             : constexpr size_suffix_t const g_size_suffixes[] =
     100             : {
     101             :     { "",     1000, 0 },
     102             :     { "B",    1000, 0 },
     103             : 
     104             :     { "kB",   1000, 1 },
     105             :     { "KiB",  1024, 1 },
     106             : 
     107             :     { "MB",   1000, 2 },
     108             :     { "MiB",  1024, 2 },
     109             : 
     110             :     { "GB",   1000, 3 },
     111             :     { "GiB",  1024, 3 },
     112             : 
     113             :     { "TB",   1000, 4 },
     114             :     { "TiB",  1024, 4 },
     115             : 
     116             :     { "PB",   1000, 5 },
     117             :     { "PiB",  1024, 5 },
     118             : 
     119             :     { "EB",   1000, 6 },
     120             :     { "EiB",  1024, 6 },
     121             : 
     122             :     { "ZB",   1000, 7 },
     123             :     { "ZiB",  1024, 7 },
     124             : 
     125             :     { "YB",   1000, 8 },
     126             :     { "YiB",  1024, 8 },
     127             : };
     128             : 
     129      123693 : std::int64_t large_rnd(bool zero_allowed = true)
     130             : {
     131             :     for(;;)
     132             :     {
     133      123693 :         std::int64_t const result((static_cast<std::int64_t>(rand()) <<  0)
     134      123693 :                                 ^ (static_cast<std::int64_t>(rand()) << 16)
     135      123693 :                                 ^ (static_cast<std::int64_t>(rand()) << 32)
     136      123693 :                                 ^ (static_cast<std::int64_t>(rand()) << 48));
     137      123693 :         if(result != 0
     138           0 :         || zero_allowed)
     139             :         {
     140      247386 :             return result;
     141             :         }
     142           0 :     }
     143             : }
     144             : 
     145             : }
     146             : 
     147             : 
     148             : 
     149           4 : CATCH_TEST_CASE("unknown_validator", "[validator][valid][validation]")
     150             : {
     151           4 :     CATCH_START_SECTION("Undefined validator")
     152             :         // this is a valid case, it does not throw, it just returns a nullptr
     153             :         //
     154           1 :         CATCH_REQUIRE(advgetopt::validator::create("unknown", advgetopt::string_list_t()) == nullptr);
     155             :     CATCH_END_SECTION()
     156             : 
     157           4 :     CATCH_START_SECTION("Empty string")
     158           1 :         CATCH_REQUIRE(advgetopt::validator::create(std::string()) == nullptr);
     159             :     CATCH_END_SECTION()
     160           2 : }
     161             : 
     162             : 
     163             : 
     164           5 : CATCH_TEST_CASE("integer_validator", "[validator][valid][validation]")
     165             : {
     166           6 :     CATCH_START_SECTION("Verify the integer validator")
     167           2 :         advgetopt::validator::pointer_t integer_validator(advgetopt::validator::create("integer", advgetopt::string_list_t()));
     168             : 
     169           1 :         CATCH_REQUIRE(integer_validator != nullptr);
     170           1 :         CATCH_REQUIRE(integer_validator->name() == "integer");
     171             : 
     172           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate(""));
     173           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("+"));
     174           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("-"));
     175             : 
     176        1001 :         for(int idx(0); idx < 1000; ++idx)
     177             :         {
     178        1000 :             std::int64_t value(large_rnd());
     179        2000 :             std::string const v(std::to_string(value));
     180             : 
     181        1000 :             CATCH_REQUIRE(integer_validator->validate(v));
     182             : 
     183        1000 :             if(value >= 0)
     184             :             {
     185         489 :                 CATCH_REQUIRE(integer_validator->validate('+' + v));
     186             :             }
     187             : 
     188        2000 :             std::string const space_before(' ' + v);
     189        1000 :             CATCH_REQUIRE_FALSE(integer_validator->validate(space_before));
     190             : 
     191        2000 :             std::string const space_after(v + ' ');
     192        1000 :             CATCH_REQUIRE_FALSE(integer_validator->validate(space_after));
     193             : 
     194        2000 :             std::string const before(static_cast<char>(rand() % 26 + 'a') + v);
     195        1000 :             CATCH_REQUIRE_FALSE(integer_validator->validate(before));
     196             : 
     197        2000 :             std::string const after(v + static_cast<char>(rand() % 26 + 'a'));
     198        1000 :             CATCH_REQUIRE_FALSE(integer_validator->validate(after));
     199             :         }
     200             : 
     201             :         // max number
     202           1 :         CATCH_REQUIRE(integer_validator->validate("9223372036854775807"));
     203           1 :         CATCH_REQUIRE(integer_validator->validate("+9223372036854775807"));
     204             : 
     205             :         // overflow
     206           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("9223372036854775808"));
     207           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("+9223372036854775808"));
     208             : 
     209             :         // min number
     210           1 :         CATCH_REQUIRE(integer_validator->validate("-9223372036854775808"));
     211             : 
     212             :         // underflow
     213           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("-9223372036854775809"));
     214             : 
     215             :         // too many digits
     216           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("92233720368547758091"));
     217           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("+92233720368547758092"));
     218           1 :         CATCH_REQUIRE_FALSE(integer_validator->validate("-92233720368547758093"));
     219             :     CATCH_END_SECTION()
     220             : 
     221           6 :     CATCH_START_SECTION("Verify the integer ranges")
     222           1 :         bool had_standalone(false);
     223          21 :         for(int count(0); count < 20 || !had_standalone; ++count)
     224             :         {
     225          20 :             std::int64_t min(large_rnd());
     226          20 :             std::int64_t max(large_rnd());
     227          20 :             if(min > max)
     228             :             {
     229          10 :                 std::swap(min, max);
     230             :             }
     231             : 
     232          40 :             std::string const & smin(std::to_string(min));
     233          40 :             std::string const & smax(std::to_string(max));
     234             : 
     235          40 :             std::string range("...");
     236          80 :             for(int three(0); three < 3; ++three)
     237             :             {
     238          60 :                 if(rand() % 5 == 0)
     239             :                 {
     240          13 :                     range = ' ' + range;
     241             :                 }
     242          60 :                 if(rand() % 5 == 0)
     243             :                 {
     244          12 :                     range = range + ' ';
     245             :                 }
     246             :             }
     247          20 :             range = smin + range + smax;
     248          80 :             for(int three(0); three < 3; ++three)
     249             :             {
     250          60 :                 if(rand() % 5 == 0)
     251             :                 {
     252          11 :                     range = ' ' + range;
     253             :                 }
     254          60 :                 if(rand() % 5 == 0)
     255             :                 {
     256          12 :                     range = range + ' ';
     257             :                 }
     258             :             }
     259             : 
     260          20 :             std::int64_t standalone(0);
     261          20 :             bool standalone_included(rand() % 4 == 0);
     262          20 :             if(standalone_included)
     263             :             {
     264          10 :                 if(min == std::numeric_limits<std::int64_t>::min()
     265           5 :                 && max == std::numeric_limits<std::int64_t>::max())
     266             :                 {
     267           0 :                     standalone_included = false;
     268             :                 }
     269             :                 else
     270             :                 {
     271           5 :                     had_standalone = true;
     272           1 :                     do
     273             :                     {
     274           6 :                         standalone = large_rnd();
     275             :                     }
     276           6 :                     while(standalone >= min && standalone <= max);
     277             : 
     278          10 :                     std::string sep(",");
     279           5 :                     if(rand() % 3 == 0)
     280             :                     {
     281           1 :                         sep = ' ' + sep;
     282             :                     }
     283           5 :                     if(rand() % 3 == 0)
     284             :                     {
     285           1 :                         sep = sep + ' ';
     286             :                     }
     287           5 :                     if(rand() % 2 == 0)
     288             :                     {
     289           1 :                         range = std::to_string(standalone) + "," + range;
     290             :                     }
     291             :                     else
     292             :                     {
     293           4 :                         range = range + "," + std::to_string(standalone);
     294             :                     }
     295             :                 }
     296             :             }
     297          40 :             advgetopt::string_list_t range_list;
     298          40 :             advgetopt::split_string(range
     299             :                        , range_list
     300          20 :                        , {","});
     301          40 :             advgetopt::validator::pointer_t integer_validator(advgetopt::validator::create("integer", range_list));
     302             : 
     303          20 :             CATCH_REQUIRE(integer_validator != nullptr);
     304          20 :             CATCH_REQUIRE(integer_validator->name() == "integer");
     305             : 
     306       20020 :             for(int idx(0); idx < 1000; ++idx)
     307             :             {
     308       20000 :                 std::int64_t value(large_rnd());
     309             : 
     310             :                 // force valid values otherwise we're likely to only have
     311             :                 // invalid ones
     312             :                 //
     313       20000 :                 if(idx % 10 == 0)
     314             :                 {
     315        2000 :                     value %= max - min + 1;
     316        2000 :                     value += min;
     317             :                 }
     318       18000 :                 else if(idx % 50 == 1 && standalone_included)
     319             :                 {
     320         100 :                     value = standalone;
     321             :                 }
     322             : 
     323       40000 :                 std::string const v(std::to_string(value));
     324             : 
     325       20000 :                 if((standalone_included && value == standalone)
     326       19900 :                 || (value >= min && value <= max))
     327             :                 {
     328        7020 :                     CATCH_REQUIRE(integer_validator->validate(v));
     329             :                 }
     330             :                 else
     331             :                 {
     332       12980 :                     CATCH_REQUIRE_FALSE(integer_validator->validate(v));
     333             :                 }
     334             : 
     335       20000 :                 if(value >= 0)
     336             :                 {
     337        9593 :                     if((standalone_included && value == standalone)
     338        9553 :                     || (value >= min && value <= max))
     339             :                     {
     340        3649 :                         CATCH_REQUIRE(integer_validator->validate('+' + v));
     341             :                     }
     342             :                     else
     343             :                     {
     344        5944 :                         CATCH_REQUIRE_FALSE(integer_validator->validate('+' + v));
     345             :                     }
     346             :                 }
     347             : 
     348       40000 :                 std::string const space_before(' ' + v);
     349       20000 :                 CATCH_REQUIRE_FALSE(integer_validator->validate(space_before));
     350             : 
     351       40000 :                 std::string const space_after(v + ' ');
     352       20000 :                 CATCH_REQUIRE_FALSE(integer_validator->validate(space_after));
     353             : 
     354       40000 :                 std::string const before(static_cast<char>(rand() % 26 + 'a') + v);
     355       20000 :                 CATCH_REQUIRE_FALSE(integer_validator->validate(before));
     356             : 
     357       40000 :                 std::string const after(v + static_cast<char>(rand() % 26 + 'a'));
     358       20000 :                 CATCH_REQUIRE_FALSE(integer_validator->validate(after));
     359             :             }
     360             :         }
     361             :     CATCH_END_SECTION()
     362             : 
     363           6 :     CATCH_START_SECTION("Verify the integer standalone list")
     364          21 :         for(int count(0); count < 20; ++count)
     365             :         {
     366          20 :             int valid(rand() % 10 + 5);
     367          40 :             std::vector<std::int64_t> numbers;
     368          20 :             numbers.reserve(valid);
     369          40 :             std::string standalone_values;
     370         211 :             for(int idx(0); idx < valid; ++idx)
     371             :             {
     372         191 :                 std::int64_t const value(large_rnd());
     373         191 :                 numbers.push_back(value);
     374         382 :                 std::string const & svalue(std::to_string(value));
     375         191 :                 if(rand() % 5 == 0)
     376             :                 {
     377          44 :                     standalone_values += ' ';
     378             :                 }
     379         191 :                 if(idx != 0)
     380             :                 {
     381         171 :                     standalone_values += ',';
     382             :                 }
     383         191 :                 if(rand() % 5 == 0)
     384             :                 {
     385          39 :                     standalone_values += ' ';
     386             :                 }
     387         191 :                 standalone_values += svalue;
     388             :             }
     389          20 :             if(rand() % 5 == 0)
     390             :             {
     391           2 :                 standalone_values += ' ';
     392             :             }
     393          40 :             advgetopt::string_list_t range_list;
     394          40 :             advgetopt::split_string(standalone_values
     395             :                        , range_list
     396          20 :                        , {","});
     397             : 
     398          40 :             advgetopt::validator::pointer_t integer_validator(advgetopt::validator::create("integer", range_list));
     399             : 
     400          20 :             CATCH_REQUIRE(integer_validator != nullptr);
     401          20 :             CATCH_REQUIRE(integer_validator->name() == "integer");
     402             : 
     403         211 :             for(size_t idx(0); idx < numbers.size(); ++idx)
     404             :             {
     405         382 :                 std::string const svalue(std::to_string(numbers[idx]));
     406             : 
     407         191 :                 CATCH_REQUIRE(integer_validator->validate(svalue));
     408             :             }
     409             : 
     410       20020 :             for(int idx(0); idx < 1000; ++idx)
     411             :             {
     412       20000 :                 std::int64_t value;
     413             : 
     414             :                 for(;;)
     415             :                 {
     416       20000 :                     value = large_rnd();
     417       20000 :                     if(std::find(numbers.begin(), numbers.end(), value) == numbers.end())
     418             :                     {
     419       20000 :                         break;
     420             :                     }
     421             :                 }
     422             : 
     423       20000 :                 CATCH_REQUIRE_FALSE(integer_validator->validate(std::to_string(value)));
     424             :             }
     425             :         }
     426             :     CATCH_END_SECTION()
     427           3 : }
     428             : 
     429             : 
     430             : 
     431             : 
     432           5 : CATCH_TEST_CASE("double_validator", "[validator][valid][validation]")
     433             : {
     434           6 :     CATCH_START_SECTION("Verify the double validator")
     435           2 :         advgetopt::validator::pointer_t double_validator(advgetopt::validator::create("double", advgetopt::string_list_t()));
     436             : 
     437           1 :         CATCH_REQUIRE(double_validator != nullptr);
     438           1 :         CATCH_REQUIRE(double_validator->name() == "double");
     439             : 
     440           1 :         CATCH_REQUIRE_FALSE(double_validator->validate(""));
     441           1 :         CATCH_REQUIRE_FALSE(double_validator->validate("+"));
     442           1 :         CATCH_REQUIRE_FALSE(double_validator->validate("-"));
     443           1 :         CATCH_REQUIRE_FALSE(double_validator->validate("alpha"));
     444             : 
     445        1001 :         for(int idx(0); idx < 1000; ++idx)
     446             :         {
     447        1000 :             double value(static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false)));
     448        2000 :             std::string const v(std::to_string(value));
     449             : 
     450        1000 :             CATCH_REQUIRE(double_validator->validate(v));
     451             : 
     452        1000 :             if(value >= 0)
     453             :             {
     454         494 :                 CATCH_REQUIRE(double_validator->validate('+' + v));
     455             :             }
     456             : 
     457        2000 :             std::string const space_before(' ' + v);
     458        1000 :             CATCH_REQUIRE_FALSE(double_validator->validate(space_before));
     459             : 
     460        2000 :             std::string const space_after(v + ' ');
     461        1000 :             CATCH_REQUIRE_FALSE(double_validator->validate(space_after));
     462             : 
     463        2000 :             std::string const before(static_cast<char>(rand() % 26 + 'a') + v);
     464        1000 :             CATCH_REQUIRE_FALSE(double_validator->validate(before));
     465             : 
     466        2000 :             std::string const after(v + static_cast<char>(rand() % 26 + 'a'));
     467        1000 :             CATCH_REQUIRE_FALSE(double_validator->validate(after));
     468             :         }
     469             :     CATCH_END_SECTION()
     470             : 
     471           6 :     CATCH_START_SECTION("Verify the double ranges")
     472           1 :         bool had_standalone(false);
     473          21 :         for(int count(0); count < 20 || !had_standalone; ++count)
     474             :         {
     475          20 :             double min(static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false)));
     476          20 :             double max(static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false)));
     477          20 :             if(min > max)
     478             :             {
     479           6 :                 std::swap(min, max);
     480             :             }
     481             : 
     482          40 :             std::string const & smin(std::to_string(min));
     483          40 :             std::string const & smax(std::to_string(max));
     484             : 
     485          40 :             std::string range("...");
     486          80 :             for(int three(0); three < 3; ++three)
     487             :             {
     488          60 :                 if(rand() % 5 == 0)
     489             :                 {
     490          11 :                     range = ' ' + range;
     491             :                 }
     492          60 :                 if(rand() % 5 == 0)
     493             :                 {
     494           9 :                     range = range + ' ';
     495             :                 }
     496             :             }
     497          20 :             range = smin + range + smax;
     498          80 :             for(int three(0); three < 3; ++three)
     499             :             {
     500          60 :                 if(rand() % 5 == 0)
     501             :                 {
     502          18 :                     range = ' ' + range;
     503             :                 }
     504          60 :                 if(rand() % 5 == 0)
     505             :                 {
     506          15 :                     range = range + ' ';
     507             :                 }
     508             :             }
     509             : 
     510          20 :             double standalone(0);
     511          20 :             bool standalone_included(rand() % 4 == 0);
     512          20 :             if(standalone_included)
     513             :             {
     514          16 :                 if(min <= std::numeric_limits<double>::min()
     515           8 :                 && max >= std::numeric_limits<double>::max())
     516             :                 {
     517           0 :                     standalone_included = false;
     518             :                 }
     519             :                 else
     520             :                 {
     521           8 :                     had_standalone = true;
     522           9 :                     do
     523             :                     {
     524          17 :                         standalone = static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false));
     525             :                     }
     526          17 :                     while(standalone >= min && standalone <= max);
     527             : 
     528          16 :                     std::string sep(",");
     529           8 :                     if(rand() % 3 == 0)
     530             :                     {
     531           2 :                         sep = ' ' + sep;
     532             :                     }
     533           8 :                     if(rand() % 3 == 0)
     534             :                     {
     535           1 :                         sep = sep + ' ';
     536             :                     }
     537           8 :                     if(rand() % 2 == 0)
     538             :                     {
     539           4 :                         range = std::to_string(standalone) + "," + range;
     540             :                     }
     541             :                     else
     542             :                     {
     543           4 :                         range = range + "," + std::to_string(standalone);
     544             :                     }
     545             :                 }
     546             :             }
     547          40 :             advgetopt::string_list_t range_list;
     548          40 :             advgetopt::split_string(range
     549             :                        , range_list
     550          20 :                        , {","});
     551          40 :             advgetopt::validator::pointer_t double_validator(advgetopt::validator::create("double", range_list));
     552             : 
     553          20 :             CATCH_REQUIRE(double_validator != nullptr);
     554          20 :             CATCH_REQUIRE(double_validator->name() == "double");
     555             : 
     556       20020 :             for(int idx(0); idx < 1000; ++idx)
     557             :             {
     558       20000 :                 double value(static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false)));
     559             : 
     560             :                 // force valid values otherwise we're likely to only have
     561             :                 // invalid ones
     562             :                 //
     563       20000 :                 if(idx % 10 == 0)
     564             :                 {
     565        2000 :                     value = fmod(value, max - min + 1.0) + min;
     566             :                 }
     567       18000 :                 else if(idx % 50 == 1 && standalone_included)
     568             :                 {
     569         160 :                     value = standalone;
     570             :                 }
     571             : 
     572       40000 :                 std::string const v(std::to_string(value));
     573             : 
     574             : #pragma GCC diagnostic push
     575             : #pragma GCC diagnostic ignored "-Wfloat-equal"
     576       20000 :                 if((standalone_included && value == standalone)
     577       19840 :                 || (value >= min && value <= max))
     578             :                 {
     579        6967 :                     CATCH_REQUIRE(double_validator->validate(v));
     580             :                 }
     581             :                 else
     582             :                 {
     583       13033 :                     CATCH_REQUIRE_FALSE(double_validator->validate(v));
     584             :                 }
     585             : 
     586       20000 :                 if(value >= 0.0)
     587             :                 {
     588        9608 :                     if((standalone_included && value == standalone)
     589        9508 :                     || (value >= min && value <= max))
     590             :                     {
     591        2876 :                         CATCH_REQUIRE(double_validator->validate('+' + v));
     592             :                     }
     593             :                     else
     594             :                     {
     595        6732 :                         CATCH_REQUIRE_FALSE(double_validator->validate('+' + v));
     596             :                     }
     597             :                 }
     598             : #pragma GCC diagnostic pop
     599             : 
     600       40000 :                 std::string const space_before(' ' + v);
     601       20000 :                 CATCH_REQUIRE_FALSE(double_validator->validate(space_before));
     602             : 
     603       40000 :                 std::string const space_after(v + ' ');
     604       20000 :                 CATCH_REQUIRE_FALSE(double_validator->validate(space_after));
     605             : 
     606       40000 :                 std::string const before(static_cast<char>(rand() % 26 + 'a') + v);
     607       20000 :                 CATCH_REQUIRE_FALSE(double_validator->validate(before));
     608             : 
     609       40000 :                 std::string const after(v + static_cast<char>(rand() % 26 + 'a'));
     610       20000 :                 CATCH_REQUIRE_FALSE(double_validator->validate(after));
     611             :             }
     612             :         }
     613             :     CATCH_END_SECTION()
     614             : 
     615           6 :     CATCH_START_SECTION("Verify the double standalone list")
     616          21 :         for(int count(0); count < 20; ++count)
     617             :         {
     618          20 :             int valid(rand() % 10 + 5);
     619          40 :             std::vector<double> numbers;
     620          20 :             numbers.reserve(valid);
     621          40 :             std::string standalone_values;
     622         191 :             for(int idx(0); idx < valid; ++idx)
     623             :             {
     624         171 :                 double const value(static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false)));
     625         171 :                 numbers.push_back(value);
     626         342 :                 std::string const & svalue(std::to_string(value));
     627         171 :                 if(rand() % 5 == 0)
     628             :                 {
     629          24 :                     standalone_values += ' ';
     630             :                 }
     631         171 :                 if(idx != 0)
     632             :                 {
     633         151 :                     standalone_values += ',';
     634             :                 }
     635         171 :                 if(rand() % 5 == 0)
     636             :                 {
     637          31 :                     standalone_values += ' ';
     638             :                 }
     639         171 :                 standalone_values += svalue;
     640             :             }
     641          20 :             if(rand() % 5 == 0)
     642             :             {
     643           6 :                 standalone_values += ' ';
     644             :             }
     645          40 :             advgetopt::string_list_t range_list;
     646          40 :             advgetopt::split_string(standalone_values
     647             :                        , range_list
     648          20 :                        , {","});
     649             : 
     650          40 :             advgetopt::validator::pointer_t double_validator(advgetopt::validator::create("double", range_list));
     651             : 
     652          20 :             CATCH_REQUIRE(double_validator != nullptr);
     653          20 :             CATCH_REQUIRE(double_validator->name() == "double");
     654             : 
     655         191 :             for(size_t idx(0); idx < numbers.size(); ++idx)
     656             :             {
     657         342 :                 std::string const svalue(std::to_string(numbers[idx]));
     658             : 
     659         171 :                 CATCH_REQUIRE(double_validator->validate(svalue));
     660             :             }
     661             : 
     662       20020 :             for(int idx(0); idx < 1000; ++idx)
     663             :             {
     664       20000 :                 std::int64_t value;
     665             : 
     666             :                 for(;;)
     667             :                 {
     668       20000 :                     value = static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false));
     669       20000 :                     if(std::find(numbers.begin(), numbers.end(), value) == numbers.end())
     670             :                     {
     671       20000 :                         break;
     672             :                     }
     673             :                 }
     674             : 
     675       20000 :                 CATCH_REQUIRE_FALSE(double_validator->validate(std::to_string(value)));
     676             :             }
     677             :         }
     678             :     CATCH_END_SECTION()
     679           3 : }
     680             : 
     681             : 
     682             : 
     683             : 
     684           5 : CATCH_TEST_CASE("duration_validator", "[validator][valid][validation]")
     685             : {
     686           6 :     CATCH_START_SECTION("Verify the duration validator (simple values)")
     687             :     {
     688           1 :         double duration(0.0);
     689             : 
     690             :         // simple seconds with decimal point
     691             :         //
     692           1 :         CATCH_REQUIRE(advgetopt::validator_duration::convert_string("22.3s", 0, duration));
     693           1 :         CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(duration, 22.3, 0.0));
     694             : 
     695             :         // "seconds" is the default
     696             :         //
     697           1 :         CATCH_REQUIRE(advgetopt::validator_duration::convert_string("1.05", 0, duration));
     698           1 :         CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(duration, 1.05, 0.0));
     699             : 
     700             :         // number can start with a decimal point
     701             :         //
     702           1 :         CATCH_REQUIRE(advgetopt::validator_duration::convert_string(".0503", 0, duration));
     703           1 :         CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(duration, 0.0503, 0.0));
     704             :     }
     705             :     CATCH_END_SECTION()
     706             : 
     707           6 :     CATCH_START_SECTION("Verify the duration validator (multiple values)")
     708             :     {
     709           1 :         double duration(0.0);
     710           1 :         CATCH_REQUIRE(advgetopt::validator_duration::convert_string("1d 3h 2m 15.3s", 0, duration));
     711           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));
     712             : 
     713           1 :         CATCH_REQUIRE(advgetopt::validator_duration::convert_string("3d 15h 52m 21.801s", 0, duration));
     714           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));
     715             :     }
     716             :     CATCH_END_SECTION()
     717             : 
     718           6 :     CATCH_START_SECTION("Verify the duration validator (one value)")
     719             :     {
     720             :         // this test does not verify that double conversion works since we
     721             :         // have a separate test for that specific validator
     722             :         //
     723           4 :         for(int size(0); size < 3; ++size)
     724             :         {
     725           3 :             advgetopt::validator_duration::flag_t flg(advgetopt::validator_duration::VALIDATOR_DURATION_DEFAULT_FLAGS);
     726           6 :             advgetopt::string_list_t flags;
     727           3 :             if(size == 1)
     728             :             {
     729           1 :                 flags.push_back("small");
     730             :             }
     731           2 :             else if(size == 2)
     732             :             {
     733           1 :                 flags.push_back("large");
     734           1 :                 flg = advgetopt::validator_duration::VALIDATOR_DURATION_LONG;
     735             :             }
     736           6 :             advgetopt::validator::pointer_t duration_validator(advgetopt::validator::create("duration", flags));
     737             : 
     738           3 :             CATCH_REQUIRE(duration_validator != nullptr);
     739           3 :             CATCH_REQUIRE(duration_validator->name() == "duration");
     740             : 
     741           3 :             CATCH_REQUIRE_FALSE(duration_validator->validate(""));
     742           3 :             CATCH_REQUIRE_FALSE(duration_validator->validate("+"));
     743           3 :             CATCH_REQUIRE_FALSE(duration_validator->validate("-"));
     744           3 :             CATCH_REQUIRE_FALSE(duration_validator->validate("alpha"));
     745           3 :             CATCH_REQUIRE_FALSE(duration_validator->validate("3.5 beta"));
     746           3 :             CATCH_REQUIRE_FALSE(duration_validator->validate("7.5delta"));
     747           3 :             CATCH_REQUIRE_FALSE(duration_validator->validate("+8.1 gamma"));
     748           3 :             CATCH_REQUIRE_FALSE(duration_validator->validate("-2.3eta"));
     749             : 
     750        3003 :             for(int idx(0); idx < 1000; ++idx)
     751             :             {
     752             :                 // use smaller values between 0 and 1
     753             :                 // (the loop is to make sure we don't end up with "123e-10"
     754             :                 // type of numbers... which do not work here)
     755             :                 //
     756        3000 :                 double value(0.0);
     757             : #pragma GCC diagnostic push
     758             : #pragma GCC diagnostic ignored "-Wfloat-equal"
     759           0 :                 do
     760             :                 {
     761        3000 :                     value = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
     762             :                 }
     763        3000 :                 while(value < 0.0001 && value != 0.0);
     764             : #pragma GCC diagnostic pop
     765        3000 :                 if(rand() % 2 == 0)
     766             :                 {
     767        1509 :                     value *= -1.0;
     768             :                 }
     769        6000 :                 std::stringstream ss;
     770        3000 :                 ss.precision(std::numeric_limits<double>::max_digits10);
     771        3000 :                 ss << value;
     772        6000 :                 std::string const v(ss.str());
     773             : 
     774       66000 :                 for(std::size_t i(0); i < std::size(g_duration_suffixes); ++i)
     775             :                 {
     776      441000 :                     for(int j(0); j <= 5; ++j)
     777             :                     {
     778      756000 :                         std::string duration(v);
     779     1323000 :                         for(int k(0); k < j; ++k)
     780             :                         {
     781             :                             // any number of spaces in between are allowed
     782             :                             //
     783      945000 :                             duration += ' ';
     784             :                         }
     785      378000 :                         duration += g_duration_suffixes[i].f_suffix;
     786             : 
     787      378000 :                         CATCH_REQUIRE(duration_validator->validate(duration));
     788      378000 :                         if(value >= 0)
     789             :                         {
     790      187866 :                             CATCH_REQUIRE(duration_validator->validate('+' + duration));
     791             :                         }
     792             : 
     793      378000 :                         double result(0.0);
     794      378000 :                         CATCH_REQUIRE(advgetopt::validator_duration::convert_string(duration, flg, result));
     795      378000 :                         if(g_duration_suffixes[i].f_factor < 0.0)
     796             :                         {
     797             :                             // the 'm' special case
     798             :                             //
     799       18000 :                             if(size == 2)
     800             :                             {
     801             :                                 // 'large' -- 1 month
     802             :                                 //
     803        6000 :                                 CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(result, value * (86400.0 * 30.0)));
     804             :                             }
     805             :                             else
     806             :                             {
     807             :                                 // 'small' -- 1 minute
     808             :                                 //
     809       12000 :                                 CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(result, value * 60.0));
     810             :                             }
     811             :                         }
     812             :                         else
     813             :                         {
     814      360000 :                             CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(result, value * g_duration_suffixes[i].f_factor));
     815             :                         }
     816             :                     }
     817             :                 }
     818             :             }
     819             :         }
     820             :     }
     821             :     CATCH_END_SECTION()
     822           3 : }
     823             : 
     824             : 
     825             : 
     826             : 
     827           3 : CATCH_TEST_CASE("size_validator", "[validator][valid][validation]")
     828             : {
     829             : #pragma GCC diagnostic push
     830             : #pragma GCC diagnostic ignored "-Wpedantic"
     831           2 :     CATCH_START_SECTION("Verify the size validator")
     832             :     {
     833             :         // this test does not verify that double conversion works since we
     834             :         // have a separate test for that specific validator
     835             :         //
     836           4 :         for(int mode(0); mode < 3; ++mode)
     837             :         {
     838           3 :             advgetopt::validator_size::flag_t flg(advgetopt::validator_size::VALIDATOR_SIZE_DEFAULT_FLAGS);
     839           6 :             advgetopt::string_list_t flags;
     840           3 :             if(mode == 1)
     841             :             {
     842           1 :                 flags.push_back("si");
     843             :             }
     844           2 :             else if(mode == 2)
     845             :             {
     846           1 :                 flags.push_back("legacy");
     847           1 :                 flg = advgetopt::validator_size::VALIDATOR_SIZE_POWER_OF_TWO;
     848             :             }
     849           6 :             advgetopt::validator::pointer_t size_validator(advgetopt::validator::create("size", flags));
     850             : 
     851           3 :             CATCH_REQUIRE(size_validator != nullptr);
     852           3 :             CATCH_REQUIRE(size_validator->name() == "size");
     853             : 
     854           3 :             CATCH_REQUIRE_FALSE(size_validator->validate(""));
     855           3 :             CATCH_REQUIRE_FALSE(size_validator->validate("+"));
     856           3 :             CATCH_REQUIRE_FALSE(size_validator->validate("-"));
     857           3 :             CATCH_REQUIRE_FALSE(size_validator->validate("alpha"));
     858           3 :             CATCH_REQUIRE_FALSE(size_validator->validate("3.5 beta"));
     859           3 :             CATCH_REQUIRE_FALSE(size_validator->validate("7.5delta"));
     860           3 :             CATCH_REQUIRE_FALSE(size_validator->validate("+8.1 gamma"));
     861           3 :             CATCH_REQUIRE_FALSE(size_validator->validate("-2.3eta"));
     862             : 
     863        3003 :             for(int idx(0); idx < 1000; ++idx)
     864             :             {
     865             :                 // use smaller values between 0 and about 5
     866             :                 //
     867        3000 :                 double value(static_cast<double>(rand()) / static_cast<double>(RAND_MAX / 5));
     868        3000 :                 if(rand() % 2 == 0)
     869             :                 {
     870        1509 :                     value *= -1.0;
     871             :                 }
     872        6000 :                 std::stringstream ss;
     873        3000 :                 ss.precision(std::numeric_limits<double>::max_digits10);
     874        3000 :                 ss << value;
     875        6000 :                 std::string const v(ss.str());
     876             : 
     877       57000 :                 for(std::size_t i(0); i < std::size(g_size_suffixes); ++i)
     878             :                 {
     879      378000 :                     for(int j(0); j <= 5; ++j)
     880             :                     {
     881      648000 :                         std::string size(v);
     882     1134000 :                         for(int k(0); k < j; ++k)
     883             :                         {
     884             :                             // any number of spaces in between are allowed
     885             :                             //
     886      810000 :                             size += ' ';
     887             :                         }
     888      324000 :                         size += g_size_suffixes[i].f_suffix;
     889             : 
     890      324000 :                         CATCH_REQUIRE(size_validator->validate(size));
     891      324000 :                         if(value >= 0)
     892             :                         {
     893      161028 :                             CATCH_REQUIRE(size_validator->validate('+' + size));
     894             :                         }
     895             : 
     896      324000 :                         __int128 result(0.0);
     897      324000 :                         CATCH_REQUIRE(advgetopt::validator_size::convert_string(size, flg, result));
     898             : 
     899      324000 :                         long double const base(mode == 2 ? 1024.0L : g_size_suffixes[i].f_base);
     900      324000 :                         long double expected(1);
     901     1620000 :                         for(int p(0); p < g_size_suffixes[i].f_power; ++p)
     902             :                         {
     903     1296000 :                             expected *= base;
     904             :                         }
     905      324000 :                         __int128 int_expected(expected * static_cast<long double>(value));
     906             : 
     907             : //std::cerr << "converted [" << size << "] to [" << result << "] wanted [" << int_expected << "]\n";
     908      324000 :                         CATCH_REQUIRE(result == int_expected);
     909             :                     }
     910             :                 }
     911             :             }
     912             :         }
     913             :     }
     914             :     CATCH_END_SECTION()
     915             : #pragma GCC diagnostic pop
     916           1 : }
     917             : 
     918             : 
     919             : 
     920             : 
     921           6 : CATCH_TEST_CASE("regex_validator", "[validator][valid][validation]")
     922             : {
     923           8 :     CATCH_START_SECTION("Verify the regex validator")
     924           2 :         advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex", {".*@.*\\..*"}));
     925             : 
     926           1 :         CATCH_REQUIRE(regex_validator != nullptr);
     927           1 :         CATCH_REQUIRE(regex_validator->name() == "regex");
     928             : 
     929           1 :         CATCH_REQUIRE(regex_validator->validate("@m2osw."));
     930           1 :         CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
     931           1 :         CATCH_REQUIRE(regex_validator->validate("Contact@m2osw.com"));
     932           1 :         CATCH_REQUIRE(regex_validator->validate("Contact@M2OSW.com"));
     933             : 
     934           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
     935           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
     936             :     CATCH_END_SECTION()
     937             : 
     938           8 :     CATCH_START_SECTION("Verify the regex string (case sensitive)")
     939           2 :         advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex", {"/contact@.*\\..*/"}));
     940             : 
     941           1 :         CATCH_REQUIRE(regex_validator != nullptr);
     942           1 :         CATCH_REQUIRE(regex_validator->name() == "regex");
     943             : 
     944           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
     945           1 :         CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
     946           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@m2osw.com"));
     947           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@M2OSW.com"));
     948             : 
     949           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
     950           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
     951             :     CATCH_END_SECTION()
     952             : 
     953           8 :     CATCH_START_SECTION("Verify the regex string (case insensitive)")
     954           2 :         advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex", {"/contact@.*\\..*/i"}));
     955             : 
     956           1 :         CATCH_REQUIRE(regex_validator != nullptr);
     957           1 :         CATCH_REQUIRE(regex_validator->name() == "regex");
     958             : 
     959           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
     960           1 :         CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
     961           1 :         CATCH_REQUIRE(regex_validator->validate("Contact@m2osw.com"));
     962           1 :         CATCH_REQUIRE(regex_validator->validate("Contact@M2OSW.com"));
     963             : 
     964           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
     965           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
     966             :     CATCH_END_SECTION()
     967             : 
     968           8 :     CATCH_START_SECTION("Verify direct regex string (case insensitive)")
     969           2 :         advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("/contact@.*\\..*/i"));
     970             : 
     971           1 :         CATCH_REQUIRE(regex_validator != nullptr);
     972           1 :         CATCH_REQUIRE(regex_validator->name() == "regex");
     973             : 
     974           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
     975           1 :         CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
     976           1 :         CATCH_REQUIRE(regex_validator->validate("Contact@m2osw.com"));
     977           1 :         CATCH_REQUIRE(regex_validator->validate("Contact@M2OSW.com"));
     978             : 
     979           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
     980           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
     981             :     CATCH_END_SECTION()
     982           4 : }
     983             : 
     984             : 
     985             : 
     986             : 
     987             : 
     988             : 
     989             : 
     990             : 
     991           8 : CATCH_TEST_CASE("invalid_validator", "[validator][invalid][validation]")
     992             : {
     993          12 :     CATCH_START_SECTION("Register duplicated factories")
     994           0 :         class duplicate_integer
     995             :             : public advgetopt::validator
     996             :         {
     997             :         public:
     998           0 :             virtual std::string const name() const
     999             :             {
    1000           0 :                 return "integer";
    1001             :             }
    1002             : 
    1003           0 :             virtual bool validate(std::string const & value) const override
    1004             :             {
    1005           0 :                 return value == "123";
    1006             :             }
    1007             :         };
    1008           3 :         class duplicate_factory
    1009             :             : public advgetopt::validator_factory
    1010             :         {
    1011             :         public:
    1012           2 :             virtual std::string get_name() const
    1013             :             {
    1014           2 :                 return "integer";
    1015             :             }
    1016             : 
    1017           0 :             virtual std::shared_ptr<advgetopt::validator> create(advgetopt::string_list_t const & data) const override
    1018             :             {
    1019           0 :                 snapdev::NOT_USED(data); // ignore `data`
    1020           0 :                 return std::make_shared<duplicate_integer>();
    1021             :             }
    1022             :         };
    1023           2 :         std::unique_ptr<advgetopt::validator_factory> factory(new duplicate_factory());
    1024           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    1025             :                   advgetopt::validator::register_validator(*factory.get())
    1026             :                 , advgetopt::getopt_logic_error
    1027             :                 , Catch::Matchers::ExceptionMessage(
    1028             :                           "getopt_logic_error: you have two or more validator factories named \"integer\"."));
    1029             :     CATCH_END_SECTION()
    1030             : 
    1031             : 
    1032          12 :     CATCH_START_SECTION("Verify invalid ranges")
    1033           1 :         advgetopt::string_list_t range{
    1034             :             "abc",
    1035             :             "abc...6",
    1036             :             "3...def",
    1037           2 :             "10...1"};
    1038             : 
    1039           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: abc is not a valid value for your ranges; it must only be digits, optionally preceeded by a sign (+ or -) and not overflow an int64_t value.");
    1040           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: abc is not a valid value for your ranges; it must only be digits, optionally preceeded by a sign (+ or -) and not overflow an int64_t value.");
    1041           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: def is not a valid value for your ranges; it must only be digits, optionally preceeded by a sign (+ or -) and not overflow an int64_t value.");
    1042           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: 10 has to be smaller or equal to 1; you have an invalid range.");
    1043             : 
    1044           2 :         advgetopt::validator::pointer_t integer_validator(advgetopt::validator::create("integer", range));
    1045           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1046             :     CATCH_END_SECTION()
    1047             : 
    1048          12 :     CATCH_START_SECTION("Verify invalid regex flags")
    1049           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag f in regular expression \"/contact@.*\\..*/f\".");
    1050             : 
    1051           2 :         advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex", {"/contact@.*\\..*/f"}));
    1052           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1053             : 
    1054           1 :         CATCH_REQUIRE(regex_validator != nullptr);
    1055           1 :         CATCH_REQUIRE(regex_validator->name() == "regex");
    1056             : 
    1057           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
    1058           1 :         CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
    1059           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@m2osw.com"));
    1060           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@M2OSW.com"));
    1061             : 
    1062           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
    1063           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
    1064             :     CATCH_END_SECTION()
    1065             : 
    1066          12 :     CATCH_START_SECTION("Verify invalid regex flags")
    1067           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag * in regular expression \"/contact@.*\\..*\".");
    1068           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag . in regular expression \"/contact@.*\\..*\".");
    1069           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag . in regular expression \"/contact@.*\\..*\".");
    1070           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag \\ in regular expression \"/contact@.*\\..*\".");
    1071           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag * in regular expression \"/contact@.*\\..*\".");
    1072           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag . in regular expression \"/contact@.*\\..*\".");
    1073           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag @ in regular expression \"/contact@.*\\..*\".");
    1074           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag t in regular expression \"/contact@.*\\..*\".");
    1075           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag c in regular expression \"/contact@.*\\..*\".");
    1076           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag a in regular expression \"/contact@.*\\..*\".");
    1077           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag t in regular expression \"/contact@.*\\..*\".");
    1078           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag n in regular expression \"/contact@.*\\..*\".");
    1079           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag o in regular expression \"/contact@.*\\..*\".");
    1080           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag c in regular expression \"/contact@.*\\..*\".");
    1081           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: invalid regex definition, ending / is missing in \"/contact@.*\\..*\".");
    1082             : 
    1083           2 :         advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex", {"/contact@.*\\..*"}));
    1084           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1085             : 
    1086           1 :         CATCH_REQUIRE(regex_validator != nullptr);
    1087           1 :         CATCH_REQUIRE(regex_validator->name() == "regex");
    1088             : 
    1089           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
    1090           1 :         CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
    1091           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@m2osw.com"));
    1092           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@M2OSW.com"));
    1093             : 
    1094           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
    1095           1 :         CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
    1096             :     CATCH_END_SECTION()
    1097             : 
    1098          12 :     CATCH_START_SECTION("Verify regex refuses more than one parameter")
    1099           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    1100             :                           "error: validator_regex() only supports one parameter;"
    1101             :                           " 2 were supplied;"
    1102             :                           " single or double quotation may be required?");
    1103           1 :         advgetopt::validator::create("regex", {"[a-z]+", "[0-9]+"});
    1104           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1105             : 
    1106           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    1107             :                           "error: validator_regex() only supports one parameter;"
    1108             :                           " 2 were supplied;"
    1109             :                           " single or double quotation may be required?");
    1110           1 :         advgetopt::validator::create("regex([a-z]+, [0-9]+)");
    1111           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1112             : 
    1113           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    1114             :                           "error: validator_regex() only supports one parameter;"
    1115             :                           " 3 were supplied;"
    1116             :                           " single or double quotation may be required?");
    1117           1 :         advgetopt::validator::create("regex", {"[a-z]+", "[0-9]+", "[#!@]"});
    1118           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1119             : 
    1120           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    1121             :                           "error: validator_regex() only supports one parameter;"
    1122             :                           " 3 were supplied;"
    1123             :                           " single or double quotation may be required?");
    1124           1 :         advgetopt::validator::create("regex(\"[a-z]+\", \"[0-9]+\", \"[#!@]\")");
    1125           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1126             :     CATCH_END_SECTION()
    1127             : 
    1128          12 :     CATCH_START_SECTION("Verify missing ')' in string based create")
    1129           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    1130             :                   advgetopt::validator::create("integer(1...7")
    1131             :                 , advgetopt::getopt_logic_error
    1132             :                 , Catch::Matchers::ExceptionMessage(
    1133             :                           "getopt_logic_error: invalid validator parameter definition: \"integer(1...7\", the ')' is missing."));
    1134             : 
    1135           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    1136             :                   advgetopt::validator::create("regex([a-z]+")
    1137             :                 , advgetopt::getopt_logic_error
    1138             :                 , Catch::Matchers::ExceptionMessage(
    1139             :                           "getopt_logic_error: invalid validator parameter definition: \"regex([a-z]+\", the ')' is missing."));
    1140             :     CATCH_END_SECTION()
    1141          12 : }
    1142             : 
    1143             : 
    1144             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13