LCOV - code coverage report
Current view: top level - tests - config_file.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1542 1555 99.2 %
Date: 2020-11-13 17:54:34 Functions: 20 20 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13