LCOV - code coverage report
Current view: top level - tests - catch_config_file.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1750 1763 99.3 %
Date: 2022-05-26 21:41:34 Functions: 20 20 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             : // self
      21             : //
      22             : #include    "catch_main.h"
      23             : 
      24             : 
      25             : // advgetopt lib
      26             : //
      27             : #include    <advgetopt/conf_file.h>
      28             : #include    <advgetopt/exception.h>
      29             : 
      30             : 
      31             : // snapdev lib
      32             : //
      33             : #include    <snapdev/safe_setenv.h>
      34             : #include    <snapdev/tokenize_string.h>
      35             : 
      36             : 
      37             : // C++ lib
      38             : //
      39             : #include    <fstream>
      40             : 
      41             : 
      42             : // C lib
      43             : //
      44             : #include    <unistd.h>
      45             : 
      46             : 
      47             : // last include
      48             : //
      49             : #include    <snapdev/poison.h>
      50             : 
      51             : 
      52             : 
      53             : 
      54             : 
      55             : 
      56             : 
      57           3 : CATCH_TEST_CASE("configuration_spaces", "[config][getopt][valid]")
      58             : {
      59           2 :     CATCH_START_SECTION("Verify Configuration Spaces")
      60             :     {
      61     1114113 :         for(int c(0); c < 0x110000; ++c)
      62             :         {
      63     1114112 :             if(c == '\r'
      64     1114111 :             || c == '\n')
      65             :             {
      66           2 :                 CATCH_REQUIRE_FALSE(advgetopt::iswspace(c));
      67             :             }
      68     1114110 :             else if(std::iswspace(c))
      69             :             {
      70           4 :                 CATCH_REQUIRE(advgetopt::iswspace(c));
      71             :             }
      72             :             else
      73             :             {
      74     1114106 :                 CATCH_REQUIRE_FALSE(advgetopt::iswspace(c));
      75             :             }
      76             :         }
      77             :     }
      78             :     CATCH_END_SECTION()
      79           1 : }
      80             : 
      81             : 
      82           4 : CATCH_TEST_CASE("configuration_setup", "[config][getopt][valid]")
      83             : {
      84           4 :     CATCH_START_SECTION("Check All Setups")
      85             :     {
      86             :         // 5 * 6 * 8 * 8 * 16 = 30720
      87           6 :         for(int count(0); count < 5; ++count)
      88             :         {
      89           5 :             int const id(rand());
      90          10 :             std::string const name("setup-file-" + std::to_string(id));
      91             : 
      92           5 :             SNAP_CATCH2_NAMESPACE::init_tmp_dir("setup", name);
      93             : 
      94             :             {
      95          10 :                 std::ofstream config_file;
      96           5 :                 config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
      97           5 :                 CATCH_REQUIRE(config_file.good());
      98           5 :                 config_file <<
      99             :                     "# Auto-generated\n"
     100             :                     "param=optional\n"
     101             :                 ;
     102             :             }
     103             : 
     104          35 :             for(int lc(static_cast<int>(advgetopt::line_continuation_t::line_continuation_single_line));
     105          35 :                 lc <= static_cast<int>(advgetopt::line_continuation_t::line_continuation_semicolon);
     106             :                 ++lc)
     107             :             {
     108         270 :                 for(advgetopt::assignment_operator_t ao(0);
     109         270 :                     ao <= advgetopt::ASSIGNMENT_OPERATOR_MASK;
     110             :                     ++ao)
     111             :                 {
     112        1920 :                     for(advgetopt::comment_t c(0);
     113        1920 :                         c < advgetopt::COMMENT_MASK;
     114             :                         ++c)
     115             :                     {
     116       26880 :                         for(advgetopt::section_operator_t so(0);
     117       26880 :                             so < advgetopt::SECTION_OPERATOR_MASK;
     118             :                             ++so)
     119             :                         {
     120       25200 :                             advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
     121             :                                                 , static_cast<advgetopt::line_continuation_t>(lc)
     122             :                                                 , ao
     123             :                                                 , c
     124       50400 :                                                 , so);
     125             : 
     126       25200 :                             advgetopt::assignment_operator_t real_ao(ao == 0 ? advgetopt::ASSIGNMENT_OPERATOR_EQUAL : ao);
     127             : 
     128       25200 :                             CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
     129             : 
     130       25200 :                             CATCH_REQUIRE(setup.is_valid());
     131       50400 :                             std::unique_ptr<char, decltype(&::free)> fn(realpath(SNAP_CATCH2_NAMESPACE::g_config_filename.c_str(), nullptr), &::free);
     132       25200 :                             CATCH_REQUIRE(setup.get_filename() == fn.get());
     133       25200 :                             CATCH_REQUIRE(setup.get_line_continuation() == static_cast<advgetopt::line_continuation_t>(lc));
     134       25200 :                             CATCH_REQUIRE(setup.get_assignment_operator() == real_ao);
     135       25200 :                             CATCH_REQUIRE(setup.get_comment() == c);
     136       25200 :                             CATCH_REQUIRE(setup.get_section_operator() == so);
     137             : 
     138       50400 :                             std::string const url(setup.get_config_url());
     139             : //std::cerr << "+++ " << lc << " / " << ao << " / " << c << " / " << so << " URL [" << url << "]\n";
     140       25200 :                             CATCH_REQUIRE(url.substr(0, 8) == "file:///");
     141             : 
     142       25200 :                             CATCH_REQUIRE(url.substr(7, strlen(fn.get())) == fn.get());
     143             : 
     144       25200 :                             std::string::size_type const qm_pos(url.find('?'));
     145       25200 :                             if(qm_pos == std::string::npos)
     146             :                             {
     147             :                                 // must have the defaults in this case
     148             :                                 //
     149           0 :                                 CATCH_REQUIRE(static_cast<advgetopt::line_continuation_t>(lc) == advgetopt::line_continuation_t::line_continuation_unix);
     150           0 :                                 CATCH_REQUIRE(real_ao == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
     151           0 :                                 CATCH_REQUIRE(c  == (advgetopt::COMMENT_INI | advgetopt::COMMENT_SHELL));
     152           0 :                                 CATCH_REQUIRE(so == advgetopt::SECTION_OPERATOR_INI_FILE);
     153             :                             }
     154             :                             else
     155             :                             {
     156       50400 :                                 std::string const qs(url.substr(qm_pos + 1));
     157             : 
     158       50400 :                                 std::vector<std::string> strings;
     159       25200 :                                 snapdev::tokenize_string(strings, qs, "&");
     160             : 
     161       25200 :                                 bool def_lc(true);
     162       25200 :                                 bool def_ao(true);
     163       25200 :                                 bool def_c(true);
     164       25200 :                                 bool def_so(true);
     165             : 
     166      112140 :                                 for(auto s : strings)
     167             :                                 {
     168       86940 :                                     std::string::size_type const eq_pos(s.find('='));
     169       86940 :                                     CATCH_REQUIRE(eq_pos != std::string::npos);
     170             : 
     171      173880 :                                     std::string const var_name(s.substr(0, eq_pos));
     172      173880 :                                     std::string const var_value(s.substr(eq_pos + 1));
     173             : 
     174       86940 :                                     if(var_name == "line-continuation")
     175             :                                     {
     176       21000 :                                         def_lc = false;
     177       21000 :                                         switch(static_cast<advgetopt::line_continuation_t>(lc))
     178             :                                         {
     179        4200 :                                         case advgetopt::line_continuation_t::line_continuation_single_line:
     180        4200 :                                             CATCH_REQUIRE(var_value == "single-line");
     181        4200 :                                             break;
     182             : 
     183        4200 :                                         case advgetopt::line_continuation_t::line_continuation_rfc_822:
     184        4200 :                                             CATCH_REQUIRE(var_value == "rfc-822");
     185        4200 :                                             break;
     186             : 
     187        4200 :                                         case advgetopt::line_continuation_t::line_continuation_msdos:
     188        4200 :                                             CATCH_REQUIRE(var_value == "msdos");
     189        4200 :                                             break;
     190             : 
     191           0 :                                         case advgetopt::line_continuation_t::line_continuation_unix:
     192           0 :                                             CATCH_REQUIRE(var_value == "unix");
     193           0 :                                             break;
     194             : 
     195        4200 :                                         case advgetopt::line_continuation_t::line_continuation_fortran:
     196        4200 :                                             CATCH_REQUIRE(var_value == "fortran");
     197        4200 :                                             break;
     198             : 
     199        4200 :                                         case advgetopt::line_continuation_t::line_continuation_semicolon:
     200        4200 :                                             CATCH_REQUIRE(var_value == "semi-colon");
     201        4200 :                                             break;
     202             : 
     203           0 :                                         default:
     204           0 :                                             CATCH_REQUIRE(("unknown_var_value for \"line-continuation\":" + var_value) == std::string());
     205           0 :                                             break;
     206             : 
     207             :                                         }
     208             :                                     }
     209       65940 :                                     else if(var_name == "assignment-operator")
     210             :                                     {
     211       18900 :                                         def_ao = false;
     212       37800 :                                         std::vector<std::string> operators;
     213       18900 :                                         snapdev::tokenize_string(operators, var_value, ",");
     214             : 
     215       18900 :                                         if((real_ao & advgetopt::ASSIGNMENT_OPERATOR_EQUAL) != 0)
     216             :                                         {
     217        9450 :                                             auto it(std::find(operators.begin(), operators.end(), "equal"));
     218        9450 :                                             CATCH_REQUIRE(it != operators.end());
     219        9450 :                                             operators.erase(it);
     220             :                                         }
     221       18900 :                                         if((real_ao & advgetopt::ASSIGNMENT_OPERATOR_COLON) != 0)
     222             :                                         {
     223       12600 :                                             auto it(std::find(operators.begin(), operators.end(), "colon"));
     224       12600 :                                             CATCH_REQUIRE(it != operators.end());
     225       12600 :                                             operators.erase(it);
     226             :                                         }
     227       18900 :                                         if((real_ao & advgetopt::ASSIGNMENT_OPERATOR_SPACE) != 0)
     228             :                                         {
     229       12600 :                                             auto it(std::find(operators.begin(), operators.end(), "space"));
     230       12600 :                                             CATCH_REQUIRE(it != operators.end());
     231       12600 :                                             operators.erase(it);
     232             :                                         }
     233             : 
     234       18900 :                                         CATCH_REQUIRE(operators.empty());
     235             :                                     }
     236       47040 :                                     else if(var_name == "comment")
     237             :                                     {
     238       25200 :                                         def_c = false;
     239       50400 :                                         std::vector<std::string> comments;
     240       25200 :                                         snapdev::tokenize_string(comments, var_value, ",");
     241             : 
     242       25200 :                                         if((c & advgetopt::COMMENT_INI) != 0)
     243             :                                         {
     244       10800 :                                             auto it(std::find(comments.begin(), comments.end(), "ini"));
     245       10800 :                                             CATCH_REQUIRE(it != comments.end());
     246       10800 :                                             comments.erase(it);
     247             :                                         }
     248       25200 :                                         if((c & advgetopt::COMMENT_SHELL) != 0)
     249             :                                         {
     250       10800 :                                             auto it(std::find(comments.begin(), comments.end(), "shell"));
     251       10800 :                                             CATCH_REQUIRE(it != comments.end());
     252       10800 :                                             comments.erase(it);
     253             :                                         }
     254       25200 :                                         if((c & advgetopt::COMMENT_CPP) != 0)
     255             :                                         {
     256       10800 :                                             auto it(std::find(comments.begin(), comments.end(), "cpp"));
     257       10800 :                                             CATCH_REQUIRE(it != comments.end());
     258       10800 :                                             comments.erase(it);
     259             :                                         }
     260       25200 :                                         if(c == advgetopt::COMMENT_NONE)
     261             :                                         {
     262        3600 :                                             auto it(std::find(comments.begin(), comments.end(), "none"));
     263        3600 :                                             CATCH_REQUIRE(it != comments.end());
     264        3600 :                                             comments.erase(it);
     265             :                                         }
     266             : 
     267       25200 :                                         CATCH_REQUIRE(comments.empty());
     268             :                                     }
     269       21840 :                                     else if(var_name == "section-operator")
     270             :                                     {
     271       21840 :                                         def_so = false;
     272       43680 :                                         std::vector<std::string> section_operators;
     273       21840 :                                         snapdev::tokenize_string(section_operators, var_value, ",");
     274             : 
     275       21840 :                                         if((so & advgetopt::SECTION_OPERATOR_C) != 0)
     276             :                                         {
     277       11760 :                                             auto it(std::find(section_operators.begin(), section_operators.end(), "c"));
     278       11760 :                                             CATCH_REQUIRE(it != section_operators.end());
     279       11760 :                                             section_operators.erase(it);
     280             :                                         }
     281       21840 :                                         if((so & advgetopt::SECTION_OPERATOR_CPP) != 0)
     282             :                                         {
     283       11760 :                                             auto it(std::find(section_operators.begin(), section_operators.end(), "cpp"));
     284       11760 :                                             CATCH_REQUIRE(it != section_operators.end());
     285       11760 :                                             section_operators.erase(it);
     286             :                                         }
     287       21840 :                                         if((so & advgetopt::SECTION_OPERATOR_BLOCK) != 0)
     288             :                                         {
     289       11760 :                                             auto it(std::find(section_operators.begin(), section_operators.end(), "block"));
     290       11760 :                                             CATCH_REQUIRE(it != section_operators.end());
     291       11760 :                                             section_operators.erase(it);
     292             :                                         }
     293       21840 :                                         if((so & advgetopt::SECTION_OPERATOR_INI_FILE) != 0)
     294             :                                         {
     295       10080 :                                             auto it(std::find(section_operators.begin(), section_operators.end(), "ini-file"));
     296       10080 :                                             CATCH_REQUIRE(it != section_operators.end());
     297       10080 :                                             section_operators.erase(it);
     298             :                                         }
     299             : 
     300       21840 :                                         CATCH_REQUIRE(section_operators.empty());
     301             :                                     }
     302             :                                     else
     303             :                                     {
     304           0 :                                         CATCH_REQUIRE(("unknown var_name = " + var_name) == std::string());
     305             :                                     }
     306             :                                 }
     307             : 
     308       25200 :                                 if(def_lc)
     309             :                                 {
     310        4200 :                                     CATCH_REQUIRE(static_cast<advgetopt::line_continuation_t>(lc) == advgetopt::line_continuation_t::line_continuation_unix);
     311             :                                 }
     312       25200 :                                 if(def_ao)
     313             :                                 {
     314        6300 :                                     CATCH_REQUIRE(real_ao == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
     315             :                                 }
     316       25200 :                                 if(def_c)
     317             :                                 {
     318           0 :                                     CATCH_REQUIRE(c == (advgetopt::COMMENT_INI | advgetopt::COMMENT_SHELL));
     319             :                                 }
     320             :                             }
     321             :                         }
     322             :                     }
     323             :                 }
     324             :             }
     325             :         }
     326             :     }
     327             :     CATCH_END_SECTION()
     328             : 
     329           4 :     CATCH_START_SECTION("Check non-existant filename")
     330             :     {
     331           1 :         advgetopt::conf_file_setup setup(
     332             :                       "/etc/advgetopt/unknown-file.conf"
     333             :                     , advgetopt::line_continuation_t::line_continuation_fortran
     334             :                     , advgetopt::ASSIGNMENT_OPERATOR_COLON
     335             :                     , advgetopt::COMMENT_INI
     336           2 :                     , advgetopt::SECTION_OPERATOR_CPP);
     337             : 
     338           1 :         CATCH_REQUIRE(setup.get_original_filename() == "/etc/advgetopt/unknown-file.conf");
     339             : 
     340           1 :         CATCH_REQUIRE(setup.is_valid());
     341           1 :         CATCH_REQUIRE(setup.get_filename() == "/etc/advgetopt/unknown-file.conf");
     342           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_fortran);
     343           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_COLON);
     344           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_INI);
     345           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_CPP);
     346             : 
     347           1 :         CATCH_REQUIRE(setup.get_config_url() == "file:///etc/advgetopt/unknown-file.conf?line-continuation=fortran&assignment-operator=colon&comment=ini&section-operator=cpp");
     348             :     }
     349             :     CATCH_END_SECTION()
     350           2 : }
     351             : 
     352             : 
     353             : 
     354           3 : CATCH_TEST_CASE("config_reload_tests", "[config][getopt][valid]")
     355             : {
     356           2 :     CATCH_START_SECTION("Load a file, update it, verify it does not get reloaded")
     357             :     {
     358           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("reload", "load-twice");
     359             : 
     360             :         {
     361           2 :             std::ofstream config_file;
     362           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
     363           1 :             CATCH_REQUIRE(config_file.good());
     364           1 :             config_file <<
     365             :                 "# Auto-generated\n"
     366             :                 "param=value\n"
     367             :                 "changing=without reloading is useless\n"
     368             :                 "test=1009\n"
     369             :             ;
     370             :         }
     371             : 
     372           2 :         advgetopt::conf_file::pointer_t file1;
     373             :         {
     374           1 :             advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
     375             :                                 , advgetopt::line_continuation_t::line_continuation_single_line
     376             :                                 , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
     377             :                                 , advgetopt::COMMENT_SHELL
     378           2 :                                 , advgetopt::SECTION_OPERATOR_NONE);
     379             : 
     380           1 :             CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
     381             : 
     382           1 :             CATCH_REQUIRE(setup.is_valid());
     383           1 :             CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_single_line);
     384           1 :             CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
     385           1 :             CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
     386           1 :             CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
     387             : 
     388           1 :             file1 = advgetopt::conf_file::get_conf_file(setup);
     389             : 
     390           1 :             CATCH_REQUIRE(file1->get_setup().get_config_url() == setup.get_config_url());
     391           1 :             CATCH_REQUIRE(file1->get_errno() == 0);
     392           1 :             CATCH_REQUIRE(file1->get_sections().empty());
     393           1 :             CATCH_REQUIRE(file1->get_parameters().size() == 3);
     394             : 
     395           1 :             CATCH_REQUIRE(file1->has_parameter("param"));
     396           1 :             CATCH_REQUIRE(file1->has_parameter("changing"));
     397           1 :             CATCH_REQUIRE(file1->has_parameter("test"));
     398             : 
     399           1 :             CATCH_REQUIRE(file1->get_parameter("param") == "value");
     400           1 :             CATCH_REQUIRE(file1->get_parameter("changing") == "without reloading is useless");
     401           1 :             CATCH_REQUIRE(file1->get_parameter("test") == "1009");
     402             :         }
     403             : 
     404             :         // change all the values now
     405             :         {
     406           2 :             std::ofstream config_file;
     407           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
     408           1 :             CATCH_REQUIRE(config_file.good());
     409           1 :             config_file <<
     410             :                 "# Auto-generated\n"
     411             :                 "param=new data\n"
     412             :                 "new=this is not even acknowledge\n"
     413             :                 "changing=special value\n"
     414             :                 "test=9010\n"
     415             :                 "level=three\n"
     416             :             ;
     417             :         }
     418             : 
     419             :         // "reloading" that very same file has the old data
     420             :         {
     421           1 :             advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
     422             :                                 , advgetopt::line_continuation_t::line_continuation_single_line
     423             :                                 , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
     424             :                                 , advgetopt::COMMENT_SHELL
     425           2 :                                 , advgetopt::SECTION_OPERATOR_NONE);
     426             : 
     427           1 :             CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
     428             : 
     429           1 :             CATCH_REQUIRE(setup.is_valid());
     430           1 :             CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_single_line);
     431           1 :             CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
     432           1 :             CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
     433           1 :             CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
     434             : 
     435           2 :             advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
     436             : 
     437             :             // exact same pointer
     438             :             //
     439           1 :             CATCH_REQUIRE(file == file1);
     440             : 
     441           1 :             CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
     442           1 :             CATCH_REQUIRE(file->get_errno() == 0);
     443           1 :             CATCH_REQUIRE(file->get_sections().empty());
     444           1 :             CATCH_REQUIRE(file->get_parameters().size() == 3);
     445             : 
     446           1 :             CATCH_REQUIRE(file->has_parameter("param"));
     447           1 :             CATCH_REQUIRE(file->has_parameter("changing"));
     448           1 :             CATCH_REQUIRE(file->has_parameter("test"));
     449             : 
     450           1 :             CATCH_REQUIRE(file->get_parameter("param") == "value");
     451           1 :             CATCH_REQUIRE(file->get_parameter("changing") == "without reloading is useless");
     452           1 :             CATCH_REQUIRE(file->get_parameter("test") == "1009");
     453             :         }
     454             :     }
     455             :     CATCH_END_SECTION()
     456           1 : }
     457             : 
     458             : 
     459             : 
     460           3 : CATCH_TEST_CASE("config_duplicated_variables", "[config][getopt][valid]")
     461             : {
     462           2 :     CATCH_START_SECTION("file with the same variable defined multiple times")
     463             :     {
     464           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("duplicated-variable", "multiple");
     465             : 
     466             :         {
     467           2 :             std::ofstream config_file;
     468           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
     469           1 :             CATCH_REQUIRE(config_file.good());
     470           1 :             config_file <<
     471             :                 "# Auto-generated\n"
     472             :                 "unique    = perfect  \n"
     473             :                 "multiple  = defintions\n"
     474             :                 "another   = just fine \t\n"
     475             :                 "multiple  = value\r\n"
     476             :                 "good      = variable \n"
     477             :                 "multiple  = set\n"
     478             :                 "more      = data\t \n"
     479             :             ;
     480             :         }
     481             : 
     482           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
     483             :                             , advgetopt::line_continuation_t::line_continuation_single_line
     484             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
     485             :                             , advgetopt::COMMENT_SHELL
     486           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
     487             : 
     488           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
     489             : 
     490           1 :         CATCH_REQUIRE(setup.is_valid());
     491           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_single_line);
     492           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
     493           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
     494           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
     495             : 
     496           2 :         std::unique_ptr<char, decltype(&::free)> fn(realpath(SNAP_CATCH2_NAMESPACE::g_config_filename.c_str(), nullptr), &::free);
     497           2 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
     498             :                       "warning: parameter \"multiple\" on line 5 in"
     499             :                       " configuration file \""
     500           2 :                     + std::string(fn.get())
     501           3 :                     + "\" was found twice in the same configuration file.");
     502           2 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
     503             :                       "warning: parameter \"multiple\" on line 7 in"
     504             :                       " configuration file \""
     505           2 :                     + std::string(fn.get())
     506           3 :                     + "\" was found twice in the same configuration file.");
     507           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
     508           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
     509             : 
     510           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
     511           1 :         CATCH_REQUIRE(file->get_errno() == 0);
     512           1 :         CATCH_REQUIRE(file->get_sections().empty());
     513           1 :         CATCH_REQUIRE(file->get_parameters().size() == 5);
     514             : 
     515           1 :         CATCH_REQUIRE(file->has_parameter("unique"));
     516           1 :         CATCH_REQUIRE(file->has_parameter("another"));
     517           1 :         CATCH_REQUIRE(file->has_parameter("good"));
     518           1 :         CATCH_REQUIRE(file->has_parameter("more"));
     519           1 :         CATCH_REQUIRE(file->has_parameter("multiple"));
     520             : 
     521           1 :         CATCH_REQUIRE(file->get_parameter("unique") == "perfect");
     522           1 :         CATCH_REQUIRE(file->get_parameter("another") == "just fine");
     523           1 :         CATCH_REQUIRE(file->get_parameter("good") == "variable");
     524           1 :         CATCH_REQUIRE(file->get_parameter("more") == "data");
     525           1 :         CATCH_REQUIRE(file->get_parameter("multiple") == "set");
     526             : 
     527             :         // we get a warning while reading; but not when directly
     528             :         // accessing the file object
     529             :         //
     530           1 :         CATCH_REQUIRE(file->set_parameter(std::string(), "multiple", "new value"));
     531           1 :         CATCH_REQUIRE(file->get_parameter("multiple") == "new value");
     532             :     }
     533             :     CATCH_END_SECTION()
     534           1 : }
     535             : 
     536             : 
     537             : 
     538           3 : CATCH_TEST_CASE("config_callback_calls", "[config][getopt][valid]")
     539             : {
     540           2 :     CATCH_START_SECTION("setup a callback and test the set_parameter()/erase() functions")
     541             :     {
     542           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("callback-variable", "callback");
     543             : 
     544             :         {
     545           2 :             std::ofstream config_file;
     546           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
     547           1 :             CATCH_REQUIRE(config_file.good());
     548           1 :             config_file <<
     549             :                 "# Auto-generated\n"
     550             :                 "unique     = perfect  \n"
     551             :                 "definition = long value here\n"
     552             :                 "another    = just fine \t\n"
     553             :                 "multiple   = value\r\n"
     554             :                 "good       = variable \n"
     555             :                 "organized  = set\n"
     556             :                 "more       = data\t \n"
     557             :             ;
     558             :         }
     559             : 
     560           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
     561             :                             , advgetopt::line_continuation_t::line_continuation_single_line
     562             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
     563             :                             , advgetopt::COMMENT_SHELL
     564           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
     565             : 
     566           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
     567             : 
     568           1 :         CATCH_REQUIRE(setup.is_valid());
     569           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_single_line);
     570           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
     571           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
     572           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
     573             : 
     574           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
     575             : 
     576           2 :         struct conf_data
     577             :         {
     578             :             advgetopt::conf_file::pointer_t f_conf_file = advgetopt::conf_file::pointer_t();
     579             :             advgetopt::callback_action_t    f_expected_action = advgetopt::callback_action_t::created;
     580             :             std::string                     f_expected_variable = std::string();
     581             :             std::string                     f_expected_value = std::string();
     582             :         };
     583           2 :         conf_data cf_data;
     584           1 :         cf_data.f_conf_file = file;
     585             : 
     586             :         struct conf_callback
     587             :         {
     588           6 :             void operator () (advgetopt::conf_file::pointer_t conf_file
     589             :                             , advgetopt::callback_action_t action
     590             :                             , std::string const & variable_name
     591             :                             , std::string const & value)
     592             :             {
     593           6 :                 CATCH_REQUIRE(conf_file == f_data->f_conf_file);
     594           6 :                 CATCH_REQUIRE(action == f_data->f_expected_action);
     595           6 :                 CATCH_REQUIRE(variable_name == f_data->f_expected_variable);
     596           6 :                 CATCH_REQUIRE(value == f_data->f_expected_value);
     597           6 :                 CATCH_REQUIRE(conf_file->get_parameter(variable_name) == f_data->f_expected_value);
     598           6 :             }
     599             : 
     600             :             conf_data * f_data = nullptr;
     601             :         };
     602           1 :         conf_callback cf;
     603           1 :         cf.f_data = &cf_data;
     604             : 
     605           1 :         advgetopt::conf_file::callback_id_t callback_id(file->add_callback(cf));
     606             : 
     607           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
     608           1 :         CATCH_REQUIRE(file->get_errno() == 0);
     609           1 :         CATCH_REQUIRE_FALSE(file->was_modified());
     610           1 :         CATCH_REQUIRE(file->get_sections().empty());
     611           1 :         CATCH_REQUIRE(file->get_parameters().size() == 7);
     612             : 
     613           1 :         CATCH_REQUIRE(file->has_parameter("unique"));
     614           1 :         CATCH_REQUIRE(file->has_parameter("definition"));
     615           1 :         CATCH_REQUIRE(file->has_parameter("another"));
     616           1 :         CATCH_REQUIRE(file->has_parameter("multiple"));
     617           1 :         CATCH_REQUIRE(file->has_parameter("good"));
     618           1 :         CATCH_REQUIRE(file->has_parameter("organized"));
     619           1 :         CATCH_REQUIRE(file->has_parameter("more"));
     620             : 
     621           1 :         CATCH_REQUIRE(file->get_parameter("unique") == "perfect");
     622           1 :         CATCH_REQUIRE(file->get_parameter("definition") == "long value here");
     623           1 :         CATCH_REQUIRE(file->get_parameter("another") == "just fine");
     624           1 :         CATCH_REQUIRE(file->get_parameter("multiple") == "value");
     625           1 :         CATCH_REQUIRE(file->get_parameter("good") == "variable");
     626           1 :         CATCH_REQUIRE(file->get_parameter("organized") == "set");
     627           1 :         CATCH_REQUIRE(file->get_parameter("more") == "data");
     628             : 
     629             :         // updated action
     630             :         //
     631           1 :         cf_data.f_expected_action = advgetopt::callback_action_t::updated;
     632           1 :         cf_data.f_expected_variable = "multiple";
     633           1 :         cf_data.f_expected_value = "new value";
     634           1 :         CATCH_REQUIRE(file->set_parameter(std::string(), "multiple", "new value"));
     635           1 :         CATCH_REQUIRE(file->was_modified());
     636           1 :         CATCH_REQUIRE(file->get_parameters().size() == 7);
     637           1 :         CATCH_REQUIRE(file->get_parameter("multiple") == "new value");
     638             : 
     639             :         // created action
     640             :         //
     641           1 :         cf_data.f_expected_action = advgetopt::callback_action_t::created;
     642           1 :         cf_data.f_expected_variable = "new-param";
     643           1 :         cf_data.f_expected_value = "with this value";
     644           1 :         CATCH_REQUIRE(file->set_parameter(std::string(), "new_param", "with this value"));
     645           1 :         CATCH_REQUIRE(file->was_modified());
     646           1 :         CATCH_REQUIRE(file->get_parameters().size() == 8);
     647           1 :         CATCH_REQUIRE(file->has_parameter("new-param"));
     648           1 :         CATCH_REQUIRE(file->get_parameter("new-param") == "with this value");
     649           1 :         CATCH_REQUIRE(file->has_parameter("new_param"));
     650           1 :         CATCH_REQUIRE(file->get_parameter("new_param") == "with this value");
     651             : 
     652             :         // updated action when modifying
     653             :         //
     654           1 :         cf_data.f_expected_action = advgetopt::callback_action_t::updated;
     655           1 :         cf_data.f_expected_variable = "new-param";
     656           1 :         cf_data.f_expected_value = "change completely";
     657           1 :         CATCH_REQUIRE(file->set_parameter(std::string(), "new_param", "change completely"));
     658           1 :         CATCH_REQUIRE(file->was_modified());
     659           1 :         CATCH_REQUIRE(file->get_parameters().size() == 8);
     660           1 :         CATCH_REQUIRE(file->has_parameter("new-param"));
     661           1 :         CATCH_REQUIRE(file->get_parameter("new-param") == "change completely");
     662           1 :         CATCH_REQUIRE(file->has_parameter("new_param"));
     663           1 :         CATCH_REQUIRE(file->get_parameter("new_param") == "change completely");
     664             : 
     665             :         // erased action
     666             :         //
     667           1 :         cf_data.f_expected_action = advgetopt::callback_action_t::erased;
     668           1 :         cf_data.f_expected_variable = "new-param";
     669           1 :         cf_data.f_expected_value = std::string();
     670           1 :         CATCH_REQUIRE(file->erase_parameter("new_param"));
     671           1 :         CATCH_REQUIRE(file->was_modified());
     672           1 :         CATCH_REQUIRE(file->get_parameters().size() == 7);
     673           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("new-param"));
     674           1 :         CATCH_REQUIRE(file->get_parameter("new-param") == std::string());
     675           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("new_param"));
     676           1 :         CATCH_REQUIRE(file->get_parameter("new_param") == std::string());
     677           1 :         CATCH_REQUIRE_FALSE(file->erase_parameter("new_param"));
     678             : 
     679             :         // created action again (because it was erased)
     680             :         //
     681           1 :         cf_data.f_expected_action = advgetopt::callback_action_t::created;
     682           1 :         cf_data.f_expected_variable = "new-param";
     683           1 :         cf_data.f_expected_value = "with this value";
     684           1 :         CATCH_REQUIRE(file->set_parameter(std::string(), "new_param", "with this value"));
     685           1 :         CATCH_REQUIRE(file->was_modified());
     686           1 :         CATCH_REQUIRE(file->get_parameters().size() == 8);
     687           1 :         CATCH_REQUIRE(file->has_parameter("new-param"));
     688           1 :         CATCH_REQUIRE(file->get_parameter("new-param") == "with this value");
     689           1 :         CATCH_REQUIRE(file->has_parameter("new_param"));
     690           1 :         CATCH_REQUIRE(file->get_parameter("new_param") == "with this value");
     691             : 
     692           1 :         file->remove_callback(callback_id);
     693           1 :         cf_data.f_expected_action = advgetopt::callback_action_t::created;
     694           1 :         cf_data.f_expected_variable = "ignored";
     695           1 :         cf_data.f_expected_value = "ignored";
     696           1 :         CATCH_REQUIRE(file->set_parameter(std::string(), "new_param", "unnoticed change"));
     697           1 :         CATCH_REQUIRE(file->was_modified());
     698           1 :         CATCH_REQUIRE(file->get_parameters().size() == 8);
     699           1 :         CATCH_REQUIRE(file->has_parameter("new-param"));
     700           1 :         CATCH_REQUIRE(file->get_parameter("new-param") == "unnoticed change");
     701           1 :         CATCH_REQUIRE(file->has_parameter("new_param"));
     702           1 :         CATCH_REQUIRE(file->get_parameter("new_param") == "unnoticed change");
     703             : 
     704             :         // further calls do nothing more
     705             :         //
     706           1 :         file->remove_callback(callback_id);
     707           1 :         CATCH_REQUIRE(file->set_parameter(std::string(), "new_param", "still unnoticed"));
     708           1 :         CATCH_REQUIRE(file->was_modified());
     709           1 :         CATCH_REQUIRE(file->get_parameters().size() == 8);
     710           1 :         CATCH_REQUIRE(file->has_parameter("new-param"));
     711           1 :         CATCH_REQUIRE(file->get_parameter("new-param") == "still unnoticed");
     712           1 :         CATCH_REQUIRE(file->has_parameter("new_param"));
     713           1 :         CATCH_REQUIRE(file->get_parameter("new_param") == "still unnoticed");
     714             : 
     715             :         // and we can always re-add it
     716             :         //
     717           1 :         CATCH_REQUIRE(callback_id != file->add_callback(cf));
     718           1 :         cf_data.f_expected_action = advgetopt::callback_action_t::updated;
     719           1 :         cf_data.f_expected_variable = "new-param";
     720           1 :         cf_data.f_expected_value = "we're back";
     721           1 :         CATCH_REQUIRE(file->set_parameter(std::string(), "new_param", "we're back"));
     722           1 :         CATCH_REQUIRE(file->was_modified());
     723           1 :         CATCH_REQUIRE(file->get_parameters().size() == 8);
     724           1 :         CATCH_REQUIRE(file->has_parameter("new-param"));
     725           1 :         CATCH_REQUIRE(file->get_parameter("new-param") == "we're back");
     726           1 :         CATCH_REQUIRE(file->has_parameter("new_param"));
     727           1 :         CATCH_REQUIRE(file->get_parameter("new_param") == "we're back");
     728             : 
     729             :         // until you save it remains true even if you were to restore the
     730             :         // state to "normal" (we do not keep a copy of the original value
     731             :         // as found in the file.)
     732             :         //
     733           1 :         CATCH_REQUIRE(file->was_modified());
     734             :     }
     735             :     CATCH_END_SECTION()
     736           1 : }
     737             : 
     738             : 
     739             : 
     740           8 : CATCH_TEST_CASE("config_line_continuation_tests", "[config][getopt][valid]")
     741             : {
     742          12 :     CATCH_START_SECTION("single_line")
     743             :     {
     744           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("line-continuation", "single-line");
     745             : 
     746             :         {
     747           2 :             std::ofstream config_file;
     748           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
     749           1 :             CATCH_REQUIRE(config_file.good());
     750           1 :             config_file <<
     751             :                 "# Auto-generated\n"
     752             :                 "normal=param\n"
     753             :                 "\n"
     754             :                 "rfc-822=start here\n"
     755             :                 "  continue=there\n"
     756             :                 "\n"
     757             :                 "msdos=end with &\n"
     758             :                 "  and-continue=on next line\n"
     759             :                 "\n"
     760             :                 "unix=end with \\\n"
     761             :                 "to-continue=like this\n"
     762             :                 "\n"
     763             :                 "fortran=fortran is funny\n"
     764             :                 "&since=it starts with an & on the following line\n"
     765             :                 "\n"
     766             :                 "semicolon=this ends with\n"
     767             :                 "a=semi-colon only;\n"
     768             :             ;
     769             :         }
     770             : 
     771           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
     772             :                             , advgetopt::line_continuation_t::line_continuation_single_line
     773             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
     774             :                             , advgetopt::COMMENT_SHELL
     775           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
     776             : 
     777           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
     778             : 
     779           1 :         CATCH_REQUIRE(setup.is_valid());
     780           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_single_line);
     781           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
     782           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
     783           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
     784             : 
     785           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
     786             : 
     787           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
     788           1 :         CATCH_REQUIRE(file->get_errno() == 0);
     789           1 :         CATCH_REQUIRE(file->get_sections().empty());
     790           1 :         CATCH_REQUIRE(file->get_parameters().size() == 11);
     791             : 
     792           1 :         CATCH_REQUIRE(file->has_parameter("normal"));
     793           1 :         CATCH_REQUIRE(file->has_parameter("rfc-822"));
     794           1 :         CATCH_REQUIRE(file->has_parameter("continue"));
     795           1 :         CATCH_REQUIRE(file->has_parameter("msdos"));
     796           1 :         CATCH_REQUIRE(file->has_parameter("and-continue"));
     797           1 :         CATCH_REQUIRE(file->has_parameter("unix"));
     798           1 :         CATCH_REQUIRE(file->has_parameter("to-continue"));
     799           1 :         CATCH_REQUIRE(file->has_parameter("fortran"));
     800           1 :         CATCH_REQUIRE(file->has_parameter("&since"));
     801           1 :         CATCH_REQUIRE(file->has_parameter("semicolon"));
     802           1 :         CATCH_REQUIRE(file->has_parameter("a"));
     803             : 
     804           1 :         CATCH_REQUIRE(file->get_parameter("normal") == "param");
     805           1 :         CATCH_REQUIRE(file->get_parameter("rfc-822") == "start here");
     806           1 :         CATCH_REQUIRE(file->get_parameter("continue") == "there");
     807           1 :         CATCH_REQUIRE(file->get_parameter("msdos") == "end with &");
     808           1 :         CATCH_REQUIRE(file->get_parameter("and-continue") == "on next line");
     809           1 :         CATCH_REQUIRE(file->get_parameter("unix") == "end with \\");
     810           1 :         CATCH_REQUIRE(file->get_parameter("to-continue") == "like this");
     811           1 :         CATCH_REQUIRE(file->get_parameter("fortran") == "fortran is funny");
     812           1 :         CATCH_REQUIRE(file->get_parameter("&since") == "it starts with an & on the following line");
     813           1 :         CATCH_REQUIRE(file->get_parameter("semicolon") == "this ends with");
     814           1 :         CATCH_REQUIRE(file->get_parameter("a") == "semi-colon only;");
     815             : 
     816     1114113 :         for(int c(0); c < 0x110000; ++c)
     817             :         {
     818     1114112 :             if(c == '=')
     819             :             {
     820           1 :                 CATCH_REQUIRE(file->is_assignment_operator(c));
     821             :             }
     822             :             else
     823             :             {
     824     1114111 :                 CATCH_REQUIRE_FALSE(file->is_assignment_operator(c));
     825             :             }
     826             :         }
     827             :     }
     828             :     CATCH_END_SECTION()
     829             : 
     830          12 :     CATCH_START_SECTION("rfc822")
     831             :     {
     832           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("line-continuation", "rfc822");
     833             : 
     834             :         {
     835           2 :             std::ofstream config_file;
     836           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
     837           1 :             CATCH_REQUIRE(config_file.good());
     838           1 :             config_file <<
     839             :                 "# Auto-generated\n"
     840             :                 "normal=param\n"
     841             :                 "\n"
     842             :                 "rfc-822=start here\n"
     843             :                 "  continue=there\n"
     844             :                 "\n"
     845             :                 "msdos=end with &\n"
     846             :                 "  and-continue=on next line\n"
     847             :                 "\n"
     848             :                 "unix=end with \\\n"
     849             :                 "to-continue=like this\n"
     850             :                 "\n"
     851             :                 "fortran=fortran is funny\n"
     852             :                 "&since=it starts with an & on the following line\n"
     853             :                 "\n"
     854             :                 "semicolon=this ends with\n"
     855             :                 "a=semi-colon only;\n"
     856             :             ;
     857             :         }
     858             : 
     859           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
     860             :                             , advgetopt::line_continuation_t::line_continuation_rfc_822
     861             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
     862             :                             , advgetopt::COMMENT_SHELL
     863           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
     864             : 
     865           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
     866             : 
     867           1 :         CATCH_REQUIRE(setup.is_valid());
     868           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_rfc_822);
     869           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
     870           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
     871           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
     872             : 
     873           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
     874             : 
     875           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
     876           1 :         CATCH_REQUIRE(file->get_errno() == 0);
     877           1 :         CATCH_REQUIRE(file->get_sections().empty());
     878           1 :         CATCH_REQUIRE(file->get_parameters().size() == 9);
     879             : 
     880           1 :         CATCH_REQUIRE(file->has_parameter("normal"));
     881           1 :         CATCH_REQUIRE(file->has_parameter("rfc-822"));
     882           1 :         CATCH_REQUIRE(file->has_parameter("msdos"));
     883           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("and-continue"));
     884           1 :         CATCH_REQUIRE(file->has_parameter("unix"));
     885           1 :         CATCH_REQUIRE(file->has_parameter("to-continue"));
     886           1 :         CATCH_REQUIRE(file->has_parameter("fortran"));
     887           1 :         CATCH_REQUIRE(file->has_parameter("&since"));
     888           1 :         CATCH_REQUIRE(file->has_parameter("semicolon"));
     889           1 :         CATCH_REQUIRE(file->has_parameter("a"));
     890             : 
     891           1 :         CATCH_REQUIRE(file->get_parameter("normal") == "param");
     892           1 :         CATCH_REQUIRE(file->get_parameter("rfc-822") == "start herecontinue=there");
     893           1 :         CATCH_REQUIRE(file->get_parameter("msdos") == "end with &and-continue=on next line");
     894           1 :         CATCH_REQUIRE(file->get_parameter("and-continue") == std::string());
     895           1 :         CATCH_REQUIRE(file->get_parameter("unix") == "end with \\");
     896           1 :         CATCH_REQUIRE(file->get_parameter("to-continue") == "like this");
     897           1 :         CATCH_REQUIRE(file->get_parameter("fortran") == "fortran is funny");
     898           1 :         CATCH_REQUIRE(file->get_parameter("&since") == "it starts with an & on the following line");
     899           1 :         CATCH_REQUIRE(file->get_parameter("semicolon") == "this ends with");
     900           1 :         CATCH_REQUIRE(file->get_parameter("a") == "semi-colon only;");
     901             :     }
     902             :     CATCH_END_SECTION()
     903             : 
     904          12 :     CATCH_START_SECTION("msdos")
     905             :     {
     906           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("line-continuation", "msdos");
     907             : 
     908             :         {
     909           2 :             std::ofstream config_file;
     910           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
     911           1 :             CATCH_REQUIRE(config_file.good());
     912           1 :             config_file <<
     913             :                 "# Auto-generated\n"
     914             :                 "normal=param\n"
     915             :                 "\n"
     916             :                 "rfc-822=start here\n"
     917             :                 "  continue=there\n"
     918             :                 "\n"
     919             :                 "msdos=end with &\n"
     920             :                 "  and-continue=on next line\n"
     921             :                 "\n"
     922             :                 "unix=end with \\\n"
     923             :                 "to-continue=like this\n"
     924             :                 "\n"
     925             :                 "fortran=fortran is funny\n"
     926             :                 "&since=it starts with an & on the following line\n"
     927             :                 "\n"
     928             :                 "semicolon=this ends with\n"
     929             :                 "a=semi-colon only;\n"
     930             :             ;
     931             :         }
     932             : 
     933           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
     934             :                             , advgetopt::line_continuation_t::line_continuation_msdos
     935             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
     936             :                             , advgetopt::COMMENT_SHELL
     937           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
     938             : 
     939           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
     940             : 
     941           1 :         CATCH_REQUIRE(setup.is_valid());
     942           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_msdos);
     943           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
     944           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
     945           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
     946             : 
     947           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
     948             : 
     949           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
     950           1 :         CATCH_REQUIRE(file->get_errno() == 0);
     951           1 :         CATCH_REQUIRE(file->get_sections().empty());
     952           1 :         CATCH_REQUIRE(file->get_parameters().size() == 10);
     953             : 
     954           1 :         CATCH_REQUIRE(file->has_parameter("normal"));
     955           1 :         CATCH_REQUIRE(file->has_parameter("rfc-822"));
     956           1 :         CATCH_REQUIRE(file->has_parameter("continue"));
     957           1 :         CATCH_REQUIRE(file->has_parameter("msdos"));
     958           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("and-continue"));
     959           1 :         CATCH_REQUIRE(file->has_parameter("unix"));
     960           1 :         CATCH_REQUIRE(file->has_parameter("to-continue"));
     961           1 :         CATCH_REQUIRE(file->has_parameter("fortran"));
     962           1 :         CATCH_REQUIRE(file->has_parameter("&since"));
     963           1 :         CATCH_REQUIRE(file->has_parameter("semicolon"));
     964           1 :         CATCH_REQUIRE(file->has_parameter("a"));
     965             : 
     966           1 :         CATCH_REQUIRE(file->get_parameter("normal") == "param");
     967           1 :         CATCH_REQUIRE(file->get_parameter("rfc-822") == "start here");
     968           1 :         CATCH_REQUIRE(file->get_parameter("continue") == "there");
     969           1 :         CATCH_REQUIRE(file->get_parameter("msdos") == "end with   and-continue=on next line");
     970           1 :         CATCH_REQUIRE(file->get_parameter("and-continue") == std::string());
     971           1 :         CATCH_REQUIRE(file->get_parameter("unix") == "end with \\");
     972           1 :         CATCH_REQUIRE(file->get_parameter("to-continue") == "like this");
     973           1 :         CATCH_REQUIRE(file->get_parameter("fortran") == "fortran is funny");
     974           1 :         CATCH_REQUIRE(file->get_parameter("&since") == "it starts with an & on the following line");
     975           1 :         CATCH_REQUIRE(file->get_parameter("semicolon") == "this ends with");
     976           1 :         CATCH_REQUIRE(file->get_parameter("a") == "semi-colon only;");
     977             :     }
     978             :     CATCH_END_SECTION()
     979             : 
     980          12 :     CATCH_START_SECTION("unix")
     981             :     {
     982           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("line-continuation", "unix");
     983             : 
     984             :         {
     985           2 :             std::ofstream config_file;
     986           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
     987           1 :             CATCH_REQUIRE(config_file.good());
     988           1 :             config_file <<
     989             :                 "# Auto-generated\n"
     990             :                 "normal=param\n"
     991             :                 "\n"
     992             :                 "rfc-822=start here\n"
     993             :                 "  continue=there\n"
     994             :                 "\n"
     995             :                 "msdos=end with &\n"
     996             :                 "  and-continue=on next line\n"
     997             :                 "\n"
     998             :                 "unix=end with \\\n"
     999             :                 "to-continue=like this\n"
    1000             :                 "\n"
    1001             :                 "fortran=fortran is funny\n"
    1002             :                 "&since=it starts with an & on the following line\n"
    1003             :                 "\n"
    1004             :                 "semicolon=this ends with\n"
    1005             :                 "a=semi-colon only;\n"
    1006             :             ;
    1007             :         }
    1008             : 
    1009           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1010             :                             , advgetopt::line_continuation_t::line_continuation_unix
    1011             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    1012             :                             , advgetopt::COMMENT_SHELL
    1013           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
    1014             : 
    1015           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1016             : 
    1017           1 :         CATCH_REQUIRE(setup.is_valid());
    1018           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    1019           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    1020           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    1021           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
    1022             : 
    1023           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1024             : 
    1025           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1026           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1027           1 :         CATCH_REQUIRE(file->get_sections().empty());
    1028           1 :         CATCH_REQUIRE(file->get_parameters().size() == 10);
    1029             : 
    1030           1 :         CATCH_REQUIRE(file->has_parameter("normal"));
    1031           1 :         CATCH_REQUIRE(file->has_parameter("rfc-822"));
    1032           1 :         CATCH_REQUIRE(file->has_parameter("continue"));
    1033           1 :         CATCH_REQUIRE(file->has_parameter("msdos"));
    1034           1 :         CATCH_REQUIRE(file->has_parameter("and-continue"));
    1035           1 :         CATCH_REQUIRE(file->has_parameter("unix"));
    1036           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("to-continue"));
    1037           1 :         CATCH_REQUIRE(file->has_parameter("fortran"));
    1038           1 :         CATCH_REQUIRE(file->has_parameter("&since"));
    1039           1 :         CATCH_REQUIRE(file->has_parameter("semicolon"));
    1040           1 :         CATCH_REQUIRE(file->has_parameter("a"));
    1041             : 
    1042           1 :         CATCH_REQUIRE(file->get_parameter("normal") == "param");
    1043           1 :         CATCH_REQUIRE(file->get_parameter("rfc-822") == "start here");
    1044           1 :         CATCH_REQUIRE(file->get_parameter("continue") == "there");
    1045           1 :         CATCH_REQUIRE(file->get_parameter("msdos") == "end with &");
    1046           1 :         CATCH_REQUIRE(file->get_parameter("and-continue") == "on next line");
    1047           1 :         CATCH_REQUIRE(file->get_parameter("unix") == "end with to-continue=like this");
    1048           1 :         CATCH_REQUIRE(file->get_parameter("to-continue") == std::string());
    1049           1 :         CATCH_REQUIRE(file->get_parameter("fortran") == "fortran is funny");
    1050           1 :         CATCH_REQUIRE(file->get_parameter("&since") == "it starts with an & on the following line");
    1051           1 :         CATCH_REQUIRE(file->get_parameter("semicolon") == "this ends with");
    1052           1 :         CATCH_REQUIRE(file->get_parameter("a") == "semi-colon only;");
    1053             :     }
    1054             :     CATCH_END_SECTION()
    1055             : 
    1056          12 :     CATCH_START_SECTION("fortran")
    1057             :     {
    1058           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("line-continuation", "fortran");
    1059             : 
    1060             :         {
    1061           2 :             std::ofstream config_file;
    1062           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1063           1 :             CATCH_REQUIRE(config_file.good());
    1064           1 :             config_file <<
    1065             :                 "# Auto-generated\n"
    1066             :                 "normal=param\n"
    1067             :                 "\n"
    1068             :                 "rfc-822=start here\n"
    1069             :                 "  continue=there\n"
    1070             :                 "\n"
    1071             :                 "msdos=end with &\n"
    1072             :                 "  and-continue=on next line\n"
    1073             :                 "\n"
    1074             :                 "unix=end with \\\n"
    1075             :                 "to-continue=like this\n"
    1076             :                 "\n"
    1077             :                 "fortran=fortran is funny\n"
    1078             :                 "&since=it starts with an & on the following line\n"
    1079             :                 "\n"
    1080             :                 "semicolon=this ends with\n"
    1081             :                 "a=semi-colon only;\n"
    1082             :             ;
    1083             :         }
    1084             : 
    1085           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1086             :                             , advgetopt::line_continuation_t::line_continuation_fortran
    1087             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    1088             :                             , advgetopt::COMMENT_SHELL
    1089           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
    1090             : 
    1091           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1092             : 
    1093           1 :         CATCH_REQUIRE(setup.is_valid());
    1094           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_fortran);
    1095           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    1096           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    1097           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
    1098             : 
    1099           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1100             : 
    1101           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1102           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1103           1 :         CATCH_REQUIRE(file->get_sections().empty());
    1104           1 :         CATCH_REQUIRE(file->get_parameters().size() == 10);
    1105             : 
    1106           1 :         CATCH_REQUIRE(file->has_parameter("normal"));
    1107           1 :         CATCH_REQUIRE(file->has_parameter("rfc-822"));
    1108           1 :         CATCH_REQUIRE(file->has_parameter("continue"));
    1109           1 :         CATCH_REQUIRE(file->has_parameter("msdos"));
    1110           1 :         CATCH_REQUIRE(file->has_parameter("and-continue"));
    1111           1 :         CATCH_REQUIRE(file->has_parameter("unix"));
    1112           1 :         CATCH_REQUIRE(file->has_parameter("to-continue"));
    1113           1 :         CATCH_REQUIRE(file->has_parameter("fortran"));
    1114           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("&since"));
    1115           1 :         CATCH_REQUIRE(file->has_parameter("semicolon"));
    1116           1 :         CATCH_REQUIRE(file->has_parameter("a"));
    1117             : 
    1118           1 :         CATCH_REQUIRE(file->get_parameter("normal") == "param");
    1119           1 :         CATCH_REQUIRE(file->get_parameter("rfc-822") == "start here");
    1120           1 :         CATCH_REQUIRE(file->get_parameter("continue") == "there");
    1121           1 :         CATCH_REQUIRE(file->get_parameter("msdos") == "end with &");
    1122           1 :         CATCH_REQUIRE(file->get_parameter("and-continue") == "on next line");
    1123           1 :         CATCH_REQUIRE(file->get_parameter("unix") == "end with \\");
    1124           1 :         CATCH_REQUIRE(file->get_parameter("to-continue") == "like this");
    1125           1 :         CATCH_REQUIRE(file->get_parameter("fortran") == "fortran is funnysince=it starts with an & on the following line");
    1126           1 :         CATCH_REQUIRE(file->get_parameter("&since") == std::string());
    1127           1 :         CATCH_REQUIRE(file->get_parameter("semicolon") == "this ends with");
    1128           1 :         CATCH_REQUIRE(file->get_parameter("a") == "semi-colon only;");
    1129             :     }
    1130             :     CATCH_END_SECTION()
    1131             : 
    1132          12 :     CATCH_START_SECTION("semicolon")
    1133             :     {
    1134           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("line-continuation", "semicolon");
    1135             : 
    1136             :         {
    1137           2 :             std::ofstream config_file;
    1138           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1139           1 :             CATCH_REQUIRE(config_file.good());
    1140           1 :             config_file <<
    1141             :                 "# Auto-generated\r\n"
    1142             :                 "normal=param\r\n"
    1143             :                 "\r\n"
    1144             :                 "rfc-822=start here\r\n"
    1145             :                 "  continue=there\r\n"
    1146             :                 "\r\n"
    1147             :                 "msdos=end with &\r"
    1148             :                 "  and-continue=on next line\r\n"
    1149             :                 "\r\n"
    1150             :                 "unix=end with \\\r\n"
    1151             :                 "to-continue=like this\r"
    1152             :                 "\r\n"
    1153             :                 "fortran=fortran is funny\r\n"
    1154             :                 "&since=it starts with an & on the following line\r\n"
    1155             :                 "\r"
    1156             :                 "semicolon=this ends with\r\n"
    1157             :                 "a=semi-colon only;\r\n"
    1158             :             ;
    1159             :         }
    1160             : 
    1161           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1162             :                             , advgetopt::line_continuation_t::line_continuation_semicolon
    1163             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    1164             :                             , advgetopt::COMMENT_SHELL
    1165           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
    1166             : 
    1167           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1168             : 
    1169           1 :         CATCH_REQUIRE(setup.is_valid());
    1170           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_semicolon);
    1171           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    1172           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    1173           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
    1174             : 
    1175           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1176             : 
    1177           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1178           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1179           1 :         CATCH_REQUIRE(file->get_sections().empty());
    1180           1 :         CATCH_REQUIRE(file->get_parameters().size() == 1);
    1181             : 
    1182           1 :         CATCH_REQUIRE(file->has_parameter("normal"));
    1183           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("rfc-822"));
    1184           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("continue"));
    1185           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("msdos"));
    1186           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("and-continue"));
    1187           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("unix"));
    1188           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("to-continue"));
    1189           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("fortran"));
    1190           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("&since"));
    1191           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("semicolon"));
    1192           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("a"));
    1193             : 
    1194           1 :         CATCH_REQUIRE(file->get_parameter("normal") == std::string("param\n"
    1195             : "\n"
    1196             : "rfc-822=start here\n"
    1197             : "  continue=there\n"
    1198             : "\n"
    1199             : "msdos=end with &\n"
    1200             : "  and-continue=on next line\n"
    1201             : "\n"
    1202             : "unix=end with \\\n"
    1203             : "to-continue=like this\n"
    1204             : "\n"
    1205             : "fortran=fortran is funny\n"
    1206             : "&since=it starts with an & on the following line\n"
    1207             : "\n"
    1208             : "semicolon=this ends with\n"
    1209             : "a=semi-colon only"));
    1210           1 :         CATCH_REQUIRE(file->get_parameter("rfc-822") == std::string());
    1211           1 :         CATCH_REQUIRE(file->get_parameter("continue") == std::string());
    1212           1 :         CATCH_REQUIRE(file->get_parameter("msdos") == std::string());
    1213           1 :         CATCH_REQUIRE(file->get_parameter("and-continue") == std::string());
    1214           1 :         CATCH_REQUIRE(file->get_parameter("unix") == std::string());
    1215           1 :         CATCH_REQUIRE(file->get_parameter("to-continue") == std::string());
    1216           1 :         CATCH_REQUIRE(file->get_parameter("fortran") == std::string());
    1217           1 :         CATCH_REQUIRE(file->get_parameter("&since") == std::string());
    1218           1 :         CATCH_REQUIRE(file->get_parameter("semicolon") == std::string());
    1219           1 :         CATCH_REQUIRE(file->get_parameter("a") == std::string());
    1220             :     }
    1221             :     CATCH_END_SECTION()
    1222           6 : }
    1223             : 
    1224             : 
    1225             : 
    1226           6 : CATCH_TEST_CASE("config_assignment_operator_tests", "[config][getopt][valid]")
    1227             : {
    1228           8 :     CATCH_START_SECTION("equal")
    1229             :     {
    1230           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("assignment-operator", "equal");
    1231             : 
    1232             :         {
    1233           2 :             std::ofstream config_file;
    1234           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1235           1 :             CATCH_REQUIRE(config_file.good());
    1236           1 :             config_file <<
    1237             :                 "# Auto-generated\n"
    1238             :                 "equal=value\n"
    1239             :                 "\n"
    1240             :                 "name_value=127\n"
    1241             :                 "\n"
    1242             :                 "and=no operator\n"
    1243             :             ;
    1244             :         }
    1245             : 
    1246           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1247             :                             , advgetopt::line_continuation_t::line_continuation_single_line
    1248             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    1249             :                             , advgetopt::COMMENT_SHELL
    1250           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
    1251             : 
    1252           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1253             : 
    1254           1 :         CATCH_REQUIRE(setup.is_valid());
    1255           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_single_line);
    1256           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    1257           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    1258           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
    1259             : 
    1260           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1261             : 
    1262           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1263           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1264           1 :         CATCH_REQUIRE(file->get_sections().empty());
    1265           1 :         CATCH_REQUIRE(file->get_parameters().size() == 3);
    1266             : 
    1267           1 :         CATCH_REQUIRE(file->has_parameter("equal"));
    1268           1 :         CATCH_REQUIRE(file->has_parameter("name-value"));
    1269           1 :         CATCH_REQUIRE(file->has_parameter("and"));
    1270             : 
    1271           1 :         CATCH_REQUIRE(file->get_parameter("equal") == "value");
    1272           1 :         CATCH_REQUIRE(file->get_parameter("name-value") == "127");
    1273           1 :         CATCH_REQUIRE(file->get_parameter("and") == "no operator");
    1274             :     }
    1275             :     CATCH_END_SECTION()
    1276             : 
    1277           8 :     CATCH_START_SECTION("colon")
    1278             :     {
    1279           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("assignment-operator", "colon");
    1280             : 
    1281             :         {
    1282           2 :             std::ofstream config_file;
    1283           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1284           1 :             CATCH_REQUIRE(config_file.good());
    1285           1 :             config_file <<
    1286             :                 "# Auto-generated\n"
    1287             :                 "equal_value\n"
    1288             :                 "\n"
    1289             :                 "name:value=127\n"
    1290             :                 "\n"
    1291             :                 "and_no-operator\n"
    1292             :             ;
    1293             :         }
    1294             : 
    1295           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1296             :                             , advgetopt::line_continuation_t::line_continuation_single_line
    1297             :                             , advgetopt::ASSIGNMENT_OPERATOR_COLON
    1298             :                             , advgetopt::COMMENT_SHELL
    1299           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
    1300             : 
    1301           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1302             : 
    1303           1 :         CATCH_REQUIRE(setup.is_valid());
    1304           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_single_line);
    1305           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_COLON);
    1306           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    1307           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
    1308             : 
    1309           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1310             : 
    1311           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1312           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1313           1 :         CATCH_REQUIRE(file->get_sections().empty());
    1314           1 :         CATCH_REQUIRE(file->get_parameters().size() == 3);
    1315             : 
    1316           1 :         CATCH_REQUIRE(file->has_parameter("equal-value"));
    1317           1 :         CATCH_REQUIRE(file->has_parameter("name"));
    1318           1 :         CATCH_REQUIRE(file->has_parameter("and-no-operator"));
    1319             : 
    1320           1 :         CATCH_REQUIRE(file->get_parameter("equal-value") == std::string());
    1321           1 :         CATCH_REQUIRE(file->get_parameter("name") == "value=127");
    1322           1 :         CATCH_REQUIRE(file->get_parameter("and-no-operator") == std::string());
    1323             :     }
    1324             :     CATCH_END_SECTION()
    1325             : 
    1326           8 :     CATCH_START_SECTION("space")
    1327             :     {
    1328           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("assignment-operator", "space");
    1329             : 
    1330             :         {
    1331           2 :             std::ofstream config_file;
    1332           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1333           1 :             CATCH_REQUIRE(config_file.good());
    1334           1 :             config_file <<
    1335             :                 "# Auto-generated\n"
    1336             :                 "equal-value\n"
    1337             :                 "\n"
    1338             :                 "name 127\n"
    1339             :                 "\n"
    1340             :                 "and-no operator\n"
    1341             :             ;
    1342             :         }
    1343             : 
    1344           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1345             :                             , advgetopt::line_continuation_t::line_continuation_single_line
    1346             :                             , advgetopt::ASSIGNMENT_OPERATOR_SPACE
    1347             :                             , advgetopt::COMMENT_SHELL
    1348           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
    1349             : 
    1350           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1351             : 
    1352           1 :         CATCH_REQUIRE(setup.is_valid());
    1353           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_single_line);
    1354           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_SPACE);
    1355           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    1356           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
    1357             : 
    1358           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1359             : 
    1360           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1361           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1362           1 :         CATCH_REQUIRE(file->get_sections().empty());
    1363           1 :         CATCH_REQUIRE(file->get_parameters().size() == 3);
    1364             : 
    1365           1 :         CATCH_REQUIRE(file->has_parameter("equal-value"));
    1366           1 :         CATCH_REQUIRE(file->has_parameter("name"));
    1367           1 :         CATCH_REQUIRE(file->has_parameter("and-no"));
    1368             : 
    1369           1 :         CATCH_REQUIRE(file->get_parameter("equal-value") == std::string());
    1370           1 :         CATCH_REQUIRE(file->get_parameter("name") == "127");
    1371           1 :         CATCH_REQUIRE(file->get_parameter("and-no") == "operator");
    1372             :     }
    1373             :     CATCH_END_SECTION()
    1374             : 
    1375           8 :     CATCH_START_SECTION("equal_colon_and_space")
    1376             :     {
    1377           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("assignment-operator", "all");
    1378             : 
    1379             :         {
    1380           2 :             std::ofstream config_file;
    1381           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1382           1 :             CATCH_REQUIRE(config_file.good());
    1383           1 :             config_file <<
    1384             :                 "# Auto-generated\n"
    1385             :                 "equal=value\n"
    1386             :                 "\n"
    1387             :                 "name: 127\n"
    1388             :                 "\n"
    1389             :                 "and no operator\n"
    1390             :             ;
    1391             :         }
    1392             : 
    1393           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1394             :                             , advgetopt::line_continuation_t::line_continuation_single_line
    1395             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    1396             :                             | advgetopt::ASSIGNMENT_OPERATOR_COLON
    1397             :                             | advgetopt::ASSIGNMENT_OPERATOR_SPACE
    1398             :                             , advgetopt::COMMENT_SHELL
    1399           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
    1400             : 
    1401           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1402             : 
    1403           1 :         CATCH_REQUIRE(setup.is_valid());
    1404           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_single_line);
    1405           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == (advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    1406             :                                                        | advgetopt::ASSIGNMENT_OPERATOR_COLON
    1407             :                                                        | advgetopt::ASSIGNMENT_OPERATOR_SPACE));
    1408           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    1409           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
    1410             : 
    1411           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1412             : 
    1413           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1414           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1415           1 :         CATCH_REQUIRE(file->get_sections().empty());
    1416           1 :         CATCH_REQUIRE(file->get_parameters().size() == 3);
    1417             : 
    1418           1 :         CATCH_REQUIRE(file->has_parameter("equal"));
    1419           1 :         CATCH_REQUIRE(file->has_parameter("name"));
    1420           1 :         CATCH_REQUIRE(file->has_parameter("and"));
    1421             : 
    1422           1 :         CATCH_REQUIRE(file->get_parameter("equal") == "value");
    1423           1 :         CATCH_REQUIRE(file->get_parameter("name") == "127");
    1424           1 :         CATCH_REQUIRE(file->get_parameter("and") == "no operator");
    1425             :     }
    1426             :     CATCH_END_SECTION()
    1427           4 : }
    1428             : 
    1429             : 
    1430             : 
    1431             : 
    1432             : 
    1433           6 : CATCH_TEST_CASE("config_comment_tests", "[config][getopt][valid]")
    1434             : {
    1435           8 :     CATCH_START_SECTION("ini comment")
    1436             :     {
    1437           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("comment", "ini");
    1438             : 
    1439             :         {
    1440           2 :             std::ofstream config_file;
    1441           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1442           1 :             CATCH_REQUIRE(config_file.good());
    1443           1 :             config_file <<
    1444             :                 "; Auto-generated\n"
    1445             :                 "ini=comment\n"
    1446             :                 ";ignore=this one\n"
    1447             :                 "is=the semi-colon\n"
    1448             :                 ";continuation=with Unix\\\n"
    1449             :                 "also=works for\\\n"
    1450             :                 "comments\n"
    1451             :             ;
    1452             :         }
    1453             : 
    1454           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1455             :                             , advgetopt::line_continuation_t::line_continuation_unix
    1456             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    1457             :                             , advgetopt::COMMENT_INI
    1458           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
    1459             : 
    1460           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1461             : 
    1462           1 :         CATCH_REQUIRE(setup.is_valid());
    1463           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    1464           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    1465           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_INI);
    1466           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
    1467             : 
    1468           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1469             : 
    1470           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1471           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1472           1 :         CATCH_REQUIRE(file->get_sections().empty());
    1473           1 :         CATCH_REQUIRE(file->get_parameters().size() == 2);
    1474             : 
    1475           1 :         CATCH_REQUIRE(file->has_parameter("ini"));
    1476           1 :         CATCH_REQUIRE(file->has_parameter("is"));
    1477             : 
    1478           1 :         CATCH_REQUIRE(file->get_parameter("ini") == "comment");
    1479           1 :         CATCH_REQUIRE(file->get_parameter("is") == "the semi-colon");
    1480             :     }
    1481             :     CATCH_END_SECTION()
    1482             : 
    1483           8 :     CATCH_START_SECTION("shell comment")
    1484             :     {
    1485           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("comment", "shell");
    1486             : 
    1487             :         {
    1488           2 :             std::ofstream config_file;
    1489           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1490           1 :             CATCH_REQUIRE(config_file.good());
    1491           1 :             config_file <<
    1492             :                 "# Auto-generated\n"
    1493             :                 "shell=comment\n"
    1494             :                 "#ignore=this one\n"
    1495             :                 "is=the hash (`#`) character\n"
    1496             :                 "#continuation=with Unix\\\n"
    1497             :                 "also=works for\\\n"
    1498             :                 "comments\n"
    1499             :             ;
    1500             :         }
    1501             : 
    1502           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1503             :                             , advgetopt::line_continuation_t::line_continuation_unix
    1504             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    1505             :                             , advgetopt::COMMENT_SHELL
    1506           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
    1507             : 
    1508           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1509             : 
    1510           1 :         CATCH_REQUIRE(setup.is_valid());
    1511           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    1512           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    1513           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    1514           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
    1515             : 
    1516           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1517             : 
    1518           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1519           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1520           1 :         CATCH_REQUIRE(file->get_sections().empty());
    1521           1 :         CATCH_REQUIRE(file->get_parameters().size() == 2);
    1522             : 
    1523           1 :         CATCH_REQUIRE(file->has_parameter("shell"));
    1524           1 :         CATCH_REQUIRE(file->has_parameter("is"));
    1525             : 
    1526           1 :         CATCH_REQUIRE(file->get_parameter("shell") == "comment");
    1527           1 :         CATCH_REQUIRE(file->get_parameter("is") == "the hash (`#`) character");
    1528             :     }
    1529             :     CATCH_END_SECTION()
    1530             : 
    1531           8 :     CATCH_START_SECTION("C++ comment")
    1532             :     {
    1533           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("comment", "cpp");
    1534             : 
    1535             :         {
    1536           2 :             std::ofstream config_file;
    1537           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1538           1 :             CATCH_REQUIRE(config_file.good());
    1539           1 :             config_file <<
    1540             :                 "// Auto-generated\n"
    1541             :                 "cpp=comment\n"
    1542             :                 "//ignore=this one\n"
    1543             :                 "is=the double slash (`//`)\n"
    1544             :                 "//continuation=with Unix\\\n"
    1545             :                 "also=works for\\\n"
    1546             :                 "comments\n"
    1547             :             ;
    1548             :         }
    1549             : 
    1550           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1551             :                             , advgetopt::line_continuation_t::line_continuation_unix
    1552             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    1553             :                             , advgetopt::COMMENT_CPP
    1554           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
    1555             : 
    1556           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1557             : 
    1558           1 :         CATCH_REQUIRE(setup.is_valid());
    1559           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    1560           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    1561           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_CPP);
    1562           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
    1563             : 
    1564           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1565             : 
    1566           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1567           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1568           1 :         CATCH_REQUIRE(file->get_sections().empty());
    1569           1 :         CATCH_REQUIRE(file->get_parameters().size() == 2);
    1570             : 
    1571           1 :         CATCH_REQUIRE(file->has_parameter("cpp"));
    1572           1 :         CATCH_REQUIRE(file->has_parameter("is"));
    1573             : 
    1574           1 :         CATCH_REQUIRE(file->get_parameter("cpp") == "comment");
    1575           1 :         CATCH_REQUIRE(file->get_parameter("is") == "the double slash (`//`)");
    1576             :     }
    1577             :     CATCH_END_SECTION()
    1578             : 
    1579           8 :     CATCH_START_SECTION("All three comments")
    1580             :     {
    1581           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("comment", "all-comments");
    1582             : 
    1583             :         {
    1584           2 :             std::ofstream config_file;
    1585           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1586           1 :             CATCH_REQUIRE(config_file.good());
    1587           1 :             config_file <<
    1588             :                 "// Auto-generated\n"
    1589             :                 "all=comments\n"
    1590             :                 ";ignore=this one\n"
    1591             :                 "together=for powerful config support\n"
    1592             :                 "#continuation=with Unix\\\n"
    1593             :                 "also=works for\\\n"
    1594             :                 "comments\n"
    1595             :                 "but=maybe\n"
    1596             :                 ";we=should\\\n"
    1597             :                 "test=continuation\n"
    1598             :                 "//with=each\\\n"
    1599             :                 "each=type of comment\n"
    1600             :             ;
    1601             :         }
    1602             : 
    1603           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1604             :                             , advgetopt::line_continuation_t::line_continuation_unix
    1605             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    1606             :                             , advgetopt::COMMENT_INI | advgetopt::COMMENT_SHELL | advgetopt::COMMENT_CPP
    1607           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
    1608             : 
    1609           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1610             : 
    1611           1 :         CATCH_REQUIRE(setup.is_valid());
    1612           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    1613           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    1614           1 :         CATCH_REQUIRE(setup.get_comment() == (advgetopt::COMMENT_INI | advgetopt::COMMENT_SHELL | advgetopt::COMMENT_CPP));
    1615           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
    1616             : 
    1617           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1618             : 
    1619           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1620           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1621           1 :         CATCH_REQUIRE(file->get_sections().empty());
    1622           1 :         CATCH_REQUIRE(file->get_parameters().size() == 3);
    1623             : 
    1624           1 :         CATCH_REQUIRE(file->has_parameter("all"));
    1625           1 :         CATCH_REQUIRE(file->has_parameter("together"));
    1626           1 :         CATCH_REQUIRE(file->has_parameter("but"));
    1627             : 
    1628           1 :         CATCH_REQUIRE(file->get_parameter("all") == "comments");
    1629           1 :         CATCH_REQUIRE(file->get_parameter("together") == "for powerful config support");
    1630           1 :         CATCH_REQUIRE(file->get_parameter("but") == "maybe");
    1631             :     }
    1632             :     CATCH_END_SECTION()
    1633           4 : }
    1634             : 
    1635             : 
    1636             : 
    1637             : 
    1638             : 
    1639           9 : CATCH_TEST_CASE("config_section_tests", "[config][getopt][valid]")
    1640             : {
    1641          14 :     CATCH_START_SECTION("section operator c (.)")
    1642             :     {
    1643           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("section-operator", "section-c");
    1644             : 
    1645             :         {
    1646           2 :             std::ofstream config_file;
    1647           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1648           1 :             CATCH_REQUIRE(config_file.good());
    1649           1 :             config_file <<
    1650             :                 "# Auto-generated\n"
    1651             :                 "a=color\n"
    1652             :                 "a.b=red\n"
    1653             :                 "a.b.c=122\n"
    1654             :                 "m=size\n"
    1655             :                 "z=edge\n"
    1656             :                 "z.b=line\n"
    1657             :                 "z.b.c=12.72\n"
    1658             :             ;
    1659             :         }
    1660             : 
    1661           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1662             :                             , advgetopt::line_continuation_t::line_continuation_unix
    1663             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    1664             :                             , advgetopt::COMMENT_SHELL
    1665           2 :                             , advgetopt::SECTION_OPERATOR_C);
    1666             : 
    1667           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1668             : 
    1669           1 :         CATCH_REQUIRE(setup.is_valid());
    1670           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    1671           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    1672           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    1673           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_C);
    1674             : 
    1675           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1676             : 
    1677           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1678           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1679             : 
    1680           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    1681           1 :         CATCH_REQUIRE(sections.size() == 4);
    1682           1 :         CATCH_REQUIRE(sections.find("a")    != sections.end());
    1683           1 :         CATCH_REQUIRE(sections.find("a::b") != sections.end());
    1684           1 :         CATCH_REQUIRE(sections.find("z")    != sections.end());
    1685           1 :         CATCH_REQUIRE(sections.find("z::b") != sections.end());
    1686             : 
    1687           1 :         CATCH_REQUIRE(file->get_parameters().size() == 7);
    1688             : 
    1689           1 :         CATCH_REQUIRE(file->has_parameter("a"));
    1690           1 :         CATCH_REQUIRE(file->has_parameter("a::b"));
    1691           1 :         CATCH_REQUIRE(file->has_parameter("a::b::c"));
    1692           1 :         CATCH_REQUIRE(file->has_parameter("m"));
    1693           1 :         CATCH_REQUIRE(file->has_parameter("z"));
    1694           1 :         CATCH_REQUIRE(file->has_parameter("z::b"));
    1695           1 :         CATCH_REQUIRE(file->has_parameter("z::b::c"));
    1696             : 
    1697           1 :         CATCH_REQUIRE(file->get_parameter("a") == "color");
    1698           1 :         CATCH_REQUIRE(file->get_parameter("a::b") == "red");
    1699           1 :         CATCH_REQUIRE(file->get_parameter("a::b::c") == "122");
    1700           1 :         CATCH_REQUIRE(file->get_parameter("m") == "size");
    1701           1 :         CATCH_REQUIRE(file->get_parameter("z") == "edge");
    1702           1 :         CATCH_REQUIRE(file->get_parameter("z::b") == "line");
    1703           1 :         CATCH_REQUIRE(file->get_parameter("z::b::c") == "12.72");
    1704             :     }
    1705             :     CATCH_END_SECTION()
    1706             : 
    1707          14 :     CATCH_START_SECTION("section operator c++ (::)")
    1708             :     {
    1709           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("section-operator", "section-cpp");
    1710             : 
    1711             :         {
    1712           2 :             std::ofstream config_file;
    1713           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1714           1 :             CATCH_REQUIRE(config_file.good());
    1715           1 :             config_file <<
    1716             :                 "# Auto-generated\n"
    1717             :                 "a=color\n"
    1718             :                 "a::b=red\n"
    1719             :                 "a::b::c=122\n"
    1720             :                 "m=size\n"
    1721             :                 "z=edge\n"
    1722             :                 "z::b=line\n"
    1723             :                 "z::b::c=12.72\n"
    1724             :             ;
    1725             :         }
    1726             : 
    1727           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1728             :                             , advgetopt::line_continuation_t::line_continuation_unix
    1729             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    1730             :                             , advgetopt::COMMENT_SHELL
    1731           2 :                             , advgetopt::SECTION_OPERATOR_CPP);
    1732             : 
    1733           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1734             : 
    1735           1 :         CATCH_REQUIRE(setup.is_valid());
    1736           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    1737           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    1738           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    1739           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_CPP);
    1740             : 
    1741           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1742             : 
    1743           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1744           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1745             : 
    1746           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    1747           1 :         CATCH_REQUIRE(sections.size() == 4);
    1748           1 :         CATCH_REQUIRE(sections.find("a")    != sections.end());
    1749           1 :         CATCH_REQUIRE(sections.find("a::b") != sections.end());
    1750           1 :         CATCH_REQUIRE(sections.find("z")    != sections.end());
    1751           1 :         CATCH_REQUIRE(sections.find("z::b") != sections.end());
    1752             : 
    1753           1 :         CATCH_REQUIRE(file->get_parameters().size() == 7);
    1754             : 
    1755           1 :         CATCH_REQUIRE(file->has_parameter("a"));
    1756           1 :         CATCH_REQUIRE(file->has_parameter("a::b"));
    1757           1 :         CATCH_REQUIRE(file->has_parameter("a::b::c"));
    1758           1 :         CATCH_REQUIRE(file->has_parameter("m"));
    1759           1 :         CATCH_REQUIRE(file->has_parameter("z"));
    1760           1 :         CATCH_REQUIRE(file->has_parameter("z::b"));
    1761           1 :         CATCH_REQUIRE(file->has_parameter("z::b::c"));
    1762             : 
    1763           1 :         CATCH_REQUIRE(file->get_parameter("a") == "color");
    1764           1 :         CATCH_REQUIRE(file->get_parameter("a::b") == "red");
    1765           1 :         CATCH_REQUIRE(file->get_parameter("a::b::c") == "122");
    1766           1 :         CATCH_REQUIRE(file->get_parameter("m") == "size");
    1767           1 :         CATCH_REQUIRE(file->get_parameter("z") == "edge");
    1768           1 :         CATCH_REQUIRE(file->get_parameter("z::b") == "line");
    1769           1 :         CATCH_REQUIRE(file->get_parameter("z::b::c") == "12.72");
    1770             :     }
    1771             :     CATCH_END_SECTION()
    1772             : 
    1773          14 :     CATCH_START_SECTION("section operator block ({ ... })")
    1774             :     {
    1775           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("section-operator", "section-block");
    1776             : 
    1777             :         {
    1778           2 :             std::ofstream config_file;
    1779           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1780           1 :             CATCH_REQUIRE(config_file.good());
    1781           1 :             config_file <<
    1782             :                 "# Auto-generated\n"
    1783             :                 "a=color\n"
    1784             :                 "a {\n"
    1785             :                 "  b=red\n"
    1786             :                 "  b {\n"
    1787             :                 "    c=122\n"
    1788             :                 "  }\n"
    1789             :                 "}\n"
    1790             :                 "m=size\n"
    1791             :                 "z=edge\n"
    1792             :                 "z {\n"
    1793             :                 "  b {\n"
    1794             :                 "    c=12.72\n"
    1795             :                 "  }\n"
    1796             :                 "  b=line\n"
    1797             :                 "}\n"
    1798             :             ;
    1799             :         }
    1800             : 
    1801           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1802             :                             , advgetopt::line_continuation_t::line_continuation_unix
    1803             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    1804             :                             , advgetopt::COMMENT_SHELL
    1805           2 :                             , advgetopt::SECTION_OPERATOR_BLOCK);
    1806             : 
    1807           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1808             : 
    1809           1 :         CATCH_REQUIRE(setup.is_valid());
    1810           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    1811           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    1812           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    1813           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_BLOCK);
    1814             : 
    1815           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1816             : 
    1817           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1818           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1819             : 
    1820           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    1821           1 :         CATCH_REQUIRE(sections.size() == 4);
    1822           1 :         CATCH_REQUIRE(sections.find("a")    != sections.end());
    1823           1 :         CATCH_REQUIRE(sections.find("a::b") != sections.end());
    1824           1 :         CATCH_REQUIRE(sections.find("z")    != sections.end());
    1825           1 :         CATCH_REQUIRE(sections.find("z::b") != sections.end());
    1826             : 
    1827           1 :         CATCH_REQUIRE(file->get_parameters().size() == 7);
    1828             : 
    1829           1 :         CATCH_REQUIRE(file->has_parameter("a"));
    1830           1 :         CATCH_REQUIRE(file->has_parameter("a::b"));
    1831           1 :         CATCH_REQUIRE(file->has_parameter("a::b::c"));
    1832           1 :         CATCH_REQUIRE(file->has_parameter("m"));
    1833           1 :         CATCH_REQUIRE(file->has_parameter("z"));
    1834           1 :         CATCH_REQUIRE(file->has_parameter("z::b"));
    1835           1 :         CATCH_REQUIRE(file->has_parameter("z::b::c"));
    1836             : 
    1837           1 :         CATCH_REQUIRE(file->get_parameter("a") == "color");
    1838           1 :         CATCH_REQUIRE(file->get_parameter("a::b") == "red");
    1839           1 :         CATCH_REQUIRE(file->get_parameter("a::b::c") == "122");
    1840           1 :         CATCH_REQUIRE(file->get_parameter("m") == "size");
    1841           1 :         CATCH_REQUIRE(file->get_parameter("z") == "edge");
    1842           1 :         CATCH_REQUIRE(file->get_parameter("z::b") == "line");
    1843           1 :         CATCH_REQUIRE(file->get_parameter("z::b::c") == "12.72");
    1844             :     }
    1845             :     CATCH_END_SECTION()
    1846             : 
    1847          14 :     CATCH_START_SECTION("section operator ini file ([...])")
    1848             :     {
    1849           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("section-operator", "section-ini-file");
    1850             : 
    1851             :         {
    1852           2 :             std::ofstream config_file;
    1853           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1854           1 :             CATCH_REQUIRE(config_file.good());
    1855           1 :             config_file <<
    1856             :                 "# Auto-generated\n"
    1857             :                 "a=color\n"
    1858             :                 "[a]\n"
    1859             :                 "b=red\n"
    1860             :                 "b-c=122\n"
    1861             :                 "[]\n"
    1862             :                 "m=size\n"
    1863             :                 "z=edge\n"
    1864             :                 "[z] # we allow comments here\n"
    1865             :                 "b=line\n"
    1866             :                 "b-c=12.72\n"
    1867             :                 "[p]#nospacenecessary\n"
    1868             :                 "b=comment\n"
    1869             :                 "b-c=allowed\n"
    1870             :             ;
    1871             :         }
    1872             : 
    1873           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1874             :                             , advgetopt::line_continuation_t::line_continuation_unix
    1875             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    1876             :                             , advgetopt::COMMENT_SHELL
    1877           2 :                             , advgetopt::SECTION_OPERATOR_INI_FILE);
    1878             : 
    1879           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1880             : 
    1881           1 :         CATCH_REQUIRE(setup.is_valid());
    1882           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    1883           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    1884           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    1885           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_INI_FILE);
    1886             : 
    1887           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1888             : 
    1889           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1890           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1891             : 
    1892           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    1893           1 :         CATCH_REQUIRE(sections.size() == 3);
    1894           1 :         CATCH_REQUIRE(sections.find("a") != sections.end());
    1895           1 :         CATCH_REQUIRE(sections.find("z") != sections.end());
    1896           1 :         CATCH_REQUIRE(sections.find("p") != sections.end());
    1897             : 
    1898           1 :         CATCH_REQUIRE(file->get_parameters().size() == 9);
    1899             : 
    1900           1 :         CATCH_REQUIRE(file->has_parameter("a"));
    1901           1 :         CATCH_REQUIRE(file->has_parameter("a::b"));
    1902           1 :         CATCH_REQUIRE(file->has_parameter("a::b-c"));
    1903           1 :         CATCH_REQUIRE(file->has_parameter("m"));
    1904           1 :         CATCH_REQUIRE(file->has_parameter("z"));
    1905           1 :         CATCH_REQUIRE(file->has_parameter("z::b"));
    1906           1 :         CATCH_REQUIRE(file->has_parameter("z::b-c"));
    1907           1 :         CATCH_REQUIRE(file->has_parameter("p::b"));
    1908           1 :         CATCH_REQUIRE(file->has_parameter("p::b-c"));
    1909             : 
    1910           1 :         CATCH_REQUIRE(file->get_parameter("a") == "color");
    1911           1 :         CATCH_REQUIRE(file->get_parameter("a::b") == "red");
    1912           1 :         CATCH_REQUIRE(file->get_parameter("a::b-c") == "122");
    1913           1 :         CATCH_REQUIRE(file->get_parameter("m") == "size");
    1914           1 :         CATCH_REQUIRE(file->get_parameter("z") == "edge");
    1915           1 :         CATCH_REQUIRE(file->get_parameter("z::b") == "line");
    1916           1 :         CATCH_REQUIRE(file->get_parameter("z::b-c") == "12.72");
    1917           1 :         CATCH_REQUIRE(file->get_parameter("p::b") == "comment");
    1918           1 :         CATCH_REQUIRE(file->get_parameter("p::b-c") == "allowed");
    1919             :     }
    1920             :     CATCH_END_SECTION()
    1921             : 
    1922          14 :     CATCH_START_SECTION("section operator ini-file & c++")
    1923             :     {
    1924           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("section-operator", "section-double");
    1925             : 
    1926             :         {
    1927           2 :             std::ofstream config_file;
    1928           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1929           1 :             CATCH_REQUIRE(config_file.good());
    1930           1 :             config_file <<
    1931             :                 "# Auto-generated\n"
    1932             :                 "[a]\n"
    1933             :                 "b=red\n"
    1934             :                 "b::c=209\n"
    1935             :                 "::h=high\n"
    1936             :                 "m=size\n"
    1937             :                 "[z]\n"
    1938             :                 "z=edge\n"
    1939             :                 "::b=line\n"
    1940             :                 "z::b::c=17.92\n"
    1941             :             ;
    1942             :         }
    1943             : 
    1944           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    1945             :                             , advgetopt::line_continuation_t::line_continuation_unix
    1946             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    1947             :                             , advgetopt::COMMENT_SHELL
    1948           2 :                             , advgetopt::SECTION_OPERATOR_INI_FILE | advgetopt::SECTION_OPERATOR_CPP);
    1949             : 
    1950           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    1951             : 
    1952           1 :         CATCH_REQUIRE(setup.is_valid());
    1953           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    1954           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    1955           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    1956           1 :         CATCH_REQUIRE(setup.get_section_operator() == (advgetopt::SECTION_OPERATOR_INI_FILE | advgetopt::SECTION_OPERATOR_CPP));
    1957             : 
    1958           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    1959             : 
    1960           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    1961           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    1962             : 
    1963           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    1964           1 :         CATCH_REQUIRE(sections.size() == 4);
    1965           1 :         CATCH_REQUIRE(sections.find("a")       != sections.end());
    1966           1 :         CATCH_REQUIRE(sections.find("a::b")    != sections.end());
    1967           1 :         CATCH_REQUIRE(sections.find("z")       != sections.end());
    1968           1 :         CATCH_REQUIRE(sections.find("z::z::b") != sections.end());
    1969             : 
    1970           1 :         CATCH_REQUIRE(file->get_parameters().size() == 7);
    1971             : 
    1972           1 :         CATCH_REQUIRE(file->has_parameter("a::b"));
    1973           1 :         CATCH_REQUIRE(file->has_parameter("a::b::c"));
    1974           1 :         CATCH_REQUIRE(file->has_parameter("h"));
    1975           1 :         CATCH_REQUIRE(file->has_parameter("a::m"));
    1976           1 :         CATCH_REQUIRE(file->has_parameter("z::z"));
    1977           1 :         CATCH_REQUIRE(file->has_parameter("b"));
    1978           1 :         CATCH_REQUIRE(file->has_parameter("z::z::b::c"));
    1979             : 
    1980           1 :         CATCH_REQUIRE(file->get_parameter("a::b") == "red");
    1981           1 :         CATCH_REQUIRE(file->get_parameter("a::b::c") == "209");
    1982           1 :         CATCH_REQUIRE(file->get_parameter("h") == "high");
    1983           1 :         CATCH_REQUIRE(file->get_parameter("a::m") == "size");
    1984           1 :         CATCH_REQUIRE(file->get_parameter("z::z") == "edge");
    1985           1 :         CATCH_REQUIRE(file->get_parameter("b") == "line");
    1986           1 :         CATCH_REQUIRE(file->get_parameter("z::z::b::c") == "17.92");
    1987             :     }
    1988             :     CATCH_END_SECTION()
    1989             : 
    1990          14 :     CATCH_START_SECTION("section of variables ([variables])")
    1991             :     {
    1992             :         // in a config file variables are not auto-managed
    1993             :         //
    1994           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("section-variables", "section-with-variables");
    1995             : 
    1996             :         {
    1997           2 :             std::ofstream config_file;
    1998           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    1999           1 :             CATCH_REQUIRE(config_file.good());
    2000           1 :             config_file <<
    2001             :                 "# Auto-generated\n"
    2002             :                 "edge=${blue}\n"
    2003             :                 "background=${white}\n"
    2004             :                 "foreground=${black}\n"
    2005             :                 "[error]\n"
    2006             :                 "edge=${red}\n"
    2007             :                 "background=${gray}\n"
    2008             :                 "[variables]\n"
    2009             :                 "red=\"#ff0000\"\n"
    2010             :                 "green=\"#00ff00\"\n"
    2011             :                 "blue=\"#0000ff\"\n"
    2012             :                 "no_color=\"#000000\"\n"
    2013             :                 "black=${no_color}\n"
    2014             :                 "white=\"#ffffff\"\n"
    2015             :                 "gray=\"#aaaaaa\"\n"
    2016             :             ;
    2017             :         }
    2018             : 
    2019           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    2020             :                             , advgetopt::line_continuation_t::line_continuation_unix
    2021             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    2022             :                             , advgetopt::COMMENT_SHELL
    2023           2 :                             , advgetopt::SECTION_OPERATOR_INI_FILE);
    2024             : 
    2025           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    2026             : 
    2027           1 :         CATCH_REQUIRE(setup.is_valid());
    2028           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    2029           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    2030           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    2031           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_INI_FILE);
    2032             : 
    2033           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    2034             : 
    2035           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    2036           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    2037             : 
    2038           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    2039           1 :         CATCH_REQUIRE(sections.size() == 2);
    2040           1 :         CATCH_REQUIRE(sections.find("error") != sections.end());
    2041           1 :         CATCH_REQUIRE(sections.find("variables") != sections.end());
    2042             : 
    2043           1 :         CATCH_REQUIRE(file->get_parameters().size() == 12);
    2044             : 
    2045           1 :         CATCH_REQUIRE(file->has_parameter("edge"));
    2046           1 :         CATCH_REQUIRE(file->has_parameter("background"));
    2047           1 :         CATCH_REQUIRE(file->has_parameter("foreground"));
    2048           1 :         CATCH_REQUIRE(file->has_parameter("error::edge"));
    2049           1 :         CATCH_REQUIRE(file->has_parameter("error::background"));
    2050           1 :         CATCH_REQUIRE(file->has_parameter("variables::red"));
    2051           1 :         CATCH_REQUIRE(file->has_parameter("variables::green"));
    2052           1 :         CATCH_REQUIRE(file->has_parameter("variables::blue"));
    2053           1 :         CATCH_REQUIRE(file->has_parameter("variables::no_color"));
    2054           1 :         CATCH_REQUIRE(file->has_parameter("variables::black"));
    2055           1 :         CATCH_REQUIRE(file->has_parameter("variables::white"));
    2056           1 :         CATCH_REQUIRE(file->has_parameter("variables::gray"));
    2057             : 
    2058             :         // without a variables attached, we get the raw (original) data back
    2059             :         //
    2060           1 :         CATCH_REQUIRE(file->get_parameter("edge") == "${blue}");
    2061           1 :         CATCH_REQUIRE(file->get_parameter("background") == "${white}");
    2062           1 :         CATCH_REQUIRE(file->get_parameter("foreground") == "${black}");
    2063           1 :         CATCH_REQUIRE(file->get_parameter("error::edge") == "${red}");
    2064           1 :         CATCH_REQUIRE(file->get_parameter("error::background") == "${gray}");
    2065           1 :         CATCH_REQUIRE(file->get_parameter("variables::red") == "#ff0000");
    2066           1 :         CATCH_REQUIRE(file->get_parameter("variables::green") == "#00ff00");
    2067           1 :         CATCH_REQUIRE(file->get_parameter("variables::blue") == "#0000ff");
    2068           1 :         CATCH_REQUIRE(file->get_parameter("variables::no_color") == "#000000");
    2069           1 :         CATCH_REQUIRE(file->get_parameter("variables::black") == "${no_color}");
    2070           1 :         CATCH_REQUIRE(file->get_parameter("variables::white") == "#ffffff");
    2071           1 :         CATCH_REQUIRE(file->get_parameter("variables::gray") == "#aaaaaa");
    2072             : 
    2073             :         // transform the "[variables]" section to variables
    2074             :         //
    2075           2 :         advgetopt::variables::pointer_t vars(std::make_shared<advgetopt::variables>());
    2076           1 :         CATCH_REQUIRE(file->section_to_variables("variables", vars) == 7);
    2077           1 :         file->set_variables(vars);
    2078           1 :         CATCH_REQUIRE(file->get_variables() == vars);
    2079             : 
    2080           1 :         sections = file->get_sections();
    2081           1 :         CATCH_REQUIRE(sections.size() == 1);
    2082           1 :         CATCH_REQUIRE(sections.find("error") != sections.end());
    2083           1 :         CATCH_REQUIRE(sections.find("variables") == sections.end());
    2084             : 
    2085           1 :         CATCH_REQUIRE(file->get_parameters().size() == 5);
    2086             : 
    2087           1 :         CATCH_REQUIRE(file->has_parameter("edge"));
    2088           1 :         CATCH_REQUIRE(file->has_parameter("background"));
    2089           1 :         CATCH_REQUIRE(file->has_parameter("foreground"));
    2090           1 :         CATCH_REQUIRE(file->has_parameter("error::edge"));
    2091           1 :         CATCH_REQUIRE(file->has_parameter("error::background"));
    2092           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("variables::red"));
    2093           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("variables::green"));
    2094           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("variables::blue"));
    2095           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("variables::no_color"));
    2096           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("variables::black"));
    2097           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("variables::white"));
    2098           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("variables::gray"));
    2099             : 
    2100           1 :         CATCH_REQUIRE(file->get_parameter("edge") == "#0000ff");
    2101           1 :         CATCH_REQUIRE(file->get_parameter("background") == "#ffffff");
    2102           1 :         CATCH_REQUIRE(file->get_parameter("foreground") == "#000000");
    2103           1 :         CATCH_REQUIRE(file->get_parameter("error::edge") == "#ff0000");
    2104           1 :         CATCH_REQUIRE(file->get_parameter("error::background") == "#aaaaaa");
    2105             :     }
    2106             :     CATCH_END_SECTION()
    2107             : 
    2108          14 :     CATCH_START_SECTION("command line with .conf including section of variables ([variables])")
    2109             :     {
    2110             :         // in a config file variables are not auto-managed
    2111             :         //
    2112           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("command-line-and-section-variables", "command-section-with-variables");
    2113             : 
    2114             :         {
    2115           2 :             std::ofstream config_file;
    2116           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    2117           1 :             CATCH_REQUIRE(config_file.good());
    2118           1 :             config_file <<
    2119             :                 "# Auto-generated\n"
    2120             :                 "edge=${blue}\n"
    2121             :                 "background=${white}\n"
    2122             :                 "foreground=${black}\n"
    2123             :                 "[error]\n"
    2124             :                 "edge=${red}\n"
    2125             :                 "background=${gray}\n"
    2126             :                 "[variables]\n"
    2127             :                 "red=\"#ff0000\"\n"
    2128             :                 "green=\"#00ff00\"\n"
    2129             :                 "blue=\"#0000ff\"\n"
    2130             :                 "no_color=\"#000000\"\n"
    2131             :                 "black=${no_color}\n"
    2132             :                 "orange=\"#80ff00\"\n"
    2133             :                 "white=\"#ffffff\"\n"
    2134             :                 "gray=\"#aaaaaa\"\n"
    2135             :             ;
    2136             :         }
    2137             : 
    2138           1 :         const advgetopt::option options[] =
    2139             :         {
    2140             :             advgetopt::define_option(
    2141             :                   advgetopt::Name("edge")
    2142             :                 , advgetopt::Flags(advgetopt::all_flags<
    2143             :                       advgetopt::GETOPT_FLAG_REQUIRED
    2144             :                     , advgetopt::GETOPT_FLAG_PROCESS_VARIABLES>())
    2145             :             ),
    2146             :             advgetopt::define_option(
    2147             :                   advgetopt::Name("background")
    2148             :                 , advgetopt::Flags(advgetopt::all_flags<
    2149             :                       advgetopt::GETOPT_FLAG_REQUIRED
    2150             :                     , advgetopt::GETOPT_FLAG_PROCESS_VARIABLES>())
    2151             :             ),
    2152             :             advgetopt::define_option(
    2153             :                   advgetopt::Name("foreground")
    2154             :                 , advgetopt::Flags(advgetopt::all_flags<
    2155             :                       advgetopt::GETOPT_FLAG_REQUIRED
    2156             :                     , advgetopt::GETOPT_FLAG_PROCESS_VARIABLES>())
    2157             :             ),
    2158             :             advgetopt::define_option(
    2159             :                   advgetopt::Name("error::edge")
    2160             :                 , advgetopt::Flags(advgetopt::all_flags<
    2161             :                       advgetopt::GETOPT_FLAG_REQUIRED
    2162             :                     , advgetopt::GETOPT_FLAG_PROCESS_VARIABLES>())
    2163             :             ),
    2164             :             advgetopt::define_option(
    2165             :                   advgetopt::Name("error::background")
    2166             :                 , advgetopt::Flags(advgetopt::all_flags<
    2167             :                       advgetopt::GETOPT_FLAG_REQUIRED
    2168             :                     , advgetopt::GETOPT_FLAG_PROCESS_VARIABLES>())
    2169             :             ),
    2170             :             advgetopt::define_option(
    2171             :                   advgetopt::Name("error::foreground")
    2172             :                 , advgetopt::Flags(advgetopt::all_flags<
    2173             :                       advgetopt::GETOPT_FLAG_REQUIRED
    2174             :                     , advgetopt::GETOPT_FLAG_PROCESS_VARIABLES>())
    2175             :             ),
    2176             :             advgetopt::define_option(
    2177             :                   advgetopt::Name("see-config")
    2178             :                 , advgetopt::Flags(advgetopt::standalone_command_flags<>())
    2179             :             ),
    2180             :             advgetopt::end_options()
    2181             :         };
    2182             : 
    2183           1 :         char const * const configuration_files[] =
    2184             :         {
    2185           1 :             SNAP_CATCH2_NAMESPACE::g_config_filename.c_str(),
    2186             :             nullptr
    2187           1 :         };
    2188             : 
    2189           1 :         advgetopt::options_environment environment_options;
    2190           1 :         environment_options.f_project_name = "unittest";
    2191           1 :         environment_options.f_options = options;
    2192           1 :         environment_options.f_help_header = "Usage: configuration with variables through environment.";
    2193           1 :         environment_options.f_section_variables_name = "variables";
    2194           1 :         environment_options.f_configuration_files = configuration_files;
    2195             : 
    2196           1 :         char const * cargv[] =
    2197             :         {
    2198             :             "/usr/bin/cmd-n-config",
    2199             :             "--see-config",
    2200             :             "--error::foreground",
    2201             :             "${orange}",
    2202             :             nullptr
    2203             :         };
    2204           1 :         int const argc(sizeof(cargv) / sizeof(cargv[0]) - 1);
    2205           1 :         char ** argv = const_cast<char **>(cargv);
    2206             : 
    2207           2 :         advgetopt::getopt::pointer_t opts(std::make_shared<advgetopt::getopt>(environment_options, argc, argv));
    2208           1 :         CATCH_REQUIRE(opts != nullptr);
    2209             : 
    2210           2 :         advgetopt::variables::pointer_t variables(opts->get_variables());
    2211           1 :         CATCH_REQUIRE(variables != nullptr);
    2212             : 
    2213           1 :         CATCH_REQUIRE(opts->is_defined("see-config"));
    2214           1 :         CATCH_REQUIRE(opts->is_defined("edge"));
    2215           1 :         CATCH_REQUIRE(opts->is_defined("background"));
    2216           1 :         CATCH_REQUIRE(opts->is_defined("foreground"));
    2217           1 :         CATCH_REQUIRE(opts->is_defined("error::edge"));
    2218           1 :         CATCH_REQUIRE(opts->is_defined("error::background"));
    2219           1 :         CATCH_REQUIRE(opts->is_defined("error::foreground"));
    2220           1 :         CATCH_REQUIRE_FALSE(opts->is_defined("variables::red"));
    2221           1 :         CATCH_REQUIRE_FALSE(opts->is_defined("variables::green"));
    2222           1 :         CATCH_REQUIRE_FALSE(opts->is_defined("variables::blue"));
    2223           1 :         CATCH_REQUIRE_FALSE(opts->is_defined("variables::no_color"));
    2224           1 :         CATCH_REQUIRE_FALSE(opts->is_defined("variables::black"));
    2225           1 :         CATCH_REQUIRE_FALSE(opts->is_defined("variables::orange"));
    2226           1 :         CATCH_REQUIRE_FALSE(opts->is_defined("variables::white"));
    2227           1 :         CATCH_REQUIRE_FALSE(opts->is_defined("variables::gray"));
    2228             : 
    2229           1 :         CATCH_REQUIRE(opts->get_string("edge") == "#0000ff");
    2230           1 :         CATCH_REQUIRE(opts->get_string("background") == "#ffffff");
    2231           1 :         CATCH_REQUIRE(opts->get_string("foreground") == "#000000");
    2232           1 :         CATCH_REQUIRE(opts->get_string("error::edge") == "#ff0000");
    2233           1 :         CATCH_REQUIRE(opts->get_string("error::background") == "#aaaaaa");
    2234           1 :         CATCH_REQUIRE(opts->get_string("error::foreground") == "#80ff00");
    2235             : 
    2236           1 :         CATCH_REQUIRE(opts->get_option("edge")->get_variables() == variables);
    2237           1 :         CATCH_REQUIRE(opts->get_option("background")->get_variables() == variables);
    2238           1 :         CATCH_REQUIRE(opts->get_option("foreground")->get_variables() == variables);
    2239           1 :         CATCH_REQUIRE(opts->get_option("error::edge")->get_variables() == variables);
    2240           1 :         CATCH_REQUIRE(opts->get_option("error::background")->get_variables() == variables);
    2241           1 :         CATCH_REQUIRE(opts->get_option("error::foreground")->get_variables() == variables);
    2242             :     }
    2243             :     CATCH_END_SECTION()
    2244           7 : }
    2245             : 
    2246             : 
    2247             : 
    2248             : 
    2249           3 : CATCH_TEST_CASE("save_config_file", "[config][getopt][valid]")
    2250             : {
    2251           2 :     CATCH_START_SECTION("load update save")
    2252             :     {
    2253           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("save-operation", "configuration");
    2254             : 
    2255             :         {
    2256           2 :             std::ofstream config_file;
    2257           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    2258           1 :             CATCH_REQUIRE(config_file.good());
    2259           1 :             config_file <<
    2260             :                 "# Auto-generated\n"
    2261             :                 "a=color\n"
    2262             :                 "b=red\n"
    2263             :                 "c=122\n"
    2264             :             ;
    2265             :         }
    2266             : 
    2267           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    2268             :                             , advgetopt::line_continuation_t::line_continuation_single_line
    2269             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    2270             :                             , advgetopt::COMMENT_SHELL
    2271           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
    2272             : 
    2273           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    2274             : 
    2275           1 :         CATCH_REQUIRE(setup.is_valid());
    2276           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_single_line);
    2277           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    2278           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    2279           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
    2280             : 
    2281           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    2282             : 
    2283           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    2284           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    2285             : 
    2286           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    2287           1 :         CATCH_REQUIRE(sections.empty());
    2288             : 
    2289           1 :         CATCH_REQUIRE(file->get_parameters().size() == 3);
    2290             : 
    2291           1 :         CATCH_REQUIRE(file->has_parameter("a"));
    2292           1 :         CATCH_REQUIRE(file->has_parameter("b"));
    2293           1 :         CATCH_REQUIRE(file->has_parameter("c"));
    2294             : 
    2295           1 :         CATCH_REQUIRE(file->get_parameter("a") == "color");
    2296           1 :         CATCH_REQUIRE(file->get_parameter("b") == "red");
    2297           1 :         CATCH_REQUIRE(file->get_parameter("c") == "122");
    2298             : 
    2299           1 :         CATCH_REQUIRE(file->save_configuration());
    2300             : 
    2301             :         // no backup since there was no modification so the save did nothing
    2302             :         //
    2303           1 :         CATCH_REQUIRE(access((SNAP_CATCH2_NAMESPACE::g_config_filename + ".bak").c_str(), F_OK) != 0);
    2304             : 
    2305           1 :         file->set_parameter(std::string(), "a", "size");
    2306           1 :         file->set_parameter(std::string(), "b", "tall");
    2307           1 :         file->set_parameter(std::string(), "c", "1920");
    2308             : 
    2309           1 :         CATCH_REQUIRE(file->save_configuration());
    2310             : 
    2311           1 :         CATCH_REQUIRE(access((SNAP_CATCH2_NAMESPACE::g_config_filename + ".bak").c_str(), F_OK) == 0);
    2312             : 
    2313           2 :         std::string const new_name(SNAP_CATCH2_NAMESPACE::g_config_filename + ".conf2");
    2314           1 :         rename(SNAP_CATCH2_NAMESPACE::g_config_filename.c_str(), new_name.c_str());
    2315             : 
    2316           1 :         advgetopt::conf_file_setup setup2(new_name
    2317             :                             , advgetopt::line_continuation_t::line_continuation_single_line
    2318             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    2319             :                             , advgetopt::COMMENT_SHELL
    2320           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
    2321             : 
    2322           1 :         CATCH_REQUIRE(setup.get_original_filename() == SNAP_CATCH2_NAMESPACE::g_config_filename);
    2323             : 
    2324           1 :         CATCH_REQUIRE(setup2.is_valid());
    2325           1 :         CATCH_REQUIRE(setup2.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_single_line);
    2326           1 :         CATCH_REQUIRE(setup2.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    2327           1 :         CATCH_REQUIRE(setup2.get_comment() == advgetopt::COMMENT_SHELL);
    2328           1 :         CATCH_REQUIRE(setup2.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
    2329             : 
    2330           2 :         advgetopt::conf_file::pointer_t file2(advgetopt::conf_file::get_conf_file(setup2));
    2331             : 
    2332           1 :         CATCH_REQUIRE(file2->get_setup().get_config_url() == setup2.get_config_url());
    2333           1 :         CATCH_REQUIRE(file2->get_errno() == 0);
    2334             : 
    2335           1 :         CATCH_REQUIRE(file->get_sections().empty());
    2336             : 
    2337           1 :         CATCH_REQUIRE(file2->get_parameters().size() == 3);
    2338             : 
    2339           1 :         CATCH_REQUIRE(file2->has_parameter("a"));
    2340           1 :         CATCH_REQUIRE(file2->has_parameter("b"));
    2341           1 :         CATCH_REQUIRE(file2->has_parameter("c"));
    2342             : 
    2343           1 :         CATCH_REQUIRE(file2->get_parameter("a") == "size");
    2344           1 :         CATCH_REQUIRE(file2->get_parameter("b") == "tall");
    2345           1 :         CATCH_REQUIRE(file2->get_parameter("c") == "1920");
    2346             :     }
    2347             :     CATCH_END_SECTION()
    2348           1 : }
    2349             : 
    2350             : 
    2351             : 
    2352             : 
    2353             : 
    2354             : 
    2355             : 
    2356           4 : CATCH_TEST_CASE("invalid_configuration_setup", "[config][getopt][invalid]")
    2357             : {
    2358           4 :     CATCH_START_SECTION("Empty Filename")
    2359             :     {
    2360           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    2361             :               advgetopt::conf_file_setup(
    2362             :                               std::string()
    2363             :                             , static_cast<advgetopt::line_continuation_t>(rand())
    2364             :                             , rand()
    2365             :                             , rand()
    2366             :                             , rand())
    2367             :             , advgetopt::getopt_invalid
    2368             :             , Catch::Matchers::ExceptionMessage(
    2369             :                           "getopt_exception: trying to load a configuration file using an empty filename."));
    2370             :     }
    2371             :     CATCH_END_SECTION()
    2372             : 
    2373           4 :     CATCH_START_SECTION("Invalid Line Continuation")
    2374             :     {
    2375           6 :         for(int count(0); count < 5; ++count)
    2376             :         {
    2377           5 :             advgetopt::line_continuation_t lc(advgetopt::line_continuation_t::line_continuation_unix);
    2378           0 :             do
    2379             :             {
    2380           5 :                 lc = static_cast<advgetopt::line_continuation_t>(rand());
    2381             :             }
    2382             :             while(lc >= advgetopt::line_continuation_t::line_continuation_single_line
    2383           5 :                && lc <= advgetopt::line_continuation_t::line_continuation_semicolon);
    2384             : 
    2385           5 :             advgetopt::conf_file_setup setup(
    2386             :                           "/etc/advgetopt/system.conf"
    2387             :                         , lc        // <- this is invalid
    2388           5 :                         , rand() & advgetopt::ASSIGNMENT_OPERATOR_MASK
    2389           5 :                         , rand() & advgetopt::COMMENT_MASK
    2390          20 :                         , rand() & advgetopt::SECTION_OPERATOR_MASK);
    2391             : 
    2392           5 :             CATCH_REQUIRE(setup.is_valid());
    2393             : 
    2394           5 :             CATCH_REQUIRE_THROWS_MATCHES(
    2395             :                   setup.get_config_url()
    2396             :                 , advgetopt::getopt_logic_error
    2397             :                 , Catch::Matchers::ExceptionMessage(
    2398             :                               "getopt_logic_error: unexpected line continuation."));
    2399             :         }
    2400             :     }
    2401             :     CATCH_END_SECTION()
    2402           2 : }
    2403             : 
    2404             : 
    2405             : 
    2406             : 
    2407             : 
    2408             : 
    2409             : 
    2410           3 : CATCH_TEST_CASE("config_reload_invalid_setup", "[config][getopt][invalid]")
    2411             : {
    2412           2 :     CATCH_START_SECTION("Load a file, update it, verify it does not get reloaded")
    2413             :     {
    2414           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("invalid-reload", "load-twice-wrong-parameters");
    2415             : 
    2416             :         {
    2417           2 :             std::ofstream config_file;
    2418           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    2419           1 :             CATCH_REQUIRE(config_file.good());
    2420           1 :             config_file <<
    2421             :                 "# Auto-generated\n"
    2422             :                 "duplicates=work\n"
    2423             :                 "varying=parameters\n"
    2424             :                 "however=is\n"
    2425             :                 "not=valid\n"
    2426             :             ;
    2427             :         }
    2428             : 
    2429           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    2430             :                             , advgetopt::line_continuation_t::line_continuation_single_line
    2431             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    2432             :                             , advgetopt::COMMENT_SHELL
    2433           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
    2434             : 
    2435           1 :         CATCH_REQUIRE(setup.is_valid());
    2436           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_single_line);
    2437           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    2438           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    2439           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
    2440             : 
    2441           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    2442             : 
    2443           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    2444           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    2445           1 :         CATCH_REQUIRE(file->get_sections().empty());
    2446           1 :         CATCH_REQUIRE(file->get_parameters().size() == 4);
    2447             : 
    2448           1 :         CATCH_REQUIRE(file->has_parameter("duplicates"));
    2449           1 :         CATCH_REQUIRE(file->has_parameter("varying"));
    2450           1 :         CATCH_REQUIRE(file->has_parameter("however"));
    2451           1 :         CATCH_REQUIRE(file->has_parameter("not"));
    2452             : 
    2453           1 :         CATCH_REQUIRE(file->get_parameter("duplicates") == "work");
    2454           1 :         CATCH_REQUIRE(file->get_parameter("varying") == "parameters");
    2455           1 :         CATCH_REQUIRE(file->get_parameter("however") == "is");
    2456           1 :         CATCH_REQUIRE(file->get_parameter("not") == "valid");
    2457             : 
    2458             :         // "reloading" that very same file but with the "wrong" parameters
    2459             :         // fails
    2460             :         //
    2461           7 :         for(int lc(static_cast<int>(advgetopt::line_continuation_t::line_continuation_single_line));
    2462           7 :             lc <= static_cast<int>(advgetopt::line_continuation_t::line_continuation_semicolon);
    2463             :             ++lc)
    2464             :         {
    2465           6 :             if(static_cast<advgetopt::line_continuation_t>(lc) == advgetopt::line_continuation_t::line_continuation_single_line)
    2466             :             {
    2467           1 :                 continue;
    2468             :             }
    2469             : 
    2470          45 :             for(advgetopt::assignment_operator_t ao(0);
    2471          45 :                 ao <= advgetopt::ASSIGNMENT_OPERATOR_MASK;
    2472             :                 ++ao)
    2473             :             {
    2474          40 :                 if(ao == advgetopt::ASSIGNMENT_OPERATOR_EQUAL)
    2475             :                 {
    2476           5 :                     continue;
    2477             :                 }
    2478             : 
    2479         280 :                 for(advgetopt::comment_t c(0);
    2480         280 :                     c < advgetopt::COMMENT_MASK;
    2481             :                     ++c)
    2482             :                 {
    2483         245 :                     if(c == advgetopt::COMMENT_SHELL)
    2484             :                     {
    2485          35 :                         continue;
    2486             :                     }
    2487             : 
    2488        3360 :                     for(advgetopt::section_operator_t so(0);
    2489        3360 :                         so < advgetopt::SECTION_OPERATOR_MASK;
    2490             :                         ++so)
    2491             :                     {
    2492        3150 :                         if(c == advgetopt::SECTION_OPERATOR_NONE)
    2493             :                         {
    2494         525 :                             continue;
    2495             :                         }
    2496             : 
    2497        2625 :                         advgetopt::conf_file_setup different_setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    2498             :                                         , static_cast<advgetopt::line_continuation_t>(lc)
    2499             :                                         , ao
    2500             :                                         , c
    2501        5250 :                                         , so);
    2502             : 
    2503        2625 :                         CATCH_REQUIRE_THROWS_MATCHES(
    2504             :                               advgetopt::conf_file::get_conf_file(different_setup)
    2505             :                             , advgetopt::getopt_logic_error
    2506             :                             , Catch::Matchers::ExceptionMessage(
    2507             :                                           "getopt_logic_error: trying to load configuration file \""
    2508             :                                         + different_setup.get_config_url()
    2509             :                                         + "\" but an existing configuration file with the same name was loaded with URL: \""
    2510             :                                         + setup.get_config_url()
    2511             :                                         + "\"."));
    2512             :                     }
    2513             :                 }
    2514             :             }
    2515             :         }
    2516             :     }
    2517             :     CATCH_END_SECTION()
    2518           1 : }
    2519             : 
    2520             : 
    2521           3 : CATCH_TEST_CASE("missing_configuration_file", "[config][getopt][invalid]")
    2522             : {
    2523           2 :     CATCH_START_SECTION("Create a conf_file without the file")
    2524             :     {
    2525           6 :         for(int count(0); count < 5; ++count)
    2526             :         {
    2527           5 :             int const id(rand());
    2528          10 :             std::string const name("delete-file-" + std::to_string(id));
    2529             : 
    2530           5 :             SNAP_CATCH2_NAMESPACE::init_tmp_dir("delete", name);
    2531             : 
    2532             :             {
    2533          10 :                 std::ofstream config_file;
    2534           5 :                 config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    2535           5 :                 CATCH_REQUIRE(config_file.good());
    2536           5 :                 config_file <<
    2537             :                     "# Auto-generated\n"
    2538             :                     "param=optional\n"
    2539             :                 ;
    2540             :             }
    2541             : 
    2542             :             // create the setup while the file still exists
    2543             :             //
    2544           5 :             advgetopt::conf_file_setup setup(
    2545             :                           SNAP_CATCH2_NAMESPACE::g_config_filename
    2546             :                         , advgetopt::line_continuation_t::line_continuation_unix
    2547             :                         , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    2548             :                         , advgetopt::COMMENT_SHELL
    2549          10 :                         , advgetopt::SECTION_OPERATOR_NONE);
    2550             : 
    2551             :             // get the full name before the unlink()
    2552          10 :             std::unique_ptr<char, decltype(&::free)> fn(realpath(SNAP_CATCH2_NAMESPACE::g_config_filename.c_str(), nullptr), &::free);
    2553             : 
    2554             :             // now unlink() that file
    2555             :             //
    2556           5 :             unlink(SNAP_CATCH2_NAMESPACE::g_config_filename.c_str());
    2557             : 
    2558             :             // still valid since we do not check again after the
    2559             :             // constructor ran
    2560             :             //
    2561           5 :             CATCH_REQUIRE(setup.is_valid());
    2562           5 :             CATCH_REQUIRE(setup.get_filename() == fn.get());
    2563           5 :             CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    2564           5 :             CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    2565           5 :             CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    2566           5 :             CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_NONE);
    2567             : 
    2568             :             // so when trying to create the conf_file object it fails
    2569             :             // opening the file
    2570             :             //
    2571          10 :             advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    2572           5 :             CATCH_REQUIRE(file->get_errno() == ENOENT);
    2573             :         }
    2574             :     }
    2575             :     CATCH_END_SECTION()
    2576           1 : }
    2577             : 
    2578             : 
    2579          11 : CATCH_TEST_CASE("invalid_sections", "[config][getopt][invalid]")
    2580             : {
    2581          18 :     CATCH_START_SECTION("variable name cannot start with a period when C operator is active")
    2582             :     {
    2583           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("invalid-section-operator", "period-name");
    2584             : 
    2585             :         {
    2586           2 :             std::ofstream config_file;
    2587           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    2588           1 :             CATCH_REQUIRE(config_file.good());
    2589           1 :             config_file <<
    2590             :                 "# Auto-generated\n"
    2591             :                 "a=color\n"
    2592             :                 "a..b=red\n"
    2593             :                 ".a.b.c=122\n"
    2594             :                 "m=size\n"
    2595             :                 "z=edge\n"
    2596             :                 "z.b=line\n"
    2597             :                 "z..b.c=12.72\n"
    2598             :             ;
    2599             :         }
    2600             : 
    2601           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    2602             :                             , advgetopt::line_continuation_t::line_continuation_unix
    2603             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    2604             :                             , advgetopt::COMMENT_SHELL
    2605           2 :                             , advgetopt::SECTION_OPERATOR_C);
    2606             : 
    2607           1 :         CATCH_REQUIRE(setup.is_valid());
    2608           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    2609           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    2610           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    2611           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_C);
    2612             : 
    2613           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    2614             :                     "error: option name \".a.b.c\" cannot start with"
    2615             :                     " a period (.).");
    2616           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    2617           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    2618             : 
    2619           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    2620           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    2621             : 
    2622           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    2623           1 :         CATCH_REQUIRE(sections.size() == 3);
    2624           1 :         CATCH_REQUIRE(sections.find("a")    != sections.end());
    2625           1 :         CATCH_REQUIRE(sections.find("z")    != sections.end());
    2626           1 :         CATCH_REQUIRE(sections.find("z::b") != sections.end());
    2627             : 
    2628           1 :         CATCH_REQUIRE(file->get_parameters().size() == 6);
    2629             : 
    2630           1 :         CATCH_REQUIRE(file->has_parameter("a"));
    2631           1 :         CATCH_REQUIRE(file->has_parameter("a::b"));
    2632           1 :         CATCH_REQUIRE(file->has_parameter("m"));
    2633           1 :         CATCH_REQUIRE(file->has_parameter("z"));
    2634           1 :         CATCH_REQUIRE(file->has_parameter("z::b"));
    2635           1 :         CATCH_REQUIRE(file->has_parameter("z::b::c"));
    2636             : 
    2637           1 :         CATCH_REQUIRE(file->get_parameter("a") == "color");
    2638           1 :         CATCH_REQUIRE(file->get_parameter("a::b") == "red");
    2639           1 :         CATCH_REQUIRE(file->get_parameter("m") == "size");
    2640           1 :         CATCH_REQUIRE(file->get_parameter("z") == "edge");
    2641           1 :         CATCH_REQUIRE(file->get_parameter("z::b") == "line");
    2642           1 :         CATCH_REQUIRE(file->get_parameter("z::b::c") == "12.72");
    2643             :     }
    2644             :     CATCH_END_SECTION()
    2645             : 
    2646          18 :     CATCH_START_SECTION("two section operators one after another can cause trouble")
    2647             :     {
    2648           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("invalid-section-operator", "name-period-cpp-name");
    2649             : 
    2650             :         {
    2651           2 :             std::ofstream config_file;
    2652           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    2653           1 :             CATCH_REQUIRE(config_file.good());
    2654           1 :             config_file <<
    2655             :                 "# Auto-generated\n"
    2656             :                 "a=color\n"
    2657             :                 "a..b=red\n"
    2658             :                 "a.::b.c=122\n"
    2659             :                 "m=size\n"
    2660             :                 "z=edge\n"
    2661             :                 "z.b=line\n"
    2662             :                 "z..b.c=12.72\n"
    2663             :             ;
    2664             :         }
    2665             : 
    2666           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    2667             :                             , advgetopt::line_continuation_t::line_continuation_unix
    2668             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    2669             :                             , advgetopt::COMMENT_SHELL
    2670           2 :                             , advgetopt::SECTION_OPERATOR_C | advgetopt::SECTION_OPERATOR_CPP);
    2671             : 
    2672           1 :         CATCH_REQUIRE(setup.is_valid());
    2673           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    2674           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    2675           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    2676           1 :         CATCH_REQUIRE(setup.get_section_operator() == (advgetopt::SECTION_OPERATOR_C | advgetopt::SECTION_OPERATOR_CPP));
    2677             : 
    2678           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    2679             :                     "error: option name \"a.::b.c\" cannot start with"
    2680             :                     " a scope operator (::).");
    2681           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    2682           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    2683             : 
    2684           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    2685           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    2686             : 
    2687           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    2688           1 :         CATCH_REQUIRE(sections.size() == 3);
    2689           1 :         CATCH_REQUIRE(sections.find("a")    != sections.end());
    2690           1 :         CATCH_REQUIRE(sections.find("z")    != sections.end());
    2691           1 :         CATCH_REQUIRE(sections.find("z::b") != sections.end());
    2692             : 
    2693           1 :         CATCH_REQUIRE(file->get_parameters().size() == 6);
    2694             : 
    2695           1 :         CATCH_REQUIRE(file->has_parameter("a"));
    2696           1 :         CATCH_REQUIRE(file->has_parameter("a::b"));
    2697           1 :         CATCH_REQUIRE(file->has_parameter("m"));
    2698           1 :         CATCH_REQUIRE(file->has_parameter("z"));
    2699           1 :         CATCH_REQUIRE(file->has_parameter("z::b"));
    2700           1 :         CATCH_REQUIRE(file->has_parameter("z::b::c"));
    2701             : 
    2702           1 :         CATCH_REQUIRE(file->get_parameter("a") == "color");
    2703           1 :         CATCH_REQUIRE(file->get_parameter("a::b") == "red");
    2704           1 :         CATCH_REQUIRE(file->get_parameter("m") == "size");
    2705           1 :         CATCH_REQUIRE(file->get_parameter("z") == "edge");
    2706           1 :         CATCH_REQUIRE(file->get_parameter("z::b") == "line");
    2707           1 :         CATCH_REQUIRE(file->get_parameter("z::b::c") == "12.72");
    2708             :     }
    2709             :     CATCH_END_SECTION()
    2710             : 
    2711          18 :     CATCH_START_SECTION("section operator cannot appear at the end")
    2712             :     {
    2713           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("invalid-section-operator", "name-period-name-cpp");
    2714             : 
    2715             :         {
    2716           2 :             std::ofstream config_file;
    2717           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    2718           1 :             CATCH_REQUIRE(config_file.good());
    2719           1 :             config_file <<
    2720             :                 "# Auto-generated\n"
    2721             :                 "a=color\n"
    2722             :                 "a..b=red\n"
    2723             :                 "a.b.c::=122\n"
    2724             :                 "m=size\n"
    2725             :                 "z=edge\n"
    2726             :                 "z.b=line\n"
    2727             :                 "z..b.c=12.72\n"
    2728             :             ;
    2729             :         }
    2730             : 
    2731           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    2732             :                             , advgetopt::line_continuation_t::line_continuation_unix
    2733             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    2734             :                             , advgetopt::COMMENT_SHELL
    2735           2 :                             , advgetopt::SECTION_OPERATOR_C | advgetopt::SECTION_OPERATOR_CPP);
    2736             : 
    2737           1 :         CATCH_REQUIRE(setup.is_valid());
    2738           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    2739           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    2740           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    2741           1 :         CATCH_REQUIRE(setup.get_section_operator() == (advgetopt::SECTION_OPERATOR_C | advgetopt::SECTION_OPERATOR_CPP));
    2742             : 
    2743           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    2744             :                     "error: option name \"a.b.c::\" cannot end with a"
    2745             :                     " section operator or be empty.");
    2746           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    2747           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    2748             : 
    2749           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    2750           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    2751             : 
    2752           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    2753           1 :         CATCH_REQUIRE(sections.size() == 3);
    2754           1 :         CATCH_REQUIRE(sections.find("a")    != sections.end());
    2755           1 :         CATCH_REQUIRE(sections.find("z")    != sections.end());
    2756           1 :         CATCH_REQUIRE(sections.find("z::b") != sections.end());
    2757             : 
    2758           1 :         CATCH_REQUIRE(file->get_parameters().size() == 6);
    2759             : 
    2760           1 :         CATCH_REQUIRE(file->has_parameter("a"));
    2761           1 :         CATCH_REQUIRE(file->has_parameter("a::b"));
    2762           1 :         CATCH_REQUIRE(file->has_parameter("m"));
    2763           1 :         CATCH_REQUIRE(file->has_parameter("z"));
    2764           1 :         CATCH_REQUIRE(file->has_parameter("z::b"));
    2765           1 :         CATCH_REQUIRE(file->has_parameter("z::b::c"));
    2766             : 
    2767           1 :         CATCH_REQUIRE(file->get_parameter("a") == "color");
    2768           1 :         CATCH_REQUIRE(file->get_parameter("a::b") == "red");
    2769           1 :         CATCH_REQUIRE(file->get_parameter("m") == "size");
    2770           1 :         CATCH_REQUIRE(file->get_parameter("z") == "edge");
    2771           1 :         CATCH_REQUIRE(file->get_parameter("z::b") == "line");
    2772           1 :         CATCH_REQUIRE(file->get_parameter("z::b::c") == "12.72");
    2773             :     }
    2774             :     CATCH_END_SECTION()
    2775             : 
    2776          18 :     CATCH_START_SECTION("sections not allowed")
    2777             :     {
    2778           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("invalid-section-operator", "section-not-allowed");
    2779             : 
    2780             :         {
    2781           2 :             std::ofstream config_file;
    2782           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    2783           1 :             CATCH_REQUIRE(config_file.good());
    2784           1 :             config_file <<
    2785             :                 "# Auto-generated\n"
    2786             :                 "a=color\n"
    2787             :                 "a::b=red\n"
    2788             :                 "m.n=size\n"
    2789             :                 "z=edge\n"
    2790             :             ;
    2791             :         }
    2792             : 
    2793             :         // no errors here since we do not detect the sections in this case
    2794             :         //
    2795           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    2796             :                             , advgetopt::line_continuation_t::line_continuation_unix
    2797             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    2798             :                             , advgetopt::COMMENT_SHELL
    2799           2 :                             , advgetopt::SECTION_OPERATOR_NONE);
    2800             : 
    2801           1 :         CATCH_REQUIRE(setup.is_valid());
    2802           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    2803           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    2804           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    2805           1 :         CATCH_REQUIRE(setup.get_section_operator() == (advgetopt::SECTION_OPERATOR_NONE));
    2806             : 
    2807           2 :         std::unique_ptr<char, decltype(&::free)> fn(realpath(SNAP_CATCH2_NAMESPACE::g_config_filename.c_str(), nullptr), &::free);
    2808           2 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    2809             :                   "error: parameter \"a::b\" on line 3 in configuration file \""
    2810           2 :                 + std::string(fn.get())
    2811           3 :                 + "\" includes a character not acceptable for a section or"
    2812             :                   " parameter name (controls, space, quotes, and \";#/=:?+\\\").");
    2813           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    2814           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    2815             : 
    2816           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    2817           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    2818             : 
    2819           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    2820           1 :         CATCH_REQUIRE(sections.empty());
    2821             : 
    2822           1 :         CATCH_REQUIRE(file->get_parameters().size() == 3);
    2823             : 
    2824           1 :         CATCH_REQUIRE(file->has_parameter("a"));
    2825           1 :         CATCH_REQUIRE_FALSE(file->has_parameter("a::b"));
    2826           1 :         CATCH_REQUIRE(file->has_parameter("m.n"));
    2827           1 :         CATCH_REQUIRE(file->has_parameter("z"));
    2828             : 
    2829           1 :         CATCH_REQUIRE(file->get_parameter("a") == "color");
    2830           1 :         CATCH_REQUIRE(file->get_parameter("a::b") == std::string());
    2831           1 :         CATCH_REQUIRE(file->get_parameter("m.n") == "size");
    2832           1 :         CATCH_REQUIRE(file->get_parameter("z") == "edge");
    2833             : 
    2834           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    2835             :                     "error: option name \"blue::shepard\" cannot be added to"
    2836             :                     " section \"j::k\" because there is no section support"
    2837             :                     " for this configuration file.");
    2838           1 :         file->set_parameter("j::k", "blue::shepard", "2001");
    2839           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    2840             :     }
    2841             :     CATCH_END_SECTION()
    2842             : 
    2843          18 :     CATCH_START_SECTION("invalid characters in names")
    2844             :     {
    2845           1 :         std::string const bad_chars(
    2846             :                     "\x01\x02\x03\x04\x05\x06\x07"
    2847             :                 "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
    2848             :                 "\x10\x11\x12\x13\x14\x15\x16\x17"
    2849             :                 "\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
    2850             :                 "\x20"
    2851             :                 "'\";#/=:?+\\"
    2852           2 :             );
    2853          43 :         for(auto c : bad_chars)
    2854             :         {
    2855             :             // white spaces get removed from the line so we cannot test
    2856             :             // them in this way
    2857             :             //
    2858          42 :             if(std::iswspace(c))
    2859             :             {
    2860           6 :                 continue;
    2861             :             }
    2862          72 :             std::string bc;
    2863          36 :             bc += c;
    2864             : 
    2865         144 :             for(int pos(0); pos < 3; ++pos)
    2866             :             {
    2867         216 :                 std::string spos("undefined");
    2868         216 :                 std::string bad_char("undefined");
    2869         108 :                 switch(pos)
    2870             :                 {
    2871          36 :                 case 0:
    2872          36 :                     spos = "start";
    2873          36 :                     bad_char = bc + "bad-char";
    2874          36 :                     break;
    2875             : 
    2876          36 :                 case 1:
    2877          36 :                     spos = "middle";
    2878          36 :                     bad_char = "bad" + bc + "char";
    2879          36 :                     break;
    2880             : 
    2881          36 :                 case 2:
    2882          36 :                     spos = "end";
    2883          36 :                     bad_char = "bad-char" + bc;
    2884          36 :                     break;
    2885             : 
    2886             :                 }
    2887         108 :                 SNAP_CATCH2_NAMESPACE::init_tmp_dir("invalid-characters", "bad-character-" + std::to_string(static_cast<int>(c)) + "-" + spos);
    2888             : 
    2889             :                 {
    2890         216 :                     std::ofstream config_file;
    2891         108 :                     config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    2892         108 :                     CATCH_REQUIRE(config_file.good());
    2893         108 :                     char op(c == '=' ? ':' : '=');
    2894             :                     config_file <<
    2895             :                            "good" << op << "red\n"
    2896             :                         << bad_char << op << "color\n"       // <-- bad char
    2897         108 :                            "fine" << op << "param\n";
    2898             :                     ;
    2899             :                 }
    2900             : 
    2901             :                 // no errors here since we do not detect the sections in this case
    2902             :                 //
    2903         108 :                 advgetopt::assignment_operator_t as(c == '='
    2904         108 :                                         ? advgetopt::ASSIGNMENT_OPERATOR_COLON
    2905             :                                         : advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    2906         108 :                 advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    2907             :                                     , advgetopt::line_continuation_t::line_continuation_unix
    2908             :                                     , as
    2909             :                                     , advgetopt::COMMENT_NONE
    2910         216 :                                     , advgetopt::SECTION_OPERATOR_NONE);
    2911             : 
    2912         108 :                 CATCH_REQUIRE(setup.is_valid());
    2913         108 :                 CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    2914         108 :                 CATCH_REQUIRE(setup.get_assignment_operator() == as);
    2915         108 :                 CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_NONE);
    2916         108 :                 CATCH_REQUIRE(setup.get_section_operator() == (advgetopt::SECTION_OPERATOR_NONE));
    2917             : 
    2918         216 :                 std::unique_ptr<char, decltype(&::free)> fn(realpath(SNAP_CATCH2_NAMESPACE::g_config_filename.c_str(), nullptr), &::free);
    2919         216 :                 SNAP_CATCH2_NAMESPACE::push_expected_log(
    2920             :                           "error: parameter \""
    2921         216 :                         + bad_char
    2922         324 :                         + "\" on line 2 in configuration file \""
    2923         324 :                         + fn.get()
    2924         324 :                         + "\" includes a character not acceptable for a section or"
    2925             :                           " parameter name (controls, space, quotes, and \";#/=:?+\\\").");
    2926         216 :                 advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    2927             : 
    2928         108 :                 CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    2929         108 :                 CATCH_REQUIRE(file->get_errno() == 0);
    2930             : 
    2931         216 :                 advgetopt::conf_file::sections_t sections(file->get_sections());
    2932         108 :                 CATCH_REQUIRE(sections.empty());
    2933             : 
    2934         108 :                 CATCH_REQUIRE(file->get_parameters().size() == 2);
    2935             : 
    2936         108 :                 CATCH_REQUIRE(file->has_parameter("good"));
    2937         108 :                 CATCH_REQUIRE_FALSE(file->has_parameter(bad_char));
    2938         108 :                 CATCH_REQUIRE(file->has_parameter("fine"));
    2939             : 
    2940         108 :                 CATCH_REQUIRE(file->get_parameter("good") == "red");
    2941         108 :                 CATCH_REQUIRE(file->get_parameter(bad_char) == std::string());
    2942         108 :                 CATCH_REQUIRE(file->get_parameter("fine") == "param");
    2943             :             }
    2944             :         }
    2945           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    2946             :     }
    2947             :     CATCH_END_SECTION()
    2948             : 
    2949          18 :     CATCH_START_SECTION("too many sections")
    2950             :     {
    2951           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("invalid-section-operator", "too-many-sections");
    2952             : 
    2953             :         {
    2954           2 :             std::ofstream config_file;
    2955           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    2956           1 :             CATCH_REQUIRE(config_file.good());
    2957           1 :             config_file <<
    2958             :                 "# Auto-generated\n"
    2959             :                 "a=color\n"
    2960             :                 "a::b=red\n"
    2961             :                 "m.n.o=size\n"
    2962             :                 "z=edge\n"
    2963             :             ;
    2964             :         }
    2965             : 
    2966           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    2967             :                             , advgetopt::line_continuation_t::line_continuation_unix
    2968             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    2969             :                             , advgetopt::COMMENT_SHELL
    2970           2 :                             , advgetopt::SECTION_OPERATOR_CPP | advgetopt::SECTION_OPERATOR_C | advgetopt::SECTION_OPERATOR_ONE_SECTION);
    2971             : 
    2972           1 :         CATCH_REQUIRE(setup.is_valid());
    2973           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    2974           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    2975           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    2976           1 :         CATCH_REQUIRE(setup.get_section_operator() == (advgetopt::SECTION_OPERATOR_CPP | advgetopt::SECTION_OPERATOR_C | advgetopt::SECTION_OPERATOR_ONE_SECTION));
    2977             : 
    2978           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    2979             :                     "error: option name \"m.n.o\" cannot be added to section"
    2980             :                     " \"m::n\" because this configuration only accepts one"
    2981             :                     " section level.");
    2982           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    2983           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    2984             : 
    2985           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    2986           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    2987             : 
    2988           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    2989           1 :         CATCH_REQUIRE(sections.size() == 1);
    2990           1 :         CATCH_REQUIRE(sections.find("a") != sections.end());
    2991             : 
    2992           1 :         CATCH_REQUIRE(file->get_parameters().size() == 3);
    2993             : 
    2994           1 :         CATCH_REQUIRE(file->has_parameter("a"));
    2995           1 :         CATCH_REQUIRE(file->has_parameter("a::b"));
    2996           1 :         CATCH_REQUIRE(file->has_parameter("z"));
    2997             : 
    2998           1 :         CATCH_REQUIRE(file->get_parameter("a") == "color");
    2999           1 :         CATCH_REQUIRE(file->get_parameter("a::b") == "red");
    3000           1 :         CATCH_REQUIRE(file->get_parameter("z") == "edge");
    3001             :     }
    3002             :     CATCH_END_SECTION()
    3003             : 
    3004          18 :     CATCH_START_SECTION("all '{' were not closed")
    3005             :     {
    3006           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("invalid-section-operator", "unclosed-brackets");
    3007             : 
    3008             :         {
    3009           2 :             std::ofstream config_file;
    3010           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    3011           1 :             CATCH_REQUIRE(config_file.good());
    3012           1 :             config_file <<
    3013             :                 "# Auto-generated\n"
    3014             :                 "colors {\n"
    3015             :                 "  b=red\n"
    3016             :                 "  c=blue\n"
    3017             :             ;
    3018             :         }
    3019             : 
    3020           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    3021             :                             , advgetopt::line_continuation_t::line_continuation_unix
    3022             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    3023             :                             , advgetopt::COMMENT_SHELL
    3024           2 :                             , advgetopt::SECTION_OPERATOR_BLOCK);
    3025             : 
    3026           1 :         CATCH_REQUIRE(setup.is_valid());
    3027           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    3028           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    3029           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    3030           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_BLOCK);
    3031             : 
    3032           2 :         std::unique_ptr<char, decltype(&::free)> fn(realpath(SNAP_CATCH2_NAMESPACE::g_config_filename.c_str(), nullptr), &::free);
    3033           2 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    3034             :                     "error: unterminated `section { ... }`, the `}` is missing"
    3035             :                     " in configuration file "
    3036             :                     "\""
    3037           2 :                   + std::string(fn.get())
    3038           3 :                   + "\".");
    3039           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    3040           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    3041             : 
    3042           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    3043           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    3044             : 
    3045           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    3046           1 :         CATCH_REQUIRE(sections.size() == 1);
    3047           1 :         CATCH_REQUIRE(sections.find("colors") != sections.end());
    3048             : 
    3049           1 :         CATCH_REQUIRE(file->get_parameters().size() == 2);
    3050             : 
    3051           1 :         CATCH_REQUIRE(file->has_parameter("colors::b"));
    3052           1 :         CATCH_REQUIRE(file->has_parameter("colors::c"));
    3053             : 
    3054           1 :         CATCH_REQUIRE(file->get_parameter("colors::b") == "red");
    3055           1 :         CATCH_REQUIRE(file->get_parameter("colors::c") == "blue");
    3056             :     }
    3057             :     CATCH_END_SECTION()
    3058             : 
    3059          18 :     CATCH_START_SECTION("data after ']' in INI file")
    3060             :     {
    3061           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("invalid-section-operator", "additional-data");
    3062             : 
    3063             :         {
    3064           2 :             std::ofstream config_file;
    3065           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    3066           1 :             CATCH_REQUIRE(config_file.good());
    3067           1 :             config_file <<
    3068             :                 "# Auto-generated\n"
    3069             :                 "[colors]\n"
    3070             :                 "b=red\n"
    3071             :                 "c=blue\n"
    3072             :                 "\n"
    3073             :                 "[sizes] comment\n"     // <- missing the comment introducer
    3074             :                 "q=1000\n"
    3075             :                 "r=9999\n"
    3076             :             ;
    3077             :         }
    3078             : 
    3079           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    3080             :                             , advgetopt::line_continuation_t::line_continuation_unix
    3081             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    3082             :                             , advgetopt::COMMENT_SHELL
    3083           2 :                             , advgetopt::SECTION_OPERATOR_INI_FILE);
    3084             : 
    3085           1 :         CATCH_REQUIRE(setup.is_valid());
    3086           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    3087           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    3088           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    3089           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_INI_FILE);
    3090             : 
    3091           2 :         std::unique_ptr<char, decltype(&::free)> fn(realpath(SNAP_CATCH2_NAMESPACE::g_config_filename.c_str(), nullptr), &::free);
    3092           2 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    3093             :                       "error: section names in configuration files cannot be followed by anything other than spaces in"
    3094             :                       " \"[sizes] comment\" on line 6 from configuration file \""
    3095           2 :                     + std::string(fn.get())
    3096           3 :                     + "\".");
    3097           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    3098           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    3099             : 
    3100           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    3101           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    3102             : 
    3103           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    3104           1 :         CATCH_REQUIRE(sections.size() == 1);
    3105           1 :         CATCH_REQUIRE(sections.find("colors") != sections.end());
    3106             : 
    3107           1 :         CATCH_REQUIRE(file->get_parameters().size() == 4);
    3108             : 
    3109           1 :         CATCH_REQUIRE(file->has_parameter("colors::b"));
    3110           1 :         CATCH_REQUIRE(file->has_parameter("colors::c"));
    3111           1 :         CATCH_REQUIRE(file->has_parameter("colors::q"));
    3112           1 :         CATCH_REQUIRE(file->has_parameter("colors::r"));
    3113             : 
    3114           1 :         CATCH_REQUIRE(file->get_parameter("colors::b") == "red");
    3115           1 :         CATCH_REQUIRE(file->get_parameter("colors::c") == "blue");
    3116           1 :         CATCH_REQUIRE(file->get_parameter("colors::q") == "1000");
    3117           1 :         CATCH_REQUIRE(file->get_parameter("colors::r") == "9999");
    3118             :     }
    3119             :     CATCH_END_SECTION()
    3120             : 
    3121          18 :     CATCH_START_SECTION("INI file section inside a block is not allowed")
    3122             :     {
    3123           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("invalid-section-operator", "ini-inside-block");
    3124             : 
    3125             :         {
    3126           2 :             std::ofstream config_file;
    3127           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    3128           1 :             CATCH_REQUIRE(config_file.good());
    3129           1 :             config_file <<
    3130             :                 "# Auto-generated\n"
    3131             :                 "[colors]\n"
    3132             :                 "b=red\n"
    3133             :                 "c=blue\n"
    3134             :                 "\n"
    3135             :                 "block {\n"
    3136             :                 "  b = block data\n"
    3137             :                 "  f = filename\n"
    3138             :                 "  [sizes]\n"       // <-- INI section inside a block not allowed
    3139             :                 "  q=1000\n"
    3140             :                 "  r=9999\n"
    3141             :                 "}\n"
    3142             :             ;
    3143             :         }
    3144             : 
    3145           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    3146             :                             , advgetopt::line_continuation_t::line_continuation_unix
    3147             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    3148             :                             , advgetopt::COMMENT_SHELL
    3149           2 :                             , advgetopt::SECTION_OPERATOR_BLOCK | advgetopt::SECTION_OPERATOR_INI_FILE);
    3150             : 
    3151           1 :         CATCH_REQUIRE(setup.is_valid());
    3152           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    3153           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    3154           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    3155           1 :         CATCH_REQUIRE(setup.get_section_operator() == (advgetopt::SECTION_OPERATOR_BLOCK | advgetopt::SECTION_OPERATOR_INI_FILE));
    3156             : 
    3157           2 :         std::unique_ptr<char, decltype(&::free)> fn(realpath(SNAP_CATCH2_NAMESPACE::g_config_filename.c_str(), nullptr), &::free);
    3158           2 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    3159             :                       "error: `[...]` sections can't be used within a `section"
    3160             :                       " { ... }` on line 9 from configuration file \""
    3161           2 :                     + std::string(fn.get())
    3162           3 :                     + "\".");
    3163           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    3164           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    3165             : 
    3166           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    3167           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    3168             : 
    3169           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    3170           1 :         CATCH_REQUIRE(sections.size() == 2);
    3171           1 :         CATCH_REQUIRE(sections.find("colors") != sections.end());
    3172           1 :         CATCH_REQUIRE(sections.find("colors::block") != sections.end());
    3173             : 
    3174           1 :         CATCH_REQUIRE(file->get_parameters().size() == 6);
    3175             : 
    3176           1 :         CATCH_REQUIRE(file->has_parameter("colors::b"));
    3177           1 :         CATCH_REQUIRE(file->has_parameter("colors::c"));
    3178           1 :         CATCH_REQUIRE(file->has_parameter("colors::block::b"));
    3179           1 :         CATCH_REQUIRE(file->has_parameter("colors::block::f"));
    3180           1 :         CATCH_REQUIRE(file->has_parameter("colors::block::q"));
    3181           1 :         CATCH_REQUIRE(file->has_parameter("colors::block::r"));
    3182             : 
    3183           1 :         CATCH_REQUIRE(file->get_parameter("colors::b") == "red");
    3184           1 :         CATCH_REQUIRE(file->get_parameter("colors::c") == "blue");
    3185           1 :         CATCH_REQUIRE(file->get_parameter("colors::block::b") == "block data");
    3186           1 :         CATCH_REQUIRE(file->get_parameter("colors::block::f") == "filename");
    3187           1 :         CATCH_REQUIRE(file->get_parameter("colors::block::q") == "1000");
    3188           1 :         CATCH_REQUIRE(file->get_parameter("colors::block::r") == "9999");
    3189             :     }
    3190             :     CATCH_END_SECTION()
    3191           9 : }
    3192             : 
    3193             : 
    3194             : 
    3195           7 : CATCH_TEST_CASE("invalid_variable_name", "[config][getopt][invalid]")
    3196             : {
    3197          10 :     CATCH_START_SECTION("empty variable name")
    3198             :     {
    3199           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("invalid-variable-name", "name-missing");
    3200             : 
    3201             :         {
    3202           2 :             std::ofstream config_file;
    3203           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    3204           1 :             CATCH_REQUIRE(config_file.good());
    3205           1 :             config_file <<
    3206             :                 "# Auto-generated\n"
    3207             :                 "=color\n"                  // <-- name missing
    3208             :                 "a..b=red\n"
    3209             :                 "a.b.c=142\n"
    3210             :             ;
    3211             :         }
    3212             : 
    3213           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    3214             :                             , advgetopt::line_continuation_t::line_continuation_unix
    3215             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    3216             :                             , advgetopt::COMMENT_SHELL
    3217           2 :                             , advgetopt::SECTION_OPERATOR_C);
    3218             : 
    3219           1 :         CATCH_REQUIRE(setup.is_valid());
    3220           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    3221           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    3222           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    3223           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_C);
    3224             : 
    3225           2 :         std::unique_ptr<char, decltype(&::free)> fn(realpath(SNAP_CATCH2_NAMESPACE::g_config_filename.c_str(), nullptr), &::free);
    3226           2 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    3227             :                       "error: no option name in \"=color\""
    3228             :                       " on line 2 from configuration file \""
    3229           2 :                     + std::string(fn.get())
    3230           3 :                     + "\", missing name before the assignment operator?");
    3231           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    3232           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    3233             : 
    3234           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    3235           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    3236             : 
    3237           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    3238           1 :         CATCH_REQUIRE(sections.size() == 2);
    3239           1 :         CATCH_REQUIRE(sections.find("a")    != sections.end());
    3240           1 :         CATCH_REQUIRE(sections.find("a::b") != sections.end());
    3241             : 
    3242           1 :         CATCH_REQUIRE(file->get_parameters().size() == 2);
    3243             : 
    3244           1 :         CATCH_REQUIRE(file->has_parameter("a::b"));
    3245           1 :         CATCH_REQUIRE(file->has_parameter("a::b::c"));
    3246             : 
    3247           1 :         CATCH_REQUIRE(file->get_parameter("a::b") == "red");
    3248           1 :         CATCH_REQUIRE(file->get_parameter("a::b::c") == "142");
    3249             :     }
    3250             :     CATCH_END_SECTION()
    3251             : 
    3252          10 :     CATCH_START_SECTION("empty variable name after section name")
    3253             :     {
    3254           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("invalid-variable-name", "section-and-name-missing");
    3255             : 
    3256             :         {
    3257           2 :             std::ofstream config_file;
    3258           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    3259           1 :             CATCH_REQUIRE(config_file.good());
    3260           1 :             config_file <<
    3261             :                 "# Auto-generated\n"
    3262             :                 "a..b=red\n"
    3263             :                 "a.b.=color\n"                  // <-- name missing after section name
    3264             :                 "a.b.c=142\n"
    3265             :             ;
    3266             :         }
    3267             : 
    3268           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    3269             :                             , advgetopt::line_continuation_t::line_continuation_unix
    3270             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    3271             :                             , advgetopt::COMMENT_SHELL
    3272           2 :                             , advgetopt::SECTION_OPERATOR_C);
    3273             : 
    3274           1 :         CATCH_REQUIRE(setup.is_valid());
    3275           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    3276           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    3277           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    3278           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_C);
    3279             : 
    3280           1 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    3281             :                       "error: option name \"a.b.\" cannot end with a section operator or be empty.");
    3282           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    3283           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    3284             : 
    3285           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    3286           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    3287             : 
    3288           2 :         advgetopt::conf_file::sections_t sections(file->get_sections());
    3289           1 :         CATCH_REQUIRE(sections.size() == 2);
    3290           1 :         CATCH_REQUIRE(sections.find("a") != sections.end());
    3291           1 :         CATCH_REQUIRE(sections.find("a::b") != sections.end());
    3292             : 
    3293           1 :         CATCH_REQUIRE(file->get_parameters().size() == 2);
    3294             : 
    3295           1 :         CATCH_REQUIRE(file->has_parameter("a::b"));
    3296           1 :         CATCH_REQUIRE(file->has_parameter("a::b::c"));
    3297             : 
    3298           1 :         CATCH_REQUIRE(file->get_parameter("a::b") == "red");
    3299           1 :         CATCH_REQUIRE(file->get_parameter("a::b::c") == "142");
    3300             :     }
    3301             :     CATCH_END_SECTION()
    3302             : 
    3303          10 :     CATCH_START_SECTION("variable name starts with a dash")
    3304             :     {
    3305           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("invalid-variable-name", "dash-name");
    3306             : 
    3307             :         {
    3308           2 :             std::ofstream config_file;
    3309           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    3310           1 :             CATCH_REQUIRE(config_file.good());
    3311           1 :             config_file <<
    3312             :                 "# Auto-generated\n"
    3313             :                 "a=color\n"
    3314             :                 "-bad-dash=reddish\n"            // <-- name starts with '-'
    3315             :                 "size=412\n"
    3316             :             ;
    3317             :         }
    3318             : 
    3319           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    3320             :                             , advgetopt::line_continuation_t::line_continuation_unix
    3321             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    3322             :                             , advgetopt::COMMENT_SHELL
    3323           2 :                             , advgetopt::SECTION_OPERATOR_C);
    3324             : 
    3325           1 :         CATCH_REQUIRE(setup.is_valid());
    3326           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    3327           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    3328           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    3329           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_C);
    3330             : 
    3331           2 :         std::unique_ptr<char, decltype(&::free)> fn(realpath(SNAP_CATCH2_NAMESPACE::g_config_filename.c_str(), nullptr), &::free);
    3332           2 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    3333             :                       "error: option names in configuration files cannot"
    3334             :                       " start with a dash or an underscore in"
    3335             :                       " \"-bad-dash=reddish\" on line 3 from configuration file \""
    3336           2 :                     + std::string(fn.get())
    3337           3 :                     + "\".");
    3338           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    3339           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    3340             : 
    3341           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    3342           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    3343             : 
    3344           1 :         CATCH_REQUIRE(file->get_sections().empty());
    3345             : 
    3346           1 :         CATCH_REQUIRE(file->get_parameters().size() == 2);
    3347             : 
    3348           1 :         CATCH_REQUIRE(file->has_parameter("a"));
    3349           1 :         CATCH_REQUIRE(file->has_parameter("size"));
    3350             : 
    3351           1 :         CATCH_REQUIRE(file->get_parameter("a") == "color");
    3352           1 :         CATCH_REQUIRE(file->get_parameter("size") == "412");
    3353             :     }
    3354             :     CATCH_END_SECTION()
    3355             : 
    3356          10 :     CATCH_START_SECTION("variable name starts with an underscore")
    3357             :     {
    3358           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("invalid-variable-name", "underscore-name");
    3359             : 
    3360             :         {
    3361           2 :             std::ofstream config_file;
    3362           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    3363           1 :             CATCH_REQUIRE(config_file.good());
    3364           1 :             config_file <<
    3365             :                 "# Auto-generated\n"
    3366             :                 "a_variable=color\n"
    3367             :                 "_bad_underscore=reddish\n"        // <-- name starts with '_'
    3368             :                 "pos_and_size=412x33+32-18\n"
    3369             :             ;
    3370             :         }
    3371             : 
    3372           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    3373             :                             , advgetopt::line_continuation_t::line_continuation_unix
    3374             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    3375             :                             , advgetopt::COMMENT_SHELL
    3376           2 :                             , advgetopt::SECTION_OPERATOR_C);
    3377             : 
    3378           1 :         CATCH_REQUIRE(setup.is_valid());
    3379           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    3380           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    3381           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    3382           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_C);
    3383             : 
    3384           2 :         std::unique_ptr<char, decltype(&::free)> fn(realpath(SNAP_CATCH2_NAMESPACE::g_config_filename.c_str(), nullptr), &::free);
    3385           2 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    3386             :                       "error: option names in configuration files cannot"
    3387             :                       " start with a dash or an underscore in"
    3388             :                       " \"_bad_underscore=reddish\" on line 3 from configuration file \""
    3389           2 :                     + std::string(fn.get())
    3390           3 :                     + "\".");
    3391           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    3392           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    3393             : 
    3394           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    3395           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    3396             : 
    3397           1 :         CATCH_REQUIRE(file->get_sections().empty());
    3398             : 
    3399           1 :         CATCH_REQUIRE(file->get_parameters().size() == 2);
    3400             : 
    3401           1 :         CATCH_REQUIRE(file->has_parameter("a-variable"));
    3402           1 :         CATCH_REQUIRE(file->has_parameter("pos-and-size"));
    3403             : 
    3404           1 :         CATCH_REQUIRE(file->get_parameter("a-variable") == "color");
    3405           1 :         CATCH_REQUIRE(file->get_parameter("pos-and-size") == "412x33+32-18");
    3406             :     }
    3407             :     CATCH_END_SECTION()
    3408             : 
    3409          10 :     CATCH_START_SECTION("variable name with spaces")
    3410             :     {
    3411           1 :         SNAP_CATCH2_NAMESPACE::init_tmp_dir("invalid-variable-name", "name-space-more-name");
    3412             : 
    3413             :         {
    3414           2 :             std::ofstream config_file;
    3415           1 :             config_file.open(SNAP_CATCH2_NAMESPACE::g_config_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    3416           1 :             CATCH_REQUIRE(config_file.good());
    3417           1 :             config_file <<
    3418             :                 "# Auto-generated\n"
    3419             :                 "a variable=color\n"
    3420             :                 "bad space=reddish\n"
    3421             :                 "pos and size=412x33+32-18\n"
    3422             :             ;
    3423             :         }
    3424             : 
    3425           1 :         advgetopt::conf_file_setup setup(SNAP_CATCH2_NAMESPACE::g_config_filename
    3426             :                             , advgetopt::line_continuation_t::line_continuation_unix
    3427             :                             , advgetopt::ASSIGNMENT_OPERATOR_EQUAL
    3428             :                             , advgetopt::COMMENT_SHELL
    3429           2 :                             , advgetopt::SECTION_OPERATOR_C);
    3430             : 
    3431           1 :         CATCH_REQUIRE(setup.is_valid());
    3432           1 :         CATCH_REQUIRE(setup.get_line_continuation() == advgetopt::line_continuation_t::line_continuation_unix);
    3433           1 :         CATCH_REQUIRE(setup.get_assignment_operator() == advgetopt::ASSIGNMENT_OPERATOR_EQUAL);
    3434           1 :         CATCH_REQUIRE(setup.get_comment() == advgetopt::COMMENT_SHELL);
    3435           1 :         CATCH_REQUIRE(setup.get_section_operator() == advgetopt::SECTION_OPERATOR_C);
    3436             : 
    3437           2 :         std::unique_ptr<char, decltype(&::free)> fn(realpath(SNAP_CATCH2_NAMESPACE::g_config_filename.c_str(), nullptr), &::free);
    3438           2 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    3439             :                       "error: option name from \"a variable=color\" on line"
    3440             :                       " 2 in configuration file \""
    3441           2 :                     + std::string(fn.get())
    3442           3 :                     + "\" cannot include a space, missing assignment operator?");
    3443           2 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    3444             :                       "error: option name from \"bad space=reddish\" on line"
    3445             :                       " 3 in configuration file \""
    3446           2 :                     + std::string(fn.get())
    3447           3 :                     + "\" cannot include a space, missing assignment operator?");
    3448           2 :         SNAP_CATCH2_NAMESPACE::push_expected_log(
    3449             :                       "error: option name from \"pos and size=412x33+32-18\" on line"
    3450             :                       " 4 in configuration file \""
    3451           2 :                     + std::string(fn.get())
    3452           3 :                     + "\" cannot include a space, missing assignment operator?");
    3453           2 :         advgetopt::conf_file::pointer_t file(advgetopt::conf_file::get_conf_file(setup));
    3454           1 :         SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
    3455             : 
    3456           1 :         CATCH_REQUIRE(file->get_setup().get_config_url() == setup.get_config_url());
    3457           1 :         CATCH_REQUIRE(file->get_errno() == 0);
    3458             : 
    3459           1 :         CATCH_REQUIRE(file->get_sections().empty());
    3460             : 
    3461           1 :         CATCH_REQUIRE(file->get_parameters().empty());
    3462             :     }
    3463             :     CATCH_END_SECTION()
    3464          11 : }
    3465             : 
    3466             : 
    3467             : 
    3468             : 
    3469             : 
    3470             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13