LCOV - code coverage report
Current view: top level - tests - catch_options_files.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 688 717 96.0 %
Date: 2022-07-15 09:02:52 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13