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