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

Generated by: LCOV version 1.13