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