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

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

Generated by: LCOV version 1.12