Line data Source code
1 : // Copyright (c) 2006-2025 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 : // advgetopt
21 : //
22 : #include <advgetopt/exception.h>
23 :
24 :
25 : // self
26 : //
27 : #include "catch_main.h"
28 :
29 :
30 : // snapdev
31 : //
32 : #include <snapdev/pathinfo.h>
33 : #include <snapdev/safe_setenv.h>
34 :
35 :
36 : // C++
37 : //
38 : #include <fstream>
39 :
40 :
41 : // last include
42 : //
43 : #include <snapdev/poison.h>
44 :
45 :
46 :
47 :
48 9 : CATCH_TEST_CASE("valid_options_files", "[options][valid][files]")
49 : {
50 9 : CATCH_START_SECTION("valid_options_files: check the default path with a nullptr (not a very good test, though)")
51 : {
52 1 : advgetopt::option const options[] =
53 : {
54 : advgetopt::define_option(
55 : advgetopt::Name("verbose")
56 : , advgetopt::ShortName('v')
57 : , advgetopt::Flags(advgetopt::standalone_all_flags<>())
58 : , advgetopt::Help("a verbose like option, select it or not.")
59 : ),
60 : advgetopt::end_options()
61 : };
62 :
63 1 : advgetopt::options_environment options_env;
64 1 : options_env.f_project_name = "this-is-the-name-of-a-test-project-which-wont-ever-exist";
65 1 : options_env.f_options = options;
66 1 : options_env.f_environment_variable_name = "ADVGETOPT_TEST_OPTIONS";
67 1 : options_env.f_help_header = "Usage: test valid options from file";
68 :
69 1 : char const * sub_cargv[] =
70 : {
71 : "tests/unittests/no_file_to_load",
72 : "--verbose",
73 : nullptr
74 : };
75 1 : int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
76 1 : char ** sub_argv = const_cast<char **>(sub_cargv);
77 :
78 1 : advgetopt::getopt opt(options_env, sub_argc, sub_argv);
79 :
80 : // check that the result is valid
81 :
82 : // an invalid parameter, MUST NOT EXIST
83 3 : CATCH_REQUIRE(opt.get_option("invalid-parameter") == nullptr);
84 3 : CATCH_REQUIRE_FALSE(opt.is_defined("invalid-parameter"));
85 :
86 : // the valid parameter
87 3 : CATCH_REQUIRE(opt.is_defined("verbose"));
88 3 : CATCH_REQUIRE(opt.get_default("verbose").empty());
89 3 : CATCH_REQUIRE(opt.size("verbose") == 1);
90 :
91 : // other parameters
92 1 : CATCH_REQUIRE(opt.get_program_name() == "no_file_to_load");
93 1 : CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/no_file_to_load");
94 1 : }
95 9 : CATCH_END_SECTION()
96 :
97 9 : CATCH_START_SECTION("valid_options_files: check the default path with an empty string (not a very good test, though)")
98 : {
99 1 : advgetopt::option const options[] =
100 : {
101 : advgetopt::define_option(
102 : advgetopt::Name("verbose")
103 : , advgetopt::ShortName('v')
104 : , advgetopt::Flags(advgetopt::standalone_all_flags<>())
105 : , advgetopt::Help("a verbose like option, select it or not.")
106 : ),
107 : advgetopt::end_options()
108 : };
109 :
110 1 : advgetopt::options_environment options_env;
111 1 : options_env.f_project_name = "this-is-the-name-of-a-test-project-which-wont-ever-exist";
112 1 : options_env.f_options = options;
113 1 : options_env.f_options_files_directory = "";
114 1 : options_env.f_environment_variable_name = "ADVGETOPT_TEST_OPTIONS";
115 1 : options_env.f_help_header = "Usage: test valid options from file";
116 :
117 1 : char const * sub_cargv[] =
118 : {
119 : "tests/unittests/no_file_to_load",
120 : "--verbose",
121 : nullptr
122 : };
123 1 : int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
124 1 : char ** sub_argv = const_cast<char **>(sub_cargv);
125 :
126 1 : advgetopt::getopt opt(options_env, sub_argc, sub_argv);
127 :
128 : // check that the result is valid
129 :
130 : // an invalid parameter, MUST NOT EXIST
131 3 : CATCH_REQUIRE(opt.get_option("invalid-parameter") == nullptr);
132 3 : CATCH_REQUIRE_FALSE(opt.is_defined("invalid-parameter"));
133 :
134 : // the valid parameter
135 3 : CATCH_REQUIRE(opt.is_defined("verbose"));
136 3 : CATCH_REQUIRE(opt.get_default("verbose").empty());
137 3 : CATCH_REQUIRE(opt.size("verbose") == 1);
138 :
139 : // other parameters
140 1 : CATCH_REQUIRE(opt.get_program_name() == "no_file_to_load");
141 1 : CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/no_file_to_load");
142 1 : }
143 9 : CATCH_END_SECTION()
144 :
145 9 : CATCH_START_SECTION("valid_options_files: check the parsing of a valid options.ini file (one option)")
146 : {
147 : // create a file and make sure it's not read if the project name
148 : // is empty
149 : //
150 1 : std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
151 1 : tmpdir += "/shared/advgetopt";
152 1 : std::stringstream ss;
153 1 : ss << "mkdir -p " << tmpdir;
154 1 : if(system(ss.str().c_str()) != 0)
155 : {
156 0 : std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
157 0 : exit(1);
158 : }
159 1 : std::string const options_filename(tmpdir + "/no-project-name.ini");
160 :
161 1 : advgetopt::option const valid_options_from_file_list[] =
162 : {
163 : advgetopt::define_option(
164 : advgetopt::Name("verbose")
165 : , advgetopt::ShortName('v')
166 : , advgetopt::Flags(advgetopt::standalone_all_flags<>())
167 : , advgetopt::Help("a verbose like option, select it or not.")
168 : ),
169 : advgetopt::end_options()
170 : };
171 :
172 1 : advgetopt::options_environment valid_options_from_file;
173 1 : valid_options_from_file.f_project_name = nullptr;
174 1 : valid_options_from_file.f_options = valid_options_from_file_list;
175 1 : valid_options_from_file.f_options_files_directory = tmpdir.c_str();
176 1 : valid_options_from_file.f_environment_variable_name = "ADVGETOPT_TEST_OPTIONS";
177 1 : valid_options_from_file.f_help_header = "Usage: test valid options from file";
178 :
179 : {
180 1 : std::ofstream options_file;
181 1 : options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
182 1 : CATCH_REQUIRE(options_file.good());
183 : options_file <<
184 : "# Auto-generated\n"
185 :
186 : "[no-project-name]\n"
187 : "shortname=n\n"
188 : "default='inexistent'\n"
189 : "environment_variable_name=NO_PROJECT_NAME\n"
190 : "help=Testing that this doesn't get loaded\n"
191 1 : "allowed=command-line,environment-variable,configuration-file\n"
192 : ;
193 1 : }
194 :
195 1 : char const * sub_cargv[] =
196 : {
197 : "tests/unittests/file_not_loaded",
198 : "--verbose",
199 : nullptr
200 : };
201 1 : int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
202 1 : char ** sub_argv = const_cast<char **>(sub_cargv);
203 :
204 1 : advgetopt::getopt opt(valid_options_from_file, sub_argc, sub_argv);
205 :
206 : // check that the result is valid
207 :
208 : // an invalid parameter, MUST NOT EXIST
209 3 : CATCH_REQUIRE(opt.get_option("invalid-parameter") == nullptr);
210 3 : CATCH_REQUIRE_FALSE(opt.is_defined("invalid-parameter"));
211 :
212 : // the valid parameter
213 3 : CATCH_REQUIRE(opt.is_defined("verbose"));
214 3 : CATCH_REQUIRE(opt.get_default("verbose").empty());
215 3 : CATCH_REQUIRE(opt.size("verbose") == 1);
216 :
217 : // "--no-project-name"
218 3 : CATCH_REQUIRE(opt.get_option("no-project-name") == nullptr);
219 3 : CATCH_REQUIRE_FALSE(opt.is_defined("no-project-name"));
220 :
221 : // other parameters
222 1 : CATCH_REQUIRE(opt.get_program_name() == "file_not_loaded");
223 1 : CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/file_not_loaded");
224 1 : }
225 9 : CATCH_END_SECTION()
226 :
227 9 : CATCH_START_SECTION("valid_options_files: project name is an empty string")
228 : {
229 : // create a file and make sure it's not read if the project name
230 : // is empty
231 : //
232 1 : std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
233 1 : tmpdir += "/shared/advgetopt";
234 1 : std::stringstream ss;
235 1 : ss << "mkdir -p " << tmpdir;
236 1 : if(system(ss.str().c_str()) != 0)
237 : {
238 0 : std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
239 0 : exit(1);
240 : }
241 1 : std::string const options_filename(tmpdir + "/empty-string.ini");
242 :
243 1 : advgetopt::option const valid_options_from_file_list[] =
244 : {
245 : advgetopt::define_option(
246 : advgetopt::Name("verbose")
247 : , advgetopt::ShortName('v')
248 : , advgetopt::Flags(advgetopt::standalone_all_flags<>())
249 : , advgetopt::Help("a verbose like option, select it or not.")
250 : ),
251 : advgetopt::end_options()
252 : };
253 :
254 1 : advgetopt::options_environment valid_options_from_file;
255 1 : valid_options_from_file.f_project_name = "";
256 1 : valid_options_from_file.f_options = valid_options_from_file_list;
257 1 : valid_options_from_file.f_options_files_directory = tmpdir.c_str();
258 1 : valid_options_from_file.f_environment_variable_name = "ADVGETOPT_TEST_OPTIONS";
259 1 : valid_options_from_file.f_help_header = "Usage: test valid options from file";
260 :
261 : {
262 1 : std::ofstream options_file;
263 1 : options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
264 1 : CATCH_REQUIRE(options_file.good());
265 : options_file <<
266 : "# Auto-generated\n"
267 :
268 : "[no-project-name]\n"
269 : "shortname=n\n"
270 : "default='inexistent'\n"
271 : "help=Testing that this doesn't get loaded\n"
272 1 : "allowed=command-line,environment-variable,configuration-file\n"
273 : ;
274 1 : }
275 :
276 1 : char const * sub_cargv[] =
277 : {
278 : "tests/unittests/file_not_loaded",
279 : "--verbose",
280 : nullptr
281 : };
282 1 : int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
283 1 : char ** sub_argv = const_cast<char **>(sub_cargv);
284 :
285 1 : advgetopt::getopt opt(valid_options_from_file, sub_argc, sub_argv);
286 :
287 : // check that the result is valid
288 :
289 : // an invalid parameter, MUST NOT EXIST
290 3 : CATCH_REQUIRE(opt.get_option("invalid-parameter") == nullptr);
291 3 : CATCH_REQUIRE_FALSE(opt.is_defined("invalid-parameter"));
292 :
293 : // the valid parameter
294 3 : CATCH_REQUIRE(opt.is_defined("verbose"));
295 3 : CATCH_REQUIRE(opt.get_default("verbose").empty());
296 3 : CATCH_REQUIRE(opt.size("verbose") == 1);
297 :
298 : // "--no-project-name"
299 3 : CATCH_REQUIRE(opt.get_option("no-project-name") == nullptr);
300 3 : CATCH_REQUIRE_FALSE(opt.is_defined("no-project-name"));
301 :
302 1 : advgetopt::option_info::map_by_name_t const & all_options(opt.get_options());
303 3 : auto const o(all_options.find("no-project-name"));
304 1 : CATCH_REQUIRE(o == all_options.end());
305 :
306 : // other parameters
307 1 : CATCH_REQUIRE(opt.get_program_name() == "file_not_loaded");
308 1 : CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/file_not_loaded");
309 1 : }
310 9 : CATCH_END_SECTION()
311 :
312 9 : CATCH_START_SECTION("valid_options_files: check the parsing of a valid options.ini file (many options)")
313 : {
314 1 : std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
315 1 : tmpdir += "/shared/advgetopt";
316 1 : std::stringstream ss;
317 1 : ss << "mkdir -p " << tmpdir;
318 1 : if(system(ss.str().c_str()) != 0)
319 : {
320 0 : std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
321 0 : exit(1);
322 : }
323 1 : std::string const options_filename(tmpdir + "/unittest.ini");
324 :
325 1 : advgetopt::option const valid_options_from_file_list[] =
326 : {
327 : advgetopt::define_option(
328 : advgetopt::Name("verbose")
329 : , advgetopt::ShortName('v')
330 : , advgetopt::Flags(advgetopt::standalone_all_flags<>())
331 : , advgetopt::Help("a verbose like option, select it or not.")
332 : ),
333 : advgetopt::end_options()
334 : };
335 :
336 1 : advgetopt::options_environment valid_options_from_file;
337 1 : valid_options_from_file.f_project_name = "unittest";
338 1 : valid_options_from_file.f_options = valid_options_from_file_list;
339 1 : valid_options_from_file.f_options_files_directory = tmpdir.c_str();
340 1 : valid_options_from_file.f_environment_variable_name = "ADVGETOPT_TEST_OPTIONS";
341 1 : valid_options_from_file.f_help_header = "Usage: test valid options from file";
342 :
343 1 : snapdev::safe_setenv env("ADVGETOPT_TEST_OPTIONS"
344 : , "--verbose"
345 : " --more purple"
346 : " -f left.txt center.txt right.txt"
347 : " --size 519"
348 : " --from"
349 5 : " --output destination.txt");
350 :
351 : {
352 1 : std::ofstream options_file;
353 1 : options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
354 1 : CATCH_REQUIRE(options_file.good());
355 : options_file <<
356 : "# Auto-generated\n"
357 :
358 : "[more]\n"
359 : "shortname=m\n"
360 : "default='More Stuff'\n"
361 : "help=Allow for more stuff to be added\n"
362 : "validator=regex(\"purple|yellow|blue|red|green|orange|brown\")\n"
363 : "allowed=command-line,environment-variable,configuration-file\n"
364 : "show-usage-on-error\n"
365 : "required\n"
366 :
367 : "[size]\n"
368 : "shortname=s\n"
369 : "help=Specify the size\n"
370 : "validator=/[0-9]+/\n"
371 : "allowed=environment-variable,configuration-file\n"
372 : "default=31\n"
373 : "required\n"
374 :
375 : "[files]\n"
376 : "shortname=f\n"
377 : "help=List of file names\n"
378 : "validator=/.*\\.txt/i\n"
379 : "allowed=command-line,environment-variable\n"
380 : "multiple\n"
381 : "required\n"
382 :
383 : "[from]\n"
384 : "shortname=F\n"
385 : "help=Request for the geographical location representing the origin of the files; optionally you can specify the format\n"
386 : "validator=integer\n"
387 : "environment_variable_name=FROM\n"
388 : "allowed=command-line,environment-variable,configuration-file\n"
389 :
390 : "[output]\n"
391 : "shortname=o\n"
392 : "default=a.out\n"
393 : "help=output file\n"
394 : "allowed=environment-variable\n"
395 : "environment_variable_name=OUTPUT\n"
396 : "required\n"
397 :
398 : "[license]\n"
399 : "shortname=l\n"
400 : "help=show this test license\n"
401 : "allowed=command-line\n"
402 : "no-arguments\n"
403 :
404 : "[licence]\n"
405 : "alias=license\n"
406 : "allowed=command-line\n"
407 1 : "no-arguments\n"
408 : ;
409 1 : }
410 :
411 1 : char const * sub_cargv[] =
412 : {
413 : "tests/unittests/valid_options_files",
414 : "--verbose",
415 : "--licence",
416 : nullptr
417 : };
418 1 : int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
419 1 : char ** sub_argv = const_cast<char **>(sub_cargv);
420 :
421 1 : advgetopt::getopt opt(valid_options_from_file, sub_argc, sub_argv);
422 :
423 : // check that the result is valid
424 1 : advgetopt::option_info::map_by_name_t const & options(opt.get_options());
425 1 : CATCH_REQUIRE(options.size() == 8);
426 :
427 : // an invalid parameter, MUST NOT EXIST
428 3 : CATCH_REQUIRE(opt.get_option("invalid-parameter") == nullptr);
429 3 : CATCH_REQUIRE_FALSE(opt.is_defined("invalid-parameter"));
430 :
431 : // the valid parameter
432 3 : CATCH_REQUIRE(opt.is_defined("verbose"));
433 3 : CATCH_REQUIRE(opt.get_default("verbose").empty());
434 3 : CATCH_REQUIRE(opt.size("verbose") == 1);
435 :
436 : {
437 3 : auto const o(options.find("verbose"));
438 1 : CATCH_REQUIRE(o != options.end());
439 1 : CATCH_REQUIRE(o->second->get_short_name() == U'v');
440 1 : CATCH_REQUIRE(o->second->get_help() == "a verbose like option, select it or not.");
441 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_COMMAND_LINE));
442 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE));
443 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_CONFIGURATION_FILE));
444 : }
445 :
446 : // "--more"
447 3 : CATCH_REQUIRE(opt.is_defined("more"));
448 3 : CATCH_REQUIRE(opt.get_string("more") == "purple");
449 3 : CATCH_REQUIRE(opt.get_default("more") == "More Stuff");
450 3 : CATCH_REQUIRE(opt.size("more") == 1);
451 :
452 : {
453 3 : auto const o(options.find("more"));
454 1 : CATCH_REQUIRE(o != options.end());
455 1 : CATCH_REQUIRE(o->second->get_short_name() == U'm');
456 1 : CATCH_REQUIRE(o->second->get_help() == "Allow for more stuff to be added");
457 1 : CATCH_REQUIRE(o->second->has_default());
458 1 : CATCH_REQUIRE(o->second->get_default() == "More Stuff");
459 1 : CATCH_REQUIRE(o->second->get_validator()->name() == "regex");
460 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_REQUIRED));
461 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_SHOW_USAGE_ON_ERROR));
462 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_COMMAND_LINE));
463 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE));
464 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_CONFIGURATION_FILE));
465 : }
466 :
467 : // "--size <value>"
468 3 : CATCH_REQUIRE(opt.is_defined("size"));
469 3 : CATCH_REQUIRE(opt.get_string("size") == "519");
470 3 : CATCH_REQUIRE(opt.get_string("size", 0) == "519");
471 3 : CATCH_REQUIRE(opt.get_default("size") == "31");
472 3 : CATCH_REQUIRE(opt.size("size") == 1);
473 3 : CATCH_REQUIRE(opt.get_long("size") == 519);
474 :
475 : {
476 3 : auto const o(options.find("size"));
477 1 : CATCH_REQUIRE(o != options.end());
478 1 : CATCH_REQUIRE(o->second->get_short_name() == U's');
479 1 : CATCH_REQUIRE(o->second->get_help() == "Specify the size");
480 1 : CATCH_REQUIRE(o->second->has_default());
481 1 : CATCH_REQUIRE(o->second->get_default() == "31");
482 1 : CATCH_REQUIRE(o->second->get_validator()->name() == "regex");
483 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_REQUIRED));
484 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE));
485 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_CONFIGURATION_FILE));
486 : }
487 :
488 : // "--files"
489 3 : CATCH_REQUIRE(opt.is_defined("files"));
490 3 : CATCH_REQUIRE(opt.get_string("files") == "left.txt");
491 3 : CATCH_REQUIRE(opt.get_string("files", 0) == "left.txt");
492 3 : CATCH_REQUIRE(opt.get_string("files", 1) == "center.txt");
493 3 : CATCH_REQUIRE(opt.get_string("files", 2) == "right.txt");
494 3 : CATCH_REQUIRE(opt.get_default("files").empty());
495 3 : CATCH_REQUIRE(opt.size("files") == 3);
496 :
497 : {
498 3 : auto const o(options.find("files"));
499 1 : CATCH_REQUIRE(o != options.end());
500 1 : CATCH_REQUIRE(o->second->get_short_name() == U'f');
501 1 : CATCH_REQUIRE(o->second->get_help() == "List of file names");
502 1 : CATCH_REQUIRE_FALSE(o->second->has_default());
503 1 : CATCH_REQUIRE(o->second->get_validator()->name() == "regex");
504 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_COMMAND_LINE));
505 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE));
506 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_MULTIPLE));
507 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_REQUIRED));
508 : }
509 :
510 : // "--from"
511 3 : CATCH_REQUIRE(opt.is_defined("from"));
512 3 : CATCH_REQUIRE(opt.size("from") == 1);
513 3 : CATCH_REQUIRE(opt.get_string("from") == "");
514 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: invalid number () in parameter --from at offset 0.");
515 3 : CATCH_REQUIRE(opt.get_long("from") == -1);
516 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
517 3 : CATCH_REQUIRE(opt.get_default("from").empty());
518 :
519 : {
520 3 : auto const o(options.find("from"));
521 1 : CATCH_REQUIRE(o != options.end());
522 1 : CATCH_REQUIRE(o->second->get_short_name() == U'F');
523 1 : CATCH_REQUIRE(o->second->get_help() == "Request for the geographical location representing the origin of the files; optionally you can specify the format");
524 1 : CATCH_REQUIRE_FALSE(o->second->has_default());
525 1 : CATCH_REQUIRE(o->second->get_validator()->name() == "integer");
526 1 : CATCH_REQUIRE(o->second->get_environment_variable_name() == "FROM");
527 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_COMMAND_LINE));
528 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE));
529 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_CONFIGURATION_FILE));
530 : }
531 :
532 : // "--output"
533 3 : CATCH_REQUIRE(opt.is_defined("output"));
534 3 : CATCH_REQUIRE(opt.get_string("output") == "destination.txt"); // same as index = 0
535 3 : CATCH_REQUIRE(opt.get_string("output", 0) == "destination.txt");
536 3 : CATCH_REQUIRE(opt.get_default("output") == "a.out");
537 3 : CATCH_REQUIRE(opt.size("output") == 1);
538 :
539 : {
540 3 : auto const o(options.find("output"));
541 1 : CATCH_REQUIRE(o != options.end());
542 1 : CATCH_REQUIRE(o->second->get_short_name() == U'o');
543 1 : CATCH_REQUIRE(o->second->get_help() == "output file");
544 1 : CATCH_REQUIRE(o->second->has_default());
545 1 : CATCH_REQUIRE(o->second->get_default() == "a.out");
546 1 : CATCH_REQUIRE(o->second->get_validator() == nullptr);
547 1 : CATCH_REQUIRE(o->second->get_environment_variable_name() == "OUTPUT");
548 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_REQUIRED));
549 1 : CATCH_REQUIRE(o->second->has_flag(advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE));
550 : }
551 :
552 : // "--license" / "--licence"
553 3 : CATCH_REQUIRE(opt.is_defined("license"));
554 3 : CATCH_REQUIRE(opt.is_defined("licence"));
555 3 : CATCH_REQUIRE(opt.get_string("license") == "");
556 3 : CATCH_REQUIRE(opt.get_string("licence") == "");
557 3 : CATCH_REQUIRE(opt.get_default("license").empty());
558 3 : CATCH_REQUIRE(opt.get_default("licence").empty());
559 3 : CATCH_REQUIRE(opt.size("license") == 1);
560 3 : CATCH_REQUIRE(opt.size("licence") == 1);
561 :
562 : {
563 3 : auto const os(options.find("license"));
564 1 : CATCH_REQUIRE(os != options.end());
565 1 : CATCH_REQUIRE(os->second->get_short_name() == U'l');
566 1 : CATCH_REQUIRE(os->second->get_help() == "show this test license");
567 1 : CATCH_REQUIRE_FALSE(os->second->has_default());
568 1 : CATCH_REQUIRE(os->second->get_validator() == nullptr);
569 1 : CATCH_REQUIRE(os->second->has_flag(advgetopt::GETOPT_FLAG_FLAG));
570 1 : CATCH_REQUIRE(os->second->has_flag(advgetopt::GETOPT_FLAG_COMMAND_LINE));
571 :
572 3 : auto const oc(options.find("licence"));
573 1 : CATCH_REQUIRE(oc != options.end());
574 1 : CATCH_REQUIRE(oc->second->get_short_name() == U'\0');
575 1 : CATCH_REQUIRE(oc->second->get_help() == "license"); // this is the name of the alias option
576 1 : CATCH_REQUIRE(oc->second->get_alias_destination() == os->second);
577 1 : CATCH_REQUIRE_FALSE(oc->second->has_default());
578 1 : CATCH_REQUIRE(os->second->get_validator() == nullptr);
579 1 : CATCH_REQUIRE(oc->second->has_flag(advgetopt::GETOPT_FLAG_FLAG));
580 1 : CATCH_REQUIRE(oc->second->has_flag(advgetopt::GETOPT_FLAG_COMMAND_LINE));
581 : }
582 :
583 : // other parameters
584 1 : CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
585 1 : CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
586 :
587 1 : char const * sub_cargv2[] =
588 : {
589 : "this/is/ignored",
590 : "--from",
591 : "1001",
592 : nullptr
593 : };
594 1 : int const sub_argc2(sizeof(sub_cargv2) / sizeof(sub_cargv2[0]) - 1);
595 1 : char ** sub_argv2 = const_cast<char **>(sub_cargv2);
596 :
597 1 : opt.parse_arguments(sub_argc2, sub_argv2, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
598 :
599 : // "--from"
600 3 : CATCH_REQUIRE(opt.is_defined("from"));
601 3 : CATCH_REQUIRE(opt.size("from") == 1);
602 3 : CATCH_REQUIRE(opt.get_string("from") == "1001");
603 3 : CATCH_REQUIRE(opt.get_long("from") == 1001);
604 3 : CATCH_REQUIRE(opt.get_default("from").empty());
605 :
606 : // other parameters
607 1 : CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
608 1 : CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
609 :
610 : // keep the last value...
611 : //
612 1 : opt.parse_environment_variable();
613 :
614 : // "--from"
615 3 : CATCH_REQUIRE(opt.is_defined("from"));
616 3 : CATCH_REQUIRE(opt.size("from") == 1);
617 3 : CATCH_REQUIRE(opt.get_string("from") == "");
618 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: invalid number () in parameter --from at offset 0.");
619 3 : CATCH_REQUIRE(opt.get_long("from") == -1);
620 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
621 3 : CATCH_REQUIRE(opt.get_default("from").empty());
622 :
623 : // other parameters
624 1 : CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
625 1 : CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
626 :
627 : // a reset will restore the state
628 : //
629 1 : opt.reset();
630 :
631 : // the valid parameter
632 3 : CATCH_REQUIRE_FALSE(opt.is_defined("verbose"));
633 3 : CATCH_REQUIRE(opt.get_default("verbose").empty());
634 3 : CATCH_REQUIRE(opt.size("verbose") == 0);
635 :
636 : // "--from"
637 3 : CATCH_REQUIRE_FALSE(opt.is_defined("from"));
638 3 : CATCH_REQUIRE(opt.get_default("from").empty());
639 3 : CATCH_REQUIRE(opt.size("from") == 0);
640 :
641 1 : opt.parse_environment_variable();
642 1 : opt.parse_arguments(sub_argc2, sub_argv2, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
643 :
644 : // "--from"
645 3 : CATCH_REQUIRE(opt.is_defined("from"));
646 3 : CATCH_REQUIRE(opt.get_string("from") == "1001");
647 3 : CATCH_REQUIRE(opt.get_long("from") == 1001);
648 3 : CATCH_REQUIRE(opt.get_default("from").empty());
649 3 : CATCH_REQUIRE(opt.size("from") == 1);
650 :
651 : // other parameters
652 1 : CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
653 1 : CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
654 :
655 :
656 : // test that the validators do work here (i.e. generate errors as
657 : // expected when we use the wrong options.)
658 : //
659 : {
660 1 : snapdev::safe_setenv subenv("ADVGETOPT_TEST_OPTIONS"
661 : , "--verbose"
662 : " --size '1001 meters'"
663 : " -f valid.cpp"
664 : " --from auto-build"
665 5 : " --more black");
666 1 : opt.define_environment_variable_data();
667 :
668 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: input \"1001 meters\" given to parameter --size is not considered valid: did not match the regex.");
669 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: input \"valid.cpp\" given to parameter --files is not considered valid: did not match the regex.");
670 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: input \"auto-build\" given to parameter --from is not considered valid: not a valid number.");
671 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: input \"black\" given to parameter --more is not considered valid: did not match the regex.");
672 1 : opt.parse_environment_variable();
673 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
674 1 : }
675 1 : }
676 9 : CATCH_END_SECTION()
677 :
678 9 : CATCH_START_SECTION("valid_options_files: verify that options with 2 or more namespaces fail")
679 : {
680 1 : std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
681 1 : tmpdir += "/shared/advgetopt-double-namespace";
682 1 : std::stringstream ss;
683 1 : ss << "mkdir -p " << tmpdir;
684 1 : if(system(ss.str().c_str()) != 0)
685 : {
686 0 : std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
687 0 : exit(1);
688 : }
689 1 : std::string const options_filename(tmpdir + "/unittest.ini");
690 :
691 1 : advgetopt::option const valid_options_from_file_list[] =
692 : {
693 : advgetopt::define_option(
694 : advgetopt::Name("verbose")
695 : , advgetopt::ShortName('v')
696 : , advgetopt::Flags(advgetopt::standalone_all_flags<>())
697 : , advgetopt::Help("a verbose like option, select it or not.")
698 : ),
699 : advgetopt::end_options()
700 : };
701 :
702 1 : advgetopt::options_environment valid_options_from_file;
703 1 : valid_options_from_file.f_project_name = "unittest";
704 1 : valid_options_from_file.f_options = valid_options_from_file_list;
705 1 : valid_options_from_file.f_options_files_directory = tmpdir.c_str();
706 1 : valid_options_from_file.f_environment_variable_name = "ADVGETOPT_TEST_OPTIONS";
707 1 : valid_options_from_file.f_help_header = "Usage: test valid options from file";
708 :
709 1 : snapdev::safe_setenv env("ADVGETOPT_TEST_OPTIONS"
710 : , "--verbose"
711 : " --more purple"
712 : " -f left.txt center.txt right.txt"
713 : " --size 519"
714 : " --from"
715 5 : " --output destination.txt");
716 :
717 : {
718 1 : std::ofstream options_file;
719 1 : options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
720 1 : CATCH_REQUIRE(options_file.good());
721 : options_file <<
722 : "# Auto-generated\n"
723 : "\n"
724 : "[more]\n"
725 : "shortname=m\n"
726 : "default='More Stuff'\n"
727 : "help=Allow for more stuff to be added.\n"
728 : "validator=regex(\"purple|yellow|blue|red|green|orange|brown\")\n"
729 : "allowed=command-line,environment-variable,configuration-file\n"
730 : "show-usage-on-error\n"
731 : "required\n"
732 : "\n"
733 : "[size]\n"
734 : "shortname=s\n"
735 : "help=Specify the size.\n"
736 : "validator=/[0-9]+/\n"
737 : "allowed=environment-variable,configuration-file\n"
738 : "default::integer=31\n"
739 : "default::string=\"31\"\n"
740 : "required\n"
741 : "\n"
742 : "[files]\n"
743 : "shortname=f\n"
744 : "help=List of file names.\n"
745 : "validator=/.*\\.txt/i\n"
746 : "allowed=command-line,environment-variable\n"
747 : "multiple\n"
748 : "required\n"
749 : "\n"
750 : "[from]\n"
751 : "shortname=F\n"
752 : "help=Request for the geographical location representing the origin of the files; optionally you can specify the format.\n"
753 : "validator=integer\n"
754 : "environment_variable_name=FROM\n"
755 : "allowed=command-line,environment-variable,configuration-file\n"
756 : "\n"
757 : "[output]\n"
758 : "shortname=o\n"
759 : "default=a.out\n"
760 : "help=output file\n"
761 : "allowed=environment-variable\n"
762 : "environment_variable_name=OUTPUT\n"
763 : "required\n"
764 : "flag::multiple\n"
765 : "\n"
766 : "[license]\n"
767 : "shortname=l\n"
768 : "help=Show this test license.\n"
769 : "allowed=command-line\n"
770 : "no-arguments\n"
771 : "\n"
772 : "[licence]\n"
773 : "alias=license\n"
774 : "allowed=command-line\n"
775 : "no-arguments\n"
776 1 : "\n"
777 : ;
778 1 : }
779 :
780 1 : char const * sub_cargv[] =
781 : {
782 : "tests/unittests/valid_options_files",
783 : "--verbose",
784 : "--licence",
785 : nullptr
786 : };
787 1 : int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
788 1 : char ** sub_argv = const_cast<char **>(sub_cargv);
789 :
790 : // this is a good test already, but "unfortunately" the errors
791 : // happen in the wrong place because only .ini sections are
792 : // allowed; so instead we have a second part to the test attempting
793 : // to the load the data _manually_ to hit the errors of the load
794 : // function
795 : //
796 1 : std::string errmsg;
797 1 : std::string const realpath(snapdev::pathinfo::realpath(options_filename, errmsg));
798 2 : SNAP_CATCH2_NAMESPACE::push_expected_log(
799 : "error: section \"default::integer\" from parameter \"size::default::integer\" on line 17 in configuration file \""
800 2 : + realpath
801 4 : + "\" includes a character (\\072) not acceptable for a section or parameter name (controls, space, quotes, and \";#/=:?+\\\").");
802 2 : SNAP_CATCH2_NAMESPACE::push_expected_log(
803 : "error: section \"default::string\" from parameter \"size::default::string\" on line 18 in configuration file \""
804 2 : + realpath
805 4 : + "\" includes a character (\\072) not acceptable for a section or parameter name (controls, space, quotes, and \";#/=:?+\\\").");
806 2 : SNAP_CATCH2_NAMESPACE::push_expected_log(
807 : "error: section \"flag::multiple\" from parameter \"output::flag::multiple\" on line 43 in configuration file \""
808 2 : + realpath
809 4 : + "\" includes a character (\\072) not acceptable for a section or parameter name (controls, space, quotes, and \";#/=:?+\\\").");
810 4 : CATCH_REQUIRE_THROWS_MATCHES(
811 : advgetopt::getopt(valid_options_from_file, sub_argc, sub_argv)
812 : , advgetopt::getopt_exit
813 : , Catch::Matchers::ExceptionMessage(
814 : "getopt_exception: errors were found on your command line, environment variable, or configuration file."));
815 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
816 1 : }
817 9 : CATCH_END_SECTION()
818 :
819 9 : CATCH_START_SECTION("valid_options_files: verify parse_options_from_file overflow")
820 : {
821 1 : std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
822 1 : tmpdir += "/shared/advgetopt-namespace-overflow";
823 1 : std::stringstream ss;
824 1 : ss << "mkdir -p " << tmpdir;
825 1 : if(system(ss.str().c_str()) != 0)
826 : {
827 0 : std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
828 0 : exit(1);
829 : }
830 1 : std::string const options_filename(tmpdir + "/unittest.ini");
831 :
832 1 : advgetopt::options_environment valid_options_from_file;
833 1 : valid_options_from_file.f_project_name = "unittest";
834 1 : valid_options_from_file.f_help_header = "Usage: test valid fluid-settings options from file";
835 :
836 : {
837 1 : std::ofstream options_file;
838 1 : options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
839 1 : CATCH_REQUIRE(options_file.good());
840 : options_file <<
841 : "# Auto-generated\n"
842 : "\n"
843 : "[color::more]\n"
844 : "default='More Stuff'\n"
845 : "help=Allow for more stuff to be added.\n"
846 : "validator=regex(\"purple|yellow|blue|red|green|orange|brown\")\n"
847 : "allowed=command-line,environment-variable,configuration-file\n"
848 : "show-usage-on-error\n"
849 : "required\n"
850 : "\n"
851 : "[color::size]\n"
852 : "help=Specify the size.\n"
853 : "validator=/[0-9]+/\n"
854 : "allowed=environment-variable,configuration-file\n"
855 : "default=31\n"
856 : "required\n"
857 : "\n"
858 : "[color::files]\n"
859 : "help=List of file names.\n"
860 : "validator=/.*\\.txt/i\n"
861 : "allowed=command-line,environment-variable\n"
862 : "multiple\n"
863 : "required\n"
864 : "\n"
865 : "[dimensions::from]\n"
866 : "help=Request for the geographical location representing the origin of the files; optionally you can specify the format.\n"
867 : "validator=integer\n"
868 : "environment_variable_name=FROM\n"
869 : "allowed=command-line,environment-variable,configuration-file\n"
870 : "\n"
871 : "[dimensions::output]\n"
872 : "default=a.out\n"
873 : "help=output file\n"
874 : "allowed=environment-variable\n"
875 : "environment_variable_name=OUTPUT\n"
876 : "required\n"
877 : "multiple\n"
878 : "\n"
879 : "[us::legal::department::license]\n"
880 : "help=Show this test license.\n"
881 : "allowed=command-line\n"
882 : "no-arguments\n"
883 : "\n"
884 : "[us::legal::department::licence]\n"
885 : "alias=license\n"
886 : "allowed=command-line\n"
887 : "no-arguments\n"
888 1 : "\n"
889 : ;
890 1 : }
891 :
892 1 : advgetopt::getopt::pointer_t opts(std::make_shared<advgetopt::getopt>(valid_options_from_file));
893 :
894 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: the name of a settings definition must include between 2 and 3 namespaces; \"us::legal::department::licence\" is not considered valid.");
895 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: the name of a settings definition must include between 2 and 3 namespaces; \"us::legal::department::license\" is not considered valid.");
896 1 : opts->parse_options_from_file(
897 : options_filename
898 : , 2
899 : , 3);
900 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
901 :
902 1 : advgetopt::option_info::map_by_name_t const & options(opts->get_options());
903 1 : CATCH_REQUIRE(options.size() == 5);
904 :
905 : {
906 3 : auto const o(options.find("color::more"));
907 1 : CATCH_REQUIRE(o != options.end());
908 1 : CATCH_REQUIRE(o->second->get_help() == "Allow for more stuff to be added.");
909 : }
910 :
911 : {
912 3 : auto const o(options.find("color::size"));
913 1 : CATCH_REQUIRE(o != options.end());
914 1 : CATCH_REQUIRE(o->second->get_help() == "Specify the size.");
915 : }
916 :
917 : {
918 3 : auto const o(options.find("color::files"));
919 1 : CATCH_REQUIRE(o != options.end());
920 1 : CATCH_REQUIRE(o->second->get_help() == "List of file names.");
921 : }
922 :
923 : {
924 3 : auto const o(options.find("dimensions::from"));
925 1 : CATCH_REQUIRE(o != options.end());
926 1 : CATCH_REQUIRE(o->second->get_help() == "Request for the geographical location representing the origin of the files; optionally you can specify the format.");
927 : }
928 :
929 : {
930 3 : auto const o(options.find("dimensions::output"));
931 1 : CATCH_REQUIRE(o != options.end());
932 1 : CATCH_REQUIRE(o->second->get_help() == "output file");
933 : }
934 :
935 : {
936 3 : auto const o(options.find("us::legal::department::license"));
937 1 : CATCH_REQUIRE(o == options.end());
938 : }
939 :
940 : {
941 3 : auto const o(options.find("us::legal::department::licence"));
942 1 : CATCH_REQUIRE(o == options.end());
943 : }
944 1 : }
945 9 : CATCH_END_SECTION()
946 :
947 9 : CATCH_START_SECTION("valid_options_files: verify that the parse_options_from_file supports more than one section name (used by fluid-settings)")
948 : {
949 1 : std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
950 1 : tmpdir += "/shared/advgetopt-fluid-namespaces";
951 1 : std::stringstream ss;
952 1 : ss << "mkdir -p " << tmpdir;
953 1 : if(system(ss.str().c_str()) != 0)
954 : {
955 0 : std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
956 0 : exit(1);
957 : }
958 1 : std::string const options_filename(tmpdir + "/unittest.ini");
959 :
960 1 : advgetopt::options_environment valid_options_from_file;
961 1 : valid_options_from_file.f_project_name = "unittest";
962 1 : valid_options_from_file.f_help_header = "Usage: test valid fluid-settings options from file";
963 :
964 : {
965 1 : std::ofstream options_file;
966 1 : options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
967 1 : CATCH_REQUIRE(options_file.good());
968 : options_file <<
969 : "# Auto-generated\n"
970 : "\n"
971 : "[color::more]\n"
972 : "default='More Stuff'\n"
973 : "help=Allow for more stuff to be added.\n"
974 : "validator=regex(\"purple|yellow|blue|red|green|orange|brown\")\n"
975 : "allowed=command-line,environment-variable,configuration-file\n"
976 : "show-usage-on-error\n"
977 : "required\n"
978 : "\n"
979 : "[color::size]\n"
980 : "help=Specify the size.\n"
981 : "validator=/[0-9]+/\n"
982 : "allowed=environment-variable,configuration-file\n"
983 : "default=31\n"
984 : "required\n"
985 : "\n"
986 : "[color::files]\n"
987 : "help=List of file names.\n"
988 : "validator=/.*\\.txt/i\n"
989 : "allowed=command-line,environment-variable\n"
990 : "multiple\n"
991 : "required\n"
992 : "\n"
993 : "[dimensions::from]\n"
994 : "help=Request for the geographical location representing the origin of the files; optionally you can specify the format.\n"
995 : "validator=integer\n"
996 : "environment_variable_name=FROM\n"
997 : "allowed=command-line,environment-variable,configuration-file\n"
998 : "\n"
999 : "[dimensions::output]\n"
1000 : "default=a.out\n"
1001 : "help=output file\n"
1002 : "allowed=environment-variable\n"
1003 : "environment_variable_name=OUTPUT\n"
1004 : "required\n"
1005 : "multiple\n"
1006 : "\n"
1007 : "[legal::department::license]\n"
1008 : "help=Show this test license.\n"
1009 : "allowed=command-line\n"
1010 : "no-arguments\n"
1011 : "\n"
1012 : "[legal::department::licence]\n"
1013 : "alias=license\n"
1014 : "allowed=command-line\n"
1015 : "no-arguments\n"
1016 1 : "\n"
1017 : ;
1018 1 : }
1019 :
1020 1 : advgetopt::getopt::pointer_t opts(std::make_shared<advgetopt::getopt>(valid_options_from_file));
1021 1 : opts->parse_options_from_file(
1022 : options_filename
1023 : , 2
1024 : , std::numeric_limits<int>::max());
1025 :
1026 1 : advgetopt::option_info::map_by_name_t const & options(opts->get_options());
1027 1 : CATCH_REQUIRE(options.size() == 7);
1028 :
1029 : {
1030 3 : auto const o(options.find("color::more"));
1031 1 : CATCH_REQUIRE(o != options.end());
1032 1 : CATCH_REQUIRE(o->second->get_help() == "Allow for more stuff to be added.");
1033 : }
1034 :
1035 : {
1036 3 : auto const o(options.find("color::size"));
1037 1 : CATCH_REQUIRE(o != options.end());
1038 1 : CATCH_REQUIRE(o->second->get_help() == "Specify the size.");
1039 : }
1040 :
1041 : {
1042 3 : auto const o(options.find("color::files"));
1043 1 : CATCH_REQUIRE(o != options.end());
1044 1 : CATCH_REQUIRE(o->second->get_help() == "List of file names.");
1045 : }
1046 :
1047 : {
1048 3 : auto const o(options.find("dimensions::from"));
1049 1 : CATCH_REQUIRE(o != options.end());
1050 1 : CATCH_REQUIRE(o->second->get_help() == "Request for the geographical location representing the origin of the files; optionally you can specify the format.");
1051 : }
1052 :
1053 : {
1054 3 : auto const o(options.find("dimensions::output"));
1055 1 : CATCH_REQUIRE(o != options.end());
1056 1 : CATCH_REQUIRE(o->second->get_help() == "output file");
1057 : }
1058 :
1059 : {
1060 3 : auto const o(options.find("legal::department::license"));
1061 1 : CATCH_REQUIRE(o != options.end());
1062 1 : CATCH_REQUIRE(o->second->get_help() == "Show this test license.");
1063 : }
1064 :
1065 : {
1066 3 : auto const o(options.find("legal::department::licence"));
1067 1 : CATCH_REQUIRE(o != options.end());
1068 1 : CATCH_REQUIRE(o->second->get_help() == "license");
1069 : }
1070 1 : }
1071 9 : CATCH_END_SECTION()
1072 :
1073 9 : CATCH_START_SECTION("valid_options_files: check with validators in the definition")
1074 : {
1075 1 : std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
1076 1 : tmpdir += "/shared/advgetopt-validators-in-table";
1077 1 : std::stringstream ss;
1078 1 : ss << "mkdir -p " << tmpdir;
1079 1 : if(system(ss.str().c_str()) != 0)
1080 : {
1081 0 : std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
1082 0 : exit(1);
1083 : }
1084 1 : std::string const options_filename(tmpdir + "/unittest.ini");
1085 :
1086 1 : advgetopt::option const valid_options_from_file_list[] =
1087 : {
1088 : advgetopt::define_option(
1089 : advgetopt::Name("verbose")
1090 : , advgetopt::ShortName('v')
1091 : , advgetopt::Flags(advgetopt::standalone_all_flags<>())
1092 : , advgetopt::Help("a verbose like option, select it or not.")
1093 : ),
1094 : advgetopt::define_option(
1095 : advgetopt::Name("size")
1096 : , advgetopt::ShortName('s')
1097 : , advgetopt::Flags(advgetopt::all_flags<advgetopt::GETOPT_FLAG_REQUIRED>())
1098 : , advgetopt::Help("Specify the size.")
1099 : , advgetopt::Validator("integer(0...100)")
1100 : , advgetopt::DefaultValue("31")
1101 : ),
1102 : advgetopt::define_option(
1103 : advgetopt::Name("files")
1104 : , advgetopt::ShortName('f')
1105 : , advgetopt::Help("List of file names")
1106 : , advgetopt::Validator("/.*\\.txt/i")
1107 : , advgetopt::Flags(advgetopt::all_flags<advgetopt::GETOPT_FLAG_REQUIRED, advgetopt::GETOPT_FLAG_MULTIPLE>())
1108 : ),
1109 : advgetopt::define_option(
1110 : advgetopt::Name("from")
1111 : , advgetopt::ShortName('F')
1112 : , advgetopt::Help("Request for the geographical location representing the origin of the files; optionally you can specify the format")
1113 : , advgetopt::Validator("integer")
1114 : , advgetopt::Flags(advgetopt::all_flags<>())
1115 : ),
1116 : advgetopt::define_option(
1117 : advgetopt::Name("more")
1118 : , advgetopt::ShortName('m')
1119 : , advgetopt::Help("Allow for more stuff to be added")
1120 : , advgetopt::Validator("regex(\"purple|yellow|blue|red|green|orange|brown\")")
1121 : , advgetopt::Flags(advgetopt::all_flags<advgetopt::GETOPT_FLAG_REQUIRED, advgetopt::GETOPT_FLAG_SHOW_USAGE_ON_ERROR>())
1122 : , advgetopt::DefaultValue("More Stuff")
1123 : ),
1124 : advgetopt::end_options()
1125 : };
1126 :
1127 1 : advgetopt::options_environment valid_options_from_file;
1128 1 : valid_options_from_file.f_project_name = "unittest";
1129 1 : valid_options_from_file.f_options = valid_options_from_file_list;
1130 1 : valid_options_from_file.f_options_files_directory = tmpdir.c_str();
1131 1 : valid_options_from_file.f_environment_variable_name = "ADVGETOPT_TEST_OPTIONS";
1132 1 : valid_options_from_file.f_help_header = "Usage: test valid options from file";
1133 :
1134 1 : snapdev::safe_setenv env("ADVGETOPT_TEST_OPTIONS"
1135 : , "--verbose"
1136 : " --more purple"
1137 : " -f left.txt center.txt right.txt"
1138 : " --size 19"
1139 : " --from"
1140 5 : " --output destination.txt");
1141 :
1142 : {
1143 1 : std::ofstream options_file;
1144 1 : options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
1145 1 : CATCH_REQUIRE(options_file.good());
1146 : options_file <<
1147 : "# Auto-generated\n"
1148 :
1149 : "[output]\n"
1150 : "shortname=o\n"
1151 : "default=a.out\n"
1152 : "help=output file\n"
1153 : "allowed=environment-variable\n"
1154 : "required\n"
1155 :
1156 : "[license]\n"
1157 : "shortname=l\n"
1158 : "help=show this test license\n"
1159 : "allowed=command-line\n"
1160 : "no-arguments\n"
1161 :
1162 : "[licence]\n"
1163 : "alias=license\n"
1164 : "allowed=command-line\n"
1165 1 : "no-arguments\n"
1166 : ;
1167 1 : }
1168 :
1169 1 : char const * sub_cargv[] =
1170 : {
1171 : "tests/unittests/valid_options_files",
1172 : "--verbose",
1173 : "--licence",
1174 : nullptr
1175 : };
1176 1 : int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
1177 1 : char ** sub_argv = const_cast<char **>(sub_cargv);
1178 :
1179 1 : advgetopt::getopt opt(valid_options_from_file, sub_argc, sub_argv);
1180 :
1181 : // check that the result is valid
1182 :
1183 : // an invalid parameter, MUST NOT EXIST
1184 3 : CATCH_REQUIRE(opt.get_option("invalid-parameter") == nullptr);
1185 3 : CATCH_REQUIRE_FALSE(opt.is_defined("invalid-parameter"));
1186 :
1187 : // the valid parameter
1188 3 : CATCH_REQUIRE(opt.is_defined("verbose"));
1189 3 : CATCH_REQUIRE(opt.get_default("verbose").empty());
1190 3 : CATCH_REQUIRE(opt.size("verbose") == 1);
1191 :
1192 : // "--more"
1193 3 : CATCH_REQUIRE(opt.is_defined("more"));
1194 3 : CATCH_REQUIRE(opt.get_string("more") == "purple");
1195 3 : CATCH_REQUIRE(opt.get_default("more") == "More Stuff");
1196 3 : CATCH_REQUIRE(opt.size("more") == 1);
1197 :
1198 : // "--size <value>"
1199 3 : CATCH_REQUIRE(opt.is_defined("size"));
1200 3 : CATCH_REQUIRE(opt.get_string("size") == "19");
1201 3 : CATCH_REQUIRE(opt.get_string("size", 0) == "19");
1202 3 : CATCH_REQUIRE(opt.get_default("size") == "31");
1203 3 : CATCH_REQUIRE(opt.size("size") == 1);
1204 3 : CATCH_REQUIRE(opt.get_long("size") == 19);
1205 :
1206 : // "--files"
1207 3 : CATCH_REQUIRE(opt.is_defined("files"));
1208 3 : CATCH_REQUIRE(opt.get_string("files") == "left.txt");
1209 3 : CATCH_REQUIRE(opt.get_string("files", 0) == "left.txt");
1210 3 : CATCH_REQUIRE(opt.get_string("files", 1) == "center.txt");
1211 3 : CATCH_REQUIRE(opt.get_string("files", 2) == "right.txt");
1212 3 : CATCH_REQUIRE(opt.get_default("files").empty());
1213 3 : CATCH_REQUIRE(opt.size("files") == 3);
1214 :
1215 : // "--from"
1216 3 : CATCH_REQUIRE(opt.is_defined("from"));
1217 3 : CATCH_REQUIRE(opt.size("from") == 1);
1218 3 : CATCH_REQUIRE(opt.get_string("from") == "");
1219 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: invalid number () in parameter --from at offset 0.");
1220 3 : CATCH_REQUIRE(opt.get_long("from") == -1);
1221 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1222 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: invalid number () in parameter --from at offset 0.");
1223 3 : CATCH_REQUIRE(opt.get_long("from") == -1);
1224 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1225 3 : CATCH_REQUIRE(opt.get_default("from").empty());
1226 :
1227 : // "--output"
1228 3 : CATCH_REQUIRE(opt.is_defined("output"));
1229 3 : CATCH_REQUIRE(opt.get_string("output") == "destination.txt"); // same as index = 0
1230 3 : CATCH_REQUIRE(opt.get_string("output", 0) == "destination.txt");
1231 3 : CATCH_REQUIRE(opt.get_default("output") == "a.out");
1232 3 : CATCH_REQUIRE(opt.size("output") == 1);
1233 :
1234 : // "--from"
1235 3 : CATCH_REQUIRE(opt.is_defined("license"));
1236 3 : CATCH_REQUIRE(opt.get_string("license") == "");
1237 3 : CATCH_REQUIRE(opt.get_default("license").empty());
1238 3 : CATCH_REQUIRE(opt.size("license") == 1);
1239 :
1240 : // other parameters
1241 1 : CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
1242 1 : CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
1243 :
1244 1 : char const * sub_cargv2[] =
1245 : {
1246 : "this/is/ignored",
1247 : "--from",
1248 : "1001",
1249 : nullptr
1250 : };
1251 1 : int const sub_argc2(sizeof(sub_cargv2) / sizeof(sub_cargv2[0]) - 1);
1252 1 : char ** sub_argv2 = const_cast<char **>(sub_cargv2);
1253 :
1254 1 : opt.parse_arguments(sub_argc2, sub_argv2, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
1255 :
1256 : // "--from"
1257 3 : CATCH_REQUIRE(opt.is_defined("from"));
1258 3 : CATCH_REQUIRE(opt.size("from") == 1);
1259 3 : CATCH_REQUIRE(opt.get_string("from") == "1001");
1260 3 : CATCH_REQUIRE(opt.get_long("from") == 1001);
1261 3 : CATCH_REQUIRE(opt.get_default("from").empty());
1262 :
1263 : // other parameters
1264 1 : CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
1265 1 : CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
1266 :
1267 : // keep the last value...
1268 : //
1269 1 : opt.parse_environment_variable();
1270 :
1271 : // "--from"
1272 3 : CATCH_REQUIRE(opt.is_defined("from"));
1273 3 : CATCH_REQUIRE(opt.size("from") == 1);
1274 3 : CATCH_REQUIRE(opt.get_string("from") == "");
1275 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: invalid number () in parameter --from at offset 0.");
1276 3 : CATCH_REQUIRE(opt.get_long("from") == -1);
1277 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1278 3 : CATCH_REQUIRE(opt.get_default("from").empty());
1279 :
1280 : // other parameters
1281 1 : CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
1282 1 : CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
1283 :
1284 : // a reset will restore the state
1285 : //
1286 1 : opt.reset();
1287 :
1288 : // the valid parameter
1289 3 : CATCH_REQUIRE_FALSE(opt.is_defined("verbose"));
1290 3 : CATCH_REQUIRE(opt.get_default("verbose").empty());
1291 3 : CATCH_REQUIRE(opt.size("verbose") == 0);
1292 :
1293 : // "--from"
1294 3 : CATCH_REQUIRE_FALSE(opt.is_defined("from"));
1295 3 : CATCH_REQUIRE(opt.get_default("from").empty());
1296 3 : CATCH_REQUIRE(opt.size("from") == 0);
1297 :
1298 1 : opt.parse_environment_variable();
1299 1 : opt.parse_arguments(sub_argc2, sub_argv2, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
1300 :
1301 : // "--from"
1302 3 : CATCH_REQUIRE(opt.is_defined("from"));
1303 3 : CATCH_REQUIRE(opt.get_string("from") == "1001");
1304 3 : CATCH_REQUIRE(opt.get_long("from") == 1001);
1305 3 : CATCH_REQUIRE(opt.get_default("from").empty());
1306 3 : CATCH_REQUIRE(opt.size("from") == 1);
1307 :
1308 : // other parameters
1309 1 : CATCH_REQUIRE(opt.get_program_name() == "valid_options_files");
1310 1 : CATCH_REQUIRE(opt.get_program_fullname() == "tests/unittests/valid_options_files");
1311 :
1312 : // test that the validators do work here (i.e. generate errors as
1313 : // expected when we use the wrong options.)
1314 : //
1315 1 : char const * sub_cargv3[] =
1316 : {
1317 : "this/is/ignored",
1318 : "--size",
1319 : "1001",
1320 : "-f",
1321 : "valid.cpp",
1322 : "--from",
1323 : "51",
1324 : "--more",
1325 : "black",
1326 : nullptr
1327 : };
1328 1 : int const sub_argc3(sizeof(sub_cargv3) / sizeof(sub_cargv3[0]) - 1);
1329 1 : char ** sub_argv3 = const_cast<char **>(sub_cargv3);
1330 :
1331 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: input \"1001\" given to parameter --size is not considered valid: out of range.");
1332 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: input \"valid.cpp\" given to parameter --files is not considered valid: did not match the regex.");
1333 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: input \"black\" given to parameter --more is not considered valid: did not match the regex.");
1334 1 : opt.parse_arguments(sub_argc3, sub_argv3, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
1335 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1336 1 : }
1337 9 : CATCH_END_SECTION()
1338 9 : }
1339 :
1340 :
1341 7 : CATCH_TEST_CASE("invalid_options_files", "[options][invalid][files]")
1342 : {
1343 7 : CATCH_START_SECTION("invalid_options_files: 2+ section names")
1344 : {
1345 1 : std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
1346 1 : tmpdir += "/shared/advgetopt";
1347 1 : std::stringstream ss;
1348 1 : ss << "mkdir -p " << tmpdir;
1349 1 : if(system(ss.str().c_str()) != 0)
1350 : {
1351 0 : std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
1352 0 : exit(1);
1353 : }
1354 1 : std::string const options_filename(tmpdir + "/bad-section.ini");
1355 :
1356 1 : advgetopt::option const options[] =
1357 : {
1358 : advgetopt::define_option(
1359 : advgetopt::Name("verbose")
1360 : , advgetopt::ShortName('v')
1361 : , advgetopt::Flags(advgetopt::standalone_all_flags<>())
1362 : , advgetopt::Help("a verbose like option, select it or not.")
1363 : ),
1364 : advgetopt::end_options()
1365 : };
1366 :
1367 1 : advgetopt::options_environment options_environment;
1368 1 : options_environment.f_project_name = "bad-section";
1369 1 : options_environment.f_options = options;
1370 1 : options_environment.f_options_files_directory = tmpdir.c_str();
1371 1 : options_environment.f_environment_variable_name = nullptr;
1372 1 : options_environment.f_help_header = "Usage: test invalid section name";
1373 :
1374 : {
1375 1 : std::ofstream options_file;
1376 1 : options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
1377 1 : CATCH_REQUIRE(options_file.good());
1378 : options_file <<
1379 : "# Auto-generated\n"
1380 :
1381 : "[invalid::name]\n"
1382 : "shortname=m\n"
1383 : "default='Invalid Stuff'\n"
1384 : "help=Testing that a section name can't include \"::\"\n"
1385 1 : "allowed=command-line,environment-variable,configuration-file\n"
1386 : ;
1387 1 : }
1388 :
1389 1 : char const * sub_cargv[] =
1390 : {
1391 : "tests/unittests/invalid_name_in_options_ini",
1392 : "--verbose",
1393 : nullptr
1394 : };
1395 1 : int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
1396 1 : char ** sub_argv = const_cast<char **>(sub_cargv);
1397 :
1398 3 : SNAP_CATCH2_NAMESPACE::push_expected_log(
1399 : "error: option name \"shortname\" cannot be added to"
1400 : " section \"invalid::name\" because this"
1401 : " configuration only accepts one section level.");
1402 3 : SNAP_CATCH2_NAMESPACE::push_expected_log(
1403 : "error: option name \"default\" cannot be added to"
1404 : " section \"invalid::name\" because this"
1405 : " configuration only accepts one section level.");
1406 3 : SNAP_CATCH2_NAMESPACE::push_expected_log(
1407 : "error: option name \"help\" cannot be added to"
1408 : " section \"invalid::name\" because this"
1409 : " configuration only accepts one section level.");
1410 3 : SNAP_CATCH2_NAMESPACE::push_expected_log(
1411 : "error: option name \"allowed\" cannot be added to"
1412 : " section \"invalid::name\" because this"
1413 : " configuration only accepts one section level.");
1414 1 : advgetopt::getopt::pointer_t opt(std::make_shared<advgetopt::getopt>(options_environment));
1415 : try
1416 : {
1417 1 : opt->finish_parsing(sub_argc, sub_argv);
1418 0 : CATCH_REQUIRE(false); // the library is expected to throw here
1419 : }
1420 1 : catch(advgetopt::getopt_exit const & e)
1421 : {
1422 1 : CATCH_REQUIRE(e.code() == 1);
1423 3 : CATCH_REQUIRE(e.what() == std::string("getopt_exception: errors were found on your command line, environment variable, or configuration file."));
1424 1 : }
1425 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1426 :
1427 3 : CATCH_REQUIRE(opt->size("invalid::name::shortname") == 0);
1428 3 : CATCH_REQUIRE(opt->size("shortname") == 0);
1429 1 : }
1430 7 : CATCH_END_SECTION()
1431 :
1432 7 : CATCH_START_SECTION("invalid_options_files: short name too long")
1433 : {
1434 1 : std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
1435 1 : tmpdir += "/shared/advgetopt";
1436 1 : std::stringstream ss;
1437 1 : ss << "mkdir -p " << tmpdir;
1438 1 : if(system(ss.str().c_str()) != 0)
1439 : {
1440 0 : std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
1441 0 : exit(1);
1442 : }
1443 1 : std::string const options_filename(tmpdir + "/bad-shortname.ini");
1444 :
1445 1 : advgetopt::option const options[] =
1446 : {
1447 : advgetopt::define_option(
1448 : advgetopt::Name("verbose")
1449 : , advgetopt::ShortName('v')
1450 : , advgetopt::Flags(advgetopt::standalone_all_flags<>())
1451 : , advgetopt::Help("a verbose like option, select it or not.")
1452 : ),
1453 : advgetopt::end_options()
1454 : };
1455 :
1456 1 : advgetopt::options_environment options_environment;
1457 1 : options_environment.f_project_name = "bad-shortname";
1458 1 : options_environment.f_options = options;
1459 1 : options_environment.f_options_files_directory = tmpdir.c_str();
1460 1 : options_environment.f_environment_variable_name = nullptr;
1461 1 : options_environment.f_help_header = "Usage: test invalid shortname";
1462 :
1463 : {
1464 1 : std::ofstream options_file;
1465 1 : options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
1466 1 : CATCH_REQUIRE(options_file.good());
1467 : options_file <<
1468 : "# Auto-generated\n"
1469 :
1470 : "[badname]\n"
1471 : "shortname=to\n"
1472 : "default='Invalid Stuff'\n"
1473 : "help=Testing that a shotname can't be 2 characters or more\n"
1474 1 : "allowed=command-line,environment-variable,configuration-file\n"
1475 : ;
1476 1 : }
1477 :
1478 1 : char const * sub_cargv[] =
1479 : {
1480 : "tests/unittests/invalid_name_in_options_ini",
1481 : "--verbose",
1482 : nullptr
1483 : };
1484 1 : int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
1485 1 : char ** sub_argv = const_cast<char **>(sub_cargv);
1486 :
1487 2 : CATCH_REQUIRE_THROWS_MATCHES(
1488 : std::make_shared<advgetopt::getopt>(options_environment, sub_argc, sub_argv)
1489 : , advgetopt::getopt_logic_error
1490 : , Catch::Matchers::ExceptionMessage(
1491 : "getopt_logic_error: option \"badname\" has an invalid short name in \""
1492 : + options_filename
1493 : + "\", it can't be more than one character."));
1494 1 : }
1495 7 : CATCH_END_SECTION()
1496 :
1497 7 : CATCH_START_SECTION("invalid_options_files: missing ')' in validator specification")
1498 : {
1499 1 : std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
1500 1 : tmpdir += "/shared/advgetopt";
1501 1 : std::stringstream ss;
1502 1 : ss << "mkdir -p " << tmpdir;
1503 1 : if(system(ss.str().c_str()) != 0)
1504 : {
1505 0 : std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
1506 0 : exit(1);
1507 : }
1508 1 : std::string const options_filename(tmpdir + "/bad-validator-parenthesis.ini");
1509 :
1510 1 : advgetopt::option const options[] =
1511 : {
1512 : advgetopt::define_option(
1513 : advgetopt::Name("verbose")
1514 : , advgetopt::ShortName('v')
1515 : , advgetopt::Flags(advgetopt::standalone_all_flags<>())
1516 : , advgetopt::Help("a verbose like option, select it or not.")
1517 : ),
1518 : advgetopt::end_options()
1519 : };
1520 :
1521 1 : advgetopt::options_environment options_environment;
1522 1 : options_environment.f_project_name = "bad-validator-parenthesis";
1523 1 : options_environment.f_options = options;
1524 1 : options_environment.f_options_files_directory = tmpdir.c_str();
1525 1 : options_environment.f_environment_variable_name = nullptr;
1526 1 : options_environment.f_help_header = "Usage: test invalid validator specification";
1527 :
1528 : {
1529 1 : std::ofstream options_file;
1530 1 : options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
1531 1 : CATCH_REQUIRE(options_file.good());
1532 : options_file <<
1533 : "# Auto-generated\n"
1534 :
1535 : "[bad-validator]\n"
1536 : "shortname=b\n"
1537 : "default='Invalid Stuff'\n"
1538 : "help=Testing that a validator with parenthesis must have the ')'\n"
1539 : "validator=regex(\"missing ')'\"\n"
1540 1 : "allowed=command-line,environment-variable,configuration-file\n"
1541 : ;
1542 1 : }
1543 :
1544 1 : char const * sub_cargv[] =
1545 : {
1546 : "tests/unittests/invalid_validator_specification",
1547 : "--verbose",
1548 : nullptr
1549 : };
1550 1 : int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
1551 1 : char ** sub_argv = const_cast<char **>(sub_cargv);
1552 :
1553 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): parameter list must end with ')'. Remaining input: \"...EOS\"");
1554 : //CATCH_REQUIRE(std::make_shared<advgetopt::getopt>(options_environment, sub_argc, sub_argv) != nullptr);
1555 :
1556 4 : CATCH_REQUIRE_THROWS_MATCHES(
1557 : std::make_shared<advgetopt::getopt>(options_environment, sub_argc, sub_argv)
1558 : , advgetopt::getopt_exception
1559 : , Catch::Matchers::ExceptionMessage(
1560 : "getopt_exception: errors were found on your command line,"
1561 : " environment variable, or configuration file."));
1562 :
1563 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1564 1 : }
1565 7 : CATCH_END_SECTION()
1566 :
1567 7 : CATCH_START_SECTION("invalid_options_files: alias with help")
1568 : {
1569 1 : std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
1570 1 : tmpdir += "/shared/advgetopt";
1571 1 : std::stringstream ss;
1572 1 : ss << "mkdir -p " << tmpdir;
1573 1 : if(system(ss.str().c_str()) != 0)
1574 : {
1575 0 : std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
1576 0 : exit(1);
1577 : }
1578 1 : std::string const options_filename(tmpdir + "/alias-with-help.ini");
1579 :
1580 1 : advgetopt::option const options[] =
1581 : {
1582 : advgetopt::define_option(
1583 : advgetopt::Name("verbose")
1584 : , advgetopt::ShortName('v')
1585 : , advgetopt::Flags(advgetopt::standalone_all_flags<>())
1586 : , advgetopt::Help("a verbose like option, select it or not.")
1587 : ),
1588 : advgetopt::end_options()
1589 : };
1590 :
1591 1 : advgetopt::options_environment options_environment;
1592 1 : options_environment.f_project_name = "alias-with-help";
1593 1 : options_environment.f_options = options;
1594 1 : options_environment.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
1595 1 : options_environment.f_options_files_directory = tmpdir.c_str();
1596 1 : options_environment.f_environment_variable_name = nullptr;
1597 1 : options_environment.f_help_header = "Usage: test invalid validator specification";
1598 :
1599 : {
1600 1 : std::ofstream options_file;
1601 1 : options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
1602 1 : CATCH_REQUIRE(options_file.good());
1603 : options_file <<
1604 : "# Auto-generated\n"
1605 :
1606 : "[licence]\n"
1607 : "shortname=l\n"
1608 : "default='Invalid Stuff'\n"
1609 : "alias=license\n"
1610 : "help=Testing that an alias can't accept a help string\n"
1611 1 : "allowed=command-line,environment-variable,configuration-file\n"
1612 : ;
1613 1 : }
1614 :
1615 1 : char const * sub_cargv[] =
1616 : {
1617 : "tests/unittests/invalid_alias_specification",
1618 : "--verbose",
1619 : nullptr
1620 : };
1621 1 : int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
1622 1 : char ** sub_argv = const_cast<char **>(sub_cargv);
1623 :
1624 2 : CATCH_REQUIRE_THROWS_MATCHES(std::make_shared<advgetopt::getopt>(options_environment, sub_argc, sub_argv)
1625 : , advgetopt::getopt_logic_error
1626 : , Catch::Matchers::ExceptionMessage(
1627 : "getopt_logic_error: option \"licence\" is an alias and as such it can't include a help=... parameter in \""
1628 : + options_filename
1629 : + "\"."));
1630 1 : }
1631 7 : CATCH_END_SECTION()
1632 :
1633 7 : CATCH_START_SECTION("invalid_options_files: no-name alias")
1634 : {
1635 1 : std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
1636 1 : tmpdir += "/shared/advgetopt";
1637 1 : std::stringstream ss;
1638 1 : ss << "mkdir -p " << tmpdir;
1639 1 : if(system(ss.str().c_str()) != 0)
1640 : {
1641 0 : std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
1642 0 : exit(1);
1643 : }
1644 1 : std::string const options_filename(tmpdir + "/no-name-alias.ini");
1645 :
1646 1 : advgetopt::option const options[] =
1647 : {
1648 : advgetopt::define_option(
1649 : advgetopt::Name("verbose")
1650 : , advgetopt::ShortName('v')
1651 : , advgetopt::Flags(advgetopt::standalone_all_flags<>())
1652 : , advgetopt::Help("a verbose like option, select it or not.")
1653 : ),
1654 : advgetopt::end_options()
1655 : };
1656 :
1657 1 : advgetopt::options_environment options_environment;
1658 1 : options_environment.f_project_name = "no-name-alias";
1659 1 : options_environment.f_options = options;
1660 1 : options_environment.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
1661 1 : options_environment.f_options_files_directory = tmpdir.c_str();
1662 1 : options_environment.f_environment_variable_name = nullptr;
1663 1 : options_environment.f_help_header = "Usage: test alias with no name specified";
1664 :
1665 : {
1666 1 : std::ofstream options_file;
1667 1 : options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
1668 1 : CATCH_REQUIRE(options_file.good());
1669 : options_file <<
1670 : "# Auto-generated\n"
1671 :
1672 : "[foo]\n"
1673 : "shortname=f\n"
1674 : "default='Invalid Stuff'\n"
1675 : "alias=\n" // name missing (with an equal)
1676 1 : "allowed=command-line\n"
1677 : ;
1678 1 : }
1679 :
1680 1 : char const * sub_cargv[] =
1681 : {
1682 : "tests/unittests/non_existent_alias",
1683 : "--verbose",
1684 : nullptr
1685 : };
1686 1 : int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
1687 1 : char ** sub_argv = const_cast<char **>(sub_cargv);
1688 :
1689 4 : CATCH_REQUIRE_THROWS_MATCHES(std::make_shared<advgetopt::getopt>(options_environment, sub_argc, sub_argv)
1690 : , advgetopt::getopt_logic_error
1691 : , Catch::Matchers::ExceptionMessage("getopt_logic_error: the default value of your alias cannot be an empty string for \"foo\"."));
1692 1 : }
1693 7 : CATCH_END_SECTION()
1694 :
1695 7 : CATCH_START_SECTION("invalid_options_files: no-name alias v2")
1696 : {
1697 1 : std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
1698 1 : tmpdir += "/shared/advgetopt";
1699 1 : std::stringstream ss;
1700 1 : ss << "mkdir -p " << tmpdir;
1701 1 : if(system(ss.str().c_str()) != 0)
1702 : {
1703 0 : std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
1704 0 : exit(1);
1705 : }
1706 1 : std::string const options_filename(tmpdir + "/no-name-alias-v2.ini");
1707 :
1708 1 : advgetopt::option const options[] =
1709 : {
1710 : advgetopt::define_option(
1711 : advgetopt::Name("verbose")
1712 : , advgetopt::ShortName('v')
1713 : , advgetopt::Flags(advgetopt::standalone_all_flags<>())
1714 : , advgetopt::Help("a verbose like option, select it or not.")
1715 : ),
1716 : advgetopt::end_options()
1717 : };
1718 :
1719 1 : advgetopt::options_environment options_environment;
1720 1 : options_environment.f_project_name = "no-name-alias-v2";
1721 1 : options_environment.f_options = options;
1722 1 : options_environment.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
1723 1 : options_environment.f_options_files_directory = tmpdir.c_str();
1724 1 : options_environment.f_environment_variable_name = nullptr;
1725 1 : options_environment.f_help_header = "Usage: test alias with no name specified";
1726 :
1727 : {
1728 1 : std::ofstream options_file;
1729 1 : options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
1730 1 : CATCH_REQUIRE(options_file.good());
1731 : options_file <<
1732 : "# Auto-generated\n"
1733 :
1734 : "[foo]\n"
1735 : "shortname=f\n"
1736 : "default='Invalid Stuff'\n"
1737 : "alias\n" // name missing (no equal)
1738 1 : "allowed=command-line\n"
1739 : ;
1740 1 : }
1741 :
1742 1 : char const * sub_cargv[] =
1743 : {
1744 : "tests/unittests/non_existent_alias",
1745 : "--verbose",
1746 : nullptr
1747 : };
1748 1 : int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
1749 1 : char ** sub_argv = const_cast<char **>(sub_cargv);
1750 :
1751 4 : CATCH_REQUIRE_THROWS_MATCHES(std::make_shared<advgetopt::getopt>(options_environment, sub_argc, sub_argv)
1752 : , advgetopt::getopt_logic_error
1753 : , Catch::Matchers::ExceptionMessage("getopt_logic_error: the default value of your alias cannot be an empty string for \"foo\"."));
1754 1 : }
1755 7 : CATCH_END_SECTION()
1756 :
1757 7 : CATCH_START_SECTION("invalid_options_files: non-existent alias")
1758 : {
1759 1 : std::string tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
1760 1 : tmpdir += "/shared/advgetopt";
1761 1 : std::stringstream ss;
1762 1 : ss << "mkdir -p " << tmpdir;
1763 1 : if(system(ss.str().c_str()) != 0)
1764 : {
1765 0 : std::cerr << "fatal error: creating sub-temporary directory \"" << tmpdir << "\" failed.\n";
1766 0 : exit(1);
1767 : }
1768 1 : std::string const options_filename(tmpdir + "/non-existent-alias.ini");
1769 :
1770 1 : advgetopt::option const options[] =
1771 : {
1772 : advgetopt::define_option(
1773 : advgetopt::Name("verbose")
1774 : , advgetopt::ShortName('v')
1775 : , advgetopt::Flags(advgetopt::standalone_all_flags<>())
1776 : , advgetopt::Help("a verbose like option, select it or not.")
1777 : ),
1778 : advgetopt::end_options()
1779 : };
1780 :
1781 1 : advgetopt::options_environment options_environment;
1782 1 : options_environment.f_project_name = "non-existent-alias";
1783 1 : options_environment.f_options = options;
1784 1 : options_environment.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
1785 1 : options_environment.f_options_files_directory = tmpdir.c_str();
1786 1 : options_environment.f_environment_variable_name = nullptr;
1787 1 : options_environment.f_help_header = "Usage: test invalid validator specification";
1788 :
1789 : {
1790 1 : std::ofstream options_file;
1791 1 : options_file.open(options_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
1792 1 : CATCH_REQUIRE(options_file.good());
1793 : options_file <<
1794 : "# Auto-generated\n"
1795 :
1796 : "[foo]\n"
1797 : "shortname=f\n"
1798 : "default='Invalid Stuff'\n"
1799 : "alias=bar\n" // option "bar" missing
1800 1 : "allowed=command-line\n"
1801 : ;
1802 1 : }
1803 :
1804 1 : char const * sub_cargv[] =
1805 : {
1806 : "tests/unittests/non_existent_alias",
1807 : "--verbose",
1808 : nullptr
1809 : };
1810 1 : int const sub_argc(sizeof(sub_cargv) / sizeof(sub_cargv[0]) - 1);
1811 1 : char ** sub_argv = const_cast<char **>(sub_cargv);
1812 :
1813 4 : CATCH_REQUIRE_THROWS_MATCHES(std::make_shared<advgetopt::getopt>(options_environment, sub_argc, sub_argv)
1814 : , advgetopt::getopt_logic_error
1815 : , Catch::Matchers::ExceptionMessage("getopt_logic_error: no option named \"bar\" to satisfy the alias of \"foo\"."));
1816 1 : }
1817 7 : CATCH_END_SECTION()
1818 7 : }
1819 :
1820 :
1821 :
1822 : // vim: ts=4 sw=4 et
|