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