LCOV - code coverage report
Current view: top level - tests - config_file.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1500 1511 99.3 %
Date: 2019-07-15 03:11:49 Functions: 20 20 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.12