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