2 * Copyright (c) 2019 Philippe Proulx <pproulx@efficios.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; under version 2 of the License.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "common/assert.h"
25 #include "argpar/argpar.h"
28 * Tests that the command line `cmdline`, with non-quoted
29 * space-delimited arguments, once parsed given the option descriptors
30 * `descrs` and the option `fail_on_unknown_opt`, succeeds and gives the
31 * expected command line `expected_cmd_line` and number of ingested
32 * original arguments `expected_ingested_orig_args`.
34 * The resulting command-line is built from the resulting arguments,
35 * space-delimiting each argument, preferring the `--long-opt=arg` style
36 * over the `-s arg` style, and using the `arg<A,B>` form for non-option
37 * arguments where `A` is the original argument index and `B` is the
38 * non-option argument index.
41 void test_succeed(const char *cmdline
,
42 const char *expected_cmd_line
,
43 const struct bt_argpar_opt_descr
*descrs
,
44 unsigned int expected_ingested_orig_args
)
46 struct bt_argpar_parse_ret parse_ret
;
47 GString
*res_str
= g_string_new(NULL
);
48 gchar
**argv
= g_strsplit(cmdline
, " ", 0);
53 parse_ret
= bt_argpar_parse(g_strv_length(argv
),
54 (const char * const *) argv
, descrs
, false);
56 "bt_argpar_parse() succeeds for command line `%s`", cmdline
);
58 "bt_argpar_parse() does not write an error for command line `%s`", cmdline
);
59 ok(parse_ret
.ingested_orig_args
== expected_ingested_orig_args
,
60 "bt_argpar_parse() returns the correct number of ingested "
61 "original arguments for command line `%s`", cmdline
);
62 if (parse_ret
.ingested_orig_args
!= expected_ingested_orig_args
) {
63 diag("Expected: %u Got: %u", expected_ingested_orig_args
,
64 parse_ret
.ingested_orig_args
);
67 if (!parse_ret
.items
) {
68 fail("bt_argpar_parse() returns the expected parsed arguments "
69 "for command line `%s`", cmdline
);
73 for (i
= 0; i
< parse_ret
.items
->len
; i
++) {
74 const struct bt_argpar_item
*arg
= parse_ret
.items
->pdata
[i
];
77 case BT_ARGPAR_ITEM_TYPE_OPT
:
79 const struct bt_argpar_item_opt
*arg_opt
=
82 if (arg_opt
->descr
->long_name
) {
83 g_string_append_printf(res_str
, "--%s",
84 arg_opt
->descr
->long_name
);
87 g_string_append_printf(res_str
, "=%s",
91 g_string_append_c(res_str
, ' ');
92 } else if (arg_opt
->descr
->short_name
) {
93 g_string_append_printf(res_str
, "-%c",
94 arg_opt
->descr
->short_name
);
97 g_string_append_printf(res_str
, " %s",
101 g_string_append_c(res_str
, ' ');
106 case BT_ARGPAR_ITEM_TYPE_NON_OPT
:
108 const struct bt_argpar_item_non_opt
*arg_non_opt
=
111 g_string_append_printf(res_str
, "%s<%u,%u> ",
112 arg_non_opt
->arg
, arg_non_opt
->orig_index
,
113 arg_non_opt
->non_opt_index
);
121 if (res_str
->len
> 0) {
122 g_string_truncate(res_str
, res_str
->len
- 1);
125 ok(strcmp(expected_cmd_line
, res_str
->str
) == 0,
126 "bt_argpar_parse() returns the expected parsed arguments "
127 "for command line `%s`", cmdline
);
128 if (strcmp(expected_cmd_line
, res_str
->str
) != 0) {
129 diag("Expected: `%s`", expected_cmd_line
);
130 diag("Got: `%s`", res_str
->str
);
134 bt_argpar_parse_ret_fini(&parse_ret
);
135 g_string_free(res_str
, TRUE
);
140 void succeed_tests(void)
144 const struct bt_argpar_opt_descr descrs
[] = {
145 BT_ARGPAR_OPT_DESCR_SENTINEL
154 /* Single long option */
156 const struct bt_argpar_opt_descr descrs
[] = {
157 { 0, '\0', "salut", false },
158 BT_ARGPAR_OPT_DESCR_SENTINEL
167 /* Single short option */
169 const struct bt_argpar_opt_descr descrs
[] = {
170 { 0, 'f', NULL
, false },
171 BT_ARGPAR_OPT_DESCR_SENTINEL
180 /* Short and long option (aliases) */
182 const struct bt_argpar_opt_descr descrs
[] = {
183 { 0, 'f', "flaw", false },
184 BT_ARGPAR_OPT_DESCR_SENTINEL
193 /* Long option with argument (space form) */
195 const struct bt_argpar_opt_descr descrs
[] = {
196 { 0, '\0', "tooth", true },
197 BT_ARGPAR_OPT_DESCR_SENTINEL
206 /* Long option with argument (equal form) */
208 const struct bt_argpar_opt_descr descrs
[] = {
209 { 0, '\0', "polish", true },
210 BT_ARGPAR_OPT_DESCR_SENTINEL
219 /* Short option with argument (space form) */
221 const struct bt_argpar_opt_descr descrs
[] = {
222 { 0, 'c', NULL
, true },
223 BT_ARGPAR_OPT_DESCR_SENTINEL
232 /* Short option with argument (glued form) */
234 const struct bt_argpar_opt_descr descrs
[] = {
235 { 0, 'c', NULL
, true },
236 BT_ARGPAR_OPT_DESCR_SENTINEL
245 /* Short and long option (aliases) with argument (all forms) */
247 const struct bt_argpar_opt_descr descrs
[] = {
248 { 0, 'd', "dry", true },
249 BT_ARGPAR_OPT_DESCR_SENTINEL
253 "--dry=rate -dthing --dry street --dry=shape",
254 "--dry=rate --dry=thing --dry=street --dry=shape",
258 /* Many short options, last one with argument (glued form) */
260 const struct bt_argpar_opt_descr descrs
[] = {
261 { 0, 'd', NULL
, false },
262 { 0, 'e', NULL
, false },
263 { 0, 'f', NULL
, true },
264 BT_ARGPAR_OPT_DESCR_SENTINEL
275 const struct bt_argpar_opt_descr descrs
[] = {
276 { 0, 'd', NULL
, false },
277 { 0, 'e', "east", true },
278 { 0, '\0', "mind", false },
279 BT_ARGPAR_OPT_DESCR_SENTINEL
283 "-d --mind -destart --mind --east cough -d --east=itch",
284 "-d --mind -d --east=start --mind --east=cough -d --east=itch",
288 /* Single non-option argument */
290 const struct bt_argpar_opt_descr descrs
[] = {
291 BT_ARGPAR_OPT_DESCR_SENTINEL
300 /* Two non-option arguments */
302 const struct bt_argpar_opt_descr descrs
[] = {
303 BT_ARGPAR_OPT_DESCR_SENTINEL
308 "kilojoule<0,0> mitaine<1,1>",
312 /* Single non-option argument mixed with options */
314 const struct bt_argpar_opt_descr descrs
[] = {
315 { 0, 'd', NULL
, false },
316 { 0, '\0', "squeeze", true },
317 BT_ARGPAR_OPT_DESCR_SENTINEL
321 "-d sprout yes --squeeze little bag -d",
322 "-d sprout<1,0> yes<2,1> --squeeze=little bag<5,2> -d",
326 /* Unknown short option (space form) */
328 const struct bt_argpar_opt_descr descrs
[] = {
329 { 0, 'd', NULL
, true },
330 BT_ARGPAR_OPT_DESCR_SENTINEL
334 "-d salut -e -d meow",
339 /* Unknown short option (glued form) */
341 const struct bt_argpar_opt_descr descrs
[] = {
342 { 0, 'd', NULL
, true },
343 BT_ARGPAR_OPT_DESCR_SENTINEL
347 "-dsalut -e -d meow",
352 /* Unknown long option (space form) */
354 const struct bt_argpar_opt_descr descrs
[] = {
355 { 0, '\0', "sink", true },
356 BT_ARGPAR_OPT_DESCR_SENTINEL
360 "--sink party --food --sink impulse",
365 /* Unknown long option (equal form) */
367 const struct bt_argpar_opt_descr descrs
[] = {
368 { 0, '\0', "sink", true },
369 BT_ARGPAR_OPT_DESCR_SENTINEL
373 "--sink=party --food --sink=impulse",
378 /* Unknown option before non-option argument */
380 const struct bt_argpar_opt_descr descrs
[] = {
381 { 0, '\0', "thumb", true },
382 BT_ARGPAR_OPT_DESCR_SENTINEL
386 "--thumb=party --food bateau --thumb waves",
391 /* Unknown option after non-option argument */
393 const struct bt_argpar_opt_descr descrs
[] = {
394 { 0, '\0', "thumb", true },
395 BT_ARGPAR_OPT_DESCR_SENTINEL
399 "--thumb=party wound --food --thumb waves",
400 "--thumb=party wound<1,0>",
406 const struct bt_argpar_opt_descr descrs
[] = {
407 { 0, '\0', "-fuel", true },
408 BT_ARGPAR_OPT_DESCR_SENTINEL
417 /* Long option containing `=` in argument (equal form) */
419 const struct bt_argpar_opt_descr descrs
[] = {
420 { 0, '\0', "zebra", true },
421 BT_ARGPAR_OPT_DESCR_SENTINEL
430 /* Short option's argument starting with `-` (glued form) */
432 const struct bt_argpar_opt_descr descrs
[] = {
433 { 0, 'z', NULL
, true },
434 BT_ARGPAR_OPT_DESCR_SENTINEL
443 /* Short option's argument starting with `-` (space form) */
445 const struct bt_argpar_opt_descr descrs
[] = {
446 { 0, 'z', NULL
, true },
447 BT_ARGPAR_OPT_DESCR_SENTINEL
456 /* Long option's argument starting with `-` (space form) */
458 const struct bt_argpar_opt_descr descrs
[] = {
459 { 0, '\0', "janine", true },
460 BT_ARGPAR_OPT_DESCR_SENTINEL
469 /* Long option's argument starting with `-` (equal form) */
471 const struct bt_argpar_opt_descr descrs
[] = {
472 { 0, '\0', "janine", true },
473 BT_ARGPAR_OPT_DESCR_SENTINEL
482 /* Long option's empty argument (equal form) */
484 const struct bt_argpar_opt_descr descrs
[] = {
485 { 0, 'f', NULL
, false },
486 { 0, '\0', "yeah", true },
487 BT_ARGPAR_OPT_DESCR_SENTINEL
498 * Tests that the command line `cmdline`, with non-quoted
499 * space-delimited arguments, once parsed given the option descriptors
500 * `descrs`, fails and gives the expected error `expected_error`.
503 void test_fail(const char *cmdline
, const char *expected_error
,
504 const struct bt_argpar_opt_descr
*descrs
)
506 struct bt_argpar_parse_ret parse_ret
;
507 gchar
**argv
= g_strsplit(cmdline
, " ", 0);
509 parse_ret
= bt_argpar_parse(g_strv_length(argv
),
510 (const char * const *) argv
, descrs
, true);
512 "bt_argpar_parse() fails for command line `%s`", cmdline
);
514 "bt_argpar_parse() writes an error string for command line `%s`",
516 if (parse_ret
.items
) {
517 fail("bt_argpar_parse() writes the expected error string");
521 ok(strcmp(expected_error
, parse_ret
.error
->str
) == 0,
522 "bt_argpar_parse() writes the expected error string "
523 "for command line `%s`", cmdline
);
524 if (strcmp(expected_error
, parse_ret
.error
->str
) != 0) {
525 diag("Expected: `%s`", expected_error
);
526 diag("Got: `%s`", parse_ret
.error
->str
);
530 bt_argpar_parse_ret_fini(&parse_ret
);
535 void fail_tests(void)
537 /* Unknown long option */
539 const struct bt_argpar_opt_descr descrs
[] = {
540 { 0, '\0', "thumb", true },
541 BT_ARGPAR_OPT_DESCR_SENTINEL
545 "--thumb=party --meow",
546 "While parsing argument #2 (`--meow`): Unknown option `--meow`",
550 /* Unknown short option */
552 const struct bt_argpar_opt_descr descrs
[] = {
553 { 0, '\0', "thumb", true },
554 BT_ARGPAR_OPT_DESCR_SENTINEL
559 "While parsing argument #2 (`-x`): Unknown option `-x`",
563 /* Missing long option argument */
565 const struct bt_argpar_opt_descr descrs
[] = {
566 { 0, '\0', "thumb", true },
567 BT_ARGPAR_OPT_DESCR_SENTINEL
572 "While parsing argument #1 (`--thumb`): Missing required argument for option `--thumb`",
576 /* Missing short option argument */
578 const struct bt_argpar_opt_descr descrs
[] = {
579 { 0, 'k', NULL
, true },
580 BT_ARGPAR_OPT_DESCR_SENTINEL
585 "While parsing argument #1 (`-k`): Missing required argument for option `-k`",
589 /* Missing short option argument (multiple glued) */
591 const struct bt_argpar_opt_descr descrs
[] = {
592 { 0, 'a', NULL
, false },
593 { 0, 'b', NULL
, false },
594 { 0, 'c', NULL
, true },
595 BT_ARGPAR_OPT_DESCR_SENTINEL
600 "While parsing argument #1 (`-abc`): Missing required argument for option `-c`",
606 const struct bt_argpar_opt_descr descrs
[] = {
607 { 0, 'a', NULL
, false },
608 { 0, 'b', NULL
, false },
609 { 0, 'c', NULL
, true },
610 BT_ARGPAR_OPT_DESCR_SENTINEL
615 "While parsing argument #2 (`-`): Invalid argument",
621 const struct bt_argpar_opt_descr descrs
[] = {
622 { 0, 'a', NULL
, false },
623 { 0, 'b', NULL
, false },
624 { 0, 'c', NULL
, true },
625 BT_ARGPAR_OPT_DESCR_SENTINEL
630 "While parsing argument #2 (`--`): Invalid argument",
640 return exit_status();