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