opt: wean off getopt_long, beef up tests.
[ccan] / ccan / opt / test / run-helpers.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <ccan/tap/tap.h>
4 #include <setjmp.h>
5 #include <stdlib.h>
6 #include <limits.h>
7 #include "utils.h"
8
9 /* We don't actually want it to exit... */
10 static jmp_buf exited;
11 #define exit(status) longjmp(exited, (status) + 1)
12
13 #define printf saved_printf
14 static int saved_printf(const char *fmt, ...);
15
16 #define fprintf saved_fprintf
17 static int saved_fprintf(FILE *ignored, const char *fmt, ...);
18
19 #define vfprintf(f, fmt, ap) saved_vprintf(fmt, ap)
20 static int saved_vprintf(const char *fmt, va_list ap);
21
22 #include <ccan/opt/helpers.c>
23 #include <ccan/opt/opt.c>
24 #include <ccan/opt/usage.c>
25 #include <ccan/opt/parse.c>
26
27 static void reset_options(void)
28 {
29         free(opt_table);
30         opt_table = NULL;
31         opt_count = opt_num_short = opt_num_short_arg = opt_num_long = 0;
32 }
33
34 static char *output = NULL;
35
36 static int saved_vprintf(const char *fmt, va_list ap)
37 {
38         char *p;
39         int ret = vasprintf(&p, fmt, ap);
40
41         if (output) {
42                 output = realloc(output, strlen(output) + strlen(p) + 1);
43                 strcat(output, p);
44                 free(p);
45         } else
46                 output = p;
47         return ret;
48 }
49
50 static int saved_printf(const char *fmt, ...)
51 {
52         va_list ap;
53         int ret;
54
55         va_start(ap, fmt);
56         ret = saved_vprintf(fmt, ap);
57         va_end(ap);
58         return ret;
59 }       
60
61 static int saved_fprintf(FILE *ignored, const char *fmt, ...)
62 {
63         va_list ap;
64         int ret;
65
66         va_start(ap, fmt);
67         ret = saved_vprintf(fmt, ap);
68         va_end(ap);
69         return ret;
70 }       
71
72 /* Test helpers. */
73 int main(int argc, char *argv[])
74 {
75         plan_tests(100);
76
77         /* opt_set_bool */
78         {
79                 bool arg = false;
80                 reset_options();
81                 opt_register_noarg("-a", opt_set_bool, &arg, "");
82                 ok1(parse_args(&argc, &argv, "-a", NULL));
83                 ok1(arg);
84                 opt_register_arg("-b", opt_set_bool_arg, NULL, &arg, "");
85                 ok1(parse_args(&argc, &argv, "-b", "no", NULL));
86                 ok1(!arg);
87                 ok1(parse_args(&argc, &argv, "-b", "yes", NULL));
88                 ok1(arg);
89                 ok1(parse_args(&argc, &argv, "-b", "false", NULL));
90                 ok1(!arg);
91                 ok1(parse_args(&argc, &argv, "-b", "true", NULL));
92                 ok1(arg);
93                 ok1(!parse_args(&argc, &argv, "-b", "unknown", NULL));
94                 ok1(arg);
95                 ok1(strstr(err_output, ": -b: Invalid argument 'unknown'"));
96         }
97         /* opt_set_invbool */
98         {
99                 bool arg = true;
100                 reset_options();
101                 opt_register_noarg("-a", opt_set_invbool, &arg, "");
102                 ok1(parse_args(&argc, &argv, "-a", NULL));
103                 ok1(!arg);
104                 opt_register_arg("-b", opt_set_invbool_arg, NULL,
105                                  &arg, "");
106                 ok1(parse_args(&argc, &argv, "-b", "no", NULL));
107                 ok1(arg);
108                 ok1(parse_args(&argc, &argv, "-b", "yes", NULL));
109                 ok1(!arg);
110                 ok1(parse_args(&argc, &argv, "-b", "false", NULL));
111                 ok1(arg);
112                 ok1(parse_args(&argc, &argv, "-b", "true", NULL));
113                 ok1(!arg);
114                 ok1(!parse_args(&argc, &argv, "-b", "unknown", NULL));
115                 ok1(!arg);
116                 ok1(strstr(err_output, ": -b: Invalid argument 'unknown'"));
117         }
118         /* opt_set_charp */
119         {
120                 char *arg = (char *)"wrong";
121                 reset_options();
122                 opt_register_arg("-a", opt_set_charp, NULL, &arg, "All");
123                 ok1(parse_args(&argc, &argv, "-a", "string", NULL));
124                 ok1(strcmp(arg, "string") == 0);
125         }
126         /* opt_set_intval */
127         {
128                 int arg = 1000;
129                 reset_options();
130                 opt_register_arg("-a", opt_set_intval, NULL, &arg, "All");
131                 ok1(parse_args(&argc, &argv, "-a", "9999", NULL));
132                 ok1(arg == 9999);
133                 ok1(parse_args(&argc, &argv, "-a", "-9999", NULL));
134                 ok1(arg == -9999);
135                 ok1(parse_args(&argc, &argv, "-a", "0", NULL));
136                 ok1(arg == 0);
137                 ok1(!parse_args(&argc, &argv, "-a", "100crap", NULL));
138                 if (sizeof(int) == 4)
139                         ok1(!parse_args(&argc, &argv, "-a", "4294967296", NULL));
140                 else
141                         fail("Handle other int sizes");
142         }
143         /* opt_set_uintval */
144         {
145                 unsigned int arg = 1000;
146                 reset_options();
147                 opt_register_arg("-a", opt_set_uintval, NULL, &arg, "All");
148                 ok1(parse_args(&argc, &argv, "-a", "9999", NULL));
149                 ok1(arg == 9999);
150                 ok1(!parse_args(&argc, &argv, "-a", "-9999", NULL));
151                 ok1(parse_args(&argc, &argv, "-a", "0", NULL));
152                 ok1(arg == 0);
153                 ok1(!parse_args(&argc, &argv, "-a", "100crap", NULL));
154                 ok1(!parse_args(&argc, &argv, "-a", "4294967296", NULL));
155                 if (ULONG_MAX == UINT_MAX) {
156                         pass("Can't test overflow");
157                         pass("Can't test error message");
158                 } else {
159                         char buf[30];
160                         sprintf(buf, "%lu", ULONG_MAX);
161                         ok1(!parse_args(&argc, &argv, "-a", buf, NULL));
162                         ok1(strstr(err_output, ": -a: value '")
163                             && strstr(err_output, buf)
164                             && strstr(err_output, "' does not fit into an integer"));
165                 }
166         }
167         /* opt_set_longval */
168         {
169                 long int arg = 1000;
170                 reset_options();
171                 opt_register_arg("-a", opt_set_longval, NULL, &arg, "All");
172                 ok1(parse_args(&argc, &argv, "-a", "9999", NULL));
173                 ok1(arg == 9999);
174                 ok1(parse_args(&argc, &argv, "-a", "-9999", NULL));
175                 ok1(arg == -9999);
176                 ok1(parse_args(&argc, &argv, "-a", "0", NULL));
177                 ok1(arg == 0);
178                 ok1(!parse_args(&argc, &argv, "-a", "100crap", NULL));
179                 if (sizeof(long) == 4)
180                         ok1(!parse_args(&argc, &argv, "-a", "4294967296", NULL));
181                 else if (sizeof(long)== 8)
182                         ok1(!parse_args(&argc, &argv, "-a", "18446744073709551616", NULL));
183                 else
184                         fail("FIXME: Handle other long sizes");
185         }
186         /* opt_set_ulongval */
187         {
188                 unsigned long int arg = 1000;
189                 reset_options();
190                 opt_register_arg("-a", opt_set_ulongval, NULL, &arg, "All");
191                 ok1(parse_args(&argc, &argv, "-a", "9999", NULL));
192                 ok1(arg == 9999);
193                 ok1(!parse_args(&argc, &argv, "-a", "-9999", NULL));
194                 ok1(parse_args(&argc, &argv, "-a", "0", NULL));
195                 ok1(arg == 0);
196                 ok1(!parse_args(&argc, &argv, "-a", "100crap", NULL));
197                 if (sizeof(long) == 4)
198                         ok1(!parse_args(&argc, &argv, "-a", "4294967296", NULL));
199                 else if (sizeof(long)== 8)
200                         ok1(!parse_args(&argc, &argv, "-a", "18446744073709551616", NULL));
201                 else
202                         fail("FIXME: Handle other long sizes");
203         }
204         /* opt_inc_intval */
205         {
206                 int arg = 1000;
207                 reset_options();
208                 opt_register_noarg("-a", opt_inc_intval, &arg, "");
209                 ok1(parse_args(&argc, &argv, "-a", NULL));
210                 ok1(arg == 1001);
211                 ok1(parse_args(&argc, &argv, "-a", "-a", NULL));
212                 ok1(arg == 1003);
213                 ok1(parse_args(&argc, &argv, "-aa", NULL));
214                 ok1(arg == 1005);
215         }
216
217         /* opt_show_version_and_exit. */
218         {
219                 int exitval;
220                 reset_options();
221                 opt_register_noarg("-a",
222                                    opt_version_and_exit, "1.2.3", "");
223                 exitval = setjmp(exited);
224                 if (exitval == 0) {
225                         parse_args(&argc, &argv, "-a", NULL);
226                         fail("opt_show_version_and_exit returned?");
227                 } else {
228                         ok1(exitval - 1 == 0);
229                 }
230                 ok1(strcmp(output, "1.2.3\n") == 0);
231                 free(output);
232                 output = NULL;
233         }
234
235         /* opt_usage_and_exit. */
236         {
237                 int exitval;
238                 reset_options();
239                 opt_register_noarg("-a",
240                                    opt_usage_and_exit, "[args]", "");
241                 exitval = setjmp(exited);
242                 if (exitval == 0) {
243                         parse_args(&argc, &argv, "-a", NULL);
244                         fail("opt_usage_and_exit returned?");
245                 } else {
246                         ok1(exitval - 1 == 0);
247                 }
248                 ok1(strstr(output, "[args]"));
249                 ok1(strstr(output, argv[0]));
250                 ok1(strstr(output, "[-a]"));
251                 free(output);
252                 output = NULL;
253         }
254
255         /* opt_show_bool */
256         {
257                 bool b;
258                 char buf[OPT_SHOW_LEN+2] = { 0 };
259                 buf[OPT_SHOW_LEN] = '!';
260
261                 b = true;
262                 opt_show_bool(buf, &b);
263                 ok1(strcmp(buf, "true") == 0);
264                 ok1(buf[OPT_SHOW_LEN] == '!');
265
266                 b = false;
267                 opt_show_bool(buf, &b);
268                 ok1(strcmp(buf, "false") == 0);
269                 ok1(buf[OPT_SHOW_LEN] == '!');
270         }
271
272         /* opt_show_invbool */
273         {
274                 bool b;
275                 char buf[OPT_SHOW_LEN+2] = { 0 };
276                 buf[OPT_SHOW_LEN] = '!';
277
278                 b = true;
279                 opt_show_invbool(buf, &b);
280                 ok1(strcmp(buf, "false") == 0);
281                 ok1(buf[OPT_SHOW_LEN] == '!');
282
283                 b = false;
284                 opt_show_invbool(buf, &b);
285                 ok1(strcmp(buf, "true") == 0);
286                 ok1(buf[OPT_SHOW_LEN] == '!');
287         }
288
289         /* opt_show_charp */
290         {
291                 char str[OPT_SHOW_LEN*2], *p;
292                 char buf[OPT_SHOW_LEN+2] = { 0 };
293                 buf[OPT_SHOW_LEN] = '!';
294
295                 /* Short test. */
296                 p = str;
297                 strcpy(p, "short");
298                 opt_show_charp(buf, &p);
299                 ok1(strcmp(buf, "\"short\"") == 0);
300                 ok1(buf[OPT_SHOW_LEN] == '!');
301
302                 /* Truncate test. */
303                 memset(p, 'x', OPT_SHOW_LEN*2);
304                 p[OPT_SHOW_LEN*2-1] = '\0';
305                 opt_show_charp(buf, &p);
306                 ok1(buf[0] == '"');
307                 ok1(buf[OPT_SHOW_LEN-1] == '"');
308                 ok1(buf[OPT_SHOW_LEN] == '!');
309                 ok1(strspn(buf+1, "x") == OPT_SHOW_LEN-2);
310         }
311
312         /* opt_show_intval */
313         {
314                 int i;
315                 char buf[OPT_SHOW_LEN+2] = { 0 };
316                 buf[OPT_SHOW_LEN] = '!';
317
318                 i = -77;
319                 opt_show_intval(buf, &i);
320                 ok1(strcmp(buf, "-77") == 0);
321                 ok1(buf[OPT_SHOW_LEN] == '!');
322
323                 i = 77;
324                 opt_show_intval(buf, &i);
325                 ok1(strcmp(buf, "77") == 0);
326                 ok1(buf[OPT_SHOW_LEN] == '!');
327         }
328
329         /* opt_show_uintval */
330         {
331                 unsigned int ui;
332                 char buf[OPT_SHOW_LEN+2] = { 0 };
333                 buf[OPT_SHOW_LEN] = '!';
334
335                 ui = 4294967295U;
336                 opt_show_uintval(buf, &ui);
337                 ok1(strcmp(buf, "4294967295") == 0);
338                 ok1(buf[OPT_SHOW_LEN] == '!');
339         }
340
341         /* opt_show_longval */
342         {
343                 long l;
344                 char buf[OPT_SHOW_LEN+2] = { 0 };
345                 buf[OPT_SHOW_LEN] = '!';
346
347                 l = 1234567890L;
348                 opt_show_longval(buf, &l);
349                 ok1(strcmp(buf, "1234567890") == 0);
350                 ok1(buf[OPT_SHOW_LEN] == '!');
351         }
352
353         /* opt_show_ulongval */
354         {
355                 unsigned long ul;
356                 char buf[OPT_SHOW_LEN+2] = { 0 };
357                 buf[OPT_SHOW_LEN] = '!';
358
359                 ul = 4294967295UL;
360                 opt_show_ulongval(buf, &ul);
361                 ok1(strcmp(buf, "4294967295") == 0);
362                 ok1(buf[OPT_SHOW_LEN] == '!');
363         }
364
365         /* opt_log_stderr. */
366         {
367                 reset_options();
368                 opt_register_noarg("-a",
369                                    opt_usage_and_exit, "[args]", "");
370
371                 argc = 2;
372                 argv = malloc(sizeof(argv[0]) * 3);
373                 argv[0] = "thisprog";
374                 argv[1] = "--garbage";
375                 argv[2] = NULL;
376                 ok1(!opt_parse(&argc, argv, opt_log_stderr));
377                 ok1(!strcmp(output,
378                             "thisprog: --garbage: unrecognized option\n"));
379                 free(output);
380                 output = NULL;
381         }
382
383         /* opt_log_stderr_exit. */
384         {
385                 int exitval;
386                 reset_options();
387                 opt_register_noarg("-a",
388                                    opt_usage_and_exit, "[args]", "");
389                 exitval = setjmp(exited);
390                 if (exitval == 0) {
391                         argc = 2;
392                         argv = malloc(sizeof(argv[0]) * 3);
393                         argv[0] = "thisprog";
394                         argv[1] = "--garbage";
395                         argv[2] = NULL;
396                         opt_parse(&argc, argv, opt_log_stderr_exit);
397                         fail("opt_log_stderr_exit returned?");
398                 } else {
399                         ok1(exitval - 1 == 1);
400                 }
401                 ok1(!strcmp(output,
402                             "thisprog: --garbage: unrecognized option\n"));
403                 free(output);
404                 output = NULL;
405         }
406
407         return exit_status();
408 }