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