Add error enumerators to `enum argpar_iter_parse_next_status`
[argpar.git] / tests / test_argpar.c
CommitLineData
903a5b8a 1/*
fc07e526
SM
2 * Copyright (c) 2019-2021 Philippe Proulx <pproulx@efficios.com>
3 * Copyright (c) 2020-2021 Simon Marchi <simon.marchi@efficios.com>
903a5b8a
SM
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
7ac57709 19#include <assert.h>
903a5b8a
SM
20#include <stdlib.h>
21#include <string.h>
11003cd5 22#include <stdbool.h>
903a5b8a
SM
23#include <glib.h>
24
25#include "tap/tap.h"
903a5b8a
SM
26#include "argpar/argpar.h"
27
28/*
11003cd5
PP
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.
903a5b8a
SM
38 */
39static
11003cd5
PP
40void append_to_res_str(GString * const res_str,
41 const struct argpar_item * const item)
fc07e526
SM
42{
43 if (res_str->len > 0) {
44 g_string_append_c(res_str, ' ');
45 }
46
d4539a90 47 switch (argpar_item_type(item)) {
fc07e526
SM
48 case ARGPAR_ITEM_TYPE_OPT:
49 {
d4539a90
PP
50 const struct argpar_opt_descr * const descr =
51 argpar_item_opt_descr(item);
52 const char * const arg = argpar_item_opt_arg(item);
fc07e526 53
d4539a90 54 if (descr->long_name) {
fc07e526 55 g_string_append_printf(res_str, "--%s",
d4539a90 56 descr->long_name);
fc07e526 57
d4539a90
PP
58 if (arg) {
59 g_string_append_printf(res_str, "=%s", arg);
fc07e526 60 }
d4539a90 61 } else if (descr->short_name) {
fc07e526 62 g_string_append_printf(res_str, "-%c",
d4539a90 63 descr->short_name);
fc07e526 64
d4539a90
PP
65 if (arg) {
66 g_string_append_printf(res_str, " %s", arg);
fc07e526
SM
67 }
68 }
69
70 break;
71 }
72 case ARGPAR_ITEM_TYPE_NON_OPT:
73 {
d4539a90
PP
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);
fc07e526 79
d4539a90
PP
80 g_string_append_printf(res_str, "%s<%u,%u>", arg, orig_index,
81 non_opt_index);
fc07e526
SM
82 break;
83 }
84 default:
85 abort();
86 }
87}
88
11003cd5
PP
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 */
fc07e526 101static
11003cd5
PP
102void 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)
903a5b8a 106{
1c9a6bde 107 struct argpar_parse_ret parse_ret;
11003cd5
PP
108 GString * const res_str = g_string_new(NULL);
109 gchar ** const argv = g_strsplit(cmdline, " ", 0);
903a5b8a
SM
110 unsigned int i;
111
7ac57709
SM
112 assert(argv);
113 assert(res_str);
1c9a6bde 114 parse_ret = argpar_parse(g_strv_length(argv),
903a5b8a
SM
115 (const char * const *) argv, descrs, false);
116 ok(parse_ret.items,
1c9a6bde 117 "argpar_parse() succeeds for command line `%s`", cmdline);
903a5b8a 118 ok(!parse_ret.error,
11003cd5
PP
119 "argpar_parse() doesn't set an error for command line `%s`",
120 cmdline);
903a5b8a 121 ok(parse_ret.ingested_orig_args == expected_ingested_orig_args,
1c9a6bde 122 "argpar_parse() returns the correct number of ingested "
903a5b8a 123 "original arguments for command line `%s`", cmdline);
11003cd5 124
903a5b8a
SM
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) {
11003cd5 131 fail("argpar_parse() returns the expected parsing items "
903a5b8a
SM
132 "for command line `%s`", cmdline);
133 goto end;
134 }
135
7ac57709 136 for (i = 0; i < parse_ret.items->n_items; i++) {
11003cd5 137 append_to_res_str(res_str, parse_ret.items->items[i]);
fc07e526
SM
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);
11003cd5 143
fc07e526
SM
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
149end:
150 argpar_parse_ret_fini(&parse_ret);
151 g_string_free(res_str, TRUE);
152 g_strfreev(argv);
153}
154
11003cd5
PP
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 */
fc07e526 167static
11003cd5
PP
168void 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)
fc07e526
SM
172{
173 struct argpar_iter *iter = NULL;
174 const struct argpar_item *item = NULL;
175 char *error = NULL;
11003cd5
PP
176 GString * const res_str = g_string_new(NULL);
177 gchar ** const argv = g_strsplit(cmdline, " ", 0);
fc07e526
SM
178 unsigned int i, actual_ingested_orig_args;
179
180 assert(argv);
181 assert(res_str);
fc07e526
SM
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_parse_next_status status;
188
189 ARGPAR_ITEM_DESTROY_AND_RESET(item);
190 status = argpar_iter_parse_next(iter, &item, &error);
191
192 ok(status == ARGPAR_ITER_PARSE_NEXT_STATUS_OK ||
193 status == ARGPAR_ITER_PARSE_NEXT_STATUS_END ||
194 status == ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT,
11003cd5
PP
195 "argpar_iter_parse_next() returns the expected status "
196 "(%d) for command line `%s` (call %u)",
197 status, cmdline, i + 1);
fc07e526
SM
198
199 if (status == ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
11003cd5
PP
200 ok(error,
201 "argpar_iter_parse_next() sets an error for "
202 "status `ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT` "
203 "and command line `%s` (call %u)",
204 cmdline, i + 1);
fc07e526 205 } else {
11003cd5
PP
206 ok(!error,
207 "argpar_iter_parse_next() doesn't set an error "
208 "for other status than "
209 "`ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT` "
210 "and command line `%s` (call %u)",
211 cmdline, i + 1);
903a5b8a 212 }
fc07e526
SM
213
214 if (status == ARGPAR_ITER_PARSE_NEXT_STATUS_END ||
215 status == ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
11003cd5
PP
216 ok(!item,
217 "argpar_iter_parse_next() doesn't set an item "
218 "for status `ARGPAR_ITER_PARSE_NEXT_STATUS_END` "
219 "or `ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT` "
220 "and command line `%s` (call %u)",
221 cmdline, i + 1);
903a5b8a
SM
222 break;
223 }
fc07e526
SM
224
225 append_to_res_str(res_str, item);
903a5b8a
SM
226 }
227
fc07e526
SM
228 actual_ingested_orig_args = argpar_iter_get_ingested_orig_args(iter);
229 ok(actual_ingested_orig_args == expected_ingested_orig_args,
11003cd5
PP
230 "argpar_iter_get_ingested_orig_args() returns the expected "
231 "number of ingested original arguments for command line `%s`",
232 cmdline);
233
fc07e526
SM
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);
903a5b8a
SM
237 }
238
239 ok(strcmp(expected_cmd_line, res_str->str) == 0,
11003cd5 240 "argpar_iter_parse_next() returns the expected parsing items "
903a5b8a 241 "for command line `%s`", cmdline);
11003cd5 242
903a5b8a
SM
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
fc07e526
SM
248 argpar_item_destroy(item);
249 argpar_iter_destroy(iter);
903a5b8a
SM
250 g_string_free(res_str, TRUE);
251 g_strfreev(argv);
fc07e526
SM
252 free(error);
253}
254
255/*
11003cd5
PP
256 * Calls test_succeed_argpar_parse() and test_succeed_argpar_iter()
257 * with the provided parameters.
fc07e526
SM
258 */
259static
11003cd5
PP
260void 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)
fc07e526
SM
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);
903a5b8a
SM
269}
270
271static
272void succeed_tests(void)
273{
274 /* No arguments */
275 {
1c9a6bde
SM
276 const struct argpar_opt_descr descrs[] = {
277 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
278 };
279
280 test_succeed(
281 "",
282 "",
283 descrs, 0);
284 }
285
286 /* Single long option */
287 {
1c9a6bde 288 const struct argpar_opt_descr descrs[] = {
903a5b8a 289 { 0, '\0', "salut", false },
1c9a6bde 290 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
291 };
292
293 test_succeed(
294 "--salut",
295 "--salut",
296 descrs, 1);
297 }
298
299 /* Single short option */
300 {
1c9a6bde 301 const struct argpar_opt_descr descrs[] = {
903a5b8a 302 { 0, 'f', NULL, false },
1c9a6bde 303 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
304 };
305
306 test_succeed(
307 "-f",
308 "-f",
309 descrs, 1);
310 }
311
312 /* Short and long option (aliases) */
313 {
1c9a6bde 314 const struct argpar_opt_descr descrs[] = {
903a5b8a 315 { 0, 'f', "flaw", false },
1c9a6bde 316 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
317 };
318
319 test_succeed(
320 "-f --flaw",
321 "--flaw --flaw",
322 descrs, 2);
323 }
324
325 /* Long option with argument (space form) */
326 {
1c9a6bde 327 const struct argpar_opt_descr descrs[] = {
903a5b8a 328 { 0, '\0', "tooth", true },
1c9a6bde 329 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
330 };
331
332 test_succeed(
333 "--tooth 67",
334 "--tooth=67",
335 descrs, 2);
336 }
337
338 /* Long option with argument (equal form) */
339 {
1c9a6bde 340 const struct argpar_opt_descr descrs[] = {
903a5b8a 341 { 0, '\0', "polish", true },
1c9a6bde 342 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
343 };
344
345 test_succeed(
346 "--polish=brick",
347 "--polish=brick",
348 descrs, 1);
349 }
350
351 /* Short option with argument (space form) */
352 {
1c9a6bde 353 const struct argpar_opt_descr descrs[] = {
903a5b8a 354 { 0, 'c', NULL, true },
1c9a6bde 355 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
356 };
357
358 test_succeed(
359 "-c chilly",
360 "-c chilly",
361 descrs, 2);
362 }
363
364 /* Short option with argument (glued form) */
365 {
1c9a6bde 366 const struct argpar_opt_descr descrs[] = {
903a5b8a 367 { 0, 'c', NULL, true },
1c9a6bde 368 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 379 const struct argpar_opt_descr descrs[] = {
903a5b8a 380 { 0, 'd', "dry", true },
1c9a6bde 381 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 392 const struct argpar_opt_descr descrs[] = {
903a5b8a
SM
393 { 0, 'd', NULL, false },
394 { 0, 'e', NULL, false },
395 { 0, 'f', NULL, true },
1c9a6bde 396 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
397 };
398
399 test_succeed(
400 "-defmeow",
401 "-d -e -f meow",
402 descrs, 1);
403 }
404
405 /* Many options */
406 {
1c9a6bde 407 const struct argpar_opt_descr descrs[] = {
903a5b8a
SM
408 { 0, 'd', NULL, false },
409 { 0, 'e', "east", true },
410 { 0, '\0', "mind", false },
1c9a6bde 411 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde
SM
422 const struct argpar_opt_descr descrs[] = {
423 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
424 };
425
426 test_succeed(
427 "kilojoule",
428 "kilojoule<0,0>",
429 descrs, 1);
430 }
431
432 /* Two non-option arguments */
433 {
1c9a6bde
SM
434 const struct argpar_opt_descr descrs[] = {
435 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 446 const struct argpar_opt_descr descrs[] = {
903a5b8a
SM
447 { 0, 'd', NULL, false },
448 { 0, '\0', "squeeze", true },
1c9a6bde 449 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 460 const struct argpar_opt_descr descrs[] = {
903a5b8a 461 { 0, 'd', NULL, true },
1c9a6bde 462 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 473 const struct argpar_opt_descr descrs[] = {
903a5b8a 474 { 0, 'd', NULL, true },
1c9a6bde 475 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 486 const struct argpar_opt_descr descrs[] = {
903a5b8a 487 { 0, '\0', "sink", true },
1c9a6bde 488 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 499 const struct argpar_opt_descr descrs[] = {
903a5b8a 500 { 0, '\0', "sink", true },
1c9a6bde 501 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 512 const struct argpar_opt_descr descrs[] = {
903a5b8a 513 { 0, '\0', "thumb", true },
1c9a6bde 514 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 525 const struct argpar_opt_descr descrs[] = {
903a5b8a 526 { 0, '\0', "thumb", true },
1c9a6bde 527 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 538 const struct argpar_opt_descr descrs[] = {
903a5b8a 539 { 0, '\0', "-fuel", true },
1c9a6bde 540 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 551 const struct argpar_opt_descr descrs[] = {
903a5b8a 552 { 0, '\0', "zebra", true },
1c9a6bde 553 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 564 const struct argpar_opt_descr descrs[] = {
903a5b8a 565 { 0, 'z', NULL, true },
1c9a6bde 566 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 577 const struct argpar_opt_descr descrs[] = {
903a5b8a 578 { 0, 'z', NULL, true },
1c9a6bde 579 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 590 const struct argpar_opt_descr descrs[] = {
903a5b8a 591 { 0, '\0', "janine", true },
1c9a6bde 592 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 603 const struct argpar_opt_descr descrs[] = {
903a5b8a 604 { 0, '\0', "janine", true },
1c9a6bde 605 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
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 {
1c9a6bde 616 const struct argpar_opt_descr descrs[] = {
903a5b8a
SM
617 { 0, 'f', NULL, false },
618 { 0, '\0', "yeah", true },
1c9a6bde 619 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
620 };
621
622 test_succeed(
623 "-f --yeah= -f",
624 "-f --yeah= -f",
625 descrs, 3);
626 }
627}
628
11003cd5
PP
629/*
630 * Parses `cmdline` with argpar_parse() using the option descriptors
631 * `descrs`, and ensures that the function fails and that it sets an
632 * error which is equal to `expected_error`.
633 *
634 * This function splits `cmdline` on spaces to create an original
635 * argument array.
636 */
903a5b8a 637static
11003cd5
PP
638void test_fail_argpar_parse(const char * const cmdline,
639 const char * const expected_error,
640 const struct argpar_opt_descr * const descrs)
903a5b8a 641{
1c9a6bde 642 struct argpar_parse_ret parse_ret;
11003cd5 643 gchar ** const argv = g_strsplit(cmdline, " ", 0);
903a5b8a 644
1c9a6bde 645 parse_ret = argpar_parse(g_strv_length(argv),
903a5b8a
SM
646 (const char * const *) argv, descrs, true);
647 ok(!parse_ret.items,
1c9a6bde 648 "argpar_parse() fails for command line `%s`", cmdline);
903a5b8a 649 ok(parse_ret.error,
11003cd5 650 "argpar_parse() sets an error string for command line `%s`",
903a5b8a 651 cmdline);
11003cd5 652
903a5b8a 653 if (parse_ret.items) {
11003cd5 654 fail("argpar_parse() sets the expected error string");
903a5b8a
SM
655 goto end;
656 }
657
7ac57709 658 ok(strcmp(expected_error, parse_ret.error) == 0,
11003cd5 659 "argpar_parse() sets the expected error string "
903a5b8a 660 "for command line `%s`", cmdline);
11003cd5 661
7ac57709 662 if (strcmp(expected_error, parse_ret.error) != 0) {
903a5b8a 663 diag("Expected: `%s`", expected_error);
7ac57709 664 diag("Got: `%s`", parse_ret.error);
903a5b8a
SM
665 }
666
667end:
1c9a6bde 668 argpar_parse_ret_fini(&parse_ret);
903a5b8a
SM
669 g_strfreev(argv);
670}
671
11003cd5
PP
672/*
673 * Parses `cmdline` with the iterator API using the option descriptors
d4d05805
PP
674 * `descrs`, and ensures that argpar_iter_parse_next() fails with status
675 * `expected_status` and that it sets an error which is equal to
676 * `expected_error`.
11003cd5
PP
677 *
678 * This function splits `cmdline` on spaces to create an original
679 * argument array.
680 */
fc07e526 681static
11003cd5
PP
682void test_fail_argpar_iter(const char * const cmdline,
683 const char * const expected_error,
d4d05805 684 const enum argpar_iter_parse_next_status expected_status,
11003cd5 685 const struct argpar_opt_descr * const descrs)
fc07e526
SM
686{
687 struct argpar_iter *iter = NULL;
688 const struct argpar_item *item = NULL;
11003cd5 689 gchar ** const argv = g_strsplit(cmdline, " ", 0);
fc07e526
SM
690 unsigned int i;
691 char *error = NULL;
692
693 iter = argpar_iter_create(g_strv_length(argv),
694 (const char * const *) argv, descrs);
695 assert(iter);
696
697 for (i = 0; ; i++) {
698 enum argpar_iter_parse_next_status status;
699
700 ARGPAR_ITEM_DESTROY_AND_RESET(item);
701 status = argpar_iter_parse_next(iter, &item, &error);
fc07e526 702 ok(status == ARGPAR_ITER_PARSE_NEXT_STATUS_OK ||
d4d05805 703 status == expected_status,
11003cd5
PP
704 "argpar_iter_parse_next() returns the expected status "
705 "(%d) for command line `%s` (call %u)",
706 status, cmdline, i + 1);
fc07e526
SM
707
708 if (status != ARGPAR_ITER_PARSE_NEXT_STATUS_OK) {
11003cd5
PP
709 ok(!item,
710 "argpar_iter_parse_next() doesn't set an item "
711 "for other status than "
712 "`ARGPAR_ITER_PARSE_NEXT_STATUS_OK` "
713 "and command line `%s` (call %u)",
714 cmdline, i + 1);
715 ok(error,
716 "argpar_iter_parse_next() sets an error for "
717 "other status than "
718 " `ARGPAR_ITER_PARSE_NEXT_STATUS_OK` "
719 "and command line `%s` (call %u)",
720 cmdline, i + 1);
fc07e526
SM
721 break;
722 }
723
11003cd5
PP
724 ok(item,
725 "argpar_iter_parse_next() sets an item for status "
726 "`ARGPAR_ITER_PARSE_NEXT_STATUS_OK` "
727 "and command line `%s` (call %u)",
728 cmdline, i + 1);
729 ok(!error,
730 "argpar_iter_parse_next() doesn't set an error for status "
731 "`ARGPAR_ITER_PARSE_NEXT_STATUS_OK` "
732 "and command line `%s` (call %u)",
733 cmdline, i + 1);
fc07e526
SM
734 }
735
736 ok(strcmp(expected_error, error) == 0,
11003cd5 737 "argpar_iter_parse_next() sets the expected error string "
fc07e526 738 "for command line `%s`", cmdline);
11003cd5 739
fc07e526
SM
740 if (strcmp(expected_error, error) != 0) {
741 diag("Expected: `%s`", expected_error);
742 diag("Got: `%s`", error);
743 }
744
745 argpar_item_destroy(item);
746 argpar_iter_destroy(iter);
747 free(error);
748 g_strfreev(argv);
749}
750
751/*
11003cd5
PP
752 * Calls test_fail_argpar_parse() and test_fail_argpar_iter() with the
753 * provided parameters.
fc07e526 754 */
fc07e526 755static
11003cd5 756void test_fail(const char * const cmdline, const char * const expected_error,
d4d05805 757 const enum argpar_iter_parse_next_status expected_iter_next_status,
11003cd5 758 const struct argpar_opt_descr * const descrs)
fc07e526
SM
759{
760 test_fail_argpar_parse(cmdline, expected_error, descrs);
d4d05805
PP
761 test_fail_argpar_iter(cmdline, expected_error,
762 expected_iter_next_status, descrs);
fc07e526
SM
763}
764
903a5b8a
SM
765static
766void fail_tests(void)
767{
768 /* Unknown long option */
769 {
1c9a6bde 770 const struct argpar_opt_descr descrs[] = {
903a5b8a 771 { 0, '\0', "thumb", true },
1c9a6bde 772 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
773 };
774
775 test_fail(
776 "--thumb=party --meow",
777 "While parsing argument #2 (`--meow`): Unknown option `--meow`",
d4d05805 778 ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT,
903a5b8a
SM
779 descrs);
780 }
781
782 /* Unknown short option */
783 {
1c9a6bde 784 const struct argpar_opt_descr descrs[] = {
903a5b8a 785 { 0, '\0', "thumb", true },
1c9a6bde 786 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
787 };
788
789 test_fail(
790 "--thumb=party -x",
791 "While parsing argument #2 (`-x`): Unknown option `-x`",
d4d05805 792 ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT,
903a5b8a
SM
793 descrs);
794 }
795
796 /* Missing long option argument */
797 {
1c9a6bde 798 const struct argpar_opt_descr descrs[] = {
903a5b8a 799 { 0, '\0', "thumb", true },
1c9a6bde 800 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
801 };
802
803 test_fail(
804 "--thumb",
805 "While parsing argument #1 (`--thumb`): Missing required argument for option `--thumb`",
d4d05805 806 ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MISSING_OPT_ARG,
903a5b8a
SM
807 descrs);
808 }
809
810 /* Missing short option argument */
811 {
1c9a6bde 812 const struct argpar_opt_descr descrs[] = {
903a5b8a 813 { 0, 'k', NULL, true },
1c9a6bde 814 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
815 };
816
817 test_fail(
818 "-k",
819 "While parsing argument #1 (`-k`): Missing required argument for option `-k`",
d4d05805 820 ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MISSING_OPT_ARG,
903a5b8a
SM
821 descrs);
822 }
823
824 /* Missing short option argument (multiple glued) */
825 {
1c9a6bde 826 const struct argpar_opt_descr descrs[] = {
903a5b8a
SM
827 { 0, 'a', NULL, false },
828 { 0, 'b', NULL, false },
829 { 0, 'c', NULL, true },
1c9a6bde 830 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
831 };
832
833 test_fail(
834 "-abc",
835 "While parsing argument #1 (`-abc`): Missing required argument for option `-c`",
d4d05805 836 ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MISSING_OPT_ARG,
903a5b8a
SM
837 descrs);
838 }
839
840 /* Invalid `-` */
841 {
1c9a6bde 842 const struct argpar_opt_descr descrs[] = {
903a5b8a
SM
843 { 0, 'a', NULL, false },
844 { 0, 'b', NULL, false },
845 { 0, 'c', NULL, true },
1c9a6bde 846 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
847 };
848
849 test_fail(
850 "-ab - -c",
851 "While parsing argument #2 (`-`): Invalid argument",
d4d05805 852 ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_INVALID_ARG,
903a5b8a
SM
853 descrs);
854 }
855
856 /* Invalid `--` */
857 {
1c9a6bde 858 const struct argpar_opt_descr descrs[] = {
903a5b8a
SM
859 { 0, 'a', NULL, false },
860 { 0, 'b', NULL, false },
861 { 0, 'c', NULL, true },
1c9a6bde 862 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
863 };
864
865 test_fail(
866 "-ab -- -c",
867 "While parsing argument #2 (`--`): Invalid argument",
d4d05805 868 ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_INVALID_ARG,
903a5b8a
SM
869 descrs);
870 }
430fe886
SM
871
872 {
873 const struct argpar_opt_descr descrs[] = {
874 { 0, 'c', "chevre", false },
875 ARGPAR_OPT_DESCR_SENTINEL
876 };
877
878 test_fail(
879 "--chevre=fromage",
880 "While parsing argument #1 (`--chevre=fromage`): Unexpected argument for option `--chevre`",
d4d05805 881 ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG,
430fe886
SM
882 descrs);
883 }
903a5b8a
SM
884}
885
886int main(void)
887{
fc07e526 888 plan_tests(419);
903a5b8a
SM
889 succeed_tests();
890 fail_tests();
891 return exit_status();
892}
This page took 0.102345 seconds and 4 git commands to generate.