c78b6e8a6babb71c7b362ba62eb45932e84644fb
[argpar.git] / tests / test_argpar.c
1 /*
2 * Copyright (c) 2019-2021 Philippe Proulx <pproulx@efficios.com>
3 * Copyright (c) 2020-2021 Simon Marchi <simon.marchi@efficios.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; under version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include <assert.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdbool.h>
23 #include <glib.h>
24
25 #include "tap/tap.h"
26 #include "argpar/argpar.h"
27
28 /*
29 * Formats `item` and appends the resulting string to `res_str` to
30 * incrementally build an expected command line string.
31 *
32 * This function:
33 *
34 * * Prefers the `--long-opt=arg` style over the `-s arg` style.
35 *
36 * * Uses the `arg<A,B>` form for non-option arguments, where `A` is the
37 * original argument index and `B` is the non-option argument index.
38 */
39 static
40 void append_to_res_str(GString * const res_str,
41 const struct argpar_item * const item)
42 {
43 if (res_str->len > 0) {
44 g_string_append_c(res_str, ' ');
45 }
46
47 switch (argpar_item_type(item)) {
48 case ARGPAR_ITEM_TYPE_OPT:
49 {
50 const struct argpar_opt_descr * const descr =
51 argpar_item_opt_descr(item);
52 const char * const arg = argpar_item_opt_arg(item);
53
54 if (descr->long_name) {
55 g_string_append_printf(res_str, "--%s",
56 descr->long_name);
57
58 if (arg) {
59 g_string_append_printf(res_str, "=%s", arg);
60 }
61 } else if (descr->short_name) {
62 g_string_append_printf(res_str, "-%c",
63 descr->short_name);
64
65 if (arg) {
66 g_string_append_printf(res_str, " %s", arg);
67 }
68 }
69
70 break;
71 }
72 case ARGPAR_ITEM_TYPE_NON_OPT:
73 {
74 const char * const arg = argpar_item_non_opt_arg(item);
75 const unsigned int orig_index =
76 argpar_item_non_opt_orig_index(item);
77 const unsigned int non_opt_index =
78 argpar_item_non_opt_non_opt_index(item);
79
80 g_string_append_printf(res_str, "%s<%u,%u>", arg, orig_index,
81 non_opt_index);
82 break;
83 }
84 default:
85 abort();
86 }
87 }
88
89 /*
90 * Parses `cmdline` with argpar_parse() using the option descriptors
91 * `descrs`, and ensures that the resulting effective command line is
92 * `expected_cmd_line` and that the number of ingested original
93 * arguments is `expected_ingested_orig_args`.
94 *
95 * This function splits `cmdline` on spaces to create an original
96 * argument array.
97 *
98 * This function builds the resulting command line from parsing items
99 * by space-separating each formatted item (see append_to_res_str()).
100 */
101 static
102 void test_succeed_argpar_parse(const char * const cmdline,
103 const char * const expected_cmd_line,
104 const struct argpar_opt_descr * const descrs,
105 const unsigned int expected_ingested_orig_args)
106 {
107 struct argpar_parse_ret parse_ret;
108 GString * const res_str = g_string_new(NULL);
109 gchar ** const argv = g_strsplit(cmdline, " ", 0);
110 unsigned int i;
111
112 assert(argv);
113 assert(res_str);
114 parse_ret = argpar_parse(g_strv_length(argv),
115 (const char * const *) argv, descrs, false);
116 ok(parse_ret.items,
117 "argpar_parse() succeeds for command line `%s`", cmdline);
118 ok(!parse_ret.error,
119 "argpar_parse() doesn't set an error for command line `%s`",
120 cmdline);
121 ok(parse_ret.ingested_orig_args == expected_ingested_orig_args,
122 "argpar_parse() returns the correct number of ingested "
123 "original arguments for command line `%s`", cmdline);
124
125 if (parse_ret.ingested_orig_args != expected_ingested_orig_args) {
126 diag("Expected: %u Got: %u", expected_ingested_orig_args,
127 parse_ret.ingested_orig_args);
128 }
129
130 if (!parse_ret.items) {
131 fail("argpar_parse() returns the expected parsing items "
132 "for command line `%s`", cmdline);
133 goto end;
134 }
135
136 for (i = 0; i < parse_ret.items->n_items; i++) {
137 append_to_res_str(res_str, parse_ret.items->items[i]);
138 }
139
140 ok(strcmp(expected_cmd_line, res_str->str) == 0,
141 "argpar_parse() returns the expected parsed arguments "
142 "for command line `%s`", cmdline);
143
144 if (strcmp(expected_cmd_line, res_str->str) != 0) {
145 diag("Expected: `%s`", expected_cmd_line);
146 diag("Got: `%s`", res_str->str);
147 }
148
149 end:
150 argpar_parse_ret_fini(&parse_ret);
151 g_string_free(res_str, TRUE);
152 g_strfreev(argv);
153 }
154
155 /*
156 * Parses `cmdline` with the iterator API using the option descriptors
157 * `descrs`, and ensures that the resulting effective command line is
158 * `expected_cmd_line` and that the number of ingested original
159 * arguments is `expected_ingested_orig_args`.
160 *
161 * This function splits `cmdline` on spaces to create an original
162 * argument array.
163 *
164 * This function builds the resulting command line from parsing items
165 * by space-separating each formatted item (see append_to_res_str()).
166 */
167 static
168 void test_succeed_argpar_iter(const char * const cmdline,
169 const char * const expected_cmd_line,
170 const struct argpar_opt_descr * const descrs,
171 const unsigned int expected_ingested_orig_args)
172 {
173 struct argpar_iter *iter = NULL;
174 const struct argpar_item *item = NULL;
175 char *error = NULL;
176 GString * const res_str = g_string_new(NULL);
177 gchar ** const argv = g_strsplit(cmdline, " ", 0);
178 unsigned int i, actual_ingested_orig_args;
179
180 assert(argv);
181 assert(res_str);
182 iter = argpar_iter_create(g_strv_length(argv),
183 (const char * const *) argv, descrs);
184 assert(iter);
185
186 for (i = 0; ; i++) {
187 enum argpar_iter_next_status status;
188
189 ARGPAR_ITEM_DESTROY_AND_RESET(item);
190 status = argpar_iter_next(iter, &item, &error);
191
192 ok(status == ARGPAR_ITER_NEXT_STATUS_OK ||
193 status == ARGPAR_ITER_NEXT_STATUS_END ||
194 status == ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT,
195 "argpar_iter_next() returns the expected status "
196 "(%d) for command line `%s` (call %u)",
197 status, cmdline, i + 1);
198
199 if (status == ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
200 ok(error,
201 "argpar_iter_next() sets an error for "
202 "status `ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT` "
203 "and command line `%s` (call %u)",
204 cmdline, i + 1);
205 } else {
206 ok(!error,
207 "argpar_iter_next() doesn't set an error "
208 "for other status than "
209 "`ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT` "
210 "and command line `%s` (call %u)",
211 cmdline, i + 1);
212 }
213
214 if (status == ARGPAR_ITER_NEXT_STATUS_END ||
215 status == ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
216 ok(!item,
217 "argpar_iter_next() doesn't set an item "
218 "for status `ARGPAR_ITER_NEXT_STATUS_END` "
219 "or `ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT` "
220 "and command line `%s` (call %u)",
221 cmdline, i + 1);
222 break;
223 }
224
225 append_to_res_str(res_str, item);
226 }
227
228 actual_ingested_orig_args = argpar_iter_ingested_orig_args(iter);
229 ok(actual_ingested_orig_args == expected_ingested_orig_args,
230 "argpar_iter_ingested_orig_args() returns the expected "
231 "number of ingested original arguments for command line `%s`",
232 cmdline);
233
234 if (actual_ingested_orig_args != expected_ingested_orig_args) {
235 diag("Expected: %u Got: %u", expected_ingested_orig_args,
236 actual_ingested_orig_args);
237 }
238
239 ok(strcmp(expected_cmd_line, res_str->str) == 0,
240 "argpar_iter_next() returns the expected parsing items "
241 "for command line `%s`", cmdline);
242
243 if (strcmp(expected_cmd_line, res_str->str) != 0) {
244 diag("Expected: `%s`", expected_cmd_line);
245 diag("Got: `%s`", res_str->str);
246 }
247
248 argpar_item_destroy(item);
249 argpar_iter_destroy(iter);
250 g_string_free(res_str, TRUE);
251 g_strfreev(argv);
252 free(error);
253 }
254
255 /*
256 * Calls test_succeed_argpar_parse() and test_succeed_argpar_iter()
257 * with the provided parameters.
258 */
259 static
260 void test_succeed(const char * const cmdline,
261 const char * const expected_cmd_line,
262 const struct argpar_opt_descr * const descrs,
263 const unsigned int expected_ingested_orig_args)
264 {
265 test_succeed_argpar_parse(cmdline, expected_cmd_line, descrs,
266 expected_ingested_orig_args);
267 test_succeed_argpar_iter(cmdline, expected_cmd_line, descrs,
268 expected_ingested_orig_args);
269 }
270
271 static
272 void succeed_tests(void)
273 {
274 /* No arguments */
275 {
276 const struct argpar_opt_descr descrs[] = {
277 ARGPAR_OPT_DESCR_SENTINEL
278 };
279
280 test_succeed(
281 "",
282 "",
283 descrs, 0);
284 }
285
286 /* Single long option */
287 {
288 const struct argpar_opt_descr descrs[] = {
289 { 0, '\0', "salut", false },
290 ARGPAR_OPT_DESCR_SENTINEL
291 };
292
293 test_succeed(
294 "--salut",
295 "--salut",
296 descrs, 1);
297 }
298
299 /* Single short option */
300 {
301 const struct argpar_opt_descr descrs[] = {
302 { 0, 'f', NULL, false },
303 ARGPAR_OPT_DESCR_SENTINEL
304 };
305
306 test_succeed(
307 "-f",
308 "-f",
309 descrs, 1);
310 }
311
312 /* Short and long option (aliases) */
313 {
314 const struct argpar_opt_descr descrs[] = {
315 { 0, 'f', "flaw", false },
316 ARGPAR_OPT_DESCR_SENTINEL
317 };
318
319 test_succeed(
320 "-f --flaw",
321 "--flaw --flaw",
322 descrs, 2);
323 }
324
325 /* Long option with argument (space form) */
326 {
327 const struct argpar_opt_descr descrs[] = {
328 { 0, '\0', "tooth", true },
329 ARGPAR_OPT_DESCR_SENTINEL
330 };
331
332 test_succeed(
333 "--tooth 67",
334 "--tooth=67",
335 descrs, 2);
336 }
337
338 /* Long option with argument (equal form) */
339 {
340 const struct argpar_opt_descr descrs[] = {
341 { 0, '\0', "polish", true },
342 ARGPAR_OPT_DESCR_SENTINEL
343 };
344
345 test_succeed(
346 "--polish=brick",
347 "--polish=brick",
348 descrs, 1);
349 }
350
351 /* Short option with argument (space form) */
352 {
353 const struct argpar_opt_descr descrs[] = {
354 { 0, 'c', NULL, true },
355 ARGPAR_OPT_DESCR_SENTINEL
356 };
357
358 test_succeed(
359 "-c chilly",
360 "-c chilly",
361 descrs, 2);
362 }
363
364 /* Short option with argument (glued form) */
365 {
366 const struct argpar_opt_descr descrs[] = {
367 { 0, 'c', NULL, true },
368 ARGPAR_OPT_DESCR_SENTINEL
369 };
370
371 test_succeed(
372 "-cchilly",
373 "-c chilly",
374 descrs, 1);
375 }
376
377 /* Short and long option (aliases) with argument (all forms) */
378 {
379 const struct argpar_opt_descr descrs[] = {
380 { 0, 'd', "dry", true },
381 ARGPAR_OPT_DESCR_SENTINEL
382 };
383
384 test_succeed(
385 "--dry=rate -dthing --dry street --dry=shape",
386 "--dry=rate --dry=thing --dry=street --dry=shape",
387 descrs, 5);
388 }
389
390 /* Many short options, last one with argument (glued form) */
391 {
392 const struct argpar_opt_descr descrs[] = {
393 { 0, 'd', NULL, false },
394 { 0, 'e', NULL, false },
395 { 0, 'f', NULL, true },
396 ARGPAR_OPT_DESCR_SENTINEL
397 };
398
399 test_succeed(
400 "-defmeow",
401 "-d -e -f meow",
402 descrs, 1);
403 }
404
405 /* Many options */
406 {
407 const struct argpar_opt_descr descrs[] = {
408 { 0, 'd', NULL, false },
409 { 0, 'e', "east", true },
410 { 0, '\0', "mind", false },
411 ARGPAR_OPT_DESCR_SENTINEL
412 };
413
414 test_succeed(
415 "-d --mind -destart --mind --east cough -d --east=itch",
416 "-d --mind -d --east=start --mind --east=cough -d --east=itch",
417 descrs, 8);
418 }
419
420 /* Single non-option argument */
421 {
422 const struct argpar_opt_descr descrs[] = {
423 ARGPAR_OPT_DESCR_SENTINEL
424 };
425
426 test_succeed(
427 "kilojoule",
428 "kilojoule<0,0>",
429 descrs, 1);
430 }
431
432 /* Two non-option arguments */
433 {
434 const struct argpar_opt_descr descrs[] = {
435 ARGPAR_OPT_DESCR_SENTINEL
436 };
437
438 test_succeed(
439 "kilojoule mitaine",
440 "kilojoule<0,0> mitaine<1,1>",
441 descrs, 2);
442 }
443
444 /* Single non-option argument mixed with options */
445 {
446 const struct argpar_opt_descr descrs[] = {
447 { 0, 'd', NULL, false },
448 { 0, '\0', "squeeze", true },
449 ARGPAR_OPT_DESCR_SENTINEL
450 };
451
452 test_succeed(
453 "-d sprout yes --squeeze little bag -d",
454 "-d sprout<1,0> yes<2,1> --squeeze=little bag<5,2> -d",
455 descrs, 7);
456 }
457
458 /* Unknown short option (space form) */
459 {
460 const struct argpar_opt_descr descrs[] = {
461 { 0, 'd', NULL, true },
462 ARGPAR_OPT_DESCR_SENTINEL
463 };
464
465 test_succeed(
466 "-d salut -e -d meow",
467 "-d salut",
468 descrs, 2);
469 }
470
471 /* Unknown short option (glued form) */
472 {
473 const struct argpar_opt_descr descrs[] = {
474 { 0, 'd', NULL, true },
475 ARGPAR_OPT_DESCR_SENTINEL
476 };
477
478 test_succeed(
479 "-dsalut -e -d meow",
480 "-d salut",
481 descrs, 1);
482 }
483
484 /* Unknown long option (space form) */
485 {
486 const struct argpar_opt_descr descrs[] = {
487 { 0, '\0', "sink", true },
488 ARGPAR_OPT_DESCR_SENTINEL
489 };
490
491 test_succeed(
492 "--sink party --food --sink impulse",
493 "--sink=party",
494 descrs, 2);
495 }
496
497 /* Unknown long option (equal form) */
498 {
499 const struct argpar_opt_descr descrs[] = {
500 { 0, '\0', "sink", true },
501 ARGPAR_OPT_DESCR_SENTINEL
502 };
503
504 test_succeed(
505 "--sink=party --food --sink=impulse",
506 "--sink=party",
507 descrs, 1);
508 }
509
510 /* Unknown option before non-option argument */
511 {
512 const struct argpar_opt_descr descrs[] = {
513 { 0, '\0', "thumb", true },
514 ARGPAR_OPT_DESCR_SENTINEL
515 };
516
517 test_succeed(
518 "--thumb=party --food bateau --thumb waves",
519 "--thumb=party",
520 descrs, 1);
521 }
522
523 /* Unknown option after non-option argument */
524 {
525 const struct argpar_opt_descr descrs[] = {
526 { 0, '\0', "thumb", true },
527 ARGPAR_OPT_DESCR_SENTINEL
528 };
529
530 test_succeed(
531 "--thumb=party wound --food --thumb waves",
532 "--thumb=party wound<1,0>",
533 descrs, 2);
534 }
535
536 /* Valid `---opt` */
537 {
538 const struct argpar_opt_descr descrs[] = {
539 { 0, '\0', "-fuel", true },
540 ARGPAR_OPT_DESCR_SENTINEL
541 };
542
543 test_succeed(
544 "---fuel=three",
545 "---fuel=three",
546 descrs, 1);
547 }
548
549 /* Long option containing `=` in argument (equal form) */
550 {
551 const struct argpar_opt_descr descrs[] = {
552 { 0, '\0', "zebra", true },
553 ARGPAR_OPT_DESCR_SENTINEL
554 };
555
556 test_succeed(
557 "--zebra=three=yes",
558 "--zebra=three=yes",
559 descrs, 1);
560 }
561
562 /* Short option's argument starting with `-` (glued form) */
563 {
564 const struct argpar_opt_descr descrs[] = {
565 { 0, 'z', NULL, true },
566 ARGPAR_OPT_DESCR_SENTINEL
567 };
568
569 test_succeed(
570 "-z-will",
571 "-z -will",
572 descrs, 1);
573 }
574
575 /* Short option's argument starting with `-` (space form) */
576 {
577 const struct argpar_opt_descr descrs[] = {
578 { 0, 'z', NULL, true },
579 ARGPAR_OPT_DESCR_SENTINEL
580 };
581
582 test_succeed(
583 "-z -will",
584 "-z -will",
585 descrs, 2);
586 }
587
588 /* Long option's argument starting with `-` (space form) */
589 {
590 const struct argpar_opt_descr descrs[] = {
591 { 0, '\0', "janine", true },
592 ARGPAR_OPT_DESCR_SENTINEL
593 };
594
595 test_succeed(
596 "--janine -sutto",
597 "--janine=-sutto",
598 descrs, 2);
599 }
600
601 /* Long option's argument starting with `-` (equal form) */
602 {
603 const struct argpar_opt_descr descrs[] = {
604 { 0, '\0', "janine", true },
605 ARGPAR_OPT_DESCR_SENTINEL
606 };
607
608 test_succeed(
609 "--janine=-sutto",
610 "--janine=-sutto",
611 descrs, 1);
612 }
613
614 /* Long option's empty argument (equal form) */
615 {
616 const struct argpar_opt_descr descrs[] = {
617 { 0, 'f', NULL, false },
618 { 0, '\0', "yeah", true },
619 ARGPAR_OPT_DESCR_SENTINEL
620 };
621
622 test_succeed(
623 "-f --yeah= -f",
624 "-f --yeah= -f",
625 descrs, 3);
626 }
627
628 /* `-` non-option argument */
629 {
630 const struct argpar_opt_descr descrs[] = {
631 { 0, 'f', NULL, false },
632 ARGPAR_OPT_DESCR_SENTINEL
633 };
634
635 test_succeed(
636 "-f - -f",
637 "-f -<1,0> -f",
638 descrs, 3);
639 }
640
641 /* `--` non-option argument */
642 {
643 const struct argpar_opt_descr descrs[] = {
644 { 0, 'f', NULL, false },
645 ARGPAR_OPT_DESCR_SENTINEL
646 };
647
648 test_succeed(
649 "-f -- -f",
650 "-f --<1,0> -f",
651 descrs, 3);
652 }
653 }
654
655 /*
656 * Parses `cmdline` with argpar_parse() using the option descriptors
657 * `descrs`, and ensures that the function fails and that it sets an
658 * error which is equal to `expected_error`.
659 *
660 * This function splits `cmdline` on spaces to create an original
661 * argument array.
662 */
663 static
664 void test_fail_argpar_parse(const char * const cmdline,
665 const char * const expected_error,
666 const struct argpar_opt_descr * const descrs)
667 {
668 struct argpar_parse_ret parse_ret;
669 gchar ** const argv = g_strsplit(cmdline, " ", 0);
670
671 parse_ret = argpar_parse(g_strv_length(argv),
672 (const char * const *) argv, descrs, true);
673 ok(!parse_ret.items,
674 "argpar_parse() fails for command line `%s`", cmdline);
675 ok(parse_ret.error,
676 "argpar_parse() sets an error string for command line `%s`",
677 cmdline);
678
679 if (parse_ret.items) {
680 fail("argpar_parse() sets the expected error string");
681 goto end;
682 }
683
684 ok(strcmp(expected_error, parse_ret.error) == 0,
685 "argpar_parse() sets the expected error string "
686 "for command line `%s`", cmdline);
687
688 if (strcmp(expected_error, parse_ret.error) != 0) {
689 diag("Expected: `%s`", expected_error);
690 diag("Got: `%s`", parse_ret.error);
691 }
692
693 end:
694 argpar_parse_ret_fini(&parse_ret);
695 g_strfreev(argv);
696 }
697
698 /*
699 * Parses `cmdline` with the iterator API using the option descriptors
700 * `descrs`, and ensures that argpar_iter_next() fails with status
701 * `expected_status` and that it sets an error which is equal to
702 * `expected_error`.
703 *
704 * This function splits `cmdline` on spaces to create an original
705 * argument array.
706 */
707 static
708 void test_fail_argpar_iter(const char * const cmdline,
709 const char * const expected_error,
710 const enum argpar_iter_next_status expected_status,
711 const struct argpar_opt_descr * const descrs)
712 {
713 struct argpar_iter *iter = NULL;
714 const struct argpar_item *item = NULL;
715 gchar ** const argv = g_strsplit(cmdline, " ", 0);
716 unsigned int i;
717 char *error = NULL;
718
719 iter = argpar_iter_create(g_strv_length(argv),
720 (const char * const *) argv, descrs);
721 assert(iter);
722
723 for (i = 0; ; i++) {
724 enum argpar_iter_next_status status;
725
726 ARGPAR_ITEM_DESTROY_AND_RESET(item);
727 status = argpar_iter_next(iter, &item, &error);
728 ok(status == ARGPAR_ITER_NEXT_STATUS_OK ||
729 status == expected_status,
730 "argpar_iter_next() returns the expected status "
731 "(%d) for command line `%s` (call %u)",
732 status, cmdline, i + 1);
733
734 if (status != ARGPAR_ITER_NEXT_STATUS_OK) {
735 ok(!item,
736 "argpar_iter_next() doesn't set an item "
737 "for other status than "
738 "`ARGPAR_ITER_NEXT_STATUS_OK` "
739 "and command line `%s` (call %u)",
740 cmdline, i + 1);
741 ok(error,
742 "argpar_iter_next() sets an error for "
743 "other status than "
744 " `ARGPAR_ITER_NEXT_STATUS_OK` "
745 "and command line `%s` (call %u)",
746 cmdline, i + 1);
747 break;
748 }
749
750 ok(item,
751 "argpar_iter_next() sets an item for status "
752 "`ARGPAR_ITER_NEXT_STATUS_OK` "
753 "and command line `%s` (call %u)",
754 cmdline, i + 1);
755 ok(!error,
756 "argpar_iter_next() doesn't set an error for status "
757 "`ARGPAR_ITER_NEXT_STATUS_OK` "
758 "and command line `%s` (call %u)",
759 cmdline, i + 1);
760 }
761
762 ok(strcmp(expected_error, error) == 0,
763 "argpar_iter_next() sets the expected error string "
764 "for command line `%s`", cmdline);
765
766 if (strcmp(expected_error, error) != 0) {
767 diag("Expected: `%s`", expected_error);
768 diag("Got: `%s`", error);
769 }
770
771 argpar_item_destroy(item);
772 argpar_iter_destroy(iter);
773 free(error);
774 g_strfreev(argv);
775 }
776
777 /*
778 * Calls test_fail_argpar_parse() and test_fail_argpar_iter() with the
779 * provided parameters.
780 */
781 static
782 void test_fail(const char * const cmdline, const char * const expected_error,
783 const enum argpar_iter_next_status expected_iter_next_status,
784 const struct argpar_opt_descr * const descrs)
785 {
786 test_fail_argpar_parse(cmdline, expected_error, descrs);
787 test_fail_argpar_iter(cmdline, expected_error,
788 expected_iter_next_status, descrs);
789 }
790
791 static
792 void fail_tests(void)
793 {
794 /* Unknown long option */
795 {
796 const struct argpar_opt_descr descrs[] = {
797 { 0, '\0', "thumb", true },
798 ARGPAR_OPT_DESCR_SENTINEL
799 };
800
801 test_fail(
802 "--thumb=party --meow",
803 "While parsing argument #2 (`--meow`): Unknown option `--meow`",
804 ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT,
805 descrs);
806 }
807
808 /* Unknown short option */
809 {
810 const struct argpar_opt_descr descrs[] = {
811 { 0, '\0', "thumb", true },
812 ARGPAR_OPT_DESCR_SENTINEL
813 };
814
815 test_fail(
816 "--thumb=party -x",
817 "While parsing argument #2 (`-x`): Unknown option `-x`",
818 ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT,
819 descrs);
820 }
821
822 /* Missing long option argument */
823 {
824 const struct argpar_opt_descr descrs[] = {
825 { 0, '\0', "thumb", true },
826 ARGPAR_OPT_DESCR_SENTINEL
827 };
828
829 test_fail(
830 "--thumb",
831 "While parsing argument #1 (`--thumb`): Missing required argument for option `--thumb`",
832 ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG,
833 descrs);
834 }
835
836 /* Missing short option argument */
837 {
838 const struct argpar_opt_descr descrs[] = {
839 { 0, 'k', NULL, true },
840 ARGPAR_OPT_DESCR_SENTINEL
841 };
842
843 test_fail(
844 "-k",
845 "While parsing argument #1 (`-k`): Missing required argument for option `-k`",
846 ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG,
847 descrs);
848 }
849
850 /* Missing short option argument (multiple glued) */
851 {
852 const struct argpar_opt_descr descrs[] = {
853 { 0, 'a', NULL, false },
854 { 0, 'b', NULL, false },
855 { 0, 'c', NULL, true },
856 ARGPAR_OPT_DESCR_SENTINEL
857 };
858
859 test_fail(
860 "-abc",
861 "While parsing argument #1 (`-abc`): Missing required argument for option `-c`",
862 ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG,
863 descrs);
864 }
865
866 /* Unexpected long option argument */
867 {
868 const struct argpar_opt_descr descrs[] = {
869 { 0, 'c', "chevre", false },
870 ARGPAR_OPT_DESCR_SENTINEL
871 };
872
873 test_fail(
874 "--chevre=fromage",
875 "While parsing argument #1 (`--chevre=fromage`): Unexpected argument for option `--chevre`",
876 ARGPAR_ITER_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG,
877 descrs);
878 }
879 }
880
881 int main(void)
882 {
883 plan_tests(423);
884 succeed_tests();
885 fail_tests();
886 return exit_status();
887 }
This page took 0.046164 seconds and 4 git commands to generate.