Parse `-` and `--` as non-option arguments
[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++) {
2af370d0 187 enum argpar_iter_next_status status;
fc07e526
SM
188
189 ARGPAR_ITEM_DESTROY_AND_RESET(item);
2af370d0 190 status = argpar_iter_next(iter, &item, &error);
fc07e526 191
2af370d0
PP
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 "
11003cd5
PP
196 "(%d) for command line `%s` (call %u)",
197 status, cmdline, i + 1);
fc07e526 198
2af370d0 199 if (status == ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
11003cd5 200 ok(error,
2af370d0
PP
201 "argpar_iter_next() sets an error for "
202 "status `ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT` "
11003cd5
PP
203 "and command line `%s` (call %u)",
204 cmdline, i + 1);
fc07e526 205 } else {
11003cd5 206 ok(!error,
2af370d0 207 "argpar_iter_next() doesn't set an error "
11003cd5 208 "for other status than "
2af370d0 209 "`ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT` "
11003cd5
PP
210 "and command line `%s` (call %u)",
211 cmdline, i + 1);
903a5b8a 212 }
fc07e526 213
2af370d0
PP
214 if (status == ARGPAR_ITER_NEXT_STATUS_END ||
215 status == ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
11003cd5 216 ok(!item,
2af370d0
PP
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` "
11003cd5
PP
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
f3ab5ca1 228 actual_ingested_orig_args = argpar_iter_ingested_orig_args(iter);
fc07e526 229 ok(actual_ingested_orig_args == expected_ingested_orig_args,
f3ab5ca1 230 "argpar_iter_ingested_orig_args() returns the expected "
11003cd5
PP
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,
2af370d0 240 "argpar_iter_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 }
dd757a65
PP
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 }
903a5b8a
SM
653}
654
11003cd5
PP
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 */
903a5b8a 663static
11003cd5
PP
664void test_fail_argpar_parse(const char * const cmdline,
665 const char * const expected_error,
666 const struct argpar_opt_descr * const descrs)
903a5b8a 667{
1c9a6bde 668 struct argpar_parse_ret parse_ret;
11003cd5 669 gchar ** const argv = g_strsplit(cmdline, " ", 0);
903a5b8a 670
1c9a6bde 671 parse_ret = argpar_parse(g_strv_length(argv),
903a5b8a
SM
672 (const char * const *) argv, descrs, true);
673 ok(!parse_ret.items,
1c9a6bde 674 "argpar_parse() fails for command line `%s`", cmdline);
903a5b8a 675 ok(parse_ret.error,
11003cd5 676 "argpar_parse() sets an error string for command line `%s`",
903a5b8a 677 cmdline);
11003cd5 678
903a5b8a 679 if (parse_ret.items) {
11003cd5 680 fail("argpar_parse() sets the expected error string");
903a5b8a
SM
681 goto end;
682 }
683
7ac57709 684 ok(strcmp(expected_error, parse_ret.error) == 0,
11003cd5 685 "argpar_parse() sets the expected error string "
903a5b8a 686 "for command line `%s`", cmdline);
11003cd5 687
7ac57709 688 if (strcmp(expected_error, parse_ret.error) != 0) {
903a5b8a 689 diag("Expected: `%s`", expected_error);
7ac57709 690 diag("Got: `%s`", parse_ret.error);
903a5b8a
SM
691 }
692
693end:
1c9a6bde 694 argpar_parse_ret_fini(&parse_ret);
903a5b8a
SM
695 g_strfreev(argv);
696}
697
11003cd5
PP
698/*
699 * Parses `cmdline` with the iterator API using the option descriptors
2af370d0 700 * `descrs`, and ensures that argpar_iter_next() fails with status
d4d05805
PP
701 * `expected_status` and that it sets an error which is equal to
702 * `expected_error`.
11003cd5
PP
703 *
704 * This function splits `cmdline` on spaces to create an original
705 * argument array.
706 */
fc07e526 707static
11003cd5
PP
708void test_fail_argpar_iter(const char * const cmdline,
709 const char * const expected_error,
2af370d0 710 const enum argpar_iter_next_status expected_status,
11003cd5 711 const struct argpar_opt_descr * const descrs)
fc07e526
SM
712{
713 struct argpar_iter *iter = NULL;
714 const struct argpar_item *item = NULL;
11003cd5 715 gchar ** const argv = g_strsplit(cmdline, " ", 0);
fc07e526
SM
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++) {
2af370d0 724 enum argpar_iter_next_status status;
fc07e526
SM
725
726 ARGPAR_ITEM_DESTROY_AND_RESET(item);
2af370d0
PP
727 status = argpar_iter_next(iter, &item, &error);
728 ok(status == ARGPAR_ITER_NEXT_STATUS_OK ||
d4d05805 729 status == expected_status,
2af370d0 730 "argpar_iter_next() returns the expected status "
11003cd5
PP
731 "(%d) for command line `%s` (call %u)",
732 status, cmdline, i + 1);
fc07e526 733
2af370d0 734 if (status != ARGPAR_ITER_NEXT_STATUS_OK) {
11003cd5 735 ok(!item,
2af370d0 736 "argpar_iter_next() doesn't set an item "
11003cd5 737 "for other status than "
2af370d0 738 "`ARGPAR_ITER_NEXT_STATUS_OK` "
11003cd5
PP
739 "and command line `%s` (call %u)",
740 cmdline, i + 1);
741 ok(error,
2af370d0 742 "argpar_iter_next() sets an error for "
11003cd5 743 "other status than "
2af370d0 744 " `ARGPAR_ITER_NEXT_STATUS_OK` "
11003cd5
PP
745 "and command line `%s` (call %u)",
746 cmdline, i + 1);
fc07e526
SM
747 break;
748 }
749
11003cd5 750 ok(item,
2af370d0
PP
751 "argpar_iter_next() sets an item for status "
752 "`ARGPAR_ITER_NEXT_STATUS_OK` "
11003cd5
PP
753 "and command line `%s` (call %u)",
754 cmdline, i + 1);
755 ok(!error,
2af370d0
PP
756 "argpar_iter_next() doesn't set an error for status "
757 "`ARGPAR_ITER_NEXT_STATUS_OK` "
11003cd5
PP
758 "and command line `%s` (call %u)",
759 cmdline, i + 1);
fc07e526
SM
760 }
761
762 ok(strcmp(expected_error, error) == 0,
2af370d0 763 "argpar_iter_next() sets the expected error string "
fc07e526 764 "for command line `%s`", cmdline);
11003cd5 765
fc07e526
SM
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/*
11003cd5
PP
778 * Calls test_fail_argpar_parse() and test_fail_argpar_iter() with the
779 * provided parameters.
fc07e526 780 */
fc07e526 781static
11003cd5 782void test_fail(const char * const cmdline, const char * const expected_error,
2af370d0 783 const enum argpar_iter_next_status expected_iter_next_status,
11003cd5 784 const struct argpar_opt_descr * const descrs)
fc07e526
SM
785{
786 test_fail_argpar_parse(cmdline, expected_error, descrs);
d4d05805
PP
787 test_fail_argpar_iter(cmdline, expected_error,
788 expected_iter_next_status, descrs);
fc07e526
SM
789}
790
903a5b8a
SM
791static
792void fail_tests(void)
793{
794 /* Unknown long option */
795 {
1c9a6bde 796 const struct argpar_opt_descr descrs[] = {
903a5b8a 797 { 0, '\0', "thumb", true },
1c9a6bde 798 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
799 };
800
801 test_fail(
802 "--thumb=party --meow",
803 "While parsing argument #2 (`--meow`): Unknown option `--meow`",
2af370d0 804 ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT,
903a5b8a
SM
805 descrs);
806 }
807
808 /* Unknown short option */
809 {
1c9a6bde 810 const struct argpar_opt_descr descrs[] = {
903a5b8a 811 { 0, '\0', "thumb", true },
1c9a6bde 812 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
813 };
814
815 test_fail(
816 "--thumb=party -x",
817 "While parsing argument #2 (`-x`): Unknown option `-x`",
2af370d0 818 ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT,
903a5b8a
SM
819 descrs);
820 }
821
822 /* Missing long option argument */
823 {
1c9a6bde 824 const struct argpar_opt_descr descrs[] = {
903a5b8a 825 { 0, '\0', "thumb", true },
1c9a6bde 826 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
827 };
828
829 test_fail(
830 "--thumb",
831 "While parsing argument #1 (`--thumb`): Missing required argument for option `--thumb`",
2af370d0 832 ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG,
903a5b8a
SM
833 descrs);
834 }
835
836 /* Missing short option argument */
837 {
1c9a6bde 838 const struct argpar_opt_descr descrs[] = {
903a5b8a 839 { 0, 'k', NULL, true },
1c9a6bde 840 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
841 };
842
843 test_fail(
844 "-k",
845 "While parsing argument #1 (`-k`): Missing required argument for option `-k`",
2af370d0 846 ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG,
903a5b8a
SM
847 descrs);
848 }
849
850 /* Missing short option argument (multiple glued) */
851 {
1c9a6bde 852 const struct argpar_opt_descr descrs[] = {
903a5b8a
SM
853 { 0, 'a', NULL, false },
854 { 0, 'b', NULL, false },
855 { 0, 'c', NULL, true },
1c9a6bde 856 ARGPAR_OPT_DESCR_SENTINEL
903a5b8a
SM
857 };
858
859 test_fail(
860 "-abc",
861 "While parsing argument #1 (`-abc`): Missing required argument for option `-c`",
2af370d0 862 ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG,
903a5b8a
SM
863 descrs);
864 }
865
dd757a65 866 /* Unexpected long option argument */
430fe886
SM
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`",
2af370d0 876 ARGPAR_ITER_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG,
430fe886
SM
877 descrs);
878 }
903a5b8a
SM
879}
880
881int main(void)
882{
dd757a65 883 plan_tests(423);
903a5b8a
SM
884 succeed_tests();
885 fail_tests();
886 return exit_status();
887}
This page took 0.102301 seconds and 4 git commands to generate.