1 /* Test suite for argp.
2    Copyright (C) 2006-2007, 2009-2021 Free Software Foundation, Inc.
3    This file is part of the GNUlib Library.
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; either version 3 of the License, or
8    (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
17 
18 #include <config.h>
19 
20 #include "argp.h"
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #if HAVE_STRINGS_H
26 # include <strings.h>
27 #endif
28 
29 #include "macros.h"
30 
31 struct test_args
32 {
33   int test;
34   int verbose;
35   char *file;
36   int read;
37   char *hidden;
38   int opt;
39   char *optional;
40   int optional_set;
41   int group_2_1_option;
42   int group_1_1_option;
43 };
44 
45 static struct argp_option group1_option[] = {
46   { NULL, 0, NULL, 0, "Option Group 1", 0 },
47   { "verbose", 'v', NULL, 0, "Simple option without arguments", 1 },
48   { "file", 'f', "FILE", 0, "Option with a mandatory argument", 1 },
49   { "input", 0, NULL, OPTION_ALIAS, NULL, 1 },
50   { "read", 'r', NULL, OPTION_ALIAS, NULL, 1 },
51   { "hidden", 'H', "FILE", OPTION_HIDDEN, "Hidden option", 1 },
52   { NULL, 0, NULL, 0, NULL, 0 }
53 };
54 
55 static error_t
group1_parser(int key,char * arg,struct argp_state * state)56 group1_parser (int key, char *arg, struct argp_state *state)
57 {
58   struct test_args *args = state->input;
59 
60   switch (key)
61     {
62     case 'v':
63       args->verbose++;
64       break;
65 
66     case 'r':
67       args->read = 1;
68       FALLTHROUGH;
69     case 'f':
70       args->file = arg;
71       break;
72 
73     case 'H':
74       args->hidden = arg;
75       break;
76 
77     default:
78       return ARGP_ERR_UNKNOWN;
79     }
80   return 0;
81 }
82 
83 struct argp group1_argp = {
84   group1_option,
85   group1_parser
86 };
87 
88 struct argp_child group1_child = {
89   &group1_argp,
90   0,
91   "",
92   1
93 };
94 
95 
96 static struct argp_option group1_1_option[] = {
97   { NULL, 0, NULL, 0, "Option Group 1.1", 0 },
98   { "cantiga", 'C', NULL, 0, "create a cantiga" },
99   { "sonet", 'S', NULL, 0, "create a sonet" },
100   { NULL, 0, NULL, 0, NULL, 0 }
101 };
102 
103 static error_t
group1_1_parser(int key,char * arg,struct argp_state * state)104 group1_1_parser (int key, char *arg, struct argp_state *state)
105 {
106   struct test_args *args = state->input;
107   switch (key)
108     {
109     case 'C':
110     case 'S':
111       args->group_1_1_option = key;
112       break;
113     default:
114       return ARGP_ERR_UNKNOWN;
115     }
116   return 0;
117 }
118 
119 struct argp group1_1_argp = {
120   group1_1_option,
121   group1_1_parser
122 };
123 
124 struct argp_child group1_1_child = {
125   &group1_1_argp,
126   0,
127   "",
128   2
129 };
130 
131 
132 static struct argp_option group2_option[] = {
133   { NULL, 0, NULL, 0, "Option Group 2", 0 },
134   { "option", 'O', NULL, 0, "An option", 1 },
135   { "optional", 'o', "ARG", OPTION_ARG_OPTIONAL,
136     "Option with an optional argument. ARG is one of the following:", 2 },
137   { "one", 0, NULL, OPTION_DOC | OPTION_NO_TRANS, "one unit", 3 },
138   { "two", 0, NULL, OPTION_DOC | OPTION_NO_TRANS, "two units", 3 },
139   { "many", 0, NULL, OPTION_DOC | OPTION_NO_TRANS, "many units", 3 },
140   { NULL, 0, NULL, 0, NULL, 0 }
141 };
142 
143 static error_t
group2_parser(int key,char * arg,struct argp_state * state)144 group2_parser (int key, char *arg, struct argp_state *state)
145 {
146   struct test_args *args = state->input;
147 
148   switch (key)
149     {
150     case 'O':
151       args->opt = 1;
152       break;
153 
154     case 'o':
155       args->optional_set = 1;
156       args->optional = arg;
157       break;
158 
159     default:
160       return ARGP_ERR_UNKNOWN;
161     }
162   return 0;
163 }
164 
165 struct argp group2_argp = {
166   group2_option,
167   group2_parser
168 };
169 
170 struct argp_child group2_child = {
171   &group2_argp,
172   0,
173   "",
174   2
175 };
176 
177 
178 static struct argp_option group2_1_option[] = {
179   { NULL, 0, NULL, 0, "Option Group 2.1", 0 },
180   { "poem", 'p', NULL, 0, "create a poem" },
181   { "limerick", 'l', NULL, 0, "create a limerick" },
182   { NULL, 0, NULL, 0, NULL, 0 }
183 };
184 
185 static error_t
group2_1_parser(int key,char * arg,struct argp_state * state)186 group2_1_parser (int key, char *arg, struct argp_state *state)
187 {
188   struct test_args *args = state->input;
189   switch (key)
190     {
191     case 'p':
192     case 'e':
193       args->group_2_1_option = key;
194       break;
195     default:
196       return ARGP_ERR_UNKNOWN;
197     }
198   return 0;
199 }
200 
201 struct argp group2_1_argp = {
202   group2_1_option,
203   group2_1_parser
204 };
205 
206 struct argp_child group2_1_child = {
207   &group2_1_argp,
208   0,
209   "",
210   2
211 };
212 
213 
214 static struct argp_option main_options[] = {
215   { NULL, 0, NULL, 0, "Main options", 0 },
216   { "test", 't', NULL, 0, NULL, 1 },
217   { NULL, 0, NULL, 0, NULL, 0 }
218 };
219 
220 static error_t
parse_opt(int key,char * arg,struct argp_state * state)221 parse_opt (int key, char *arg, struct argp_state *state)
222 {
223   struct test_args *args = state->input;
224   int i;
225 
226   switch (key)
227     {
228     case ARGP_KEY_INIT:
229       for (i = 0; state->root_argp->children[i].argp; i++)
230         state->child_inputs[i] = args;
231       break;
232 
233     case 't':
234       args->test = 1;
235       break;
236 
237     default:
238       return ARGP_ERR_UNKNOWN;
239     }
240   return 0;
241 }
242 
243 const char *argp_program_version = "test_argp (" PACKAGE_NAME ") " VERSION;
244 const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">";
245 static char doc[] = "documentation string";
246 
247 struct argp test_argp = {
248   main_options,
249   parse_opt,
250   "ARGS...",
251   doc,
252   NULL,
253   NULL,
254   NULL
255 };
256 
257 #define NARGS(a) (sizeof(a) / sizeof((a)[0]) - 1)
258 #define ARGV0 "test-argp"
259 #define init_args(a) memset (&(a), 0, sizeof (a));
260 
261 #define INIT_TEST_COMMON(n)     \
262  int argc = NARGS (argv);       \
263  struct test_args test_args;    \
264  init_args (test_args);         \
265  test_number = n;
266 
267 #define INIT_TEST1(n, arg1)            \
268  char *argv[] = { ARGV0, arg1, NULL }; \
269  INIT_TEST_COMMON (n)
270 
271 #define INIT_TEST2(n, arg1, arg2)            \
272  char *argv[] = { ARGV0, arg1, arg2, NULL }; \
273  INIT_TEST_COMMON (n)
274 
275 #define INIT_TEST3(n, arg1, arg2, arg3)            \
276  char *argv[] = { ARGV0, arg1, arg2, arg3, NULL }; \
277  INIT_TEST_COMMON (n)
278 
279 int test_number;
280 unsigned failure_count = 0;
281 
282 static void
fail(const char * msg)283 fail (const char *msg)
284 {
285   fprintf (stderr, "Test %d: %s\n", test_number, msg);
286   failure_count++;
287 }
288 
289 static void
test1(struct argp * argp)290 test1 (struct argp *argp)
291 {
292   INIT_TEST1 (1, "--test");
293   if (argp_parse (argp, argc, argv, 0, NULL, &test_args))
294     fail ("argp_parse failed");
295   else if (test_args.test != 1)
296     fail ("option not processed");
297 }
298 
299 static void
test2(struct argp * argp)300 test2 (struct argp *argp)
301 {
302   INIT_TEST1 (2, "-t");
303   if (argp_parse (argp, argc, argv, 0, NULL, &test_args))
304     fail ("argp_parse failed");
305   else if (test_args.test != 1)
306     fail ("option not processed");
307 }
308 
309 static void
test_file(struct argp * argp,int argc,char ** argv,struct test_args * args)310 test_file (struct argp *argp, int argc, char **argv, struct test_args *args)
311 {
312   if (argp_parse (argp, argc, argv, 0, NULL, args))
313     fail ("argp_parse failed");
314   else if (!args->file)
315     fail ("option not processed");
316   else if (strcmp (args->file, "FILE"))
317     fail ("option processed incorrectly");
318 }
319 
320 static void
test3(struct argp * argp)321 test3 (struct argp *argp)
322 {
323   INIT_TEST1 (3, "--file=FILE");
324   test_file (argp, argc, argv, &test_args);
325 }
326 
327 static void
test4(struct argp * argp)328 test4 (struct argp *argp)
329 {
330   INIT_TEST2 (4, "--file", "FILE");
331   test_file (argp, argc, argv, &test_args);
332 }
333 
334 static void
test5(struct argp * argp)335 test5 (struct argp *argp)
336 {
337   INIT_TEST1 (5, "--input=FILE");
338   test_file (argp, argc, argv, &test_args);
339 }
340 
341 static void
test6(struct argp * argp)342 test6 (struct argp *argp)
343 {
344   INIT_TEST2 (6, "--input", "FILE");
345   test_file (argp, argc, argv, &test_args);
346 }
347 
348 static void
test_optional(struct argp * argp,int argc,char ** argv,struct test_args * args,const char * val,const char * a)349 test_optional (struct argp *argp, int argc, char **argv,
350                struct test_args *args, const char *val, const char *a)
351 {
352   int index;
353   if (argp_parse (argp, argc, argv, 0, &index, args))
354     fail ("argp_parse failed");
355   else if (!args->optional_set)
356     fail ("option not processed");
357 
358   if (!val)
359     {
360       if (args->optional)
361         fail ("option processed incorrectly");
362     }
363   else if (strcmp (args->optional, val))
364     fail ("option processed incorrectly");
365 
366   if (a)
367     {
368       if (index == argc)
369         fail ("expected command line argument not found");
370       else if (strcmp (argv[index], a))
371         fail ("expected command line argument does not match");
372     }
373 }
374 
375 static void
test7(struct argp * argp)376 test7 (struct argp *argp)
377 {
378   INIT_TEST1 (7, "-oARG");
379   test_optional (argp, argc, argv, &test_args, "ARG", NULL);
380 }
381 
382 static void
test8(struct argp * argp)383 test8 (struct argp *argp)
384 {
385   INIT_TEST2 (8, "-o", "ARG");
386   test_optional (argp, argc, argv, &test_args, NULL, "ARG");
387 }
388 
389 static void
test9(struct argp * argp)390 test9 (struct argp *argp)
391 {
392   INIT_TEST1 (9, "--optional=ARG");
393   test_optional (argp, argc, argv, &test_args, "ARG", NULL);
394 }
395 
396 static void
test10(struct argp * argp)397 test10 (struct argp *argp)
398 {
399   INIT_TEST2 (10, "--optional", "ARG");
400   test_optional (argp, argc, argv, &test_args, NULL, "ARG");
401 }
402 
403 static void
test11(struct argp * argp)404 test11 (struct argp *argp)
405 {
406   INIT_TEST1 (11, "--optiona=ARG");
407   test_optional (argp, argc, argv, &test_args, "ARG", NULL);
408 }
409 
410 static void
test12(struct argp * argp)411 test12 (struct argp *argp)
412 {
413   INIT_TEST3 (12, "--option", "--optional=OPT", "FILE");
414   test_optional (argp, argc, argv, &test_args, "OPT", "FILE");
415 }
416 
417 static void
test13(struct argp * argp)418 test13 (struct argp *argp)
419 {
420   INIT_TEST1 (1, "--cantiga");
421   if (argp_parse (argp, argc, argv, 0, NULL, &test_args))
422     fail ("argp_parse failed");
423   else if (test_args.group_1_1_option != 'C')
424     fail ("option not processed");
425 }
426 
427 static void
test14(struct argp * argp)428 test14 (struct argp *argp)
429 {
430   INIT_TEST1 (1, "--limerick");
431   if (argp_parse (argp, argc, argv, 0, NULL, &test_args))
432     fail ("argp_parse failed");
433   else if (test_args.group_2_1_option != 'l')
434     fail ("option not processed");
435 }
436 
437 static void
test15(struct argp * argp)438 test15 (struct argp *argp)
439 {
440   INIT_TEST2 (1, "-r", "FILE");
441   test_file (argp, argc, argv, &test_args);
442   if (!test_args.read)
443     fail ("short alias not recognized properly");
444 }
445 
446 
447 typedef void (*test_fp) (struct argp *argp);
448 
449 static test_fp test_fun[] = {
450   test1,  test2,  test3,  test4,
451   test5,  test6,  test7,  test8,
452   test9,  test10, test11, test12,
453   test13, test14, test15,
454   NULL
455 };
456 
457 int
main(int argc,char ** argv)458 main (int argc, char **argv)
459 {
460   struct argp_child argp_children[3], group1_children[2], group2_children[2];
461   test_fp *fun;
462 
463   group1_children[0] = group1_1_child;
464   group1_children[1].argp = NULL;
465   group1_argp.children = group1_children;
466 
467   group2_children[0] = group2_1_child;
468   group2_children[1].argp = NULL;
469   group2_argp.children = group2_children;
470 
471   argp_children[0] = group1_child;
472   argp_children[1] = group2_child;
473   argp_children[2].argp = NULL;
474   test_argp.children = argp_children;
475 
476   if (argc > 0)
477     {
478       struct test_args test_args;
479       init_args (test_args);
480       return argp_parse (&test_argp, argc, argv, 0, NULL, &test_args);
481     }
482 
483   for (fun = test_fun; *fun; fun++)
484     (*fun) (&test_argp);
485 
486   if (failure_count)
487     return 1;
488 
489   return 0;
490 }
491