LCOV - code coverage report
Current view: top level - tests - catch_config_file.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1702 1715 99.2 %
Date: 2022-03-01 20:39:45 Functions: 20 20 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13