LCOV - code coverage report
Current view: top level - tests - catch_config_file.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1618 1631 99.2 %
Date: 2021-09-08 17:05:25 Functions: 20 20 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13