LCOV - code coverage report
Current view: top level - tests - catch_options_files.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 96.2 % 773 744
Test Date: 2026-01-18 09:38:57 Functions: 100.0 % 2 2
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2006-2025  Made to Order Software Corp.  All Rights Reserved
       2              : //
       3              : // https://snapwebsites.org/project/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/exception.h>
      23              : 
      24              : 
      25              : // self
      26              : //
      27              : #include    "catch_main.h"
      28              : 
      29              : 
      30              : // snapdev
      31              : //
      32              : #include    <snapdev/pathinfo.h>
      33              : #include    <snapdev/safe_setenv.h>
      34              : 
      35              : 
      36              : // C++
      37              : //
      38              : #include    <fstream>
      39              : 
      40              : 
      41              : // last include
      42              : //
      43              : #include    <snapdev/poison.h>
      44              : 
      45              : 
      46              : 
      47              : 
      48            9 : CATCH_TEST_CASE("valid_options_files", "[options][valid][files]")
      49              : {
      50            9 :     CATCH_START_SECTION("valid_options_files: check the default path with a nullptr (not a very good test, though)")
      51              :     {
      52            1 :         advgetopt::option const options[] =
      53              :         {
      54              :             advgetopt::define_option(
      55              :                   advgetopt::Name("verbose")
      56              :                 , advgetopt::ShortName('v')
      57              :                 , advgetopt::Flags(advgetopt::standalone_all_flags<>())
      58              :                 , advgetopt::Help("a verbose like option, select it or not.")
      59              :             ),
      60              :             advgetopt::end_options()
      61              :         };
      62              : 
      63            1 :         advgetopt::options_environment options_env;
      64            1 :         options_env.f_project_name = "this-is-the-name-of-a-test-project-which-wont-ever-exist";
      65            1 :         options_env.f_options = options;
      66            1 :         options_env.f_environment_variable_name = "ADVGETOPT_TEST_OPTIONS";
      67            1 :         options_env.f_help_header = "Usage: test valid options from file";
      68              : 
      69            1 :         char const * sub_cargv[] =
      70              :         {
      71              :             "tests/unittests/no_file_to_load",
      72              :             "--verbose",
      73              :             nullptr
      74              :         };
      75            1 :         int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
      76            1 :         char ** sub_argv = const_cast<char **>(sub_cargv);
      77              : 
      78            1 :         advgetopt::getopt opt(options_env, sub_argc, sub_argv);
      79              : 
      80              :         // check that the result is valid
      81              : 
      82              :         // an invalid parameter, MUST NOT EXIST
      83            3 :         CATCH_REQUIRE(opt.get_option("invalid-parameter") == nullptr);
      84            3 :         CATCH_REQUIRE_FALSE(opt.is_defined("invalid-parameter"));
      85              : 
      86              :         // the valid parameter
      87            3 :         CATCH_REQUIRE(opt.is_defined("verbose"));
      88            3 :         CATCH_REQUIRE(opt.get_default("verbose").empty());
      89            3 :         CATCH_REQUIRE(opt.size("verbose") == 1);
      90              : 
      91              :         // other parameters
      92            1 :         CATCH_REQUIRE(opt.get_program_name() == "no_file_to_load");
      93            1 :         CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/no_file_to_load");
      94            1 :     }
      95            9 :     CATCH_END_SECTION()
      96              : 
      97            9 :     CATCH_START_SECTION("valid_options_files: check the default path with an empty string (not a very good test, though)")
      98              :     {
      99            1 :         advgetopt::option const options[] =
     100              :         {
     101              :             advgetopt::define_option(
     102              :                   advgetopt::Name("verbose")
     103              :                 , advgetopt::ShortName('v')
     104              :                 , advgetopt::Flags(advgetopt::standalone_all_flags<>())
     105              :                 , advgetopt::Help("a verbose like option, select it or not.")
     106              :             ),
     107              :             advgetopt::end_options()
     108              :         };
     109              : 
     110            1 :         advgetopt::options_environment options_env;
     111            1 :         options_env.f_project_name = "this-is-the-name-of-a-test-project-which-wont-ever-exist";
     112            1 :         options_env.f_options = options;
     113            1 :         options_env.f_options_files_directory = "";
     114            1 :         options_env.f_environment_variable_name = "ADVGETOPT_TEST_OPTIONS";
     115            1 :         options_env.f_help_header = "Usage: test valid options from file";
     116              : 
     117            1 :         char const * sub_cargv[] =
     118              :         {
     119              :             "tests/unittests/no_file_to_load",
     120              :             "--verbose",
     121              :             nullptr
     122              :         };
     123            1 :         int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
     124            1 :         char ** sub_argv = const_cast<char **>(sub_cargv);
     125              : 
     126            1 :         advgetopt::getopt opt(options_env, sub_argc, sub_argv);
     127              : 
     128              :         // check that the result is valid
     129              : 
     130              :         // an invalid parameter, MUST NOT EXIST
     131            3 :         CATCH_REQUIRE(opt.get_option("invalid-parameter") == nullptr);
     132            3 :         CATCH_REQUIRE_FALSE(opt.is_defined("invalid-parameter"));
     133              : 
     134              :         // the valid parameter
     135            3 :         CATCH_REQUIRE(opt.is_defined("verbose"));
     136            3 :         CATCH_REQUIRE(opt.get_default("verbose").empty());
     137            3 :         CATCH_REQUIRE(opt.size("verbose") == 1);
     138              : 
     139              :         // other parameters
     140            1 :         CATCH_REQUIRE(opt.get_program_name() == "no_file_to_load");
     141            1 :         CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/no_file_to_load");
     142            1 :     }
     143            9 :     CATCH_END_SECTION()
     144              : 
     145            9 :     CATCH_START_SECTION("valid_options_files: check the parsing of a valid options.ini file (one option)")
     146              :     {
     147              :         // create a file and make sure it's not read if the project name
     148              :         // is empty
     149              :         //
     150            1 :         std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
     151            1 :         tmpdir += "/shared/advgetopt";
     152            1 :         std::stringstream ss;
     153            1 :         ss << "mkdir -p " << tmpdir;
     154            1 :         if(system(ss.str().c_str()) != 0)
     155              :         {
     156            0 :             std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
     157            0 :             exit(1);
     158              :         }
     159            1 :         std::string const options_filename(tmpdir + "/no-project-name.ini");
     160              : 
     161            1 :         advgetopt::option const valid_options_from_file_list[] =
     162              :         {
     163              :             advgetopt::define_option(
     164              :                   advgetopt::Name("verbose")
     165              :                 , advgetopt::ShortName('v')
     166              :                 , advgetopt::Flags(advgetopt::standalone_all_flags<>())
     167              :                 , advgetopt::Help("a verbose like option, select it or not.")
     168              :             ),
     169              :             advgetopt::end_options()
     170              :         };
     171              : 
     172            1 :         advgetopt::options_environment valid_options_from_file;
     173            1 :         valid_options_from_file.f_project_name = nullptr;
     174            1 :         valid_options_from_file.f_options = valid_options_from_file_list;
     175            1 :         valid_options_from_file.f_options_files_directory = tmpdir.c_str();
     176            1 :         valid_options_from_file.f_environment_variable_name = "ADVGETOPT_TEST_OPTIONS";
     177            1 :         valid_options_from_file.f_help_header = "Usage: test valid options from file";
     178              : 
     179              :         {
     180            1 :             std::ofstream options_file;
     181            1 :             options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
     182            1 :             CATCH_REQUIRE(options_file.good());
     183              :             options_file <<
     184              :                 "# Auto-generated\n"
     185              : 
     186              :                 "[no-project-name]\n"
     187              :                 "shortname=n\n"
     188              :                 "default='inexistent'\n"
     189              :                 "environment_variable_name=NO_PROJECT_NAME\n"
     190              :                 "help=Testing that this doesn't get loaded\n"
     191            1 :                 "allowed=command-line,environment-variable,configuration-file\n"
     192              :             ;
     193            1 :         }
     194              : 
     195            1 :         char const * sub_cargv[] =
     196              :         {
     197              :             "tests/unittests/file_not_loaded",
     198              :             "--verbose",
     199              :             nullptr
     200              :         };
     201            1 :         int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
     202            1 :         char ** sub_argv = const_cast<char **>(sub_cargv);
     203              : 
     204            1 :         advgetopt::getopt opt(valid_options_from_file, sub_argc, sub_argv);
     205              : 
     206              :         // check that the result is valid
     207              : 
     208              :         // an invalid parameter, MUST NOT EXIST
     209            3 :         CATCH_REQUIRE(opt.get_option("invalid-parameter") == nullptr);
     210            3 :         CATCH_REQUIRE_FALSE(opt.is_defined("invalid-parameter"));
     211              : 
     212              :         // the valid parameter
     213            3 :         CATCH_REQUIRE(opt.is_defined("verbose"));
     214            3 :         CATCH_REQUIRE(opt.get_default("verbose").empty());
     215            3 :         CATCH_REQUIRE(opt.size("verbose") == 1);
     216              : 
     217              :         // "--no-project-name"
     218            3 :         CATCH_REQUIRE(opt.get_option("no-project-name") == nullptr);
     219            3 :         CATCH_REQUIRE_FALSE(opt.is_defined("no-project-name"));
     220              : 
     221              :         // other parameters
     222            1 :         CATCH_REQUIRE(opt.get_program_name() == "file_not_loaded");
     223            1 :         CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/file_not_loaded");
     224            1 :     }
     225            9 :     CATCH_END_SECTION()
     226              : 
     227            9 :     CATCH_START_SECTION("valid_options_files: project name is an empty string")
     228              :     {
     229              :         // create a file and make sure it's not read if the project name
     230              :         // is empty
     231              :         //
     232            1 :         std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
     233            1 :         tmpdir += "/shared/advgetopt";
     234            1 :         std::stringstream ss;
     235            1 :         ss << "mkdir -p " << tmpdir;
     236            1 :         if(system(ss.str().c_str()) != 0)
     237              :         {
     238            0 :             std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
     239            0 :             exit(1);
     240              :         }
     241            1 :         std::string const options_filename(tmpdir + "/empty-string.ini");
     242              : 
     243            1 :         advgetopt::option const valid_options_from_file_list[] =
     244              :         {
     245              :             advgetopt::define_option(
     246              :                   advgetopt::Name("verbose")
     247              :                 , advgetopt::ShortName('v')
     248              :                 , advgetopt::Flags(advgetopt::standalone_all_flags<>())
     249              :                 , advgetopt::Help("a verbose like option, select it or not.")
     250              :             ),
     251              :             advgetopt::end_options()
     252              :         };
     253              : 
     254            1 :         advgetopt::options_environment valid_options_from_file;
     255            1 :         valid_options_from_file.f_project_name = "";
     256            1 :         valid_options_from_file.f_options = valid_options_from_file_list;
     257            1 :         valid_options_from_file.f_options_files_directory = tmpdir.c_str();
     258            1 :         valid_options_from_file.f_environment_variable_name = "ADVGETOPT_TEST_OPTIONS";
     259            1 :         valid_options_from_file.f_help_header = "Usage: test valid options from file";
     260              : 
     261              :         {
     262            1 :             std::ofstream options_file;
     263            1 :             options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
     264            1 :             CATCH_REQUIRE(options_file.good());
     265              :             options_file <<
     266              :                 "# Auto-generated\n"
     267              : 
     268              :                 "[no-project-name]\n"
     269              :                 "shortname=n\n"
     270              :                 "default='inexistent'\n"
     271              :                 "help=Testing that this doesn't get loaded\n"
     272            1 :                 "allowed=command-line,environment-variable,configuration-file\n"
     273              :             ;
     274            1 :         }
     275              : 
     276            1 :         char const * sub_cargv[] =
     277              :         {
     278              :             "tests/unittests/file_not_loaded",
     279              :             "--verbose",
     280              :             nullptr
     281              :         };
     282            1 :         int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
     283            1 :         char ** sub_argv = const_cast<char **>(sub_cargv);
     284              : 
     285            1 :         advgetopt::getopt opt(valid_options_from_file, sub_argc, sub_argv);
     286              : 
     287              :         // check that the result is valid
     288              : 
     289              :         // an invalid parameter, MUST NOT EXIST
     290            3 :         CATCH_REQUIRE(opt.get_option("invalid-parameter") == nullptr);
     291            3 :         CATCH_REQUIRE_FALSE(opt.is_defined("invalid-parameter"));
     292              : 
     293              :         // the valid parameter
     294            3 :         CATCH_REQUIRE(opt.is_defined("verbose"));
     295            3 :         CATCH_REQUIRE(opt.get_default("verbose").empty());
     296            3 :         CATCH_REQUIRE(opt.size("verbose") == 1);
     297              : 
     298              :         // "--no-project-name"
     299            3 :         CATCH_REQUIRE(opt.get_option("no-project-name") == nullptr);
     300            3 :         CATCH_REQUIRE_FALSE(opt.is_defined("no-project-name"));
     301              : 
     302            1 :         advgetopt::option_info::map_by_name_t const & all_options(opt.get_options());
     303            3 :         auto const o(all_options.find("no-project-name"));
     304            1 :         CATCH_REQUIRE(o == all_options.end());
     305              : 
     306              :         // other parameters
     307            1 :         CATCH_REQUIRE(opt.get_program_name() == "file_not_loaded");
     308            1 :         CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/file_not_loaded");
     309            1 :     }
     310            9 :     CATCH_END_SECTION()
     311              : 
     312            9 :     CATCH_START_SECTION("valid_options_files: check the parsing of a valid options.ini file (many options)")
     313              :     {
     314            1 :         std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
     315            1 :         tmpdir += "/shared/advgetopt";
     316            1 :         std::stringstream ss;
     317            1 :         ss << "mkdir -p " << tmpdir;
     318            1 :         if(system(ss.str().c_str()) != 0)
     319              :         {
     320            0 :             std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
     321            0 :             exit(1);
     322              :         }
     323            1 :         std::string const options_filename(tmpdir + "/unittest.ini");
     324              : 
     325            1 :         advgetopt::option const valid_options_from_file_list[] =
     326              :         {
     327              :             advgetopt::define_option(
     328              :                   advgetopt::Name("verbose")
     329              :                 , advgetopt::ShortName('v')
     330              :                 , advgetopt::Flags(advgetopt::standalone_all_flags<>())
     331              :                 , advgetopt::Help("a verbose like option, select it or not.")
     332              :             ),
     333              :             advgetopt::end_options()
     334              :         };
     335              : 
     336            1 :         advgetopt::options_environment valid_options_from_file;
     337            1 :         valid_options_from_file.f_project_name = "unittest";
     338            1 :         valid_options_from_file.f_options = valid_options_from_file_list;
     339            1 :         valid_options_from_file.f_options_files_directory = tmpdir.c_str();
     340            1 :         valid_options_from_file.f_environment_variable_name = "ADVGETOPT_TEST_OPTIONS";
     341            1 :         valid_options_from_file.f_help_header = "Usage: test valid options from file";
     342              : 
     343            1 :         snapdev::safe_setenv env("ADVGETOPT_TEST_OPTIONS"
     344              :                             , "--verbose"
     345              :                              " --more purple"
     346              :                              " -f left.txt center.txt right.txt"
     347              :                              " --size 519"
     348              :                              " --from"
     349            5 :                              " --output destination.txt");
     350              : 
     351              :         {
     352            1 :             std::ofstream options_file;
     353            1 :             options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
     354            1 :             CATCH_REQUIRE(options_file.good());
     355              :             options_file <<
     356              :                 "# Auto-generated\n"
     357              : 
     358              :                 "[more]\n"
     359              :                 "shortname=m\n"
     360              :                 "default='More Stuff'\n"
     361              :                 "help=Allow for more stuff to be added\n"
     362              :                 "validator=regex(\"purple|yellow|blue|red|green|orange|brown\")\n"
     363              :                 "allowed=command-line,environment-variable,configuration-file\n"
     364              :                 "show-usage-on-error\n"
     365              :                 "required\n"
     366              : 
     367              :                 "[size]\n"
     368              :                 "shortname=s\n"
     369              :                 "help=Specify the size\n"
     370              :                 "validator=/[0-9]+/\n"
     371              :                 "allowed=environment-variable,configuration-file\n"
     372              :                 "default=31\n"
     373              :                 "required\n"
     374              : 
     375              :                 "[files]\n"
     376              :                 "shortname=f\n"
     377              :                 "help=List of file names\n"
     378              :                 "validator=/.*\\.txt/i\n"
     379              :                 "allowed=command-line,environment-variable\n"
     380              :                 "multiple\n"
     381              :                 "required\n"
     382              : 
     383              :                 "[from]\n"
     384              :                 "shortname=F\n"
     385              :                 "help=Request for the geographical location representing the origin of the files; optionally you can specify the format\n"
     386              :                 "validator=integer\n"
     387              :                 "environment_variable_name=FROM\n"
     388              :                 "allowed=command-line,environment-variable,configuration-file\n"
     389              : 
     390              :                 "[output]\n"
     391              :                 "shortname=o\n"
     392              :                 "default=a.out\n"
     393              :                 "help=output file\n"
     394              :                 "allowed=environment-variable\n"
     395              :                 "environment_variable_name=OUTPUT\n"
     396              :                 "required\n"
     397              : 
     398              :                 "[license]\n"
     399              :                 "shortname=l\n"
     400              :                 "help=show this test license\n"
     401              :                 "allowed=command-line\n"
     402              :                 "no-arguments\n"
     403              : 
     404              :                 "[licence]\n"
     405              :                 "alias=license\n"
     406              :                 "allowed=command-line\n"
     407            1 :                 "no-arguments\n"
     408              :             ;
     409            1 :         }
     410              : 
     411            1 :         char const * sub_cargv[] =
     412              :         {
     413              :             "tests/unittests/valid_options_files",
     414              :             "--verbose",
     415              :             "--licence",
     416              :             nullptr
     417              :         };
     418            1 :         int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
     419            1 :         char ** sub_argv = const_cast<char **>(sub_cargv);
     420              : 
     421            1 :         advgetopt::getopt opt(valid_options_from_file, sub_argc, sub_argv);
     422              : 
     423              :         // check that the result is valid
     424            1 :         advgetopt::option_info::map_by_name_t const & options(opt.get_options());
     425            1 :         CATCH_REQUIRE(options.size() == 8);
     426              : 
     427              :         // an invalid parameter, MUST NOT EXIST
     428            3 :         CATCH_REQUIRE(opt.get_option("invalid-parameter") == nullptr);
     429            3 :         CATCH_REQUIRE_FALSE(opt.is_defined("invalid-parameter"));
     430              : 
     431              :         // the valid parameter
     432            3 :         CATCH_REQUIRE(opt.is_defined("verbose"));
     433            3 :         CATCH_REQUIRE(opt.get_default("verbose").empty());
     434            3 :         CATCH_REQUIRE(opt.size("verbose") == 1);
     435              : 
     436              :         {
     437            3 :             auto const o(options.find("verbose"));
     438            1 :             CATCH_REQUIRE(o != options.end());
     439            1 :             CATCH_REQUIRE(o->second->get_short_name() == U'v');
     440            1 :             CATCH_REQUIRE(o->second->get_help() == "a verbose like option, select it or not.");
     441            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_COMMAND_LINE));
     442            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE));
     443            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_CONFIGURATION_FILE));
     444              :         }
     445              : 
     446              :         // "--more"
     447            3 :         CATCH_REQUIRE(opt.is_defined("more"));
     448            3 :         CATCH_REQUIRE(opt.get_string("more") == "purple");
     449            3 :         CATCH_REQUIRE(opt.get_default("more") == "More Stuff");
     450            3 :         CATCH_REQUIRE(opt.size("more") == 1);
     451              : 
     452              :         {
     453            3 :             auto const o(options.find("more"));
     454            1 :             CATCH_REQUIRE(o != options.end());
     455            1 :             CATCH_REQUIRE(o->second->get_short_name() == U'm');
     456            1 :             CATCH_REQUIRE(o->second->get_help() == "Allow for more stuff to be added");
     457            1 :             CATCH_REQUIRE(o->second->has_default());
     458            1 :             CATCH_REQUIRE(o->second->get_default() == "More Stuff");
     459            1 :             CATCH_REQUIRE(o->second->get_validator()->name() == "regex");
     460            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_REQUIRED));
     461            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_SHOW_USAGE_ON_ERROR));
     462            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_COMMAND_LINE));
     463            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE));
     464            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_CONFIGURATION_FILE));
     465              :         }
     466              : 
     467              :         // "--size <value>"
     468            3 :         CATCH_REQUIRE(opt.is_defined("size"));
     469            3 :         CATCH_REQUIRE(opt.get_string("size") == "519");
     470            3 :         CATCH_REQUIRE(opt.get_string("size", 0) == "519");
     471            3 :         CATCH_REQUIRE(opt.get_default("size") == "31");
     472            3 :         CATCH_REQUIRE(opt.size("size") == 1);
     473            3 :         CATCH_REQUIRE(opt.get_long("size") == 519);
     474              : 
     475              :         {
     476            3 :             auto const o(options.find("size"));
     477            1 :             CATCH_REQUIRE(o != options.end());
     478            1 :             CATCH_REQUIRE(o->second->get_short_name() == U's');
     479            1 :             CATCH_REQUIRE(o->second->get_help() == "Specify the size");
     480            1 :             CATCH_REQUIRE(o->second->has_default());
     481            1 :             CATCH_REQUIRE(o->second->get_default() == "31");
     482            1 :             CATCH_REQUIRE(o->second->get_validator()->name() == "regex");
     483            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_REQUIRED));
     484            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE));
     485            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_CONFIGURATION_FILE));
     486              :         }
     487              : 
     488              :         // "--files"
     489            3 :         CATCH_REQUIRE(opt.is_defined("files"));
     490            3 :         CATCH_REQUIRE(opt.get_string("files") == "left.txt");
     491            3 :         CATCH_REQUIRE(opt.get_string("files", 0) == "left.txt");
     492            3 :         CATCH_REQUIRE(opt.get_string("files", 1) == "center.txt");
     493            3 :         CATCH_REQUIRE(opt.get_string("files", 2) == "right.txt");
     494            3 :         CATCH_REQUIRE(opt.get_default("files").empty());
     495            3 :         CATCH_REQUIRE(opt.size("files") == 3);
     496              : 
     497              :         {
     498            3 :             auto const o(options.find("files"));
     499            1 :             CATCH_REQUIRE(o != options.end());
     500            1 :             CATCH_REQUIRE(o->second->get_short_name() == U'f');
     501            1 :             CATCH_REQUIRE(o->second->get_help() == "List of file names");
     502            1 :             CATCH_REQUIRE_FALSE(o->second->has_default());
     503            1 :             CATCH_REQUIRE(o->second->get_validator()->name() == "regex");
     504            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_COMMAND_LINE));
     505            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE));
     506            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_MULTIPLE));
     507            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_REQUIRED));
     508              :         }
     509              : 
     510              :         // "--from"
     511            3 :         CATCH_REQUIRE(opt.is_defined("from"));
     512            3 :         CATCH_REQUIRE(opt.size("from") == 1);
     513            3 :         CATCH_REQUIRE(opt.get_string("from") == "");
     514            3 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: invalid number () in parameter --from at offset 0.");
     515            3 :         CATCH_REQUIRE(opt.get_long("from") == -1);
     516            1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
     517            3 :         CATCH_REQUIRE(opt.get_default("from").empty());
     518              : 
     519              :         {
     520            3 :             auto const o(options.find("from"));
     521            1 :             CATCH_REQUIRE(o != options.end());
     522            1 :             CATCH_REQUIRE(o->second->get_short_name() == U'F');
     523            1 :             CATCH_REQUIRE(o->second->get_help() == "Request for the geographical location representing the origin of the files; optionally you can specify the format");
     524            1 :             CATCH_REQUIRE_FALSE(o->second->has_default());
     525            1 :             CATCH_REQUIRE(o->second->get_validator()->name() == "integer");
     526            1 :             CATCH_REQUIRE(o->second->get_environment_variable_name() == "FROM");
     527            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_COMMAND_LINE));
     528            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE));
     529            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_CONFIGURATION_FILE));
     530              :         }
     531              : 
     532              :         // "--output"
     533            3 :         CATCH_REQUIRE(opt.is_defined("output"));
     534            3 :         CATCH_REQUIRE(opt.get_string("output") == "destination.txt"); // same as index = 0
     535            3 :         CATCH_REQUIRE(opt.get_string("output",  0) == "destination.txt");
     536            3 :         CATCH_REQUIRE(opt.get_default("output") == "a.out");
     537            3 :         CATCH_REQUIRE(opt.size("output") == 1);
     538              : 
     539              :         {
     540            3 :             auto const o(options.find("output"));
     541            1 :             CATCH_REQUIRE(o != options.end());
     542            1 :             CATCH_REQUIRE(o->second->get_short_name() == U'o');
     543            1 :             CATCH_REQUIRE(o->second->get_help() == "output file");
     544            1 :             CATCH_REQUIRE(o->second->has_default());
     545            1 :             CATCH_REQUIRE(o->second->get_default() == "a.out");
     546            1 :             CATCH_REQUIRE(o->second->get_validator() == nullptr);
     547            1 :             CATCH_REQUIRE(o->second->get_environment_variable_name() == "OUTPUT");
     548            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_REQUIRED));
     549            1 :             CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE));
     550              :         }
     551              : 
     552              :         // "--license" / "--licence"
     553            3 :         CATCH_REQUIRE(opt.is_defined("license"));
     554            3 :         CATCH_REQUIRE(opt.is_defined("licence"));
     555            3 :         CATCH_REQUIRE(opt.get_string("license") == "");
     556            3 :         CATCH_REQUIRE(opt.get_string("licence") == "");
     557            3 :         CATCH_REQUIRE(opt.get_default("license").empty());
     558            3 :         CATCH_REQUIRE(opt.get_default("licence").empty());
     559            3 :         CATCH_REQUIRE(opt.size("license") == 1);
     560            3 :         CATCH_REQUIRE(opt.size("licence") == 1);
     561              : 
     562              :         {
     563            3 :             auto const os(options.find("license"));
     564            1 :             CATCH_REQUIRE(os != options.end());
     565            1 :             CATCH_REQUIRE(os->second->get_short_name() == U'l');
     566            1 :             CATCH_REQUIRE(os->second->get_help() == "show this test license");
     567            1 :             CATCH_REQUIRE_FALSE(os->second->has_default());
     568            1 :             CATCH_REQUIRE(os->second->get_validator() == nullptr);
     569            1 :             CATCH_REQUIRE(os->second->has_flag(advgetopt::GETOPT_FLAG_FLAG));
     570            1 :             CATCH_REQUIRE(os->second->has_flag(advgetopt::GETOPT_FLAG_COMMAND_LINE));
     571              : 
     572            3 :             auto const oc(options.find("licence"));
     573            1 :             CATCH_REQUIRE(oc != options.end());
     574            1 :             CATCH_REQUIRE(oc->second->get_short_name() == U'\0');
     575            1 :             CATCH_REQUIRE(oc->second->get_help() == "license");     // this is the name of the alias option
     576            1 :             CATCH_REQUIRE(oc->second->get_alias_destination() == os->second);
     577            1 :             CATCH_REQUIRE_FALSE(oc->second->has_default());
     578            1 :             CATCH_REQUIRE(os->second->get_validator() == nullptr);
     579            1 :             CATCH_REQUIRE(oc->second->has_flag(advgetopt::GETOPT_FLAG_FLAG));
     580            1 :             CATCH_REQUIRE(oc->second->has_flag(advgetopt::GETOPT_FLAG_COMMAND_LINE));
     581              :         }
     582              : 
     583              :         // other parameters
     584            1 :         CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
     585            1 :         CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
     586              : 
     587            1 :         char const * sub_cargv2[] =
     588              :         {
     589              :             "this/is/ignored",
     590              :             "--from",
     591              :             "1001",
     592              :             nullptr
     593              :         };
     594            1 :         int const sub_argc2(sizeof(sub_cargv2) / sizeof(sub_cargv2[0]) - 1);
     595            1 :         char ** sub_argv2 = const_cast<char **>(sub_cargv2);
     596              : 
     597            1 :         opt.parse_arguments(sub_argc2, sub_argv2, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
     598              : 
     599              :         // "--from"
     600            3 :         CATCH_REQUIRE(opt.is_defined("from"));
     601            3 :         CATCH_REQUIRE(opt.size("from") == 1);
     602            3 :         CATCH_REQUIRE(opt.get_string("from") == "1001");
     603            3 :         CATCH_REQUIRE(opt.get_long("from") == 1001);
     604            3 :         CATCH_REQUIRE(opt.get_default("from").empty());
     605              : 
     606              :         // other parameters
     607            1 :         CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
     608            1 :         CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
     609              : 
     610              :         // keep the last value...
     611              :         //
     612            1 :         opt.parse_environment_variable();
     613              : 
     614              :         // "--from"
     615            3 :         CATCH_REQUIRE(opt.is_defined("from"));
     616            3 :         CATCH_REQUIRE(opt.size("from") == 1);
     617            3 :         CATCH_REQUIRE(opt.get_string("from") == "");
     618            3 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: invalid number () in parameter --from at offset 0.");
     619            3 :         CATCH_REQUIRE(opt.get_long("from") == -1);
     620            1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
     621            3 :         CATCH_REQUIRE(opt.get_default("from").empty());
     622              : 
     623              :         // other parameters
     624            1 :         CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
     625            1 :         CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
     626              : 
     627              :         // a reset will restore the state
     628              :         //
     629            1 :         opt.reset();
     630              : 
     631              :         // the valid parameter
     632            3 :         CATCH_REQUIRE_FALSE(opt.is_defined("verbose"));
     633            3 :         CATCH_REQUIRE(opt.get_default("verbose").empty());
     634            3 :         CATCH_REQUIRE(opt.size("verbose") == 0);
     635              : 
     636              :         // "--from"
     637            3 :         CATCH_REQUIRE_FALSE(opt.is_defined("from"));
     638            3 :         CATCH_REQUIRE(opt.get_default("from").empty());
     639            3 :         CATCH_REQUIRE(opt.size("from") == 0);
     640              : 
     641            1 :         opt.parse_environment_variable();
     642            1 :         opt.parse_arguments(sub_argc2, sub_argv2, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
     643              : 
     644              :         // "--from"
     645            3 :         CATCH_REQUIRE(opt.is_defined("from"));
     646            3 :         CATCH_REQUIRE(opt.get_string("from") == "1001");
     647            3 :         CATCH_REQUIRE(opt.get_long("from") == 1001);
     648            3 :         CATCH_REQUIRE(opt.get_default("from").empty());
     649            3 :         CATCH_REQUIRE(opt.size("from") == 1);
     650              : 
     651              :         // other parameters
     652            1 :         CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
     653            1 :         CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
     654              : 
     655              : 
     656              :         // test that the validators do work here (i.e. generate errors as
     657              :         // expected when we use the wrong options.)
     658              :         //
     659              :         {
     660            1 :             snapdev::safe_setenv subenv("ADVGETOPT_TEST_OPTIONS"
     661              :                                 , "--verbose"
     662              :                                  " --size '1001 meters'"
     663              :                                  " -f valid.cpp"
     664              :                                  " --from auto-build"
     665            5 :                                  " --more black");
     666            1 :             opt.define_environment_variable_data();
     667              : 
     668            3 :             SNAP_CATCH2_NAMESPACE::push_expected_log("error: input \"1001 meters\" given to parameter --size is not considered valid: did not match the regex.");
     669            3 :             SNAP_CATCH2_NAMESPACE::push_expected_log("error: input \"valid.cpp\" given to parameter --files is not considered valid: did not match the regex.");
     670            3 :             SNAP_CATCH2_NAMESPACE::push_expected_log("error: input \"auto-build\" given to parameter --from is not considered valid: not a valid number.");
     671            3 :             SNAP_CATCH2_NAMESPACE::push_expected_log("error: input \"black\" given to parameter --more is not considered valid: did not match the regex.");
     672            1 :             opt.parse_environment_variable();
     673            1 :             SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
     674            1 :         }
     675            1 :     }
     676            9 :     CATCH_END_SECTION()
     677              : 
     678            9 :     CATCH_START_SECTION("valid_options_files: verify that options with 2 or more namespaces fail")
     679              :     {
     680            1 :         std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
     681            1 :         tmpdir += "/shared/advgetopt-double-namespace";
     682            1 :         std::stringstream ss;
     683            1 :         ss << "mkdir -p " << tmpdir;
     684            1 :         if(system(ss.str().c_str()) != 0)
     685              :         {
     686            0 :             std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
     687            0 :             exit(1);
     688              :         }
     689            1 :         std::string const options_filename(tmpdir + "/unittest.ini");
     690              : 
     691            1 :         advgetopt::option const valid_options_from_file_list[] =
     692              :         {
     693              :             advgetopt::define_option(
     694              :                   advgetopt::Name("verbose")
     695              :                 , advgetopt::ShortName('v')
     696              :                 , advgetopt::Flags(advgetopt::standalone_all_flags<>())
     697              :                 , advgetopt::Help("a verbose like option, select it or not.")
     698              :             ),
     699              :             advgetopt::end_options()
     700              :         };
     701              : 
     702            1 :         advgetopt::options_environment valid_options_from_file;
     703            1 :         valid_options_from_file.f_project_name = "unittest";
     704            1 :         valid_options_from_file.f_options = valid_options_from_file_list;
     705            1 :         valid_options_from_file.f_options_files_directory = tmpdir.c_str();
     706            1 :         valid_options_from_file.f_environment_variable_name = "ADVGETOPT_TEST_OPTIONS";
     707            1 :         valid_options_from_file.f_help_header = "Usage: test valid options from file";
     708              : 
     709            1 :         snapdev::safe_setenv env("ADVGETOPT_TEST_OPTIONS"
     710              :                             , "--verbose"
     711              :                              " --more purple"
     712              :                              " -f left.txt center.txt right.txt"
     713              :                              " --size 519"
     714              :                              " --from"
     715            5 :                              " --output destination.txt");
     716              : 
     717              :         {
     718            1 :             std::ofstream options_file;
     719            1 :             options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
     720            1 :             CATCH_REQUIRE(options_file.good());
     721              :             options_file <<
     722              :                 "# Auto-generated\n"
     723              :                 "\n"
     724              :                 "[more]\n"
     725              :                 "shortname=m\n"
     726              :                 "default='More Stuff'\n"
     727              :                 "help=Allow for more stuff to be added.\n"
     728              :                 "validator=regex(\"purple|yellow|blue|red|green|orange|brown\")\n"
     729              :                 "allowed=command-line,environment-variable,configuration-file\n"
     730              :                 "show-usage-on-error\n"
     731              :                 "required\n"
     732              :                 "\n"
     733              :                 "[size]\n"
     734              :                 "shortname=s\n"
     735              :                 "help=Specify the size.\n"
     736              :                 "validator=/[0-9]+/\n"
     737              :                 "allowed=environment-variable,configuration-file\n"
     738              :                 "default::integer=31\n"
     739              :                 "default::string=\"31\"\n"
     740              :                 "required\n"
     741              :                 "\n"
     742              :                 "[files]\n"
     743              :                 "shortname=f\n"
     744              :                 "help=List of file names.\n"
     745              :                 "validator=/.*\\.txt/i\n"
     746              :                 "allowed=command-line,environment-variable\n"
     747              :                 "multiple\n"
     748              :                 "required\n"
     749              :                 "\n"
     750              :                 "[from]\n"
     751              :                 "shortname=F\n"
     752              :                 "help=Request for the geographical location representing the origin of the files; optionally you can specify the format.\n"
     753              :                 "validator=integer\n"
     754              :                 "environment_variable_name=FROM\n"
     755              :                 "allowed=command-line,environment-variable,configuration-file\n"
     756              :                 "\n"
     757              :                 "[output]\n"
     758              :                 "shortname=o\n"
     759              :                 "default=a.out\n"
     760              :                 "help=output file\n"
     761              :                 "allowed=environment-variable\n"
     762              :                 "environment_variable_name=OUTPUT\n"
     763              :                 "required\n"
     764              :                 "flag::multiple\n"
     765              :                 "\n"
     766              :                 "[license]\n"
     767              :                 "shortname=l\n"
     768              :                 "help=Show this test license.\n"
     769              :                 "allowed=command-line\n"
     770              :                 "no-arguments\n"
     771              :                 "\n"
     772              :                 "[licence]\n"
     773              :                 "alias=license\n"
     774              :                 "allowed=command-line\n"
     775              :                 "no-arguments\n"
     776            1 :                 "\n"
     777              :             ;
     778            1 :         }
     779              : 
     780            1 :         char const * sub_cargv[] =
     781              :         {
     782              :             "tests/unittests/valid_options_files",
     783              :             "--verbose",
     784              :             "--licence",
     785              :             nullptr
     786              :         };
     787            1 :         int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
     788            1 :         char ** sub_argv = const_cast<char **>(sub_cargv);
     789              : 
     790              :         // this is a good test already, but "unfortunately" the errors
     791              :         // happen in the wrong place because only .ini sections are
     792              :         // allowed; so instead we have a second part to the test attempting
     793              :         // to the load the data _manually_ to hit the errors of the load
     794              :         // function
     795              :         //
     796            1 :         std::string errmsg;
     797            1 :         std::string const realpath(snapdev::pathinfo::realpath(options_filename, errmsg));
     798            2 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
     799              :               "error: section \"default::integer\" from parameter \"size::default::integer\" on line 17 in configuration file \""
     800            2 :             + realpath
     801            4 :             + "\" includes a character (\\072) not acceptable for a section or parameter name (controls, space, quotes, and \";#/=:?+\\\").");
     802            2 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
     803              :               "error: section \"default::string\" from parameter \"size::default::string\" on line 18 in configuration file \""
     804            2 :             + realpath
     805            4 :             + "\" includes a character (\\072) not acceptable for a section or parameter name (controls, space, quotes, and \";#/=:?+\\\").");
     806            2 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
     807              :               "error: section \"flag::multiple\" from parameter \"output::flag::multiple\" on line 43 in configuration file \""
     808            2 :             + realpath
     809            4 :             + "\" includes a character (\\072) not acceptable for a section or parameter name (controls, space, quotes, and \";#/=:?+\\\").");
     810            4 :         CATCH_REQUIRE_THROWS_MATCHES(
     811              :                       advgetopt::getopt(valid_options_from_file, sub_argc, sub_argv)
     812              :                     , advgetopt::getopt_exit
     813              :                     , Catch::Matchers::ExceptionMessage(
     814              :                               "getopt_exception: errors were found on your command line, environment variable, or configuration file."));
     815            1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
     816            1 :     }
     817            9 :     CATCH_END_SECTION()
     818              : 
     819            9 :     CATCH_START_SECTION("valid_options_files: verify parse_options_from_file overflow")
     820              :     {
     821            1 :         std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
     822            1 :         tmpdir += "/shared/advgetopt-namespace-overflow";
     823            1 :         std::stringstream ss;
     824            1 :         ss << "mkdir -p " << tmpdir;
     825            1 :         if(system(ss.str().c_str()) != 0)
     826              :         {
     827            0 :             std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
     828            0 :             exit(1);
     829              :         }
     830            1 :         std::string const options_filename(tmpdir + "/unittest.ini");
     831              : 
     832            1 :         advgetopt::options_environment valid_options_from_file;
     833            1 :         valid_options_from_file.f_project_name = "unittest";
     834            1 :         valid_options_from_file.f_help_header = "Usage: test valid fluid-settings options from file";
     835              : 
     836              :         {
     837            1 :             std::ofstream options_file;
     838            1 :             options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
     839            1 :             CATCH_REQUIRE(options_file.good());
     840              :             options_file <<
     841              :                 "# Auto-generated\n"
     842              :                 "\n"
     843              :                 "[color::more]\n"
     844              :                 "default='More Stuff'\n"
     845              :                 "help=Allow for more stuff to be added.\n"
     846              :                 "validator=regex(\"purple|yellow|blue|red|green|orange|brown\")\n"
     847              :                 "allowed=command-line,environment-variable,configuration-file\n"
     848              :                 "show-usage-on-error\n"
     849              :                 "required\n"
     850              :                 "\n"
     851              :                 "[color::size]\n"
     852              :                 "help=Specify the size.\n"
     853              :                 "validator=/[0-9]+/\n"
     854              :                 "allowed=environment-variable,configuration-file\n"
     855              :                 "default=31\n"
     856              :                 "required\n"
     857              :                 "\n"
     858              :                 "[color::files]\n"
     859              :                 "help=List of file names.\n"
     860              :                 "validator=/.*\\.txt/i\n"
     861              :                 "allowed=command-line,environment-variable\n"
     862              :                 "multiple\n"
     863              :                 "required\n"
     864              :                 "\n"
     865              :                 "[dimensions::from]\n"
     866              :                 "help=Request for the geographical location representing the origin of the files; optionally you can specify the format.\n"
     867              :                 "validator=integer\n"
     868              :                 "environment_variable_name=FROM\n"
     869              :                 "allowed=command-line,environment-variable,configuration-file\n"
     870              :                 "\n"
     871              :                 "[dimensions::output]\n"
     872              :                 "default=a.out\n"
     873              :                 "help=output file\n"
     874              :                 "allowed=environment-variable\n"
     875              :                 "environment_variable_name=OUTPUT\n"
     876              :                 "required\n"
     877              :                 "multiple\n"
     878              :                 "\n"
     879              :                 "[us::legal::department::license]\n"
     880              :                 "help=Show this test license.\n"
     881              :                 "allowed=command-line\n"
     882              :                 "no-arguments\n"
     883              :                 "\n"
     884              :                 "[us::legal::department::licence]\n"
     885              :                 "alias=license\n"
     886              :                 "allowed=command-line\n"
     887              :                 "no-arguments\n"
     888            1 :                 "\n"
     889              :             ;
     890            1 :         }
     891              : 
     892            1 :         advgetopt::getopt::pointer_t opts(std::make_shared<advgetopt::getopt>(valid_options_from_file));
     893              : 
     894            3 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: the name of a settings definition must include between 2 and 3 namespaces; \"us::legal::department::licence\" is not considered valid.");
     895            3 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: the name of a settings definition must include between 2 and 3 namespaces; \"us::legal::department::license\" is not considered valid.");
     896            1 :         opts->parse_options_from_file(
     897              :                   options_filename
     898              :                 , 2
     899              :                 , 3);
     900            1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
     901              : 
     902            1 :         advgetopt::option_info::map_by_name_t const & options(opts->get_options());
     903            1 :         CATCH_REQUIRE(options.size() == 5);
     904              : 
     905              :         {
     906            3 :             auto const o(options.find("color::more"));
     907            1 :             CATCH_REQUIRE(o != options.end());
     908            1 :             CATCH_REQUIRE(o->second->get_help() == "Allow for more stuff to be added.");
     909              :         }
     910              : 
     911              :         {
     912            3 :             auto const o(options.find("color::size"));
     913            1 :             CATCH_REQUIRE(o != options.end());
     914            1 :             CATCH_REQUIRE(o->second->get_help() == "Specify the size.");
     915              :         }
     916              : 
     917              :         {
     918            3 :             auto const o(options.find("color::files"));
     919            1 :             CATCH_REQUIRE(o != options.end());
     920            1 :             CATCH_REQUIRE(o->second->get_help() == "List of file names.");
     921              :         }
     922              : 
     923              :         {
     924            3 :             auto const o(options.find("dimensions::from"));
     925            1 :             CATCH_REQUIRE(o != options.end());
     926            1 :             CATCH_REQUIRE(o->second->get_help() == "Request for the geographical location representing the origin of the files; optionally you can specify the format.");
     927              :         }
     928              : 
     929              :         {
     930            3 :             auto const o(options.find("dimensions::output"));
     931            1 :             CATCH_REQUIRE(o != options.end());
     932            1 :             CATCH_REQUIRE(o->second->get_help() == "output file");
     933              :         }
     934              : 
     935              :         {
     936            3 :             auto const o(options.find("us::legal::department::license"));
     937            1 :             CATCH_REQUIRE(o == options.end());
     938              :         }
     939              : 
     940              :         {
     941            3 :             auto const o(options.find("us::legal::department::licence"));
     942            1 :             CATCH_REQUIRE(o == options.end());
     943              :         }
     944            1 :     }
     945            9 :     CATCH_END_SECTION()
     946              : 
     947            9 :     CATCH_START_SECTION("valid_options_files: verify that the parse_options_from_file supports more than one section name (used by fluid-settings)")
     948              :     {
     949            1 :         std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
     950            1 :         tmpdir += "/shared/advgetopt-fluid-namespaces";
     951            1 :         std::stringstream ss;
     952            1 :         ss << "mkdir -p " << tmpdir;
     953            1 :         if(system(ss.str().c_str()) != 0)
     954              :         {
     955            0 :             std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
     956            0 :             exit(1);
     957              :         }
     958            1 :         std::string const options_filename(tmpdir + "/unittest.ini");
     959              : 
     960            1 :         advgetopt::options_environment valid_options_from_file;
     961            1 :         valid_options_from_file.f_project_name = "unittest";
     962            1 :         valid_options_from_file.f_help_header = "Usage: test valid fluid-settings options from file";
     963              : 
     964              :         {
     965            1 :             std::ofstream options_file;
     966            1 :             options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
     967            1 :             CATCH_REQUIRE(options_file.good());
     968              :             options_file <<
     969              :                 "# Auto-generated\n"
     970              :                 "\n"
     971              :                 "[color::more]\n"
     972              :                 "default='More Stuff'\n"
     973              :                 "help=Allow for more stuff to be added.\n"
     974              :                 "validator=regex(\"purple|yellow|blue|red|green|orange|brown\")\n"
     975              :                 "allowed=command-line,environment-variable,configuration-file\n"
     976              :                 "show-usage-on-error\n"
     977              :                 "required\n"
     978              :                 "\n"
     979              :                 "[color::size]\n"
     980              :                 "help=Specify the size.\n"
     981              :                 "validator=/[0-9]+/\n"
     982              :                 "allowed=environment-variable,configuration-file\n"
     983              :                 "default=31\n"
     984              :                 "required\n"
     985              :                 "\n"
     986              :                 "[color::files]\n"
     987              :                 "help=List of file names.\n"
     988              :                 "validator=/.*\\.txt/i\n"
     989              :                 "allowed=command-line,environment-variable\n"
     990              :                 "multiple\n"
     991              :                 "required\n"
     992              :                 "\n"
     993              :                 "[dimensions::from]\n"
     994              :                 "help=Request for the geographical location representing the origin of the files; optionally you can specify the format.\n"
     995              :                 "validator=integer\n"
     996              :                 "environment_variable_name=FROM\n"
     997              :                 "allowed=command-line,environment-variable,configuration-file\n"
     998              :                 "\n"
     999              :                 "[dimensions::output]\n"
    1000              :                 "default=a.out\n"
    1001              :                 "help=output file\n"
    1002              :                 "allowed=environment-variable\n"
    1003              :                 "environment_variable_name=OUTPUT\n"
    1004              :                 "required\n"
    1005              :                 "multiple\n"
    1006              :                 "\n"
    1007              :                 "[legal::department::license]\n"
    1008              :                 "help=Show this test license.\n"
    1009              :                 "allowed=command-line\n"
    1010              :                 "no-arguments\n"
    1011              :                 "\n"
    1012              :                 "[legal::department::licence]\n"
    1013              :                 "alias=license\n"
    1014              :                 "allowed=command-line\n"
    1015              :                 "no-arguments\n"
    1016            1 :                 "\n"
    1017              :             ;
    1018            1 :         }
    1019              : 
    1020            1 :         advgetopt::getopt::pointer_t opts(std::make_shared<advgetopt::getopt>(valid_options_from_file));
    1021            1 :         opts->parse_options_from_file(
    1022              :                   options_filename
    1023              :                 , 2
    1024              :                 , std::numeric_limits<int>::max());
    1025              : 
    1026            1 :         advgetopt::option_info::map_by_name_t const & options(opts->get_options());
    1027            1 :         CATCH_REQUIRE(options.size() == 7);
    1028              : 
    1029              :         {
    1030            3 :             auto const o(options.find("color::more"));
    1031            1 :             CATCH_REQUIRE(o != options.end());
    1032            1 :             CATCH_REQUIRE(o->second->get_help() == "Allow for more stuff to be added.");
    1033              :         }
    1034              : 
    1035              :         {
    1036            3 :             auto const o(options.find("color::size"));
    1037            1 :             CATCH_REQUIRE(o != options.end());
    1038            1 :             CATCH_REQUIRE(o->second->get_help() == "Specify the size.");
    1039              :         }
    1040              : 
    1041              :         {
    1042            3 :             auto const o(options.find("color::files"));
    1043            1 :             CATCH_REQUIRE(o != options.end());
    1044            1 :             CATCH_REQUIRE(o->second->get_help() == "List of file names.");
    1045              :         }
    1046              : 
    1047              :         {
    1048            3 :             auto const o(options.find("dimensions::from"));
    1049            1 :             CATCH_REQUIRE(o != options.end());
    1050            1 :             CATCH_REQUIRE(o->second->get_help() == "Request for the geographical location representing the origin of the files; optionally you can specify the format.");
    1051              :         }
    1052              : 
    1053              :         {
    1054            3 :             auto const o(options.find("dimensions::output"));
    1055            1 :             CATCH_REQUIRE(o != options.end());
    1056            1 :             CATCH_REQUIRE(o->second->get_help() == "output file");
    1057              :         }
    1058              : 
    1059              :         {
    1060            3 :             auto const o(options.find("legal::department::license"));
    1061            1 :             CATCH_REQUIRE(o != options.end());
    1062            1 :             CATCH_REQUIRE(o->second->get_help() == "Show this test license.");
    1063              :         }
    1064              : 
    1065              :         {
    1066            3 :             auto const o(options.find("legal::department::licence"));
    1067            1 :             CATCH_REQUIRE(o != options.end());
    1068            1 :             CATCH_REQUIRE(o->second->get_help() == "license");
    1069              :         }
    1070            1 :     }
    1071            9 :     CATCH_END_SECTION()
    1072              : 
    1073            9 :     CATCH_START_SECTION("valid_options_files: check with validators in the definition")
    1074              :     {
    1075            1 :         std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
    1076            1 :         tmpdir += "/shared/advgetopt-validators-in-table";
    1077            1 :         std::stringstream ss;
    1078            1 :         ss << "mkdir -p " << tmpdir;
    1079            1 :         if(system(ss.str().c_str()) != 0)
    1080              :         {
    1081            0 :             std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
    1082            0 :             exit(1);
    1083              :         }
    1084            1 :         std::string const options_filename(tmpdir + "/unittest.ini");
    1085              : 
    1086            1 :         advgetopt::option const valid_options_from_file_list[] =
    1087              :         {
    1088              :             advgetopt::define_option(
    1089              :                   advgetopt::Name("verbose")
    1090              :                 , advgetopt::ShortName('v')
    1091              :                 , advgetopt::Flags(advgetopt::standalone_all_flags<>())
    1092              :                 , advgetopt::Help("a verbose like option, select it or not.")
    1093              :             ),
    1094              :             advgetopt::define_option(
    1095              :                   advgetopt::Name("size")
    1096              :                 , advgetopt::ShortName('s')
    1097              :                 , advgetopt::Flags(advgetopt::all_flags<advgetopt::GETOPT_FLAG_REQUIRED>())
    1098              :                 , advgetopt::Help("Specify the size.")
    1099              :                 , advgetopt::Validator("integer(0...100)")
    1100              :                 , advgetopt::DefaultValue("31")
    1101              :             ),
    1102              :             advgetopt::define_option(
    1103              :                   advgetopt::Name("files")
    1104              :                 , advgetopt::ShortName('f')
    1105              :                 , advgetopt::Help("List of file names")
    1106              :                 , advgetopt::Validator("/.*\\.txt/i")
    1107              :                 , advgetopt::Flags(advgetopt::all_flags<advgetopt::GETOPT_FLAG_REQUIRED, advgetopt::GETOPT_FLAG_MULTIPLE>())
    1108              :             ),
    1109              :             advgetopt::define_option(
    1110              :                   advgetopt::Name("from")
    1111              :                 , advgetopt::ShortName('F')
    1112              :                 , advgetopt::Help("Request for the geographical location representing the origin of the files; optionally you can specify the format")
    1113              :                 , advgetopt::Validator("integer")
    1114              :                 , advgetopt::Flags(advgetopt::all_flags<>())
    1115              :             ),
    1116              :             advgetopt::define_option(
    1117              :                   advgetopt::Name("more")
    1118              :                 , advgetopt::ShortName('m')
    1119              :                 , advgetopt::Help("Allow for more stuff to be added")
    1120              :                 , advgetopt::Validator("regex(\"purple|yellow|blue|red|green|orange|brown\")")
    1121              :                 , advgetopt::Flags(advgetopt::all_flags<advgetopt::GETOPT_FLAG_REQUIRED, advgetopt::GETOPT_FLAG_SHOW_USAGE_ON_ERROR>())
    1122              :                 , advgetopt::DefaultValue("More Stuff")
    1123              :             ),
    1124              :             advgetopt::end_options()
    1125              :         };
    1126              : 
    1127            1 :         advgetopt::options_environment valid_options_from_file;
    1128            1 :         valid_options_from_file.f_project_name = "unittest";
    1129            1 :         valid_options_from_file.f_options = valid_options_from_file_list;
    1130            1 :         valid_options_from_file.f_options_files_directory = tmpdir.c_str();
    1131            1 :         valid_options_from_file.f_environment_variable_name = "ADVGETOPT_TEST_OPTIONS";
    1132            1 :         valid_options_from_file.f_help_header = "Usage: test valid options from file";
    1133              : 
    1134            1 :         snapdev::safe_setenv env("ADVGETOPT_TEST_OPTIONS"
    1135              :                             , "--verbose"
    1136              :                              " --more purple"
    1137              :                              " -f left.txt center.txt right.txt"
    1138              :                              " --size 19"
    1139              :                              " --from"
    1140            5 :                              " --output destination.txt");
    1141              : 
    1142              :         {
    1143            1 :             std::ofstream options_file;
    1144            1 :             options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1145            1 :             CATCH_REQUIRE(options_file.good());
    1146              :             options_file <<
    1147              :                 "# Auto-generated\n"
    1148              : 
    1149              :                 "[output]\n"
    1150              :                 "shortname=o\n"
    1151              :                 "default=a.out\n"
    1152              :                 "help=output file\n"
    1153              :                 "allowed=environment-variable\n"
    1154              :                 "required\n"
    1155              : 
    1156              :                 "[license]\n"
    1157              :                 "shortname=l\n"
    1158              :                 "help=show this test license\n"
    1159              :                 "allowed=command-line\n"
    1160              :                 "no-arguments\n"
    1161              : 
    1162              :                 "[licence]\n"
    1163              :                 "alias=license\n"
    1164              :                 "allowed=command-line\n"
    1165            1 :                 "no-arguments\n"
    1166              :             ;
    1167            1 :         }
    1168              : 
    1169            1 :         char const * sub_cargv[] =
    1170              :         {
    1171              :             "tests/unittests/valid_options_files",
    1172              :             "--verbose",
    1173              :             "--licence",
    1174              :             nullptr
    1175              :         };
    1176            1 :         int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
    1177            1 :         char ** sub_argv = const_cast<char **>(sub_cargv);
    1178              : 
    1179            1 :         advgetopt::getopt opt(valid_options_from_file, sub_argc, sub_argv);
    1180              : 
    1181              :         // check that the result is valid
    1182              : 
    1183              :         // an invalid parameter, MUST NOT EXIST
    1184            3 :         CATCH_REQUIRE(opt.get_option("invalid-parameter") == nullptr);
    1185            3 :         CATCH_REQUIRE_FALSE(opt.is_defined("invalid-parameter"));
    1186              : 
    1187              :         // the valid parameter
    1188            3 :         CATCH_REQUIRE(opt.is_defined("verbose"));
    1189            3 :         CATCH_REQUIRE(opt.get_default("verbose").empty());
    1190            3 :         CATCH_REQUIRE(opt.size("verbose") == 1);
    1191              : 
    1192              :         // "--more"
    1193            3 :         CATCH_REQUIRE(opt.is_defined("more"));
    1194            3 :         CATCH_REQUIRE(opt.get_string("more") == "purple");
    1195            3 :         CATCH_REQUIRE(opt.get_default("more") == "More Stuff");
    1196            3 :         CATCH_REQUIRE(opt.size("more") == 1);
    1197              : 
    1198              :         // "--size <value>"
    1199            3 :         CATCH_REQUIRE(opt.is_defined("size"));
    1200            3 :         CATCH_REQUIRE(opt.get_string("size") == "19");
    1201            3 :         CATCH_REQUIRE(opt.get_string("size", 0) == "19");
    1202            3 :         CATCH_REQUIRE(opt.get_default("size") == "31");
    1203            3 :         CATCH_REQUIRE(opt.size("size") == 1);
    1204            3 :         CATCH_REQUIRE(opt.get_long("size") == 19);
    1205              : 
    1206              :         // "--files"
    1207            3 :         CATCH_REQUIRE(opt.is_defined("files"));
    1208            3 :         CATCH_REQUIRE(opt.get_string("files") == "left.txt");
    1209            3 :         CATCH_REQUIRE(opt.get_string("files", 0) == "left.txt");
    1210            3 :         CATCH_REQUIRE(opt.get_string("files", 1) == "center.txt");
    1211            3 :         CATCH_REQUIRE(opt.get_string("files", 2) == "right.txt");
    1212            3 :         CATCH_REQUIRE(opt.get_default("files").empty());
    1213            3 :         CATCH_REQUIRE(opt.size("files") == 3);
    1214              : 
    1215              :         // "--from"
    1216            3 :         CATCH_REQUIRE(opt.is_defined("from"));
    1217            3 :         CATCH_REQUIRE(opt.size("from") == 1);
    1218            3 :         CATCH_REQUIRE(opt.get_string("from") == "");
    1219            3 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: invalid number () in parameter --from at offset 0.");
    1220            3 :         CATCH_REQUIRE(opt.get_long("from") == -1);
    1221            1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1222            3 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: invalid number () in parameter --from at offset 0.");
    1223            3 :         CATCH_REQUIRE(opt.get_long("from") == -1);
    1224            1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1225            3 :         CATCH_REQUIRE(opt.get_default("from").empty());
    1226              : 
    1227              :         // "--output"
    1228            3 :         CATCH_REQUIRE(opt.is_defined("output"));
    1229            3 :         CATCH_REQUIRE(opt.get_string("output") == "destination.txt"); // same as index = 0
    1230            3 :         CATCH_REQUIRE(opt.get_string("output",  0) == "destination.txt");
    1231            3 :         CATCH_REQUIRE(opt.get_default("output") == "a.out");
    1232            3 :         CATCH_REQUIRE(opt.size("output") == 1);
    1233              : 
    1234              :         // "--from"
    1235            3 :         CATCH_REQUIRE(opt.is_defined("license"));
    1236            3 :         CATCH_REQUIRE(opt.get_string("license") == "");
    1237            3 :         CATCH_REQUIRE(opt.get_default("license").empty());
    1238            3 :         CATCH_REQUIRE(opt.size("license") == 1);
    1239              : 
    1240              :         // other parameters
    1241            1 :         CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
    1242            1 :         CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
    1243              : 
    1244            1 :         char const * sub_cargv2[] =
    1245              :         {
    1246              :             "this/is/ignored",
    1247              :             "--from",
    1248              :             "1001",
    1249              :             nullptr
    1250              :         };
    1251            1 :         int const sub_argc2(sizeof(sub_cargv2) / sizeof(sub_cargv2[0]) - 1);
    1252            1 :         char ** sub_argv2 = const_cast<char **>(sub_cargv2);
    1253              : 
    1254            1 :         opt.parse_arguments(sub_argc2, sub_argv2, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
    1255              : 
    1256              :         // "--from"
    1257            3 :         CATCH_REQUIRE(opt.is_defined("from"));
    1258            3 :         CATCH_REQUIRE(opt.size("from") == 1);
    1259            3 :         CATCH_REQUIRE(opt.get_string("from") == "1001");
    1260            3 :         CATCH_REQUIRE(opt.get_long("from") == 1001);
    1261            3 :         CATCH_REQUIRE(opt.get_default("from").empty());
    1262              : 
    1263              :         // other parameters
    1264            1 :         CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
    1265            1 :         CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
    1266              : 
    1267              :         // keep the last value...
    1268              :         //
    1269            1 :         opt.parse_environment_variable();
    1270              : 
    1271              :         // "--from"
    1272            3 :         CATCH_REQUIRE(opt.is_defined("from"));
    1273            3 :         CATCH_REQUIRE(opt.size("from") == 1);
    1274            3 :         CATCH_REQUIRE(opt.get_string("from") == "");
    1275            3 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: invalid number () in parameter --from at offset 0.");
    1276            3 :         CATCH_REQUIRE(opt.get_long("from") == -1);
    1277            1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1278            3 :         CATCH_REQUIRE(opt.get_default("from").empty());
    1279              : 
    1280              :         // other parameters
    1281            1 :         CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
    1282            1 :         CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
    1283              : 
    1284              :         // a reset will restore the state
    1285              :         //
    1286            1 :         opt.reset();
    1287              : 
    1288              :         // the valid parameter
    1289            3 :         CATCH_REQUIRE_FALSE(opt.is_defined("verbose"));
    1290            3 :         CATCH_REQUIRE(opt.get_default("verbose").empty());
    1291            3 :         CATCH_REQUIRE(opt.size("verbose") == 0);
    1292              : 
    1293              :         // "--from"
    1294            3 :         CATCH_REQUIRE_FALSE(opt.is_defined("from"));
    1295            3 :         CATCH_REQUIRE(opt.get_default("from").empty());
    1296            3 :         CATCH_REQUIRE(opt.size("from") == 0);
    1297              : 
    1298            1 :         opt.parse_environment_variable();
    1299            1 :         opt.parse_arguments(sub_argc2, sub_argv2, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
    1300              : 
    1301              :         // "--from"
    1302            3 :         CATCH_REQUIRE(opt.is_defined("from"));
    1303            3 :         CATCH_REQUIRE(opt.get_string("from") == "1001");
    1304            3 :         CATCH_REQUIRE(opt.get_long("from") == 1001);
    1305            3 :         CATCH_REQUIRE(opt.get_default("from").empty());
    1306            3 :         CATCH_REQUIRE(opt.size("from") == 1);
    1307              : 
    1308              :         // other parameters
    1309            1 :         CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
    1310            1 :         CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
    1311              : 
    1312              :         // test that the validators do work here (i.e. generate errors as
    1313              :         // expected when we use the wrong options.)
    1314              :         //
    1315            1 :         char const * sub_cargv3[] =
    1316              :         {
    1317              :             "this/is/ignored",
    1318              :             "--size",
    1319              :             "1001",
    1320              :             "-f",
    1321              :             "valid.cpp",
    1322              :             "--from",
    1323              :             "51",
    1324              :             "--more",
    1325              :             "black",
    1326              :             nullptr
    1327              :         };
    1328            1 :         int const sub_argc3(sizeof(sub_cargv3) / sizeof(sub_cargv3[0]) - 1);
    1329            1 :         char ** sub_argv3 = const_cast<char **>(sub_cargv3);
    1330              : 
    1331            3 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: input \"1001\" given to parameter --size is not considered valid: out of range.");
    1332            3 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: input \"valid.cpp\" given to parameter --files is not considered valid: did not match the regex.");
    1333            3 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: input \"black\" given to parameter --more is not considered valid: did not match the regex.");
    1334            1 :         opt.parse_arguments(sub_argc3, sub_argv3, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
    1335            1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1336            1 :     }
    1337            9 :     CATCH_END_SECTION()
    1338            9 : }
    1339              : 
    1340              : 
    1341            7 : CATCH_TEST_CASE("invalid_options_files", "[options][invalid][files]")
    1342              : {
    1343            7 :     CATCH_START_SECTION("invalid_options_files: 2+ section names")
    1344              :     {
    1345            1 :         std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
    1346            1 :         tmpdir += "/shared/advgetopt";
    1347            1 :         std::stringstream ss;
    1348            1 :         ss << "mkdir -p " << tmpdir;
    1349            1 :         if(system(ss.str().c_str()) != 0)
    1350              :         {
    1351            0 :             std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
    1352            0 :             exit(1);
    1353              :         }
    1354            1 :         std::string const options_filename(tmpdir + "/bad-section.ini");
    1355              : 
    1356            1 :         advgetopt::option const options[] =
    1357              :         {
    1358              :             advgetopt::define_option(
    1359              :                   advgetopt::Name("verbose")
    1360              :                 , advgetopt::ShortName('v')
    1361              :                 , advgetopt::Flags(advgetopt::standalone_all_flags<>())
    1362              :                 , advgetopt::Help("a verbose like option, select it or not.")
    1363              :             ),
    1364              :             advgetopt::end_options()
    1365              :         };
    1366              : 
    1367            1 :         advgetopt::options_environment options_environment;
    1368            1 :         options_environment.f_project_name = "bad-section";
    1369            1 :         options_environment.f_options = options;
    1370            1 :         options_environment.f_options_files_directory = tmpdir.c_str();
    1371            1 :         options_environment.f_environment_variable_name = nullptr;
    1372            1 :         options_environment.f_help_header = "Usage: test invalid section name";
    1373              : 
    1374              :         {
    1375            1 :             std::ofstream options_file;
    1376            1 :             options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1377            1 :             CATCH_REQUIRE(options_file.good());
    1378              :             options_file <<
    1379              :                 "# Auto-generated\n"
    1380              : 
    1381              :                 "[invalid::name]\n"
    1382              :                 "shortname=m\n"
    1383              :                 "default='Invalid Stuff'\n"
    1384              :                 "help=Testing that a section name can't include \"::\"\n"
    1385            1 :                 "allowed=command-line,environment-variable,configuration-file\n"
    1386              :             ;
    1387            1 :         }
    1388              : 
    1389            1 :         char const * sub_cargv[] =
    1390              :         {
    1391              :             "tests/unittests/invalid_name_in_options_ini",
    1392              :             "--verbose",
    1393              :             nullptr
    1394              :         };
    1395            1 :         int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
    1396            1 :         char ** sub_argv = const_cast<char **>(sub_cargv);
    1397              : 
    1398            3 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    1399              :                     "error: option name \"shortname\" cannot be added to"
    1400              :                     " section \"invalid::name\" because this"
    1401              :                     " configuration only accepts one section level.");
    1402            3 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    1403              :                     "error: option name \"default\" cannot be added to"
    1404              :                     " section \"invalid::name\" because this"
    1405              :                     " configuration only accepts one section level.");
    1406            3 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    1407              :                     "error: option name \"help\" cannot be added to"
    1408              :                     " section \"invalid::name\" because this"
    1409              :                     " configuration only accepts one section level.");
    1410            3 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    1411              :                     "error: option name \"allowed\" cannot be added to"
    1412              :                     " section \"invalid::name\" because this"
    1413              :                     " configuration only accepts one section level.");
    1414            1 :         advgetopt::getopt::pointer_t opt(std::make_shared<advgetopt::getopt>(options_environment));
    1415              :         try
    1416              :         {
    1417            1 :             opt->finish_parsing(sub_argc, sub_argv);
    1418            0 :             CATCH_REQUIRE(false);   // the library is expected to throw here
    1419              :         }
    1420            1 :         catch(advgetopt::getopt_exit const & e)
    1421              :         {
    1422            1 :             CATCH_REQUIRE(e.code() == 1);
    1423            3 :             CATCH_REQUIRE(e.what() == std::string("getopt_exception: errors were found on your command line, environment variable, or configuration file."));
    1424            1 :         }
    1425            1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1426              : 
    1427            3 :         CATCH_REQUIRE(opt->size("invalid::name::shortname") == 0);
    1428            3 :         CATCH_REQUIRE(opt->size("shortname") == 0);
    1429            1 :     }
    1430            7 :     CATCH_END_SECTION()
    1431              : 
    1432            7 :     CATCH_START_SECTION("invalid_options_files: short name too long")
    1433              :     {
    1434            1 :         std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
    1435            1 :         tmpdir += "/shared/advgetopt";
    1436            1 :         std::stringstream ss;
    1437            1 :         ss << "mkdir -p " << tmpdir;
    1438            1 :         if(system(ss.str().c_str()) != 0)
    1439              :         {
    1440            0 :             std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
    1441            0 :             exit(1);
    1442              :         }
    1443            1 :         std::string const options_filename(tmpdir + "/bad-shortname.ini");
    1444              : 
    1445            1 :         advgetopt::option const options[] =
    1446              :         {
    1447              :             advgetopt::define_option(
    1448              :                   advgetopt::Name("verbose")
    1449              :                 , advgetopt::ShortName('v')
    1450              :                 , advgetopt::Flags(advgetopt::standalone_all_flags<>())
    1451              :                 , advgetopt::Help("a verbose like option, select it or not.")
    1452              :             ),
    1453              :             advgetopt::end_options()
    1454              :         };
    1455              : 
    1456            1 :         advgetopt::options_environment options_environment;
    1457            1 :         options_environment.f_project_name = "bad-shortname";
    1458            1 :         options_environment.f_options = options;
    1459            1 :         options_environment.f_options_files_directory = tmpdir.c_str();
    1460            1 :         options_environment.f_environment_variable_name = nullptr;
    1461            1 :         options_environment.f_help_header = "Usage: test invalid shortname";
    1462              : 
    1463              :         {
    1464            1 :             std::ofstream options_file;
    1465            1 :             options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1466            1 :             CATCH_REQUIRE(options_file.good());
    1467              :             options_file <<
    1468              :                 "# Auto-generated\n"
    1469              : 
    1470              :                 "[badname]\n"
    1471              :                 "shortname=to\n"
    1472              :                 "default='Invalid Stuff'\n"
    1473              :                 "help=Testing that a shotname can't be 2 characters or more\n"
    1474            1 :                 "allowed=command-line,environment-variable,configuration-file\n"
    1475              :             ;
    1476            1 :         }
    1477              : 
    1478            1 :         char const * sub_cargv[] =
    1479              :         {
    1480              :             "tests/unittests/invalid_name_in_options_ini",
    1481              :             "--verbose",
    1482              :             nullptr
    1483              :         };
    1484            1 :         int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
    1485            1 :         char ** sub_argv = const_cast<char **>(sub_cargv);
    1486              : 
    1487            2 :         CATCH_REQUIRE_THROWS_MATCHES(
    1488              :                       std::make_shared<advgetopt::getopt>(options_environment, sub_argc, sub_argv)
    1489              :                     , advgetopt::getopt_logic_error
    1490              :                     , Catch::Matchers::ExceptionMessage(
    1491              :                               "getopt_logic_error: option \"badname\" has an invalid short name in \""
    1492              :                             + options_filename
    1493              :                             + "\", it can't be more than one character."));
    1494            1 :     }
    1495            7 :     CATCH_END_SECTION()
    1496              : 
    1497            7 :     CATCH_START_SECTION("invalid_options_files: missing ')' in validator specification")
    1498              :     {
    1499            1 :         std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
    1500            1 :         tmpdir += "/shared/advgetopt";
    1501            1 :         std::stringstream ss;
    1502            1 :         ss << "mkdir -p " << tmpdir;
    1503            1 :         if(system(ss.str().c_str()) != 0)
    1504              :         {
    1505            0 :             std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
    1506            0 :             exit(1);
    1507              :         }
    1508            1 :         std::string const options_filename(tmpdir + "/bad-validator-parenthesis.ini");
    1509              : 
    1510            1 :         advgetopt::option const options[] =
    1511              :         {
    1512              :             advgetopt::define_option(
    1513              :                   advgetopt::Name("verbose")
    1514              :                 , advgetopt::ShortName('v')
    1515              :                 , advgetopt::Flags(advgetopt::standalone_all_flags<>())
    1516              :                 , advgetopt::Help("a verbose like option, select it or not.")
    1517              :             ),
    1518              :             advgetopt::end_options()
    1519              :         };
    1520              : 
    1521            1 :         advgetopt::options_environment options_environment;
    1522            1 :         options_environment.f_project_name = "bad-validator-parenthesis";
    1523            1 :         options_environment.f_options = options;
    1524            1 :         options_environment.f_options_files_directory = tmpdir.c_str();
    1525            1 :         options_environment.f_environment_variable_name = nullptr;
    1526            1 :         options_environment.f_help_header = "Usage: test invalid validator specification";
    1527              : 
    1528              :         {
    1529            1 :             std::ofstream options_file;
    1530            1 :             options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1531            1 :             CATCH_REQUIRE(options_file.good());
    1532              :             options_file <<
    1533              :                 "# Auto-generated\n"
    1534              : 
    1535              :                 "[bad-validator]\n"
    1536              :                 "shortname=b\n"
    1537              :                 "default='Invalid Stuff'\n"
    1538              :                 "help=Testing that a validator with parenthesis must have the ')'\n"
    1539              :                 "validator=regex(\"missing ')'\"\n"
    1540            1 :                 "allowed=command-line,environment-variable,configuration-file\n"
    1541              :             ;
    1542            1 :         }
    1543              : 
    1544            1 :         char const * sub_cargv[] =
    1545              :         {
    1546              :             "tests/unittests/invalid_validator_specification",
    1547              :             "--verbose",
    1548              :             nullptr
    1549              :         };
    1550            1 :         int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
    1551            1 :         char ** sub_argv = const_cast<char **>(sub_cargv);
    1552              : 
    1553            3 :         SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): parameter list must end with ')'. Remaining input: \"...EOS\"");
    1554              :         //CATCH_REQUIRE(std::make_shared<advgetopt::getopt>(options_environment, sub_argc, sub_argv) != nullptr);
    1555              : 
    1556            4 :         CATCH_REQUIRE_THROWS_MATCHES(
    1557              :                   std::make_shared<advgetopt::getopt>(options_environment, sub_argc, sub_argv)
    1558              :                 , advgetopt::getopt_exception
    1559              :                 , Catch::Matchers::ExceptionMessage(
    1560              :                     "getopt_exception: errors were found on your command line,"
    1561              :                     " environment variable, or configuration file."));
    1562              : 
    1563            1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    1564            1 :     }
    1565            7 :     CATCH_END_SECTION()
    1566              : 
    1567            7 :     CATCH_START_SECTION("invalid_options_files: alias with help")
    1568              :     {
    1569            1 :         std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
    1570            1 :         tmpdir += "/shared/advgetopt";
    1571            1 :         std::stringstream ss;
    1572            1 :         ss << "mkdir -p " << tmpdir;
    1573            1 :         if(system(ss.str().c_str()) != 0)
    1574              :         {
    1575            0 :             std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
    1576            0 :             exit(1);
    1577              :         }
    1578            1 :         std::string const options_filename(tmpdir + "/alias-with-help.ini");
    1579              : 
    1580            1 :         advgetopt::option const options[] =
    1581              :         {
    1582              :             advgetopt::define_option(
    1583              :                   advgetopt::Name("verbose")
    1584              :                 , advgetopt::ShortName('v')
    1585              :                 , advgetopt::Flags(advgetopt::standalone_all_flags<>())
    1586              :                 , advgetopt::Help("a verbose like option, select it or not.")
    1587              :             ),
    1588              :             advgetopt::end_options()
    1589              :         };
    1590              : 
    1591            1 :         advgetopt::options_environment options_environment;
    1592            1 :         options_environment.f_project_name = "alias-with-help";
    1593            1 :         options_environment.f_options = options;
    1594            1 :         options_environment.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
    1595            1 :         options_environment.f_options_files_directory = tmpdir.c_str();
    1596            1 :         options_environment.f_environment_variable_name = nullptr;
    1597            1 :         options_environment.f_help_header = "Usage: test invalid validator specification";
    1598              : 
    1599              :         {
    1600            1 :             std::ofstream options_file;
    1601            1 :             options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1602            1 :             CATCH_REQUIRE(options_file.good());
    1603              :             options_file <<
    1604              :                 "# Auto-generated\n"
    1605              : 
    1606              :                 "[licence]\n"
    1607              :                 "shortname=l\n"
    1608              :                 "default='Invalid Stuff'\n"
    1609              :                 "alias=license\n"
    1610              :                 "help=Testing that an alias can't accept a help string\n"
    1611            1 :                 "allowed=command-line,environment-variable,configuration-file\n"
    1612              :             ;
    1613            1 :         }
    1614              : 
    1615            1 :         char const * sub_cargv[] =
    1616              :         {
    1617              :             "tests/unittests/invalid_alias_specification",
    1618              :             "--verbose",
    1619              :             nullptr
    1620              :         };
    1621            1 :         int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
    1622            1 :         char ** sub_argv = const_cast<char **>(sub_cargv);
    1623              : 
    1624            2 :         CATCH_REQUIRE_THROWS_MATCHES(std::make_shared<advgetopt::getopt>(options_environment, sub_argc, sub_argv)
    1625              :                     , advgetopt::getopt_logic_error
    1626              :                     , Catch::Matchers::ExceptionMessage(
    1627              :                               "getopt_logic_error: option \"licence\" is an alias and as such it can't include a help=... parameter in \""
    1628              :                             + options_filename
    1629              :                             + "\"."));
    1630            1 :     }
    1631            7 :     CATCH_END_SECTION()
    1632              : 
    1633            7 :     CATCH_START_SECTION("invalid_options_files: no-name alias")
    1634              :     {
    1635            1 :         std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
    1636            1 :         tmpdir += "/shared/advgetopt";
    1637            1 :         std::stringstream ss;
    1638            1 :         ss << "mkdir -p " << tmpdir;
    1639            1 :         if(system(ss.str().c_str()) != 0)
    1640              :         {
    1641            0 :             std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
    1642            0 :             exit(1);
    1643              :         }
    1644            1 :         std::string const options_filename(tmpdir + "/no-name-alias.ini");
    1645              : 
    1646            1 :         advgetopt::option const options[] =
    1647              :         {
    1648              :             advgetopt::define_option(
    1649              :                   advgetopt::Name("verbose")
    1650              :                 , advgetopt::ShortName('v')
    1651              :                 , advgetopt::Flags(advgetopt::standalone_all_flags<>())
    1652              :                 , advgetopt::Help("a verbose like option, select it or not.")
    1653              :             ),
    1654              :             advgetopt::end_options()
    1655              :         };
    1656              : 
    1657            1 :         advgetopt::options_environment options_environment;
    1658            1 :         options_environment.f_project_name = "no-name-alias";
    1659            1 :         options_environment.f_options = options;
    1660            1 :         options_environment.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
    1661            1 :         options_environment.f_options_files_directory = tmpdir.c_str();
    1662            1 :         options_environment.f_environment_variable_name = nullptr;
    1663            1 :         options_environment.f_help_header = "Usage: test alias with no name specified";
    1664              : 
    1665              :         {
    1666            1 :             std::ofstream options_file;
    1667            1 :             options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1668            1 :             CATCH_REQUIRE(options_file.good());
    1669              :             options_file <<
    1670              :                 "# Auto-generated\n"
    1671              : 
    1672              :                 "[foo]\n"
    1673              :                 "shortname=f\n"
    1674              :                 "default='Invalid Stuff'\n"
    1675              :                 "alias=\n"      // name missing (with an equal)
    1676            1 :                 "allowed=command-line\n"
    1677              :             ;
    1678            1 :         }
    1679              : 
    1680            1 :         char const * sub_cargv[] =
    1681              :         {
    1682              :             "tests/unittests/non_existent_alias",
    1683              :             "--verbose",
    1684              :             nullptr
    1685              :         };
    1686            1 :         int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
    1687            1 :         char ** sub_argv = const_cast<char **>(sub_cargv);
    1688              : 
    1689            4 :         CATCH_REQUIRE_THROWS_MATCHES(std::make_shared<advgetopt::getopt>(options_environment, sub_argc, sub_argv)
    1690              :                     , advgetopt::getopt_logic_error
    1691              :                     , Catch::Matchers::ExceptionMessage("getopt_logic_error: the default value of your alias cannot be an empty string for \"foo\"."));
    1692            1 :     }
    1693            7 :     CATCH_END_SECTION()
    1694              : 
    1695            7 :     CATCH_START_SECTION("invalid_options_files: no-name alias v2")
    1696              :     {
    1697            1 :         std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
    1698            1 :         tmpdir += "/shared/advgetopt";
    1699            1 :         std::stringstream ss;
    1700            1 :         ss << "mkdir -p " << tmpdir;
    1701            1 :         if(system(ss.str().c_str()) != 0)
    1702              :         {
    1703            0 :             std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
    1704            0 :             exit(1);
    1705              :         }
    1706            1 :         std::string const options_filename(tmpdir + "/no-name-alias-v2.ini");
    1707              : 
    1708            1 :         advgetopt::option const options[] =
    1709              :         {
    1710              :             advgetopt::define_option(
    1711              :                   advgetopt::Name("verbose")
    1712              :                 , advgetopt::ShortName('v')
    1713              :                 , advgetopt::Flags(advgetopt::standalone_all_flags<>())
    1714              :                 , advgetopt::Help("a verbose like option, select it or not.")
    1715              :             ),
    1716              :             advgetopt::end_options()
    1717              :         };
    1718              : 
    1719            1 :         advgetopt::options_environment options_environment;
    1720            1 :         options_environment.f_project_name = "no-name-alias-v2";
    1721            1 :         options_environment.f_options = options;
    1722            1 :         options_environment.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
    1723            1 :         options_environment.f_options_files_directory = tmpdir.c_str();
    1724            1 :         options_environment.f_environment_variable_name = nullptr;
    1725            1 :         options_environment.f_help_header = "Usage: test alias with no name specified";
    1726              : 
    1727              :         {
    1728            1 :             std::ofstream options_file;
    1729            1 :             options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1730            1 :             CATCH_REQUIRE(options_file.good());
    1731              :             options_file <<
    1732              :                 "# Auto-generated\n"
    1733              : 
    1734              :                 "[foo]\n"
    1735              :                 "shortname=f\n"
    1736              :                 "default='Invalid Stuff'\n"
    1737              :                 "alias\n"      // name missing (no equal)
    1738            1 :                 "allowed=command-line\n"
    1739              :             ;
    1740            1 :         }
    1741              : 
    1742            1 :         char const * sub_cargv[] =
    1743              :         {
    1744              :             "tests/unittests/non_existent_alias",
    1745              :             "--verbose",
    1746              :             nullptr
    1747              :         };
    1748            1 :         int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
    1749            1 :         char ** sub_argv = const_cast<char **>(sub_cargv);
    1750              : 
    1751            4 :         CATCH_REQUIRE_THROWS_MATCHES(std::make_shared<advgetopt::getopt>(options_environment, sub_argc, sub_argv)
    1752              :                     , advgetopt::getopt_logic_error
    1753              :                     , Catch::Matchers::ExceptionMessage("getopt_logic_error: the default value of your alias cannot be an empty string for \"foo\"."));
    1754            1 :     }
    1755            7 :     CATCH_END_SECTION()
    1756              : 
    1757            7 :     CATCH_START_SECTION("invalid_options_files: non-existent alias")
    1758              :     {
    1759            1 :         std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
    1760            1 :         tmpdir += "/shared/advgetopt";
    1761            1 :         std::stringstream ss;
    1762            1 :         ss << "mkdir -p " << tmpdir;
    1763            1 :         if(system(ss.str().c_str()) != 0)
    1764              :         {
    1765            0 :             std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
    1766            0 :             exit(1);
    1767              :         }
    1768            1 :         std::string const options_filename(tmpdir + "/non-existent-alias.ini");
    1769              : 
    1770            1 :         advgetopt::option const options[] =
    1771              :         {
    1772              :             advgetopt::define_option(
    1773              :                   advgetopt::Name("verbose")
    1774              :                 , advgetopt::ShortName('v')
    1775              :                 , advgetopt::Flags(advgetopt::standalone_all_flags<>())
    1776              :                 , advgetopt::Help("a verbose like option, select it or not.")
    1777              :             ),
    1778              :             advgetopt::end_options()
    1779              :         };
    1780              : 
    1781            1 :         advgetopt::options_environment options_environment;
    1782            1 :         options_environment.f_project_name = "non-existent-alias";
    1783            1 :         options_environment.f_options = options;
    1784            1 :         options_environment.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
    1785            1 :         options_environment.f_options_files_directory = tmpdir.c_str();
    1786            1 :         options_environment.f_environment_variable_name = nullptr;
    1787            1 :         options_environment.f_help_header = "Usage: test invalid validator specification";
    1788              : 
    1789              :         {
    1790            1 :             std::ofstream options_file;
    1791            1 :             options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1792            1 :             CATCH_REQUIRE(options_file.good());
    1793              :             options_file <<
    1794              :                 "# Auto-generated\n"
    1795              : 
    1796              :                 "[foo]\n"
    1797              :                 "shortname=f\n"
    1798              :                 "default='Invalid Stuff'\n"
    1799              :                 "alias=bar\n"       // option "bar" missing
    1800            1 :                 "allowed=command-line\n"
    1801              :             ;
    1802            1 :         }
    1803              : 
    1804            1 :         char const * sub_cargv[] =
    1805              :         {
    1806              :             "tests/unittests/non_existent_alias",
    1807              :             "--verbose",
    1808              :             nullptr
    1809              :         };
    1810            1 :         int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
    1811            1 :         char ** sub_argv = const_cast<char **>(sub_cargv);
    1812              : 
    1813            4 :         CATCH_REQUIRE_THROWS_MATCHES(std::make_shared<advgetopt::getopt>(options_environment, sub_argc, sub_argv)
    1814              :                     , advgetopt::getopt_logic_error
    1815              :                     , Catch::Matchers::ExceptionMessage("getopt_logic_error: no option named \"bar\" to satisfy the alias of \"foo\"."));
    1816            1 :     }
    1817            7 :     CATCH_END_SECTION()
    1818            7 : }
    1819              : 
    1820              : 
    1821              : 
    1822              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

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