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